| OLD | NEW |
| 1 // Copyright (c) 2012, the Dart project authors. Please see the AUTHORS file | 1 // Copyright (c) 2012, the Dart project authors. Please see the AUTHORS file |
| 2 // for details. All rights reserved. Use of this source code is governed by a | 2 // for details. All rights reserved. Use of this source code is governed by a |
| 3 // BSD-style license that can be found in the LICENSE file. | 3 // BSD-style license that can be found in the LICENSE file. |
| 4 | 4 |
| 5 part of $LIBRARYNAME; | 5 part of $LIBRARYNAME; |
| 6 | 6 |
| 7 class _ChildrenElementList extends ListBase<Element> | 7 class _ChildrenElementList extends ListBase<Element> |
| 8 implements NodeListWrapper { | 8 implements NodeListWrapper { |
| 9 // Raw Element. | 9 // Raw Element. |
| 10 final Element _element; | 10 final Element _element; |
| (...skipping 83 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 94 } | 94 } |
| 95 | 95 |
| 96 void setRange(int start, int end, Iterable<Element> iterable, | 96 void setRange(int start, int end, Iterable<Element> iterable, |
| 97 [int skipCount = 0]) { | 97 [int skipCount = 0]) { |
| 98 throw new UnimplementedError(); | 98 throw new UnimplementedError(); |
| 99 } | 99 } |
| 100 | 100 |
| 101 bool remove(Object object) { | 101 bool remove(Object object) { |
| 102 if (object is Element) { | 102 if (object is Element) { |
| 103 Element element = object; | 103 Element element = object; |
| 104 $if JSINTEROP | |
| 105 // We aren't preserving identity of nodes in JSINTEROP mode | |
| 106 if (element.parentNode == _element) { | |
| 107 $else | |
| 108 if (identical(element.parentNode, _element)) { | 104 if (identical(element.parentNode, _element)) { |
| 109 $endif | |
| 110 _element._removeChild(element); | 105 _element._removeChild(element); |
| 111 return true; | 106 return true; |
| 112 } | 107 } |
| 113 } | 108 } |
| 114 return false; | 109 return false; |
| 115 } | 110 } |
| 116 | 111 |
| 117 void insert(int index, Element element) { | 112 void insert(int index, Element element) { |
| 118 if (index < 0 || index > length) { | 113 if (index < 0 || index > length) { |
| 119 throw new RangeError.range(index, 0, length); | 114 throw new RangeError.range(index, 0, length); |
| (...skipping 145 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 265 // Wrapper over an immutable NodeList to make it implement ElementList. | 260 // Wrapper over an immutable NodeList to make it implement ElementList. |
| 266 // | 261 // |
| 267 // Clients are {`Document`, `DocumentFragment`}.`querySelectorAll` which are | 262 // Clients are {`Document`, `DocumentFragment`}.`querySelectorAll` which are |
| 268 // declared to return `ElementList`. This provides all the static analysis | 263 // declared to return `ElementList`. This provides all the static analysis |
| 269 // benefit so there is no need for this class have a constrained type parameter. | 264 // benefit so there is no need for this class have a constrained type parameter. |
| 270 // | 265 // |
| 271 class _FrozenElementList<E extends Element> extends ListBase<E> | 266 class _FrozenElementList<E extends Element> extends ListBase<E> |
| 272 implements ElementList<E>, NodeListWrapper { | 267 implements ElementList<E>, NodeListWrapper { |
| 273 final List<Node> _nodeList; | 268 final List<Node> _nodeList; |
| 274 | 269 |
| 275 $if JSINTEROP | |
| 276 var dartClass_instance; | |
| 277 | |
| 278 _FrozenElementList._wrap(this._nodeList) { | |
| 279 this.dartClass_instance = this._nodeList; | |
| 280 } | |
| 281 $else | |
| 282 _FrozenElementList._wrap(this._nodeList); | 270 _FrozenElementList._wrap(this._nodeList); |
| 283 $endif | |
| 284 | 271 |
| 285 int get length => _nodeList.length; | 272 int get length => _nodeList.length; |
| 286 | 273 |
| 287 E operator [](int index) => _downcast/*<Node, E>*/(_nodeList[index]); | 274 E operator [](int index) => _downcast/*<Node, E>*/(_nodeList[index]); |
| 288 | 275 |
| 289 void operator []=(int index, E value) { | 276 void operator []=(int index, E value) { |
| 290 throw new UnsupportedError('Cannot modify list'); | 277 throw new UnsupportedError('Cannot modify list'); |
| 291 } | 278 } |
| 292 | 279 |
| 293 set length(int newLength) { | 280 set length(int newLength) { |
| (...skipping 83 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 377 * | 364 * |
| 378 * class CustomElement extends Element { | 365 * class CustomElement extends Element { |
| 379 * factory CustomElement() => new Element.tag('x-custom'); | 366 * factory CustomElement() => new Element.tag('x-custom'); |
| 380 * | 367 * |
| 381 * CustomElement.created() : super.created() { | 368 * CustomElement.created() : super.created() { |
| 382 * // Perform any element initialization. | 369 * // Perform any element initialization. |
| 383 * } | 370 * } |
| 384 * } | 371 * } |
| 385 * document.registerElement('x-custom', CustomElement); | 372 * document.registerElement('x-custom', CustomElement); |
| 386 */ | 373 */ |
| 387 $if DART2JS | |
| 388 Element.created() : super._created(); | 374 Element.created() : super._created(); |
| 389 $else | |
| 390 Element.created() : super._created() { | |
| 391 // Validate that this is a custom element & possibly perform additional | |
| 392 // initialization. | |
| 393 _blink.Blink_Utils.initializeCustomElement(this); | |
| 394 } | |
| 395 $endif | |
| 396 | 375 |
| 397 /** | 376 /** |
| 398 * Creates the HTML element specified by the tag name. | 377 * Creates the HTML element specified by the tag name. |
| 399 * | 378 * |
| 400 * This is similar to [Document.createElement]. | 379 * This is similar to [Document.createElement]. |
| 401 * [tag] should be a valid HTML tag name. If [tag] is an unknown tag then | 380 * [tag] should be a valid HTML tag name. If [tag] is an unknown tag then |
| 402 * this will create an [UnknownElement]. | 381 * this will create an [UnknownElement]. |
| 403 * | 382 * |
| 404 * var divElement = new Element.tag('div'); | 383 * var divElement = new Element.tag('div'); |
| 405 * print(divElement is DivElement); // 'true' | 384 * print(divElement is DivElement); // 'true' |
| (...skipping 426 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 832 **/ | 811 **/ |
| 833 @Experimental() | 812 @Experimental() |
| 834 @SupportedBrowser(SupportedBrowser.CHROME, '36') | 813 @SupportedBrowser(SupportedBrowser.CHROME, '36') |
| 835 Animation animate(Iterable<Map<String, dynamic>> frames, [timing]) { | 814 Animation animate(Iterable<Map<String, dynamic>> frames, [timing]) { |
| 836 if (frames is! Iterable || !(frames.every((x) => x is Map))) { | 815 if (frames is! Iterable || !(frames.every((x) => x is Map))) { |
| 837 throw new ArgumentError("The frames parameter should be a List of Maps " | 816 throw new ArgumentError("The frames parameter should be a List of Maps " |
| 838 "with frame information"); | 817 "with frame information"); |
| 839 } | 818 } |
| 840 var convertedFrames; | 819 var convertedFrames; |
| 841 if (frames is Iterable) { | 820 if (frames is Iterable) { |
| 842 $if DART2JS | |
| 843 convertedFrames = frames.map(convertDartToNative_Dictionary).toList(); | 821 convertedFrames = frames.map(convertDartToNative_Dictionary).toList(); |
| 844 $else | |
| 845 convertedFrames = convertDartToNative_List( | |
| 846 frames.map(convertDartToNative_Dictionary).toList()); | |
| 847 $endif | |
| 848 } else { | 822 } else { |
| 849 convertedFrames = frames; | 823 convertedFrames = frames; |
| 850 } | 824 } |
| 851 var convertedTiming = timing is Map ? convertDartToNative_Dictionary(timing)
: timing; | 825 var convertedTiming = timing is Map ? convertDartToNative_Dictionary(timing)
: timing; |
| 852 return convertedTiming == null | 826 return convertedTiming == null |
| 853 ? _animate(convertedFrames) | 827 ? _animate(convertedFrames) |
| 854 : _animate(convertedFrames, convertedTiming); | 828 : _animate(convertedFrames, convertedTiming); |
| 855 } | 829 } |
| 856 | 830 |
| 857 $if DART2JS | |
| 858 @DomName('Element.animate') | 831 @DomName('Element.animate') |
| 859 @JSName('animate') | 832 @JSName('animate') |
| 860 @Experimental() // untriaged | 833 @Experimental() // untriaged |
| 861 Animation _animate(Object effect, [timing]) native; | 834 Animation _animate(Object effect, [timing]) native; |
| 862 $endif | |
| 863 /** | 835 /** |
| 864 * Called by the DOM whenever an attribute on this has been changed. | 836 * Called by the DOM whenever an attribute on this has been changed. |
| 865 */ | 837 */ |
| 866 void attributeChanged(String name, String oldValue, String newValue) {} | 838 void attributeChanged(String name, String oldValue, String newValue) {} |
| 867 | 839 |
| 868 // Hooks to support custom WebComponents. | 840 // Hooks to support custom WebComponents. |
| 869 | 841 |
| 870 $if DART2JS | |
| 871 @Creates('Null') // Set from Dart code; does not instantiate a native type. | 842 @Creates('Null') // Set from Dart code; does not instantiate a native type. |
| 872 $endif | |
| 873 Element _xtag; | 843 Element _xtag; |
| 874 | 844 |
| 875 /** | 845 /** |
| 876 * Experimental support for [web components][wc]. This field stores a | 846 * Experimental support for [web components][wc]. This field stores a |
| 877 * reference to the component implementation. It was inspired by Mozilla's | 847 * reference to the component implementation. It was inspired by Mozilla's |
| 878 * [x-tags][] project. Please note: in the future it may be possible to | 848 * [x-tags][] project. Please note: in the future it may be possible to |
| 879 * `extend Element` from your class, in which case this field will be | 849 * `extend Element` from your class, in which case this field will be |
| 880 * deprecated. | 850 * deprecated. |
| 881 * | 851 * |
| 882 * If xtag has not been set, it will simply return `this` [Element]. | 852 * If xtag has not been set, it will simply return `this` [Element]. |
| 883 * | 853 * |
| 884 * [wc]: http://dvcs.w3.org/hg/webcomponents/raw-file/tip/explainer/index.html | 854 * [wc]: http://dvcs.w3.org/hg/webcomponents/raw-file/tip/explainer/index.html |
| 885 * [x-tags]: http://x-tags.org/ | 855 * [x-tags]: http://x-tags.org/ |
| 886 */ | 856 */ |
| 887 // Note: return type is `dynamic` for convenience to suppress warnings when | 857 // Note: return type is `dynamic` for convenience to suppress warnings when |
| 888 // members of the component are used. The actual type is a subtype of Element. | 858 // members of the component are used. The actual type is a subtype of Element. |
| 889 get xtag => _xtag != null ? _xtag : this; | 859 get xtag => _xtag != null ? _xtag : this; |
| 890 | 860 |
| 891 set xtag(Element value) { | 861 set xtag(Element value) { |
| 892 _xtag = value; | 862 _xtag = value; |
| 893 } | 863 } |
| 894 | 864 |
| 895 @DomName('Element.localName') | 865 @DomName('Element.localName') |
| 896 @DocsEditable() | 866 @DocsEditable() |
| 897 $if DART2JS | |
| 898 @Returns('String') | 867 @Returns('String') |
| 899 // Non-null for Elements. | 868 // Non-null for Elements. |
| 900 String get localName => JS('String', '#', _localName); | 869 String get localName => JS('String', '#', _localName); |
| 901 $else | |
| 902 String get localName => _localName; | |
| 903 $endif | |
| 904 | 870 |
| 905 /** | 871 /** |
| 906 * A URI that identifies the XML namespace of this element. | 872 * A URI that identifies the XML namespace of this element. |
| 907 * | 873 * |
| 908 * `null` if no namespace URI is specified. | 874 * `null` if no namespace URI is specified. |
| 909 * | 875 * |
| 910 * ## Other resources | 876 * ## Other resources |
| 911 * | 877 * |
| 912 * * [Node.namespaceURI](http://www.w3.org/TR/DOM-Level-3-Core/core.html#ID-No
deNSname) | 878 * * [Node.namespaceURI](http://www.w3.org/TR/DOM-Level-3-Core/core.html#ID-No
deNSname) |
| 913 * from W3C. | 879 * from W3C. |
| (...skipping 20 matching lines...) Expand all Loading... |
| 934 * alignCenter is specified but not supported then this will fall back to | 900 * alignCenter is specified but not supported then this will fall back to |
| 935 * alignTop. | 901 * alignTop. |
| 936 * | 902 * |
| 937 * See also: | 903 * See also: |
| 938 * | 904 * |
| 939 * * [scrollIntoView](http://docs.webplatform.org/wiki/dom/methods/scrollIntoV
iew) | 905 * * [scrollIntoView](http://docs.webplatform.org/wiki/dom/methods/scrollIntoV
iew) |
| 940 * * [scrollIntoViewIfNeeded](http://docs.webplatform.org/wiki/dom/methods/scr
ollIntoViewIfNeeded) | 906 * * [scrollIntoViewIfNeeded](http://docs.webplatform.org/wiki/dom/methods/scr
ollIntoViewIfNeeded) |
| 941 */ | 907 */ |
| 942 void scrollIntoView([ScrollAlignment alignment]) { | 908 void scrollIntoView([ScrollAlignment alignment]) { |
| 943 var hasScrollIntoViewIfNeeded = true; | 909 var hasScrollIntoViewIfNeeded = true; |
| 944 $if DART2JS | |
| 945 hasScrollIntoViewIfNeeded = | 910 hasScrollIntoViewIfNeeded = |
| 946 JS('bool', '!!(#.scrollIntoViewIfNeeded)', this); | 911 JS('bool', '!!(#.scrollIntoViewIfNeeded)', this); |
| 947 $endif | |
| 948 if (alignment == ScrollAlignment.TOP) { | 912 if (alignment == ScrollAlignment.TOP) { |
| 949 this._scrollIntoView(true); | 913 this._scrollIntoView(true); |
| 950 } else if (alignment == ScrollAlignment.BOTTOM) { | 914 } else if (alignment == ScrollAlignment.BOTTOM) { |
| 951 this._scrollIntoView(false); | 915 this._scrollIntoView(false); |
| 952 } else if (hasScrollIntoViewIfNeeded) { | 916 } else if (hasScrollIntoViewIfNeeded) { |
| 953 if (alignment == ScrollAlignment.CENTER) { | 917 if (alignment == ScrollAlignment.CENTER) { |
| 954 this._scrollIntoViewIfNeeded(true); | 918 this._scrollIntoViewIfNeeded(true); |
| 955 } else { | 919 } else { |
| 956 this._scrollIntoViewIfNeeded(); | 920 this._scrollIntoViewIfNeeded(); |
| 957 } | 921 } |
| 958 } else { | 922 } else { |
| 959 this._scrollIntoView(); | 923 this._scrollIntoView(); |
| 960 } | 924 } |
| 961 } | 925 } |
| 962 | 926 |
| 963 $if DART2JS | |
| 964 /** | 927 /** |
| 965 * Static factory designed to expose `mousewheel` events to event | 928 * Static factory designed to expose `mousewheel` events to event |
| 966 * handlers that are not necessarily instances of [Element]. | 929 * handlers that are not necessarily instances of [Element]. |
| 967 * | 930 * |
| 968 * See [EventStreamProvider] for usage information. | 931 * See [EventStreamProvider] for usage information. |
| 969 */ | 932 */ |
| 970 @DomName('Element.mouseWheelEvent') | 933 @DomName('Element.mouseWheelEvent') |
| 971 static const EventStreamProvider<WheelEvent> mouseWheelEvent = | 934 static const EventStreamProvider<WheelEvent> mouseWheelEvent = |
| 972 const _CustomEventStreamProvider<WheelEvent>( | 935 const _CustomEventStreamProvider<WheelEvent>( |
| 973 Element._determineMouseWheelEventType); | 936 Element._determineMouseWheelEventType); |
| (...skipping 34 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 1008 if (JS('bool', '!!#.insertAdjacentText', this)) { | 971 if (JS('bool', '!!#.insertAdjacentText', this)) { |
| 1009 _insertAdjacentText(where, text); | 972 _insertAdjacentText(where, text); |
| 1010 } else { | 973 } else { |
| 1011 _insertAdjacentNode(where, new Text(text)); | 974 _insertAdjacentNode(where, new Text(text)); |
| 1012 } | 975 } |
| 1013 } | 976 } |
| 1014 | 977 |
| 1015 @JSName('insertAdjacentText') | 978 @JSName('insertAdjacentText') |
| 1016 void _insertAdjacentText(String where, String text) native; | 979 void _insertAdjacentText(String where, String text) native; |
| 1017 | 980 |
| 1018 $else | |
| 1019 $endif | |
| 1020 | 981 |
| 1021 /** | 982 /** |
| 1022 * Parses text as an HTML fragment and inserts it into the DOM at the | 983 * Parses text as an HTML fragment and inserts it into the DOM at the |
| 1023 * specified location. | 984 * specified location. |
| 1024 * | 985 * |
| 1025 * The [where] parameter indicates where to insert the HTML fragment: | 986 * The [where] parameter indicates where to insert the HTML fragment: |
| 1026 * | 987 * |
| 1027 * * 'beforeBegin': Immediately before this element. | 988 * * 'beforeBegin': Immediately before this element. |
| 1028 * * 'afterBegin': As the first child of this element. | 989 * * 'afterBegin': As the first child of this element. |
| 1029 * * 'beforeEnd': As the last child of this element. | 990 * * 'beforeEnd': As the last child of this element. |
| (...skipping 13 matching lines...) Expand all Loading... |
| 1043 void insertAdjacentHtml(String where, String html, {NodeValidator validator, | 1004 void insertAdjacentHtml(String where, String html, {NodeValidator validator, |
| 1044 NodeTreeSanitizer treeSanitizer}) { | 1005 NodeTreeSanitizer treeSanitizer}) { |
| 1045 if (treeSanitizer is _TrustedHtmlTreeSanitizer) { | 1006 if (treeSanitizer is _TrustedHtmlTreeSanitizer) { |
| 1046 _insertAdjacentHtml(where, html); | 1007 _insertAdjacentHtml(where, html); |
| 1047 } else { | 1008 } else { |
| 1048 _insertAdjacentNode(where, createFragment(html, | 1009 _insertAdjacentNode(where, createFragment(html, |
| 1049 validator: validator, treeSanitizer: treeSanitizer)); | 1010 validator: validator, treeSanitizer: treeSanitizer)); |
| 1050 } | 1011 } |
| 1051 } | 1012 } |
| 1052 | 1013 |
| 1053 $if DART2JS | |
| 1054 | 1014 |
| 1055 @JSName('insertAdjacentHTML') | 1015 @JSName('insertAdjacentHTML') |
| 1056 void _insertAdjacentHtml(String where, String text) native; | 1016 void _insertAdjacentHtml(String where, String text) native; |
| 1057 | 1017 |
| 1058 /** | 1018 /** |
| 1059 * Inserts [element] into the DOM at the specified location. | 1019 * Inserts [element] into the DOM at the specified location. |
| 1060 * | 1020 * |
| 1061 * To see the possible values for [where], read the doc for | 1021 * To see the possible values for [where], read the doc for |
| 1062 * [insertAdjacentHtml]. | 1022 * [insertAdjacentHtml]. |
| 1063 * | 1023 * |
| 1064 * See also: | 1024 * See also: |
| 1065 * | 1025 * |
| 1066 * * [insertAdjacentHtml] | 1026 * * [insertAdjacentHtml] |
| 1067 */ | 1027 */ |
| 1068 Element insertAdjacentElement(String where, Element element) { | 1028 Element insertAdjacentElement(String where, Element element) { |
| 1069 if (JS('bool', '!!#.insertAdjacentElement', this)) { | 1029 if (JS('bool', '!!#.insertAdjacentElement', this)) { |
| 1070 _insertAdjacentElement(where, element); | 1030 _insertAdjacentElement(where, element); |
| 1071 } else { | 1031 } else { |
| 1072 _insertAdjacentNode(where, element); | 1032 _insertAdjacentNode(where, element); |
| 1073 } | 1033 } |
| 1074 return element; | 1034 return element; |
| 1075 } | 1035 } |
| 1076 | 1036 |
| 1077 @JSName('insertAdjacentElement') | 1037 @JSName('insertAdjacentElement') |
| 1078 void _insertAdjacentElement(String where, Element element) native; | 1038 void _insertAdjacentElement(String where, Element element) native; |
| 1079 $else | |
| 1080 $endif | |
| 1081 | 1039 |
| 1082 void _insertAdjacentNode(String where, Node node) { | 1040 void _insertAdjacentNode(String where, Node node) { |
| 1083 switch (where.toLowerCase()) { | 1041 switch (where.toLowerCase()) { |
| 1084 case 'beforebegin': | 1042 case 'beforebegin': |
| 1085 this.parentNode.insertBefore(node, this); | 1043 this.parentNode.insertBefore(node, this); |
| 1086 break; | 1044 break; |
| 1087 case 'afterbegin': | 1045 case 'afterbegin': |
| 1088 var first = this.nodes.length > 0 ? this.nodes[0] : null; | 1046 var first = this.nodes.length > 0 ? this.nodes[0] : null; |
| 1089 this.insertBefore(node, first); | 1047 this.insertBefore(node, first); |
| 1090 break; | 1048 break; |
| 1091 case 'beforeend': | 1049 case 'beforeend': |
| 1092 this.append(node); | 1050 this.append(node); |
| 1093 break; | 1051 break; |
| 1094 case 'afterend': | 1052 case 'afterend': |
| 1095 this.parentNode.insertBefore(node, this.nextNode); | 1053 this.parentNode.insertBefore(node, this.nextNode); |
| 1096 break; | 1054 break; |
| 1097 default: | 1055 default: |
| 1098 throw new ArgumentError("Invalid position ${where}"); | 1056 throw new ArgumentError("Invalid position ${where}"); |
| 1099 } | 1057 } |
| 1100 } | 1058 } |
| 1101 | 1059 |
| 1102 $if DART2JS | |
| 1103 /** | 1060 /** |
| 1104 * Checks if this element matches the CSS selectors. | 1061 * Checks if this element matches the CSS selectors. |
| 1105 */ | 1062 */ |
| 1106 @Experimental() | 1063 @Experimental() |
| 1107 bool matches(String selectors) { | 1064 bool matches(String selectors) { |
| 1108 if (JS('bool', '!!#.matches', this)) { | 1065 if (JS('bool', '!!#.matches', this)) { |
| 1109 return JS('bool', '#.matches(#)', this, selectors); | 1066 return JS('bool', '#.matches(#)', this, selectors); |
| 1110 } else if (JS('bool', '!!#.webkitMatchesSelector', this)) { | 1067 } else if (JS('bool', '!!#.webkitMatchesSelector', this)) { |
| 1111 return JS('bool', '#.webkitMatchesSelector(#)', this, selectors); | 1068 return JS('bool', '#.webkitMatchesSelector(#)', this, selectors); |
| 1112 } else if (JS('bool', '!!#.mozMatchesSelector', this)) { | 1069 } else if (JS('bool', '!!#.mozMatchesSelector', this)) { |
| 1113 return JS('bool', '#.mozMatchesSelector(#)', this, selectors); | 1070 return JS('bool', '#.mozMatchesSelector(#)', this, selectors); |
| 1114 } else if (JS('bool', '!!#.msMatchesSelector', this)) { | 1071 } else if (JS('bool', '!!#.msMatchesSelector', this)) { |
| 1115 return JS('bool', '#.msMatchesSelector(#)', this, selectors); | 1072 return JS('bool', '#.msMatchesSelector(#)', this, selectors); |
| 1116 } else if (JS('bool', '!!#.oMatchesSelector', this)) { | 1073 } else if (JS('bool', '!!#.oMatchesSelector', this)) { |
| 1117 return JS('bool', '#.oMatchesSelector(#)', this, selectors); | 1074 return JS('bool', '#.oMatchesSelector(#)', this, selectors); |
| 1118 } else { | 1075 } else { |
| 1119 throw new UnsupportedError("Not supported on this platform"); | 1076 throw new UnsupportedError("Not supported on this platform"); |
| 1120 } | 1077 } |
| 1121 } | 1078 } |
| 1122 $else | |
| 1123 $endif | |
| 1124 | 1079 |
| 1125 /** Checks if this element or any of its parents match the CSS selectors. */ | 1080 /** Checks if this element or any of its parents match the CSS selectors. */ |
| 1126 @Experimental() | 1081 @Experimental() |
| 1127 bool matchesWithAncestors(String selectors) { | 1082 bool matchesWithAncestors(String selectors) { |
| 1128 var elem = this; | 1083 var elem = this; |
| 1129 do { | 1084 do { |
| 1130 if (elem.matches(selectors)) return true; | 1085 if (elem.matches(selectors)) return true; |
| 1131 elem = elem.parent; | 1086 elem = elem.parent; |
| 1132 } while(elem != null); | 1087 } while(elem != null); |
| 1133 return false; | 1088 return false; |
| 1134 } | 1089 } |
| 1135 | 1090 |
| 1136 $if DART2JS | |
| 1137 /** | 1091 /** |
| 1138 * Creates a new shadow root for this shadow host. | 1092 * Creates a new shadow root for this shadow host. |
| 1139 * | 1093 * |
| 1140 * ## Other resources | 1094 * ## Other resources |
| 1141 * | 1095 * |
| 1142 * * [Shadow DOM 101](http://www.html5rocks.com/en/tutorials/webcomponents/sha
dowdom/) | 1096 * * [Shadow DOM 101](http://www.html5rocks.com/en/tutorials/webcomponents/sha
dowdom/) |
| 1143 * from HTML5Rocks. | 1097 * from HTML5Rocks. |
| 1144 * * [Shadow DOM specification](http://www.w3.org/TR/shadow-dom/) from W3C. | 1098 * * [Shadow DOM specification](http://www.w3.org/TR/shadow-dom/) from W3C. |
| 1145 */ | 1099 */ |
| 1146 @DomName('Element.createShadowRoot') | 1100 @DomName('Element.createShadowRoot') |
| (...skipping 13 matching lines...) Expand all Loading... |
| 1160 * * [Shadow DOM 101](http://www.html5rocks.com/en/tutorials/webcomponents/sha
dowdom/) | 1114 * * [Shadow DOM 101](http://www.html5rocks.com/en/tutorials/webcomponents/sha
dowdom/) |
| 1161 * from HTML5Rocks. | 1115 * from HTML5Rocks. |
| 1162 * * [Shadow DOM specification](http://www.w3.org/TR/shadow-dom/) | 1116 * * [Shadow DOM specification](http://www.w3.org/TR/shadow-dom/) |
| 1163 * from W3C. | 1117 * from W3C. |
| 1164 */ | 1118 */ |
| 1165 @DomName('Element.shadowRoot') | 1119 @DomName('Element.shadowRoot') |
| 1166 @SupportedBrowser(SupportedBrowser.CHROME, '25') | 1120 @SupportedBrowser(SupportedBrowser.CHROME, '25') |
| 1167 @Experimental() | 1121 @Experimental() |
| 1168 ShadowRoot get shadowRoot => | 1122 ShadowRoot get shadowRoot => |
| 1169 JS('ShadowRoot|Null', '#.shadowRoot || #.webkitShadowRoot', this, this); | 1123 JS('ShadowRoot|Null', '#.shadowRoot || #.webkitShadowRoot', this, this); |
| 1170 $endif | |
| 1171 | 1124 |
| 1172 /** | 1125 /** |
| 1173 * Access this element's content position. | 1126 * Access this element's content position. |
| 1174 * | 1127 * |
| 1175 * This returns a rectangle with the dimensions actually available for content | 1128 * This returns a rectangle with the dimensions actually available for content |
| 1176 * in this element, in pixels, regardless of this element's box-sizing | 1129 * in this element, in pixels, regardless of this element's box-sizing |
| 1177 * property. Unlike [getBoundingClientRect], the dimensions of this rectangle | 1130 * property. Unlike [getBoundingClientRect], the dimensions of this rectangle |
| 1178 * will return the same numerical height if the element is hidden or not. | 1131 * will return the same numerical height if the element is hidden or not. |
| 1179 * | 1132 * |
| 1180 * _Important_ _note_: use of this method _will_ perform CSS calculations that | 1133 * _Important_ _note_: use of this method _will_ perform CSS calculations that |
| (...skipping 86 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 1267 @Experimental() | 1220 @Experimental() |
| 1268 Point offsetTo(Element parent) { | 1221 Point offsetTo(Element parent) { |
| 1269 return Element._offsetToHelper(this, parent); | 1222 return Element._offsetToHelper(this, parent); |
| 1270 } | 1223 } |
| 1271 | 1224 |
| 1272 static Point _offsetToHelper(Element current, Element parent) { | 1225 static Point _offsetToHelper(Element current, Element parent) { |
| 1273 // We're hopping from _offsetParent_ to offsetParent (not just parent), so | 1226 // We're hopping from _offsetParent_ to offsetParent (not just parent), so |
| 1274 // offsetParent, "tops out" at BODY. But people could conceivably pass in | 1227 // offsetParent, "tops out" at BODY. But people could conceivably pass in |
| 1275 // the document.documentElement and I want it to return an absolute offset, | 1228 // the document.documentElement and I want it to return an absolute offset, |
| 1276 // so we have the special case checking for HTML. | 1229 // so we have the special case checking for HTML. |
| 1277 $if JSINTEROP | |
| 1278 bool sameAsParent = current == parent; | |
| 1279 $else | |
| 1280 bool sameAsParent = identical(current, parent); | 1230 bool sameAsParent = identical(current, parent); |
| 1281 $endif | |
| 1282 bool foundAsParent = sameAsParent || parent.tagName == 'HTML'; | 1231 bool foundAsParent = sameAsParent || parent.tagName == 'HTML'; |
| 1283 if (current == null || sameAsParent) { | 1232 if (current == null || sameAsParent) { |
| 1284 if (foundAsParent) return new Point/*<num>*/(0, 0); | 1233 if (foundAsParent) return new Point/*<num>*/(0, 0); |
| 1285 throw new ArgumentError("Specified element is not a transitive offset " | 1234 throw new ArgumentError("Specified element is not a transitive offset " |
| 1286 "parent of this element."); | 1235 "parent of this element."); |
| 1287 } | 1236 } |
| 1288 Element parentOffset = current.offsetParent; | 1237 Element parentOffset = current.offsetParent; |
| 1289 Point p = Element._offsetToHelper(parentOffset, parent); | 1238 Point p = Element._offsetToHelper(parentOffset, parent); |
| 1290 return new Point/*<num>*/(p.x + current.offsetLeft, p.y + current.offsetTop)
; | 1239 return new Point/*<num>*/(p.x + current.offsetLeft, p.y + current.offsetTop)
; |
| 1291 } | 1240 } |
| (...skipping 156 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 1448 * used when an explicit accessor is not available. | 1397 * used when an explicit accessor is not available. |
| 1449 */ | 1398 */ |
| 1450 ElementEvents get on => new ElementEvents(this); | 1399 ElementEvents get on => new ElementEvents(this); |
| 1451 | 1400 |
| 1452 /** | 1401 /** |
| 1453 * Verify if any of the attributes that we use in the sanitizer look unexpecte
d, | 1402 * Verify if any of the attributes that we use in the sanitizer look unexpecte
d, |
| 1454 * possibly indicating DOM clobbering attacks. | 1403 * possibly indicating DOM clobbering attacks. |
| 1455 * | 1404 * |
| 1456 * Those attributes are: attributes, lastChild, children, previousNode and tag
Name. | 1405 * Those attributes are: attributes, lastChild, children, previousNode and tag
Name. |
| 1457 */ | 1406 */ |
| 1458 $if DART2JS | |
| 1459 static bool _hasCorruptedAttributes(Element element) { | 1407 static bool _hasCorruptedAttributes(Element element) { |
| 1460 return JS('bool', r''' | 1408 return JS('bool', r''' |
| 1461 (function(element) { | 1409 (function(element) { |
| 1462 if (!(element.attributes instanceof NamedNodeMap)) { | 1410 if (!(element.attributes instanceof NamedNodeMap)) { |
| 1463 return true; | 1411 return true; |
| 1464 } | 1412 } |
| 1465 var childNodes = element.childNodes; | 1413 var childNodes = element.childNodes; |
| 1466 if (element.lastChild && | 1414 if (element.lastChild && |
| 1467 element.lastChild !== childNodes[childNodes.length -1]) { | 1415 element.lastChild !== childNodes[childNodes.length -1]) { |
| 1468 return true; | 1416 return true; |
| (...skipping 23 matching lines...) Expand all Loading... |
| 1492 } | 1440 } |
| 1493 } | 1441 } |
| 1494 return false; | 1442 return false; |
| 1495 })(#)''', element); | 1443 })(#)''', element); |
| 1496 } | 1444 } |
| 1497 | 1445 |
| 1498 /// A secondary check for corruption, needed on IE | 1446 /// A secondary check for corruption, needed on IE |
| 1499 static bool _hasCorruptedAttributesAdditionalCheck(Element element) { | 1447 static bool _hasCorruptedAttributesAdditionalCheck(Element element) { |
| 1500 return JS('bool', r'!(#.attributes instanceof NamedNodeMap)', element); | 1448 return JS('bool', r'!(#.attributes instanceof NamedNodeMap)', element); |
| 1501 } | 1449 } |
| 1502 $else | |
| 1503 | 1450 |
| 1504 static var _namedNodeMap = js.context["NamedNodeMap"]; | |
| 1505 static var _htmlCollection = js.context["HTMLCollection"]; | |
| 1506 static var _nodeList = js.context["NodeList"]; | |
| 1507 | |
| 1508 static const _evilAttributeNames = | |
| 1509 const ['attributes', 'lastChild', 'children', 'childNodes']; | |
| 1510 | |
| 1511 static bool _hasCorruptedAttributes(Element element) { | |
| 1512 // We have trusted access to children and to attributes of objects, | |
| 1513 // so we can inspect directly for attempts at DOM clobbering. | |
| 1514 var child = element.firstChild; | |
| 1515 while( child != null) { | |
| 1516 if (child is Element) { | |
| 1517 for (var attributeName in ["id", "name"]) { | |
| 1518 var childAttribute = child.getAttribute(attributeName); | |
| 1519 if (_evilAttributeNames.contains(childAttribute)) return true; | |
| 1520 }} | |
| 1521 child = child.nextNode; | |
| 1522 } | |
| 1523 return false; | |
| 1524 } | |
| 1525 | |
| 1526 /// A secondary check for corruption, needed on IE | |
| 1527 static bool _hasCorruptedAttributesAdditionalCheck(Element element) => false; | |
| 1528 $endif | |
| 1529 | |
| 1530 $if DART2JS | |
| 1531 static String _safeTagName(element) { | 1451 static String _safeTagName(element) { |
| 1532 String result = 'element tag unavailable'; | 1452 String result = 'element tag unavailable'; |
| 1533 try { | 1453 try { |
| 1534 if (element.tagName is String) { | 1454 if (element.tagName is String) { |
| 1535 result = element.tagName; | 1455 result = element.tagName; |
| 1536 } | 1456 } |
| 1537 } catch (e) {} | 1457 } catch (e) {} |
| 1538 return result; | 1458 return result; |
| 1539 } | 1459 } |
| 1540 $else | |
| 1541 static String _safeTagName(element) { | |
| 1542 try { | |
| 1543 // Safe as we plumb directly to a C++ native method. | |
| 1544 return element.tagName; | |
| 1545 } catch (e) {} | |
| 1546 return 'element tag unavailable'; | |
| 1547 } | |
| 1548 $endif | |
| 1549 | 1460 |
| 1550 $if DART2JS | |
| 1551 @DomName('Element.offsetParent') | 1461 @DomName('Element.offsetParent') |
| 1552 @DocsEditable() | 1462 @DocsEditable() |
| 1553 final Element offsetParent; | 1463 final Element offsetParent; |
| 1554 | 1464 |
| 1555 @DomName('Element.offsetHeight') | 1465 @DomName('Element.offsetHeight') |
| 1556 @DocsEditable() | 1466 @DocsEditable() |
| 1557 int get offsetHeight => JS('num', '#.offsetHeight', this).round(); | 1467 int get offsetHeight => JS('num', '#.offsetHeight', this).round(); |
| 1558 | 1468 |
| 1559 @DomName('Element.offsetLeft') | 1469 @DomName('Element.offsetLeft') |
| 1560 @DocsEditable() | 1470 @DocsEditable() |
| (...skipping 28 matching lines...) Expand all Loading... |
| 1589 @DomName('Element.scrollTop') | 1499 @DomName('Element.scrollTop') |
| 1590 @DocsEditable() | 1500 @DocsEditable() |
| 1591 set scrollTop(int value) { | 1501 set scrollTop(int value) { |
| 1592 JS("void", "#.scrollTop = #", this, value.round()); | 1502 JS("void", "#.scrollTop = #", this, value.round()); |
| 1593 } | 1503 } |
| 1594 | 1504 |
| 1595 @DomName('Element.scrollWidth') | 1505 @DomName('Element.scrollWidth') |
| 1596 @DocsEditable() | 1506 @DocsEditable() |
| 1597 int get scrollWidth => JS('num', '#.scrollWidth', this).round(); | 1507 int get scrollWidth => JS('num', '#.scrollWidth', this).round(); |
| 1598 | 1508 |
| 1599 $else | |
| 1600 // Need to explicitly delegate because Element is no longer abstract for Darti
um. | |
| 1601 bool get isContentEditable => _blink.BlinkHTMLElement.instance.isContentEditab
le_Getter_(this); | |
| 1602 void click() => _blink.BlinkHTMLElement.instance.click_Callback_0_(this); | |
| 1603 | |
| 1604 @DomName('Element.offsetParent') | |
| 1605 @DocsEditable() | |
| 1606 Element get offsetParent => _blink.BlinkHTMLElement.instance.offsetParent_Gett
er_(this); | |
| 1607 | |
| 1608 @DomName('Element.offsetHeight') | |
| 1609 @DocsEditable() | |
| 1610 int get offsetHeight => _blink.BlinkHTMLElement.instance.offsetHeight_Getter_(
this); | |
| 1611 | |
| 1612 @DomName('Element.offsetLeft') | |
| 1613 @DocsEditable() | |
| 1614 int get offsetLeft => _blink.BlinkHTMLElement.instance.offsetLeft_Getter_(this
); | |
| 1615 | |
| 1616 @DomName('Element.offsetTop') | |
| 1617 @DocsEditable() | |
| 1618 int get offsetTop => _blink.BlinkHTMLElement.instance.offsetTop_Getter_(this); | |
| 1619 | |
| 1620 @DomName('Element.offsetWidth') | |
| 1621 @DocsEditable() | |
| 1622 int get offsetWidth => _blink.BlinkHTMLElement.instance.offsetWidth_Getter_(th
is); | |
| 1623 | |
| 1624 @DomName('Element.scrollHeight') | |
| 1625 @DocsEditable() | |
| 1626 int get scrollHeight => _blink.BlinkElement.instance.scrollHeight_Getter_(this
).round(); | |
| 1627 | |
| 1628 @DomName('Element.scrollLeft') | |
| 1629 @DocsEditable() | |
| 1630 int get scrollLeft => _blink.BlinkElement.instance.scrollLeft_Getter_(this).ro
und(); | |
| 1631 | |
| 1632 @DomName('Element.scrollLeft') | |
| 1633 @DocsEditable() | |
| 1634 set scrollLeft(int value) => _blink.BlinkElement.instance.scrollLeft_Setter_(t
his, value.round()); | |
| 1635 | |
| 1636 @DomName('Element.scrollTop') | |
| 1637 @DocsEditable() | |
| 1638 int get scrollTop => _blink.BlinkElement.instance.scrollTop_Getter_(this).roun
d(); | |
| 1639 | |
| 1640 @DomName('Element.scrollTop') | |
| 1641 @DocsEditable() | |
| 1642 set scrollTop(int value) => _blink.BlinkElement.instance.scrollTop_Setter_(thi
s, value.round()); | |
| 1643 | |
| 1644 @DomName('Element.scrollWidth') | |
| 1645 @DocsEditable() | |
| 1646 int get scrollWidth => _blink.BlinkElement.instance.scrollWidth_Getter_(this).
round(); | |
| 1647 $endif | |
| 1648 | |
| 1649 $!MEMBERS | 1509 $!MEMBERS |
| 1650 } | 1510 } |
| 1651 | 1511 |
| 1652 | 1512 |
| 1653 class _ElementFactoryProvider { | 1513 class _ElementFactoryProvider { |
| 1654 | 1514 |
| 1655 @DomName('Document.createElement') | 1515 @DomName('Document.createElement') |
| 1656 $if DART2JS | |
| 1657 // Optimization to improve performance until the dart2js compiler inlines this | 1516 // Optimization to improve performance until the dart2js compiler inlines this |
| 1658 // method. | 1517 // method. |
| 1659 static dynamic createElement_tag(String tag, String typeExtension) { | 1518 static dynamic createElement_tag(String tag, String typeExtension) { |
| 1660 // Firefox may return a JS function for some types (Embed, Object). | 1519 // Firefox may return a JS function for some types (Embed, Object). |
| 1661 if (typeExtension != null) { | 1520 if (typeExtension != null) { |
| 1662 return JS('Element|=Object', 'document.createElement(#, #)', | 1521 return JS('Element|=Object', 'document.createElement(#, #)', |
| 1663 tag, typeExtension); | 1522 tag, typeExtension); |
| 1664 } | 1523 } |
| 1665 // Should be able to eliminate this and just call the two-arg version above | 1524 // Should be able to eliminate this and just call the two-arg version above |
| 1666 // with null typeExtension, but Chrome treats the tag as case-sensitive if | 1525 // with null typeExtension, but Chrome treats the tag as case-sensitive if |
| 1667 // typeExtension is null. | 1526 // typeExtension is null. |
| 1668 // https://code.google.com/p/chromium/issues/detail?id=282467 | 1527 // https://code.google.com/p/chromium/issues/detail?id=282467 |
| 1669 return JS('Element|=Object', 'document.createElement(#)', tag); | 1528 return JS('Element|=Object', 'document.createElement(#)', tag); |
| 1670 } | 1529 } |
| 1671 | 1530 |
| 1672 $else | |
| 1673 static Element createElement_tag(String tag, String typeExtension) => | |
| 1674 document.createElement(tag, typeExtension); | |
| 1675 $endif | |
| 1676 } | 1531 } |
| 1677 | 1532 |
| 1678 | 1533 |
| 1679 /** | 1534 /** |
| 1680 * Options for Element.scrollIntoView. | 1535 * Options for Element.scrollIntoView. |
| 1681 */ | 1536 */ |
| 1682 class ScrollAlignment { | 1537 class ScrollAlignment { |
| 1683 final _value; | 1538 final _value; |
| 1684 const ScrollAlignment._internal(this._value); | 1539 const ScrollAlignment._internal(this._value); |
| 1685 toString() => 'ScrollAlignment.$_value'; | 1540 toString() => 'ScrollAlignment.$_value'; |
| 1686 | 1541 |
| 1687 /// Attempt to align the element to the top of the scrollable area. | 1542 /// Attempt to align the element to the top of the scrollable area. |
| 1688 static const TOP = const ScrollAlignment._internal('TOP'); | 1543 static const TOP = const ScrollAlignment._internal('TOP'); |
| 1689 /// Attempt to center the element in the scrollable area. | 1544 /// Attempt to center the element in the scrollable area. |
| 1690 static const CENTER = const ScrollAlignment._internal('CENTER'); | 1545 static const CENTER = const ScrollAlignment._internal('CENTER'); |
| 1691 /// Attempt to align the element to the bottom of the scrollable area. | 1546 /// Attempt to align the element to the bottom of the scrollable area. |
| 1692 static const BOTTOM = const ScrollAlignment._internal('BOTTOM'); | 1547 static const BOTTOM = const ScrollAlignment._internal('BOTTOM'); |
| 1693 } | 1548 } |
| OLD | NEW |