Chromium Code Reviews| Index: client/html/src/ElementWrappingImplementation.dart |
| diff --git a/client/html/src/ElementWrappingImplementation.dart b/client/html/src/ElementWrappingImplementation.dart |
| index 38b82dff028c94a10426cd2c1c21c7c9095387d1..b514ff6542507b0caf998cd0582e596cf35ade80 100644 |
| --- a/client/html/src/ElementWrappingImplementation.dart |
| +++ b/client/html/src/ElementWrappingImplementation.dart |
| @@ -1,4 +1,4 @@ |
| -// Copyright (c) 2011, the Dart project authors. Please see the AUTHORS file |
| +// Copyright (c) 2012, the Dart project authors. Please see the AUTHORS file |
| // for details. All rights reserved. Use of this source code is governed by a |
| // BSD-style license that can be found in the LICENSE file. |
| @@ -12,6 +12,7 @@ class _ChildrenElementList implements ElementList { |
| : _childElements = element.children, |
| _element = element; |
| + bool get _inDocument() => _nodeInDocument(_element); |
| List<Element> _toList() { |
| final output = new List(_childElements.length); |
| for (int i = 0, len = _childElements.length; i < len; i++) { |
| @@ -79,6 +80,7 @@ class _ChildrenElementList implements ElementList { |
| } |
| void operator []=(int index, Element value) { |
| + assert(!_inMeasurementFrame || (!_inDocument && !value._inDocument)); |
| _element.replaceChild(LevelDom.unwrap(value), _childElements.item(index)); |
| } |
| @@ -88,6 +90,7 @@ class _ChildrenElementList implements ElementList { |
| } |
| Element add(Element value) { |
| + assert(!_inMeasurementFrame || (!_inDocument && !value._inDocument)); |
| _element.appendChild(LevelDom.unwrap(value)); |
| return value; |
| } |
| @@ -97,7 +100,9 @@ class _ChildrenElementList implements ElementList { |
| Iterator<Element> iterator() => _toList().iterator(); |
| void addAll(Collection<Element> collection) { |
| + assert(!_inMeasurementFrame || !_inDocument); |
| for (Element element in collection) { |
| + assert(!_inMeasurementFrame || !element._inDocument); |
| _element.appendChild(LevelDom.unwrap(element)); |
| } |
| } |
| @@ -136,11 +141,13 @@ class _ChildrenElementList implements ElementList { |
| } |
| void clear() { |
| + assert(!_inMeasurementFrame || !_inDocument); |
| // It is unclear if we want to keep non element nodes? |
| _element.textContent = ''; |
| } |
| Element removeLast() { |
| + assert(!_inMeasurementFrame || !_inDocument); |
| final last = this.last(); |
| if (last != null) { |
| _element.removeChild(LevelDom.unwrap(last)); |
| @@ -327,10 +334,12 @@ class ElementAttributeMap implements Map<String, String> { |
| } |
| String remove(String key) { |
| + assert(!_inMeasurementFrame || !_nodeInDocument(_element)); |
| _element.removeAttribute(key); |
| } |
| void clear() { |
| + assert(!_inMeasurementFrame || !_nodeInDocument(_element)); |
| final attributes = _element.attributes; |
| for (int i = attributes.length - 1; i >= 0; i--) { |
| _element.removeAttribute(attributes.item(i).name); |
| @@ -449,48 +458,52 @@ class SimpleClientRect implements ClientRect { |
| String toString() => "($left, $top, $width, $height)"; |
| } |
| -// TODO(jacobr): we cannot currently be lazy about calculating the client |
| -// rects as we must perform all measurement queries at a safe point to avoid |
| -// triggering unneeded layouts. |
| /** |
| - * All your element measurement needs in one place |
| + * All your element measurement needs in one place. |
| + * All members of this class can only be cassed when inside a measurement |
| + * frame or when the element is not attached to the DOM. |
| * @domName none |
| */ |
| class ElementRectWrappingImplementation implements ElementRect { |
| - final ClientRect client; |
| - final ClientRect offset; |
| - final ClientRect scroll; |
| - |
| - // TODO(jacobr): should we move these outside of ElementRect to avoid the |
| - // overhead of computing them every time even though they are rarely used. |
| - // This should be type dom.ClientRect but that fails on dartium. b/5522629 |
| - final _boundingClientRect; |
| - // an exception due to a dartium bug. |
| - final _clientRects; // TODO(jacobr): should be dom.ClientRectList |
| - |
| - ElementRectWrappingImplementation(dom.HTMLElement element) : |
| - client = new SimpleClientRect(element.clientLeft, |
| - element.clientTop, |
| - element.clientWidth, |
| - element.clientHeight), |
| - offset = new SimpleClientRect(element.offsetLeft, |
| - element.offsetTop, |
| - element.offsetWidth, |
| - element.offsetHeight), |
| - scroll = new SimpleClientRect(element.scrollLeft, |
| - element.scrollTop, |
| - element.scrollWidth, |
| - element.scrollHeight), |
| - _boundingClientRect = element.getBoundingClientRect(), |
| - _clientRects = element.getClientRects(); |
| - |
| - ClientRect get bounding() => |
| - LevelDom.wrapClientRect(_boundingClientRect); |
| + final dom.HTMLElement _element; |
| + |
| + ElementRectWrappingImplementation(this._element); |
| + |
| + ClientRect get client() { |
| + assert(window.inMeasurementFrame || !_nodeInDocument(_element)); |
| + return new SimpleClientRect(_element.clientLeft, |
| + _element.clientTop, |
| + _element.clientWidth, |
| + _element.clientHeight); |
| + } |
| + |
| + ClientRect get offset() { |
| + assert(window.inMeasurementFrame || !_nodeInDocument(_element)); |
| + return new SimpleClientRect(_element.offsetLeft, |
| + _element.offsetTop, |
| + _element.offsetWidth, |
| + _element.offsetHeight); |
| + } |
| + |
| + ClientRect get scroll() { |
| + assert(window.inMeasurementFrame || !_nodeInDocument(_element)); |
| + return new SimpleClientRect(_element.scrollLeft, |
| + _element.scrollTop, |
| + _element.scrollWidth, |
| + _element.scrollHeight); |
| + } |
| + |
| + ClientRect get bounding() { |
| + assert(window.inMeasurementFrame || !_nodeInDocument(_element)); |
| + return LevelDom.wrapClientRect(_element.getBoundingClientRect()); |
| + } |
| List<ClientRect> get clientRects() { |
| - final out = new List(_clientRects.length); |
| - for (num i = 0; i < _clientRects.length; i++) { |
| - out[i] = LevelDom.wrapClientRect(_clientRects.item(i)); |
| + assert(window.inMeasurementFrame || !_nodeInDocument(_element)); |
| + final clientRects = _element.getClientRects(); |
| + final out = new List(clientRects.length); |
| + for (num i = 0, len = clientRects.length; i < len; i++) { |
| + out[i] = LevelDom.wrapClientRect(clientRects.item(i)); |
| } |
| return out; |
| } |
| @@ -574,6 +587,7 @@ class ElementWrappingImplementation extends NodeWrappingImplementation implement |
| } |
| void set attributes(Map<String, String> value) { |
| + assert(!_inMeasurementFrame || !_inDocument); |
| Map<String, String> attributes = this.attributes; |
| attributes.clear(); |
| for (String key in value.getKeys()) { |
| @@ -582,6 +596,7 @@ class ElementWrappingImplementation extends NodeWrappingImplementation implement |
| } |
| void set elements(Collection<Element> value) { |
| + assert(!_inMeasurementFrame || !_inDocument); |
| final elements = this.elements; |
| elements.clear(); |
| elements.addAll(value); |
| @@ -607,6 +622,7 @@ class ElementWrappingImplementation extends NodeWrappingImplementation implement |
| } |
| void set classes(Collection<String> value) { |
| + assert(!_inMeasurementFrame || !_inDocument); |
| _CssClassSet classSet = classes; |
| classSet.clear(); |
| classSet.addAll(value); |
| @@ -620,6 +636,7 @@ class ElementWrappingImplementation extends NodeWrappingImplementation implement |
| } |
| void set dataAttributes(Map<String, String> value) { |
| + assert(!_inMeasurementFrame || !_inDocument); |
| Map<String, String> dataAttributes = this.dataAttributes; |
| dataAttributes.clear(); |
| for (String key in value.getKeys()) { |
| @@ -629,11 +646,15 @@ class ElementWrappingImplementation extends NodeWrappingImplementation implement |
| String get contentEditable() => _ptr.contentEditable; |
| + // TODO(jacobr): does this dirty the layout? |
|
arv (Not doing code reviews)
2012/01/17 20:25:00
Yes it does
Jacob
2012/01/21 03:01:25
Done.
|
| void set contentEditable(String value) { _ptr.contentEditable = value; } |
| String get dir() => _ptr.dir; |
| - void set dir(String value) { _ptr.dir = value; } |
| + void set dir(String value) { |
| + assert(!_inMeasurementFrame || !_inDocument); |
| + _ptr.dir = value; |
| + } |
| bool get draggable() => _ptr.draggable; |
| @@ -643,21 +664,33 @@ class ElementWrappingImplementation extends NodeWrappingImplementation implement |
| bool get hidden() => _ptr.hidden; |
| - void set hidden(bool value) { _ptr.hidden = value; } |
| + void set hidden(bool value) { |
| + assert(!_inMeasurementFrame || !_inDocument); |
| + _ptr.hidden = value; |
| + } |
| String get id() => _ptr.id; |
| - void set id(String value) { _ptr.id = value; } |
| + void set id(String value) { |
| + assert(!_inMeasurementFrame || !_inDocument); |
| + _ptr.id = value; |
| + } |
| String get innerHTML() => _ptr.innerHTML; |
| - void set innerHTML(String value) { _ptr.innerHTML = value; } |
| + void set innerHTML(String value) { |
| + assert(!_inMeasurementFrame || !_inDocument); |
| + _ptr.innerHTML = value; |
| + } |
| bool get isContentEditable() => _ptr.isContentEditable; |
| String get lang() => _ptr.lang; |
| - void set lang(String value) { _ptr.lang = value; } |
| + void set lang(String value) { |
| + assert(!_inMeasurementFrame || !_inDocument); |
| + _ptr.lang = value; |
| + } |
| Element get lastElementChild() => LevelDom.wrapElement(_ptr.lastElementChild); |
| @@ -671,25 +704,46 @@ class ElementWrappingImplementation extends NodeWrappingImplementation implement |
| bool get spellcheck() => _ptr.spellcheck; |
| - void set spellcheck(bool value) { _ptr.spellcheck = value; } |
| + void set spellcheck(bool value) { |
| + assert(!_inMeasurementFrame || !_inDocument); |
| + _ptr.spellcheck = value; |
| + } |
| - CSSStyleDeclaration get style() => LevelDom.wrapCSSStyleDeclaration(_ptr.style); |
| + CSSStyleDeclaration get style() { |
| + // Changes to this CSSStyleDeclaration dirty the layout so we must pass |
| + // the associated Element to the CSSStyleDeclaration constructor so that |
| + // we can compute whether the current element is attached to the document |
| + // which is required to decide whether modification inside a measurement |
| + // frame is allowed. |
| + final raw = _ptr.style; |
| + return raw.dartObjectLocalStorage !== null ? |
| + raw.dartObjectLocalStorage : |
| + new CSSStyleDeclarationWrappingImplementation._wrapWithElement( |
| + raw, this); |
| + } |
| int get tabIndex() => _ptr.tabIndex; |
| - void set tabIndex(int value) { _ptr.tabIndex = value; } |
| + void set tabIndex(int value) { |
| + assert(!_inMeasurementFrame || !_inDocument); |
| + _ptr.tabIndex = value; |
| + } |
| String get tagName() => _ptr.tagName; |
| String get title() => _ptr.title; |
| - void set title(String value) { _ptr.title = value; } |
| + void set title(String value) { |
| + assert(!_inMeasurementFrame || !_inDocument); |
| + _ptr.title = value; |
| + } |
| String get webkitdropzone() => _ptr.webkitdropzone; |
| void set webkitdropzone(String value) { _ptr.webkitdropzone = value; } |
| void blur() { |
| + assert(!_inMeasurementFrame || !_inDocument); |
| _ptr.blur(); |
| } |
| @@ -698,18 +752,22 @@ class ElementWrappingImplementation extends NodeWrappingImplementation implement |
| } |
| void focus() { |
| + assert(!_inMeasurementFrame || !_inDocument); |
| _ptr.focus(); |
| } |
| Element insertAdjacentElement([String where = null, Element element = null]) { |
| + assert(!_inMeasurementFrame || !_inDocument); |
| return LevelDom.wrapElement(_ptr.insertAdjacentElement(where, LevelDom.unwrap(element))); |
| } |
| void insertAdjacentHTML([String position_OR_where = null, String text = null]) { |
| + assert(!_inMeasurementFrame || !_inDocument); |
| _ptr.insertAdjacentHTML(position_OR_where, text); |
| } |
| void insertAdjacentText([String where = null, String text = null]) { |
| + assert(!_inMeasurementFrame || !_inDocument); |
| _ptr.insertAdjacentText(where, text); |
| } |
| @@ -754,24 +812,21 @@ class ElementWrappingImplementation extends NodeWrappingImplementation implement |
| * clientTop, clientLeft, offsetHeight, offsetWidth, offsetTop, offsetLeft, |
| * scrollHeight, scrollWidth, scrollTop, scrollLeft |
| */ |
| - Future<ElementRect> get rect() { |
| - return _createMeasurementFuture( |
| - () => new ElementRectWrappingImplementation(_ptr), |
| - new Completer<ElementRect>()); |
| + ElementRect get rect() { |
| + return new ElementRectWrappingImplementation(_ptr); |
| } |
| /** @domName Window.getComputedStyle */ |
| - Future<CSSStyleDeclaration> get computedStyle() { |
| + CSSStyleDeclaration get computedStyle() { |
| // TODO(jacobr): last param should be null, see b/5045788 |
| - return getComputedStyle(''); |
| + return getComputedStyle(''); |
| } |
| /** @domName Window.getComputedStyle */ |
| - Future<CSSStyleDeclaration> getComputedStyle(String pseudoElement) { |
| - return _createMeasurementFuture(() => |
| - LevelDom.wrapCSSStyleDeclaration( |
| - dom.window.getComputedStyle(_ptr, pseudoElement)), |
| - new Completer<CSSStyleDeclaration>()); |
| + CSSStyleDeclaration getComputedStyle(String pseudoElement) { |
| + assert(window.inMeasurementFrame || !_inDocument); |
| + return LevelDom.wrapCSSStyleDeclaration( |
| + dom.window.getComputedStyle(_ptr, pseudoElement)); |
| } |
| ElementEvents get on() { |