Chromium Code Reviews| Index: client/html/src/ElementWrappingImplementation.dart |
| diff --git a/client/html/src/ElementWrappingImplementation.dart b/client/html/src/ElementWrappingImplementation.dart |
| index 6f33dc949e91339d206082c9b3d3495c047f761c..dc5f39c18b7c26d40047c039808f556ad27d79d3 100644 |
| --- a/client/html/src/ElementWrappingImplementation.dart |
| +++ b/client/html/src/ElementWrappingImplementation.dart |
| @@ -411,20 +411,120 @@ class ElementEventsImplementation extends EventsImplementation implements Elemen |
| EventListenerList get touchMove() => _get("touchmove"); |
| EventListenerList get touchStart() => _get("touchstart"); |
| EventListenerList get transitionEnd() => _get("webkitTransitionEnd"); |
| - EventListenerList get fullscreenChange() => _get("fullscreenchange"); |
| + EventListenerList get fullscreenChange() => _get("webkitfullscreenchange"); |
| +} |
| + |
| +class SimpleClientRect implements ClientRect { |
| + final num left; |
| + final num top; |
| + final num width; |
| + final num height; |
| + num get right() => left + width; |
| + num get bottom() => top + height; |
| + |
| + const SimpleClientRect(this.left, this.top, this.width, this.height); |
| + |
| + bool operator ==(ClientRect other) { |
| + return other !== null && left == other.left && top == other.top |
| + && width == other.width && height == other.height; |
| + } |
| + |
| + String toString() => "($left, $top, $width, $height)"; |
|
nweiz
2011/10/28 03:58:38
Might we want this to indicate that the object in
Jacob
2011/10/31 22:09:50
Chatted with the rest of the team over here are ou
nweiz
2011/11/01 00:49:22
In my experience, "what is this object I have?" is
Jacob
2011/11/01 02:42:39
Agreed. Lets take that discussion to the style gui
|
| +} |
| + |
| +// 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 |
| + */ |
| +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 dom.ClientRectList _clientRects; |
| + |
| + ElementRectWrappingImplementation(dom.HTMLElement element) : |
| + client = new SimpleClientRect(element.clientLeft, |
| + element.clientTop, |
|
nweiz
2011/10/28 03:58:38
Isn't the correct indentation four spaces farther
Jacob
2011/10/31 22:09:50
fixed the busted indentation.
I did a find and rep
|
| + 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); |
| + |
| + 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)); |
| + } |
| + return out; |
| + } |
| } |
| class ElementWrappingImplementation extends NodeWrappingImplementation implements Element { |
| + |
| + static final _START_TAG_REGEXP = const RegExp('<(\\w+)'); |
| + static final _CUSTOM_PARENT_TAG_MAP = const { |
| + 'body' : 'html', |
| + 'head' : 'html', |
| + 'caption' : 'table', |
| + 'td': 'tr', |
| + 'tbody': 'table', |
| + 'colgroup': 'table', |
| + 'col' : 'colgroup', |
| + 'tr' : 'tbody', |
| + 'tbody' : 'table', |
| + 'tfoot' : 'table', |
| + 'thead' : 'table', |
| + 'track' : 'audio', |
| + }; |
| factory ElementWrappingImplementation.html(String html) { |
| - final temp = dom.document.createElement('div'); |
| + // TODO(jacobr): this method can be made more robust and performant. |
| + // 1) Cache the dummy parent elements required to use innerHTML rather than |
| + // creating them every call. |
| + // 2) Verify that the html does not contain leading or trailing text nodes. |
| + // 3) Verify that the html does not contain both <head> and <body> tags. |
| + // 4) Detatch the created element from its dummy parent. |
| + String parentTag = 'div'; |
| + String tag; |
| + final match = _START_TAG_REGEXP.firstMatch(html); |
| + if (null != match) { |
|
nweiz
2011/10/28 03:58:38
Style nit: match != null here and elsewhere.
Jacob
2011/10/31 22:09:50
null != foo is faster
than foo != null
I agree th
nweiz
2011/11/01 00:49:22
That definitely seems like a problem for the compi
|
| + tag = match.group(1).toLowerCase(); |
| + if (_CUSTOM_PARENT_TAG_MAP.containsKey(tag)) { |
| + parentTag = _CUSTOM_PARENT_TAG_MAP[tag]; |
| + } |
| + } |
| + final temp = dom.document.createElement(parentTag); |
| temp.innerHTML = html; |
| - if (temp.childElementCount != 1) { |
| + if (temp.childElementCount == 1) { |
| + return LevelDom.wrapElement(temp.firstElementChild); |
| + } else if (parentTag == 'html' && temp.childElementCount == 2) { |
| + // Work around for edge case in WebKit and possibly other browsers where |
| + // both body and head elements are created even though the inner html |
| + // only contains a head or body element. |
| + return LevelDom.wrapElement(temp.children.item(tag == 'head' ? 0 : 1)); |
| + } else { |
| throw 'HTML had ${temp.childElementCount} top level elements but 1 expected'; |
| } |
| - |
| - return LevelDom.wrapElement(temp.firstElementChild); |
| } |
| factory ElementWrappingImplementation.tag(String tag) { |
| @@ -496,14 +596,6 @@ class ElementWrappingImplementation extends NodeWrappingImplementation implement |
| } |
| } |
| - int get clientHeight() => _ptr.clientHeight; |
| - |
| - int get clientLeft() => _ptr.clientLeft; |
| - |
| - int get clientTop() => _ptr.clientTop; |
| - |
| - int get clientWidth() => _ptr.clientWidth; |
| - |
| String get contentEditable() => _ptr.contentEditable; |
| void set contentEditable(String value) { _ptr.contentEditable = value; } |
| @@ -540,32 +632,12 @@ class ElementWrappingImplementation extends NodeWrappingImplementation implement |
| Element get nextElementSibling() => LevelDom.wrapElement(_ptr.nextElementSibling); |
| - int get offsetHeight() => _ptr.offsetHeight; |
| - |
| - int get offsetLeft() => _ptr.offsetLeft; |
| - |
| Element get offsetParent() => LevelDom.wrapElement(_ptr.offsetParent); |
| - int get offsetTop() => _ptr.offsetTop; |
| - |
| - int get offsetWidth() => _ptr.offsetWidth; |
| - |
| String get outerHTML() => _ptr.outerHTML; |
| Element get previousElementSibling() => LevelDom.wrapElement(_ptr.previousElementSibling); |
| - int get scrollHeight() => _ptr.scrollHeight; |
| - |
| - int get scrollLeft() => _ptr.scrollLeft; |
| - |
| - void set scrollLeft(int value) { _ptr.scrollLeft = value; } |
| - |
| - int get scrollTop() => _ptr.scrollTop; |
| - |
| - void set scrollTop(int value) { _ptr.scrollTop = value; } |
| - |
| - int get scrollWidth() => _ptr.scrollWidth; |
| - |
| bool get spellcheck() => _ptr.spellcheck; |
| void set spellcheck(bool value) { _ptr.spellcheck = value; } |
| @@ -598,19 +670,6 @@ class ElementWrappingImplementation extends NodeWrappingImplementation implement |
| _ptr.focus(); |
| } |
| - ClientRect getBoundingClientRect() { |
| - return LevelDom.wrapClientRect(_ptr.getBoundingClientRect()); |
| - } |
| - |
| - List<ClientRect> getClientRects() { |
| - var rects = _ptr.getClientRects(); |
| - var out = new List(rects.length); |
| - for (var i = 0; i < rects.length; i++) { |
| - out.add(LevelDom.wrapClientRect(rects.item(i))); |
| - } |
| - return out; |
| - } |
| - |
| Element insertAdjacentElement([String where = null, Element element = null]) { |
| return LevelDom.wrapElement(_ptr.insertAdjacentElement(where, LevelDom.unwrap(element))); |
| } |
| @@ -649,6 +708,28 @@ class ElementWrappingImplementation extends NodeWrappingImplementation implement |
| return _ptr.webkitMatchesSelector(selectors); |
| } |
| + void set scrollLeft(int value) { _ptr.scrollLeft = value; } |
| + |
| + void set scrollTop(int value) { _ptr.scrollTop = value; } |
| + |
| + Future<ElementRect> get rect() { |
| + return _createMeasurementFuture( |
| + () => new ElementRectWrappingImplementation(_ptr), |
| + new Completer<ElementRect>()); |
| + } |
| + |
| + Future<CSSStyleDeclaration> get computedStyle() { |
| + // TODO(jacobr): last param should be null, see b/5045788 |
| + return getComputedStyle(''); |
| + } |
| + |
| + Future<CSSStyleDeclaration> getComputedStyle(String pseudoElement) { |
| + return _createMeasurementFuture(() => |
| + LevelDom.wrapCSSStyleDeclaration( |
| + dom.window.getComputedStyle(_ptr, pseudoElement)), |
| + new Completer<CSSStyleDeclaration>()); |
| + } |
| + |
| ElementEvents get on() { |
| if (_on === null) { |
| _on = new ElementEventsImplementation._wrap(_ptr); |