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 |