Index: client/html/src/ElementWrappingImplementation.dart |
diff --git a/client/html/src/ElementWrappingImplementation.dart b/client/html/src/ElementWrappingImplementation.dart |
index 8f9abb72c0912f01c9f612180b4ec7d5751087e5..5220caaa8dc97e9e282ddfeb85c385bf3267c48e 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++) { |
@@ -61,6 +62,7 @@ class _ChildrenElementList implements ElementList { |
} |
void operator []=(int index, Element value) { |
+ assert(!_inMeasurementFrame || (!_inDocument && !value._inDocument)); |
_element.replaceChild(LevelDom.unwrap(value), _childElements.item(index)); |
} |
@@ -70,6 +72,7 @@ class _ChildrenElementList implements ElementList { |
} |
Element add(Element value) { |
+ assert(!_inMeasurementFrame || (!_inDocument && !value._inDocument)); |
_element.appendChild(LevelDom.unwrap(value)); |
return value; |
} |
@@ -79,7 +82,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)); |
} |
} |
@@ -114,11 +119,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)); |
@@ -312,10 +319,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); |
@@ -434,48 +443,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; |
} |
@@ -559,6 +572,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()) { |
@@ -567,6 +581,7 @@ class ElementWrappingImplementation extends NodeWrappingImplementation implement |
} |
void set elements(Collection<Element> value) { |
+ assert(!_inMeasurementFrame || !_inDocument); |
final elements = this.elements; |
elements.clear(); |
elements.addAll(value); |
@@ -592,6 +607,7 @@ class ElementWrappingImplementation extends NodeWrappingImplementation implement |
} |
void set classes(Collection<String> value) { |
+ assert(!_inMeasurementFrame || !_inDocument); |
_CssClassSet classSet = classes; |
classSet.clear(); |
classSet.addAll(value); |
@@ -605,6 +621,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()) { |
@@ -614,11 +631,17 @@ class ElementWrappingImplementation extends NodeWrappingImplementation implement |
String get contentEditable() => _ptr.contentEditable; |
- void set contentEditable(String value) { _ptr.contentEditable = value; } |
+ void set contentEditable(String value) { |
+ assert(!_inMeasurementFrame || !_inDocument); |
+ _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; |
@@ -628,21 +651,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); |
@@ -656,25 +691,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(); |
} |
@@ -683,18 +739,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); |
} |
@@ -739,24 +799,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() { |