Index: sdk/lib/html/templates/html/impl/impl_Element.darttemplate |
diff --git a/sdk/lib/html/templates/html/impl/impl_Element.darttemplate b/sdk/lib/html/templates/html/impl/impl_Element.darttemplate |
deleted file mode 100644 |
index f05eb15fdd55cc6383adf13ee8d3536d9049509a..0000000000000000000000000000000000000000 |
--- a/sdk/lib/html/templates/html/impl/impl_Element.darttemplate |
+++ /dev/null |
@@ -1,781 +0,0 @@ |
-// 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. |
- |
-part of html; |
- |
-// TODO(jacobr): use _Lists.dart to remove some of the duplicated |
-// functionality. |
-class _ChildrenElementList implements List { |
- // Raw Element. |
- final Element _element; |
- final HtmlCollection _childElements; |
- |
- _ChildrenElementList._wrap(Element element) |
- : _childElements = element.$dom_children, |
- _element = element; |
- |
- List<Element> _toList() { |
- final output = new List(_childElements.length); |
- for (int i = 0, len = _childElements.length; i < len; i++) { |
- output[i] = _childElements[i]; |
- } |
- return output; |
- } |
- |
- bool contains(Element element) => _childElements.contains(element); |
- |
- void forEach(void f(Element element)) { |
- for (Element element in _childElements) { |
- f(element); |
- } |
- } |
- |
- List<Element> filter(bool f(Element element)) { |
- final output = []; |
- forEach((Element element) { |
- if (f(element)) { |
- output.add(element); |
- } |
- }); |
- return new _FrozenElementList._wrap(output); |
- } |
- |
- bool every(bool f(Element element)) { |
- for (Element element in this) { |
- if (!f(element)) { |
- return false; |
- } |
- }; |
- return true; |
- } |
- |
- bool some(bool f(Element element)) { |
- for (Element element in this) { |
- if (f(element)) { |
- return true; |
- } |
- }; |
- return false; |
- } |
- |
- Collection map(f(Element element)) { |
- final out = []; |
- for (Element el in this) { |
- out.add(f(el)); |
- } |
- return out; |
- } |
- |
- bool get isEmpty { |
- return _element.$dom_firstElementChild == null; |
- } |
- |
- int get length { |
- return _childElements.length; |
- } |
- |
- Element operator [](int index) { |
- return _childElements[index]; |
- } |
- |
- void operator []=(int index, Element value) { |
- _element.$dom_replaceChild(value, _childElements[index]); |
- } |
- |
- void set length(int newLength) { |
- // TODO(jacobr): remove children when length is reduced. |
- throw new UnsupportedError(''); |
- } |
- |
- Element add(Element value) { |
- _element.$dom_appendChild(value); |
- return value; |
- } |
- |
- Element addLast(Element value) => add(value); |
- |
- Iterator<Element> iterator() => _toList().iterator(); |
- |
- void addAll(Collection<Element> collection) { |
- for (Element element in collection) { |
- _element.$dom_appendChild(element); |
- } |
- } |
- |
- void sort([int compare(Element a, Element b)]) { |
- throw new UnsupportedError('TODO(jacobr): should we impl?'); |
- } |
- |
- dynamic reduce(dynamic initialValue, |
- dynamic combine(dynamic previousValue, Element element)) { |
- return Collections.reduce(this, initialValue, combine); |
- } |
- |
- void setRange(int start, int rangeLength, List from, [int startFrom = 0]) { |
- throw new UnimplementedError(); |
- } |
- |
- void removeRange(int start, int rangeLength) { |
- throw new UnimplementedError(); |
- } |
- |
- void insertRange(int start, int rangeLength, [initialValue = null]) { |
- throw new UnimplementedError(); |
- } |
- |
- List getRange(int start, int rangeLength) => |
- new _FrozenElementList._wrap(Lists.getRange(this, start, rangeLength, |
- [])); |
- |
- int indexOf(Element element, [int start = 0]) { |
- return Lists.indexOf(this, element, start, this.length); |
- } |
- |
- int lastIndexOf(Element element, [int start = null]) { |
- if (start == null) start = length - 1; |
- return Lists.lastIndexOf(this, element, start); |
- } |
- |
- void clear() { |
- // It is unclear if we want to keep non element nodes? |
- _element.text = ''; |
- } |
- |
- Element removeAt(int index) { |
- final result = this[index]; |
- if (result != null) { |
- _element.$dom_removeChild(result); |
- } |
- return result; |
- } |
- |
- Element removeLast() { |
- final result = this.last; |
- if (result != null) { |
- _element.$dom_removeChild(result); |
- } |
- return result; |
- } |
- |
- Element get first { |
- return _element.$dom_firstElementChild; |
- } |
- |
- |
- Element get last { |
- return _element.$dom_lastElementChild; |
- } |
-} |
- |
-// TODO(jacobr): this is an inefficient implementation but it is hard to see |
-// a better option given that we cannot quite force NodeList to be an |
-// ElementList as there are valid cases where a NodeList JavaScript object |
-// contains Node objects that are not Elements. |
-class _FrozenElementList implements List { |
- final List<Node> _nodeList; |
- |
- _FrozenElementList._wrap(this._nodeList); |
- |
- bool contains(Element element) { |
- for (Element el in this) { |
- if (el == element) return true; |
- } |
- return false; |
- } |
- |
- void forEach(void f(Element element)) { |
- for (Element el in this) { |
- f(el); |
- } |
- } |
- |
- Collection map(f(Element element)) { |
- final out = []; |
- for (Element el in this) { |
- out.add(f(el)); |
- } |
- return out; |
- } |
- |
- List<Element> filter(bool f(Element element)) { |
- final out = []; |
- for (Element el in this) { |
- if (f(el)) out.add(el); |
- } |
- return out; |
- } |
- |
- bool every(bool f(Element element)) { |
- for(Element element in this) { |
- if (!f(element)) { |
- return false; |
- } |
- }; |
- return true; |
- } |
- |
- bool some(bool f(Element element)) { |
- for(Element element in this) { |
- if (f(element)) { |
- return true; |
- } |
- }; |
- return false; |
- } |
- |
- bool get isEmpty => _nodeList.isEmpty; |
- |
- int get length => _nodeList.length; |
- |
- Element operator [](int index) => _nodeList[index]; |
- |
- void operator []=(int index, Element value) { |
- throw new UnsupportedError(''); |
- } |
- |
- void set length(int newLength) { |
- _nodeList.length = newLength; |
- } |
- |
- void add(Element value) { |
- throw new UnsupportedError(''); |
- } |
- |
- void addLast(Element value) { |
- throw new UnsupportedError(''); |
- } |
- |
- Iterator<Element> iterator() => new _FrozenElementListIterator(this); |
- |
- void addAll(Collection<Element> collection) { |
- throw new UnsupportedError(''); |
- } |
- |
- void sort([int compare(Element a, Element b)]) { |
- throw new UnsupportedError(''); |
- } |
- |
- dynamic reduce(dynamic initialValue, |
- dynamic combine(dynamic previousValue, Element element)) { |
- return Collections.reduce(this, initialValue, combine); |
- } |
- |
- void setRange(int start, int rangeLength, List from, [int startFrom = 0]) { |
- throw new UnsupportedError(''); |
- } |
- |
- void removeRange(int start, int rangeLength) { |
- throw new UnsupportedError(''); |
- } |
- |
- void insertRange(int start, int rangeLength, [initialValue = null]) { |
- throw new UnsupportedError(''); |
- } |
- |
- List<Element> getRange(int start, int rangeLength) => |
- new _FrozenElementList._wrap(_nodeList.getRange(start, rangeLength)); |
- |
- int indexOf(Element element, [int start = 0]) => |
- _nodeList.indexOf(element, start); |
- |
- int lastIndexOf(Element element, [int start = null]) => |
- _nodeList.lastIndexOf(element, start); |
- |
- void clear() { |
- throw new UnsupportedError(''); |
- } |
- |
- Element removeAt(int index) { |
- throw new UnsupportedError(''); |
- } |
- |
- Element removeLast() { |
- throw new UnsupportedError(''); |
- } |
- |
- Element get first => _nodeList.first; |
- |
- Element get last => _nodeList.last; |
-} |
- |
-class _FrozenElementListIterator implements Iterator<Element> { |
- final _FrozenElementList _list; |
- int _index = 0; |
- |
- _FrozenElementListIterator(this._list); |
- |
- /** |
- * Gets the next element in the iteration. Throws a |
- * [StateError("No more elements")] if no element is left. |
- */ |
- Element next() { |
- if (!hasNext) { |
- throw new StateError("No more elements"); |
- } |
- |
- return _list[_index++]; |
- } |
- |
- /** |
- * Returns whether the [Iterator] has elements left. |
- */ |
- bool get hasNext => _index < _list.length; |
-} |
- |
-class _ElementCssClassSet extends CssClassSet { |
- |
- final Element _element; |
- |
- _ElementCssClassSet(this._element); |
- |
- Set<String> readClasses() { |
- var s = new Set<String>(); |
- var classname = _element.$dom_className; |
- |
- for (String name in classname.split(' ')) { |
- String trimmed = name.trim(); |
- if (!trimmed.isEmpty) { |
- s.add(trimmed); |
- } |
- } |
- return s; |
- } |
- |
- void writeClasses(Set<String> s) { |
- List list = new List.from(s); |
- _element.$dom_className = Strings.join(list, ' '); |
- } |
-} |
- |
-/** |
- * An abstract class, which all HTML elements extend. |
- */ |
-abstract class $CLASSNAME$EXTENDS$IMPLEMENTS$NATIVESPEC { |
- |
- /** |
- * Creates an HTML element from a valid fragment of HTML. |
- * |
- * The [html] fragment must represent valid HTML with a single element root, |
- * which will be parsed and returned. |
- * |
- * Important: the contents of [html] should not contain any user-supplied |
- * data. Without strict data validation it is impossible to prevent script |
- * injection exploits. |
- * |
- * It is instead recommended that elements be constructed via [Element.tag] |
- * and text be added via [text]. |
- * |
- * var element = new Element.html('<div class="foo">content</div>'); |
- */ |
- factory $CLASSNAME.html(String html) => |
- _$(CLASSNAME)FactoryProvider.createElement_html(html); |
- |
- /** |
- * Creates the HTML element specified by the tag name. |
- * |
- * This is similar to [Document.createElement]. |
- * [tag] should be a valid HTML tag name. If [tag] is an unknown tag then |
- * this will create an [UnknownElement]. |
- * |
- * var divElement = new Element.tag('div'); |
- * print(divElement is DivElement); // 'true' |
- * var myElement = new Element.tag('unknownTag'); |
- * print(myElement is UnknownElement); // 'true' |
- * |
- * For standard elements it is more preferable to use the type constructors: |
- * var element = new DivElement(); |
- */ |
- factory $CLASSNAME.tag(String tag) => |
- _$(CLASSNAME)FactoryProvider.createElement_tag(tag); |
- |
- /** |
- * All attributes on this element. |
- * |
- * Any modifications to the attribute map will automatically be applied to |
- * this element. |
- * |
- * This only includes attributes which are not in a namespace |
- * (such as 'xlink:href'), additional attributes can be accessed via |
- * [getNamespacedAttributes]. |
- */ |
- Map<String, String> get attributes => new _ElementAttributeMap(this); |
- |
- void set attributes(Map<String, String> value) { |
- Map<String, String> attributes = this.attributes; |
- attributes.clear(); |
- for (String key in value.keys) { |
- attributes[key] = value[key]; |
- } |
- } |
- |
- /** |
- * Deprecated, use innerHtml instead. |
- */ |
- @deprecated |
- String get innerHTML => this.innerHtml; |
- @deprecated |
- void set innerHTML(String value) { |
- this.innerHtml = value; |
- } |
- |
- @deprecated |
- void set elements(Collection<Element> value) { |
- this.children = value; |
- } |
- |
- /** |
- * Deprecated, use [children] instead. |
- */ |
- @deprecated |
- List<Element> get elements => this.children; |
- |
- /** |
- * List of the direct children of this element. |
- * |
- * This collection can be used to add and remove elements from the document. |
- * |
- * var item = new DivElement(); |
- * item.text = 'Something'; |
- * document.body.children.add(item) // Item is now displayed on the page. |
- * for (var element in document.body.children) { |
- * element.style.background = 'red'; // Turns every child of body red. |
- * } |
- */ |
- List<Element> get children => new _ChildrenElementList._wrap(this); |
- |
- void set children(List<Element> value) { |
- // Copy list first since we don't want liveness during iteration. |
- List copy = new List.from(value); |
- var children = this.children; |
- children.clear(); |
- children.addAll(copy); |
- } |
- |
- /** |
- * Finds the first descendant element of this element that matches the |
- * specified group of selectors. |
- * |
- * [selectors] should be a string using CSS selector syntax. |
- * |
- * // Gets the first descendant with the class 'classname' |
- * var element = element.query('.className'); |
- * // Gets the element with id 'id' |
- * var element = element.query('#id'); |
- * // Gets the first descendant [ImageElement] |
- * var img = element.query('img'); |
- * |
- * See also: |
- * |
- * * [CSS Selectors](http://docs.webplatform.org/wiki/css/selectors) |
- */ |
- Element query(String selectors) => $dom_querySelector(selectors); |
- |
- /** |
- * Finds all descendent elements of this element that match the specified |
- * group of selectors. |
- * |
- * [selectors] should be a string using CSS selector syntax. |
- * |
- * var items = element.query('.itemClassName'); |
- */ |
- List<Element> queryAll(String selectors) => |
- new _FrozenElementList._wrap($dom_querySelectorAll(selectors)); |
- |
- /** |
- * The set of CSS classes applied to this element. |
- * |
- * This set makes it easy to add, remove or toggle the classes applied to |
- * this element. |
- * |
- * element.classes.add('selected'); |
- * element.classes.toggle('isOnline'); |
- * element.classes.remove('selected'); |
- */ |
- CssClassSet get classes => new _ElementCssClassSet(this); |
- |
- void set classes(Collection<String> value) { |
- CssClassSet classSet = classes; |
- classSet.clear(); |
- classSet.addAll(value); |
- } |
- |
- /** |
- * Allows access to all custom data attributes (data-*) set on this element. |
- * |
- * The keys for the map must follow these rules: |
- * |
- * * The name must not begin with 'xml'. |
- * * The name cannot contain a semi-colon (';'). |
- * * The name cannot contain any capital letters. |
- * |
- * Any keys from markup will be converted to camel-cased keys in the map. |
- * |
- * For example, HTML specified as: |
- * |
- * <div data-my-random-value='value'></div> |
- * |
- * Would be accessed in Dart as: |
- * |
- * var value = element.dataAttributes['myRandomValue']; |
- * |
- * See also: |
- * |
- * * [Custom data attributes](http://www.w3.org/TR/html5/global-attributes.html#custom-data-attribute) |
- */ |
- Map<String, String> get dataAttributes => |
- new _DataAttributeMap(attributes); |
- |
- void set dataAttributes(Map<String, String> value) { |
- final dataAttributes = this.dataAttributes; |
- dataAttributes.clear(); |
- for (String key in value.keys) { |
- dataAttributes[key] = value[key]; |
- } |
- } |
- |
- /** |
- * Gets a map for manipulating the attributes of a particular namespace. |
- * |
- * This is primarily useful for SVG attributes such as xref:link. |
- */ |
- Map<String, String> getNamespacedAttributes(String namespace) { |
- return new _NamespacedAttributeMap(this, namespace); |
- } |
- |
- /** |
- * The set of all CSS values applied to this element, including inherited |
- * and default values. |
- * |
- * The computedStyle contains values that are inherited from other |
- * sources, such as parent elements or stylesheets. This differs from the |
- * [style] property, which contains only the values specified directly on this |
- * element. |
- * |
- * See also: |
- * |
- * * [CSS Inheritance and Cascade](http://docs.webplatform.org/wiki/tutorials/inheritance_and_cascade) |
- */ |
- Future<CssStyleDeclaration> get computedStyle { |
- // TODO(jacobr): last param should be null, see b/5045788 |
- return getComputedStyle(''); |
- } |
- |
- /** |
- * Returns the computed styles for pseudo-elements such as `::after`, |
- * `::before`, `::marker`, `::line-marker`. |
- * |
- * See also: |
- * |
- * * [Pseudo-elements](http://docs.webplatform.org/wiki/css/selectors/pseudo-elements) |
- */ |
- Future<CssStyleDeclaration> getComputedStyle(String pseudoElement) { |
- return _createMeasurementFuture( |
- () => window.$dom_getComputedStyle(this, pseudoElement), |
- new Completer<CssStyleDeclaration>()); |
- } |
- |
- /** |
- * Adds the specified element to after the last child of this element. |
- */ |
- void append(Element e) { |
- this.children.add(e); |
- } |
- |
- /** |
- * Adds the specified text as a text node after the last child of this |
- * element. |
- */ |
- void appendText(String text) { |
- this.insertAdjacentText('beforeend', text); |
- } |
- |
- /** |
- * Parses the specified text as HTML and adds the resulting node after the |
- * last child of this element. |
- */ |
- void appendHtml(String text) { |
- this.insertAdjacentHtml('beforeend', text); |
- } |
- |
- // Hooks to support custom WebComponents. |
- /** |
- * Experimental support for [web components][wc]. This field stores a |
- * reference to the component implementation. It was inspired by Mozilla's |
- * [x-tags][] project. Please note: in the future it may be possible to |
- * `extend Element` from your class, in which case this field will be |
- * deprecated and will simply return this [Element] object. |
- * |
- * [wc]: http://dvcs.w3.org/hg/webcomponents/raw-file/tip/explainer/index.html |
- * [x-tags]: http://x-tags.org/ |
- */ |
-$if DART2JS |
- @Creates('Null') // Set from Dart code; does not instantiate a native type. |
-$endif |
- var xtag; |
- |
-$if DART2JS |
- /** |
- * Creates a text node and inserts it into the DOM at the specified location. |
- * |
- * To see the possible values for [where], read the doc for |
- * [insertAdjacentHtml]. |
- * |
- * See also: |
- * |
- * * [insertAdjacentHtml] |
- */ |
- void insertAdjacentText(String where, String text) { |
- if (JS('bool', '!!#.insertAdjacentText', this)) { |
- _insertAdjacentText(where, text); |
- } else { |
- _insertAdjacentNode(where, new Text(text)); |
- } |
- } |
- |
- @JSName('insertAdjacentText') |
- void _insertAdjacentText(String where, String text) native; |
- |
- /** |
- * Parses text as an HTML fragment and inserts it into the DOM at the |
- * specified location. |
- * |
- * The [where] parameter indicates where to insert the HTML fragment: |
- * |
- * * 'beforeBegin': Immediately before this element. |
- * * 'afterBegin': As the first child of this element. |
- * * 'beforeEnd': As the last child of this element. |
- * * 'afterEnd': Immediately after this element. |
- * |
- * var html = '<div class="something">content</div>'; |
- * // Inserts as the first child |
- * document.body.insertAdjacentHtml('afterBegin', html); |
- * var createdElement = document.body.children[0]; |
- * print(createdElement.classes[0]); // Prints 'something' |
- * |
- * See also: |
- * |
- * * [insertAdjacentText] |
- * * [insertAdjacentElement] |
- */ |
- void insertAdjacentHtml(String where, String text) { |
- if (JS('bool', '!!#.insertAdjacentHtml', this)) { |
- _insertAdjacentHtml(where, text); |
- } else { |
- _insertAdjacentNode(where, new DocumentFragment.html(text)); |
- } |
- } |
- |
- @JSName('insertAdjacentHTML') |
- void _insertAdjacentHTML(String where, String text) native; |
- |
- /** |
- * Inserts [element] into the DOM at the specified location. |
- * |
- * To see the possible values for [where], read the doc for |
- * [insertAdjacentHtml]. |
- * |
- * See also: |
- * |
- * * [insertAdjacentHtml] |
- */ |
- Element insertAdjacentElement(String where, Element element) { |
- if (JS('bool', '!!#.insertAdjacentElement', this)) { |
- _insertAdjacentElement(where, element); |
- } else { |
- _insertAdjacentNode(where, element); |
- } |
- return element; |
- } |
- |
- @JSName('insertAdjacentElement') |
- void _insertAdjacentElement(String where, Element element) native; |
- |
- void _insertAdjacentNode(String where, Node node) { |
- switch (where.toLowerCase()) { |
- case 'beforebegin': |
- this.parentNode.insertBefore(node, this); |
- break; |
- case 'afterbegin': |
- var first = this.nodes.length > 0 ? this.nodes[0] : null; |
- this.insertBefore(node, first); |
- break; |
- case 'beforeend': |
- this.nodes.add(node); |
- break; |
- case 'afterend': |
- this.parentNode.insertBefore(node, this.nextNode); |
- break; |
- default: |
- throw new ArgumentError("Invalid position ${where}"); |
- } |
- } |
-$else |
-$endif |
- |
-$!MEMBERS |
-} |
- |
-final _START_TAG_REGEXP = new RegExp('<(\\w+)'); |
-class _ElementFactoryProvider { |
- static final _CUSTOM_PARENT_TAG_MAP = const { |
- 'body' : 'html', |
- 'head' : 'html', |
- 'caption' : 'table', |
- 'td': 'tr', |
- 'colgroup': 'table', |
- 'col' : 'colgroup', |
- 'tr' : 'tbody', |
- 'tbody' : 'table', |
- 'tfoot' : 'table', |
- 'thead' : 'table', |
- 'track' : 'audio', |
- }; |
- |
- /** @domName Document.createElement */ |
- static Element createElement_html(String html) { |
- // 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 (match != null) { |
- tag = match.group(1).toLowerCase(); |
- if (_CUSTOM_PARENT_TAG_MAP.containsKey(tag)) { |
- parentTag = _CUSTOM_PARENT_TAG_MAP[tag]; |
- } |
- } |
- final Element temp = new Element.tag(parentTag); |
- temp.innerHtml = html; |
- |
- Element element; |
- if (temp.children.length == 1) { |
- element = temp.children[0]; |
- } else if (parentTag == 'html' && temp.children.length == 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. |
- element = temp.children[tag == 'head' ? 0 : 1]; |
- } else { |
- throw new ArgumentError('HTML had ${temp.children.length} ' |
- 'top level elements but 1 expected'); |
- } |
- element.remove(); |
- return element; |
- } |
- |
- /** @domName Document.createElement */ |
-$if DART2JS |
- // Optimization to improve performance until the dart2js compiler inlines this |
- // method. |
- static Element createElement_tag(String tag) => |
- JS('Element', 'document.createElement(#)', tag); |
-$else |
- static Element createElement_tag(String tag) => |
- document.$dom_createElement(tag); |
-$endif |
-} |