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 15 matching lines...) Expand all Loading... |
26 } | 26 } |
27 | 27 |
28 Element operator [](int index) { | 28 Element operator [](int index) { |
29 return _childElements[index]; | 29 return _childElements[index]; |
30 } | 30 } |
31 | 31 |
32 void operator []=(int index, Element value) { | 32 void operator []=(int index, Element value) { |
33 _element._replaceChild(value, _childElements[index]); | 33 _element._replaceChild(value, _childElements[index]); |
34 } | 34 } |
35 | 35 |
36 void set length(int newLength) { | 36 set length(int newLength) { |
37 // TODO(jacobr): remove children when length is reduced. | 37 // TODO(jacobr): remove children when length is reduced. |
38 throw new UnsupportedError('Cannot resize element lists'); | 38 throw new UnsupportedError('Cannot resize element lists'); |
39 } | 39 } |
40 | 40 |
41 Element add(Element value) { | 41 Element add(Element value) { |
42 _element.append(value); | 42 _element.append(value); |
43 return value; | 43 return value; |
44 } | 44 } |
45 | 45 |
46 Iterator<Element> get iterator => toList().iterator; | 46 Iterator<Element> get iterator => toList().iterator; |
(...skipping 43 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
90 throw new UnimplementedError(); | 90 throw new UnimplementedError(); |
91 } | 91 } |
92 | 92 |
93 void fillRange(int start, int end, [Element fillValue]) { | 93 void fillRange(int start, int end, [Element fillValue]) { |
94 throw new UnimplementedError(); | 94 throw new UnimplementedError(); |
95 } | 95 } |
96 | 96 |
97 bool remove(Object object) { | 97 bool remove(Object object) { |
98 if (object is Element) { | 98 if (object is Element) { |
99 Element element = object; | 99 Element element = object; |
| 100 $if JSINTEROP |
| 101 // We aren't preserving identity of nodes in JSINTEROP mode |
| 102 if (element.parentNode == _element) { |
| 103 $else |
100 if (identical(element.parentNode, _element)) { | 104 if (identical(element.parentNode, _element)) { |
| 105 $endif |
101 _element._removeChild(element); | 106 _element._removeChild(element); |
102 return true; | 107 return true; |
103 } | 108 } |
104 } | 109 } |
105 return false; | 110 return false; |
106 } | 111 } |
107 | 112 |
108 void insert(int index, Element element) { | 113 void insert(int index, Element element) { |
109 if (index < 0 || index > length) { | 114 if (index < 0 || index > length) { |
110 throw new RangeError.range(index, 0, length); | 115 throw new RangeError.range(index, 0, length); |
(...skipping 163 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
274 $endif | 279 $endif |
275 | 280 |
276 int get length => _nodeList.length; | 281 int get length => _nodeList.length; |
277 | 282 |
278 Element operator [](int index) => _nodeList[index]; | 283 Element operator [](int index) => _nodeList[index]; |
279 | 284 |
280 void operator []=(int index, Element value) { | 285 void operator []=(int index, Element value) { |
281 throw new UnsupportedError('Cannot modify list'); | 286 throw new UnsupportedError('Cannot modify list'); |
282 } | 287 } |
283 | 288 |
284 void set length(int newLength) { | 289 set length(int newLength) { |
285 throw new UnsupportedError('Cannot modify list'); | 290 throw new UnsupportedError('Cannot modify list'); |
286 } | 291 } |
287 | 292 |
288 void sort([Comparator<Element> compare]) { | 293 void sort([Comparator<Element> compare]) { |
289 throw new UnsupportedError('Cannot sort list'); | 294 throw new UnsupportedError('Cannot sort list'); |
290 } | 295 } |
291 | 296 |
292 void shuffle([Random random]) { | 297 void shuffle([Random random]) { |
293 throw new UnsupportedError('Cannot shuffle list'); | 298 throw new UnsupportedError('Cannot shuffle list'); |
294 } | 299 } |
295 | 300 |
296 Element get first => _nodeList.first; | 301 Element get first => _nodeList.first; |
297 | 302 |
298 Element get last => _nodeList.last; | 303 Element get last => _nodeList.last; |
299 | 304 |
300 Element get single => _nodeList.single; | 305 Element get single => _nodeList.single; |
301 | 306 |
302 CssClassSet get classes => new _MultiElementCssClassSet(this); | 307 CssClassSet get classes => new _MultiElementCssClassSet(this); |
303 | 308 |
304 CssStyleDeclarationBase get style => | 309 CssStyleDeclarationBase get style => |
305 new _CssStyleDeclarationSet(this); | 310 new _CssStyleDeclarationSet(this); |
306 | 311 |
307 void set classes(Iterable<String> value) { | 312 set classes(Iterable<String> value) { |
308 // TODO(sra): This might be faster for Sets: | 313 // TODO(sra): This might be faster for Sets: |
309 // | 314 // |
310 // new _MultiElementCssClassSet(this).writeClasses(value) | 315 // new _MultiElementCssClassSet(this).writeClasses(value) |
311 // | 316 // |
312 // as the code below converts the Iterable[value] to a string multiple | 317 // as the code below converts the Iterable[value] to a string multiple |
313 // times. Maybe compute the string and set className here. | 318 // times. Maybe compute the string and set className here. |
314 _nodeList.forEach((e) => e.classes = value); | 319 _nodeList.forEach((e) => e.classes = value); |
315 } | 320 } |
316 | 321 |
317 CssRect get contentEdge => new _ContentCssListRect(this); | 322 CssRect get contentEdge => new _ContentCssListRect(this); |
318 | 323 |
319 CssRect get paddingEdge => this.first.paddingEdge; | 324 CssRect get paddingEdge => this.first.paddingEdge; |
320 | 325 |
321 CssRect get borderEdge => this.first.borderEdge; | 326 CssRect get borderEdge => this.first.borderEdge; |
322 | 327 |
323 CssRect get marginEdge => this.first.marginEdge; | 328 CssRect get marginEdge => this.first.marginEdge; |
324 | 329 |
325 List<Node> get rawList => _nodeList; | 330 List<Node> get rawList => _nodeList; |
326 | 331 |
327 $!ELEMENT_STREAM_GETTERS | 332 $!ELEMENT_STREAM_GETTERS |
328 } | 333 } |
329 | 334 |
330 @DocsEditable() | 335 @DocsEditable() |
331 $(ANNOTATIONS)$(NATIVESPEC)abstract class $CLASSNAME$EXTENDS$IMPLEMENTS { | 336 $(ANNOTATIONS)$(NATIVESPEC)class $CLASSNAME$EXTENDS$IMPLEMENTS { |
332 | 337 |
333 /** | 338 /** |
334 * Creates an HTML element from a valid fragment of HTML. | 339 * Creates an HTML element from a valid fragment of HTML. |
335 * | 340 * |
336 * var element = new Element.html('<div class="foo">content</div>'); | 341 * var element = new Element.html('<div class="foo">content</div>'); |
337 * | 342 * |
338 * The HTML fragment should contain only one single root element, any | 343 * The HTML fragment should contain only one single root element, any |
339 * leading or trailing text nodes will be removed. | 344 * leading or trailing text nodes will be removed. |
340 * | 345 * |
341 * The HTML fragment is parsed as if it occurred within the context of a | 346 * The HTML fragment is parsed as if it occurred within the context of a |
(...skipping 26 matching lines...) Expand all Loading... |
368 * | 373 * |
369 * class CustomElement extends Element { | 374 * class CustomElement extends Element { |
370 * factory CustomElement() => new Element.tag('x-custom'); | 375 * factory CustomElement() => new Element.tag('x-custom'); |
371 * | 376 * |
372 * CustomElement.created() : super.created() { | 377 * CustomElement.created() : super.created() { |
373 * // Perform any element initialization. | 378 * // Perform any element initialization. |
374 * } | 379 * } |
375 * } | 380 * } |
376 * document.registerElement('x-custom', CustomElement); | 381 * document.registerElement('x-custom', CustomElement); |
377 */ | 382 */ |
378 Element.created() : super._created() { | 383 Element.created() : super._created(); |
379 // Validate that this is a custom element & perform any additional | |
380 // initialization. | |
381 _initializeCustomElement(this); | |
382 } | |
383 | 384 |
384 /** | 385 /** |
385 * Creates the HTML element specified by the tag name. | 386 * Creates the HTML element specified by the tag name. |
386 * | 387 * |
387 * This is similar to [Document.createElement]. | 388 * This is similar to [Document.createElement]. |
388 * [tag] should be a valid HTML tag name. If [tag] is an unknown tag then | 389 * [tag] should be a valid HTML tag name. If [tag] is an unknown tag then |
389 * this will create an [UnknownElement]. | 390 * this will create an [UnknownElement]. |
390 * | 391 * |
391 * var divElement = new Element.tag('div'); | 392 * var divElement = new Element.tag('div'); |
392 * print(divElement is DivElement); // 'true' | 393 * print(divElement is DivElement); // 'true' |
(...skipping 160 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
553 * | 554 * |
554 * Any modifications to the attribute map will automatically be applied to | 555 * Any modifications to the attribute map will automatically be applied to |
555 * this element. | 556 * this element. |
556 * | 557 * |
557 * This only includes attributes which are not in a namespace | 558 * This only includes attributes which are not in a namespace |
558 * (such as 'xlink:href'), additional attributes can be accessed via | 559 * (such as 'xlink:href'), additional attributes can be accessed via |
559 * [getNamespacedAttributes]. | 560 * [getNamespacedAttributes]. |
560 */ | 561 */ |
561 Map<String, String> get attributes => new _ElementAttributeMap(this); | 562 Map<String, String> get attributes => new _ElementAttributeMap(this); |
562 | 563 |
563 void set attributes(Map<String, String> value) { | 564 set attributes(Map<String, String> value) { |
564 Map<String, String> attributes = this.attributes; | 565 Map<String, String> attributes = this.attributes; |
565 attributes.clear(); | 566 attributes.clear(); |
566 for (String key in value.keys) { | 567 for (String key in value.keys) { |
567 attributes[key] = value[key]; | 568 attributes[key] = value[key]; |
568 } | 569 } |
569 } | 570 } |
570 | 571 |
571 /** | 572 /** |
572 * List of the direct children of this element. | 573 * List of the direct children of this element. |
573 * | 574 * |
574 * This collection can be used to add and remove elements from the document. | 575 * This collection can be used to add and remove elements from the document. |
575 * | 576 * |
576 * var item = new DivElement(); | 577 * var item = new DivElement(); |
577 * item.text = 'Something'; | 578 * item.text = 'Something'; |
578 * document.body.children.add(item) // Item is now displayed on the page. | 579 * document.body.children.add(item) // Item is now displayed on the page. |
579 * for (var element in document.body.children) { | 580 * for (var element in document.body.children) { |
580 * element.style.background = 'red'; // Turns every child of body red. | 581 * element.style.background = 'red'; // Turns every child of body red. |
581 * } | 582 * } |
582 */ | 583 */ |
583 $if DART2JS | |
584 List<Element> get children => new _ChildrenElementList._wrap(this); | 584 List<Element> get children => new _ChildrenElementList._wrap(this); |
585 $else | |
586 $if JSINTEROP | |
587 List<Element> get children => new FilteredElementList(this); | |
588 $else | |
589 List<Element> get children => new _ChildrenElementList._wrap(this); | |
590 $endif | |
591 $endif | |
592 | 585 |
593 void set children(List<Element> value) { | 586 set children(List<Element> value) { |
594 // Copy list first since we don't want liveness during iteration. | 587 // Copy list first since we don't want liveness during iteration. |
595 List copy = new List.from(value); | 588 List copy = new List.from(value); |
596 var children = this.children; | 589 var children = this.children; |
597 children.clear(); | 590 children.clear(); |
598 children.addAll(copy); | 591 children.addAll(copy); |
599 } | 592 } |
600 | 593 |
601 /** | 594 /** |
602 * Finds all descendent elements of this element that match the specified | 595 * Finds all descendent elements of this element that match the specified |
603 * group of selectors. | 596 * group of selectors. |
604 * | 597 * |
605 * [selectors] should be a string using CSS selector syntax. | 598 * [selectors] should be a string using CSS selector syntax. |
606 * | 599 * |
607 * var items = element.querySelectorAll('.itemClassName'); | 600 * var items = element.querySelectorAll('.itemClassName'); |
608 * | 601 * |
609 * For details about CSS selector syntax, see the | 602 * For details about CSS selector syntax, see the |
610 * [CSS selector specification](http://www.w3.org/TR/css3-selectors/). | 603 * [CSS selector specification](http://www.w3.org/TR/css3-selectors/). |
611 */ | 604 */ |
612 @DomName('Element.querySelectorAll') | 605 @DomName('Element.querySelectorAll') |
613 ElementList<Element> querySelectorAll(String selectors) => | 606 ElementList<Element> querySelectorAll(String selectors) => |
614 $if JSINTEROP | |
615 _querySelectorAll(selectors); | |
616 $else | |
617 new _FrozenElementList._wrap(_querySelectorAll(selectors)); | 607 new _FrozenElementList._wrap(_querySelectorAll(selectors)); |
618 $endif | |
619 | 608 |
620 /** | 609 /** |
621 * Alias for [querySelector]. Note this function is deprecated because its | 610 * Alias for [querySelector]. Note this function is deprecated because its |
622 * semantics will be changing in the future. | 611 * semantics will be changing in the future. |
623 */ | 612 */ |
624 @deprecated | 613 @deprecated |
625 @DomName('Element.querySelector') | 614 @DomName('Element.querySelector') |
626 @Experimental() | 615 @Experimental() |
627 Element query(String relativeSelectors) => querySelector(relativeSelectors); | 616 Element query(String relativeSelectors) => querySelector(relativeSelectors); |
628 | 617 |
(...skipping 12 matching lines...) Expand all Loading... |
641 * | 630 * |
642 * This set makes it easy to add, remove or toggle the classes applied to | 631 * This set makes it easy to add, remove or toggle the classes applied to |
643 * this element. | 632 * this element. |
644 * | 633 * |
645 * element.classes.add('selected'); | 634 * element.classes.add('selected'); |
646 * element.classes.toggle('isOnline'); | 635 * element.classes.toggle('isOnline'); |
647 * element.classes.remove('selected'); | 636 * element.classes.remove('selected'); |
648 */ | 637 */ |
649 CssClassSet get classes => new _ElementCssClassSet(this); | 638 CssClassSet get classes => new _ElementCssClassSet(this); |
650 | 639 |
651 void set classes(Iterable<String> value) { | 640 set classes(Iterable<String> value) { |
652 // TODO(sra): Do this without reading the classes in clear() and addAll(), | 641 // TODO(sra): Do this without reading the classes in clear() and addAll(), |
653 // or writing the classes in clear(). | 642 // or writing the classes in clear(). |
654 CssClassSet classSet = classes; | 643 CssClassSet classSet = classes; |
655 classSet.clear(); | 644 classSet.clear(); |
656 classSet.addAll(value); | 645 classSet.addAll(value); |
657 } | 646 } |
658 | 647 |
659 /** | 648 /** |
660 * Allows access to all custom data attributes (data-*) set on this element. | 649 * Allows access to all custom data attributes (data-*) set on this element. |
661 * | 650 * |
(...skipping 13 matching lines...) Expand all Loading... |
675 * | 664 * |
676 * var value = element.dataset['myRandomValue']; | 665 * var value = element.dataset['myRandomValue']; |
677 * | 666 * |
678 * See also: | 667 * See also: |
679 * | 668 * |
680 * * [Custom data attributes](http://www.w3.org/TR/html5/global-attributes.htm
l#custom-data-attribute) | 669 * * [Custom data attributes](http://www.w3.org/TR/html5/global-attributes.htm
l#custom-data-attribute) |
681 */ | 670 */ |
682 Map<String, String> get dataset => | 671 Map<String, String> get dataset => |
683 new _DataAttributeMap(attributes); | 672 new _DataAttributeMap(attributes); |
684 | 673 |
685 void set dataset(Map<String, String> value) { | 674 set dataset(Map<String, String> value) { |
686 final data = this.dataset; | 675 final data = this.dataset; |
687 data.clear(); | 676 data.clear(); |
688 for (String key in value.keys) { | 677 for (String key in value.keys) { |
689 data[key] = value[key]; | 678 data[key] = value[key]; |
690 } | 679 } |
691 } | 680 } |
692 | 681 |
693 /** | 682 /** |
694 * Gets a map for manipulating the attributes of a particular namespace. | 683 * Gets a map for manipulating the attributes of a particular namespace. |
695 * | 684 * |
(...skipping 98 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
794 /** *Deprecated*: override [attached] instead. */ | 783 /** *Deprecated*: override [attached] instead. */ |
795 @Experimental() | 784 @Experimental() |
796 @deprecated | 785 @deprecated |
797 void enteredView() {} | 786 void enteredView() {} |
798 | 787 |
799 /** *Deprecated*: override [detached] instead. */ | 788 /** *Deprecated*: override [detached] instead. */ |
800 @Experimental() | 789 @Experimental() |
801 @deprecated | 790 @deprecated |
802 void leftView() {} | 791 void leftView() {} |
803 | 792 |
804 $if DART2JS | |
805 /** | 793 /** |
806 * Creates a new AnimationEffect object whose target element is the object | 794 * Creates a new AnimationEffect object whose target element is the object |
807 * on which the method is called, and calls the play() method of the | 795 * on which the method is called, and calls the play() method of the |
808 * AnimationTimeline object of the document timeline of the node document | 796 * AnimationTimeline object of the document timeline of the node document |
809 * of the element, passing the newly created AnimationEffect as the argument | 797 * of the element, passing the newly created AnimationEffect as the argument |
810 * to the method. Returns an AnimationPlayer for the effect. | 798 * to the method. Returns an AnimationPlayer for the effect. |
811 * | 799 * |
812 * Examples | 800 * Examples |
813 * | 801 * |
814 * var animation = elem.animate([{"opacity": 75}, {"opacity": 0}], 200); | 802 * var animation = elem.animate([{"opacity": 75}, {"opacity": 0}], 200); |
815 * | 803 * |
816 * var animation = elem.animate([ | 804 * var animation = elem.animate([ |
817 * {"transform": "translate(100px, -100%)"}, | 805 * {"transform": "translate(100px, -100%)"}, |
818 * {"transform" : "translate(400px, 500px)"} | 806 * {"transform" : "translate(400px, 500px)"} |
819 * ], 1500); | 807 * ], 1500); |
820 * | 808 * |
821 * The [frames] parameter is an Iterable<Map>, where the | 809 * The [frames] parameter is an Iterable<Map>, where the |
822 * map entries specify CSS animation effects. The | 810 * map entries specify CSS animation effects. The |
823 * [timing] paramter can be a double, representing the number of milliseconds | 811 * [timing] paramter can be a double, representing the number of milliseconds |
824 * for the transition, or a Map with fields corresponding to those | 812 * for the transition, or a Map with fields corresponding to those |
825 * of the [Timing] object. | 813 * of the [Timing] object. |
826 * | |
827 * This is not yet supported in Dartium. | |
828 **/ | 814 **/ |
829 // TODO(alanknight): Correct above comment once it works in Dartium. | |
830 @Experimental | 815 @Experimental |
831 @SupportedBrowser(SupportedBrowser.CHROME, '36') | 816 @SupportedBrowser(SupportedBrowser.CHROME, '36') |
832 AnimationPlayer animate(Iterable<Map<String, dynamic>> frames, [timing]) { | 817 AnimationPlayer animate(Iterable<Map<String, dynamic>> frames, [timing]) { |
833 if (frames is! Iterable || !(frames.every((x) => x is Map))) { | 818 if (frames is! Iterable || !(frames.every((x) => x is Map))) { |
834 throw new ArgumentError("The frames parameter should be a List of Maps " | 819 throw new ArgumentError("The frames parameter should be a List of Maps " |
835 "with frame information"); | 820 "with frame information"); |
836 } | 821 } |
837 var convertedFrames = frames; | 822 var convertedFrames = frames; |
838 if (convertedFrames is Iterable) { | 823 if (convertedFrames is Iterable) { |
839 convertedFrames = frames.map(convertDartToNative_Dictionary).toList(); | 824 convertedFrames = convertDartToNative_List( |
| 825 frames.map(convertDartToNative_Dictionary).toList()); |
840 } | 826 } |
841 var convertedTiming = timing; | 827 var convertedTiming = timing; |
842 if (convertedTiming is Map) { | 828 if (convertedTiming is Map) { |
843 convertedTiming = convertDartToNative_Dictionary(convertedTiming); | 829 convertedTiming = convertDartToNative_Dictionary(convertedTiming); |
844 } | 830 } |
845 return convertedTiming == null | 831 return convertedTiming == null |
846 ? _animate(convertedFrames) | 832 ? _animate(convertedFrames) |
847 : _animate(convertedFrames, convertedTiming); | 833 : _animate(convertedFrames, convertedTiming); |
848 } | 834 } |
849 | 835 |
| 836 $if DART2JS |
850 @DomName('Element.animate') | 837 @DomName('Element.animate') |
851 @JSName('animate') | 838 @JSName('animate') |
852 @Experimental() // untriaged | 839 @Experimental() // untriaged |
853 AnimationPlayer _animate(Object effect, [timing]) native; | 840 AnimationPlayer _animate(Object effect, [timing]) native; |
854 $endif | 841 $endif |
855 /** | 842 /** |
856 * Called by the DOM whenever an attribute on this has been changed. | 843 * Called by the DOM whenever an attribute on this has been changed. |
857 */ | 844 */ |
858 void attributeChanged(String name, String oldValue, String newValue) {} | 845 void attributeChanged(String name, String oldValue, String newValue) {} |
859 | 846 |
(...skipping 13 matching lines...) Expand all Loading... |
873 * | 860 * |
874 * If xtag has not been set, it will simply return `this` [Element]. | 861 * If xtag has not been set, it will simply return `this` [Element]. |
875 * | 862 * |
876 * [wc]: http://dvcs.w3.org/hg/webcomponents/raw-file/tip/explainer/index.html | 863 * [wc]: http://dvcs.w3.org/hg/webcomponents/raw-file/tip/explainer/index.html |
877 * [x-tags]: http://x-tags.org/ | 864 * [x-tags]: http://x-tags.org/ |
878 */ | 865 */ |
879 // Note: return type is `dynamic` for convenience to suppress warnings when | 866 // Note: return type is `dynamic` for convenience to suppress warnings when |
880 // members of the component are used. The actual type is a subtype of Element. | 867 // members of the component are used. The actual type is a subtype of Element. |
881 get xtag => _xtag != null ? _xtag : this; | 868 get xtag => _xtag != null ? _xtag : this; |
882 | 869 |
883 void set xtag(Element value) { | 870 set xtag(Element value) { |
884 _xtag = value; | 871 _xtag = value; |
885 } | 872 } |
886 | 873 |
887 @DomName('Element.localName') | 874 @DomName('Element.localName') |
888 @DocsEditable() | 875 @DocsEditable() |
889 $if DART2JS | 876 $if DART2JS |
890 @Returns('String') | 877 @Returns('String') |
891 // Non-null for Elements. | 878 // Non-null for Elements. |
892 String get localName => JS('String', '#', _localName); | 879 String get localName => JS('String', '#', _localName); |
893 $else | 880 $else |
(...skipping 105 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
999 void insertAdjacentText(String where, String text) { | 986 void insertAdjacentText(String where, String text) { |
1000 if (JS('bool', '!!#.insertAdjacentText', this)) { | 987 if (JS('bool', '!!#.insertAdjacentText', this)) { |
1001 _insertAdjacentText(where, text); | 988 _insertAdjacentText(where, text); |
1002 } else { | 989 } else { |
1003 _insertAdjacentNode(where, new Text(text)); | 990 _insertAdjacentNode(where, new Text(text)); |
1004 } | 991 } |
1005 } | 992 } |
1006 | 993 |
1007 @JSName('insertAdjacentText') | 994 @JSName('insertAdjacentText') |
1008 void _insertAdjacentText(String where, String text) native; | 995 void _insertAdjacentText(String where, String text) native; |
1009 | 996 |
1010 $else | 997 $else |
1011 $endif | 998 $endif |
1012 | 999 |
1013 /** | 1000 /** |
1014 * Parses text as an HTML fragment and inserts it into the DOM at the | 1001 * Parses text as an HTML fragment and inserts it into the DOM at the |
1015 * specified location. | 1002 * specified location. |
1016 * | 1003 * |
1017 * The [where] parameter indicates where to insert the HTML fragment: | 1004 * The [where] parameter indicates where to insert the HTML fragment: |
1018 * | 1005 * |
1019 * * 'beforeBegin': Immediately before this element. | 1006 * * 'beforeBegin': Immediately before this element. |
(...skipping 242 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
1262 @Experimental() | 1249 @Experimental() |
1263 Point offsetTo(Element parent) { | 1250 Point offsetTo(Element parent) { |
1264 return Element._offsetToHelper(this, parent); | 1251 return Element._offsetToHelper(this, parent); |
1265 } | 1252 } |
1266 | 1253 |
1267 static Point _offsetToHelper(Element current, Element parent) { | 1254 static Point _offsetToHelper(Element current, Element parent) { |
1268 // We're hopping from _offsetParent_ to offsetParent (not just parent), so | 1255 // We're hopping from _offsetParent_ to offsetParent (not just parent), so |
1269 // offsetParent, "tops out" at BODY. But people could conceivably pass in | 1256 // offsetParent, "tops out" at BODY. But people could conceivably pass in |
1270 // the document.documentElement and I want it to return an absolute offset, | 1257 // the document.documentElement and I want it to return an absolute offset, |
1271 // so we have the special case checking for HTML. | 1258 // so we have the special case checking for HTML. |
1272 bool foundAsParent = identical(current, parent) || parent.tagName == 'HTML'; | 1259 $if JSINTEROP |
1273 if (current == null || identical(current, parent)) { | 1260 bool sameAsParent = current == parent; |
| 1261 $else |
| 1262 bool sameAsParent = identical(current, parent); |
| 1263 $endif |
| 1264 bool foundAsParent = sameAsParent || parent.tagName == 'HTML'; |
| 1265 if (current == null || sameAsParent) { |
1274 if (foundAsParent) return new Point(0, 0); | 1266 if (foundAsParent) return new Point(0, 0); |
1275 throw new ArgumentError("Specified element is not a transitive offset " | 1267 throw new ArgumentError("Specified element is not a transitive offset " |
1276 "parent of this element."); | 1268 "parent of this element."); |
1277 } | 1269 } |
1278 Element parentOffset = current.offsetParent; | 1270 Element parentOffset = current.offsetParent; |
1279 Point p = Element._offsetToHelper(parentOffset, parent); | 1271 Point p = Element._offsetToHelper(parentOffset, parent); |
1280 return new Point(p.x + current.offsetLeft, p.y + current.offsetTop); | 1272 return new Point(p.x + current.offsetLeft, p.y + current.offsetTop); |
1281 } | 1273 } |
1282 | 1274 |
1283 static HtmlDocument _parseDocument; | 1275 static HtmlDocument _parseDocument; |
(...skipping 37 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
1321 } | 1313 } |
1322 treeSanitizer = _defaultSanitizer; | 1314 treeSanitizer = _defaultSanitizer; |
1323 } else if (validator != null) { | 1315 } else if (validator != null) { |
1324 throw new ArgumentError( | 1316 throw new ArgumentError( |
1325 'validator can only be passed if treeSanitizer is null'); | 1317 'validator can only be passed if treeSanitizer is null'); |
1326 } | 1318 } |
1327 | 1319 |
1328 if (_parseDocument == null) { | 1320 if (_parseDocument == null) { |
1329 _parseDocument = document.implementation.createHtmlDocument(''); | 1321 _parseDocument = document.implementation.createHtmlDocument(''); |
1330 _parseRange = _parseDocument.createRange(); | 1322 _parseRange = _parseDocument.createRange(); |
1331 » | 1323 |
1332 // Workaround for Safari bug. Was also previously Chrome bug 229142 | 1324 // Workaround for Safari bug. Was also previously Chrome bug 229142 |
1333 // - URIs are not resolved in new doc.» | 1325 // - URIs are not resolved in new doc. |
1334 var base = _parseDocument.createElement('base');» | 1326 var base = _parseDocument.createElement('base'); |
1335 base.href = document.baseUri;» | 1327 base.href = document.baseUri; |
1336 _parseDocument.head.append(base); | 1328 _parseDocument.head.append(base); |
1337 } | 1329 } |
1338 var contextElement; | 1330 var contextElement; |
1339 if (this is BodyElement) { | 1331 if (this is BodyElement) { |
1340 contextElement = _parseDocument.body; | 1332 contextElement = _parseDocument.body; |
1341 } else { | 1333 } else { |
1342 contextElement = _parseDocument.createElement(tagName); | 1334 contextElement = _parseDocument.createElement(tagName); |
1343 _parseDocument.body.append(contextElement); | 1335 _parseDocument.body.append(contextElement); |
1344 } | 1336 } |
1345 var fragment; | 1337 var fragment; |
(...skipping 37 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
1383 'BASE', 'BASEFONT', 'BR', 'COL', 'COLGROUP', 'EMBED', 'FRAME', 'FRAMESET', | 1375 'BASE', 'BASEFONT', 'BR', 'COL', 'COLGROUP', 'EMBED', 'FRAME', 'FRAMESET', |
1384 'HR', 'IMAGE', 'IMG', 'INPUT', 'ISINDEX', 'LINK', 'META', 'PARAM', | 1376 'HR', 'IMAGE', 'IMG', 'INPUT', 'ISINDEX', 'LINK', 'META', 'PARAM', |
1385 'SOURCE', 'STYLE', 'TITLE', 'WBR']; | 1377 'SOURCE', 'STYLE', 'TITLE', 'WBR']; |
1386 | 1378 |
1387 /** | 1379 /** |
1388 * Parses the HTML fragment and sets it as the contents of this element. | 1380 * Parses the HTML fragment and sets it as the contents of this element. |
1389 * | 1381 * |
1390 * This uses the default sanitization behavior to sanitize the HTML fragment, | 1382 * This uses the default sanitization behavior to sanitize the HTML fragment, |
1391 * use [setInnerHtml] to override the default behavior. | 1383 * use [setInnerHtml] to override the default behavior. |
1392 */ | 1384 */ |
1393 void set innerHtml(String html) { | 1385 set innerHtml(String html) { |
1394 this.setInnerHtml(html); | 1386 this.setInnerHtml(html); |
1395 } | 1387 } |
1396 | 1388 |
1397 /** | 1389 /** |
1398 * Parses the HTML fragment and sets it as the contents of this element. | 1390 * Parses the HTML fragment and sets it as the contents of this element. |
1399 * This ensures that the generated content follows the sanitization rules | 1391 * This ensures that the generated content follows the sanitization rules |
1400 * specified by the validator or treeSanitizer. | 1392 * specified by the validator or treeSanitizer. |
1401 * | 1393 * |
1402 * If the default validation behavior is too restrictive then a new | 1394 * If the default validation behavior is too restrictive then a new |
1403 * NodeValidator should be created, either extending or wrapping a default | 1395 * NodeValidator should be created, either extending or wrapping a default |
(...skipping 21 matching lines...) Expand all Loading... |
1425 html, validator: validator, treeSanitizer: treeSanitizer)); | 1417 html, validator: validator, treeSanitizer: treeSanitizer)); |
1426 } | 1418 } |
1427 } | 1419 } |
1428 String get innerHtml => _innerHtml; | 1420 String get innerHtml => _innerHtml; |
1429 | 1421 |
1430 /** | 1422 /** |
1431 * This is an ease-of-use accessor for event streams which should only be | 1423 * This is an ease-of-use accessor for event streams which should only be |
1432 * used when an explicit accessor is not available. | 1424 * used when an explicit accessor is not available. |
1433 */ | 1425 */ |
1434 ElementEvents get on => new ElementEvents(this); | 1426 ElementEvents get on => new ElementEvents(this); |
1435 | 1427 |
1436 /** | 1428 /** |
1437 * Verify if any of the attributes that we use in the sanitizer look unexpecte
d, | 1429 * Verify if any of the attributes that we use in the sanitizer look unexpecte
d, |
1438 * possibly indicating DOM clobbering attacks. | 1430 * possibly indicating DOM clobbering attacks. |
1439 * | 1431 * |
1440 * Those attributes are: attributes, lastChild, children, previousNode and tag
Name. | 1432 * Those attributes are: attributes, lastChild, children, previousNode and tag
Name. |
1441 */ | 1433 */ |
1442 $if DART2JS | 1434 $if DART2JS |
1443 static bool _hasCorruptedAttributes(Element element) { | 1435 static bool _hasCorruptedAttributes(Element element) { |
1444 return JS('bool', r''' | 1436 return JS('bool', r''' |
1445 (function(element) { | 1437 (function(element) { |
1446 if (!(element.attributes instanceof NamedNodeMap)) { | 1438 if (!(element.attributes instanceof NamedNodeMap)) { |
1447 return true; | 1439 return true; |
1448 } | 1440 } |
1449 var childNodes = element.childNodes; | 1441 var childNodes = element.childNodes; |
1450 if (element.lastChild && | 1442 if (element.lastChild && |
1451 element.lastChild !== childNodes[childNodes.length -1]) { | 1443 element.lastChild !== childNodes[childNodes.length -1]) { |
1452 return true; | 1444 return true; |
1453 } | 1445 } |
1454 if (element.children) { // On Safari, children can apparently be null. | 1446 if (element.children) { // On Safari, children can apparently be null. |
1455 if (!((element.children instanceof HTMLCollection) || | 1447 if (!((element.children instanceof HTMLCollection) || |
1456 (element.children instanceof NodeList))) { | 1448 (element.children instanceof NodeList))) { |
1457 return true; | 1449 return true; |
1458 } | 1450 } |
1459 } | 1451 } |
1460 return false; | 1452 return false; |
1461 })(#)''', element); | 1453 })(#)''', element); |
1462 } | 1454 } |
1463 $else | 1455 $else |
1464 // Dartium isn't affected by these attacks, because it goes directly to the C+
+ API. | 1456 |
1465 static bool _hasCorruptedAttributes(Element element) => false; | 1457 static var _namedNodeMap = js.context["NamedNodeMap"]; |
| 1458 static var _htmlCollection = js.context["HTMLCollection"]; |
| 1459 static var _nodeList = js.context["NodeList"]; |
| 1460 |
| 1461 static bool _hasCorruptedAttributes(Element element) { |
| 1462 var attributes = unwrap_jso(element)["attributes"]; |
| 1463 if (!attributes.instanceof(_namedNodeMap)) { |
| 1464 return true; |
| 1465 } |
| 1466 var childNodes = unwrap_jso(element.childNodes); |
| 1467 var length = childNodes["length"]; |
| 1468 var lastChild = unwrap_jso(element.lastChild); |
| 1469 if (null != lastChild && |
| 1470 lastChild != childNodes[length - 1]) { |
| 1471 return true; |
| 1472 } |
| 1473 var children = unwrap_jso(element._children); |
| 1474 if (null != children) { // On Safari, children can apparently be null. |
| 1475 if (!children.instanceof(_htmlCollection) || |
| 1476 children.instanceof(_nodeList)) { |
| 1477 » return true; |
| 1478 } |
| 1479 } |
| 1480 return false; |
| 1481 } |
1466 $endif | 1482 $endif |
1467 | 1483 |
| 1484 String get _safeTagName { |
| 1485 String result = 'element tag unavailable'; |
| 1486 try { |
| 1487 if (tagName is String) { |
| 1488 result = tagName; |
| 1489 } |
| 1490 } catch (e) {} |
| 1491 return result; |
| 1492 } |
| 1493 |
1468 $if DART2JS | 1494 $if DART2JS |
1469 @DomName('Element.offsetHeight') | 1495 @DomName('Element.offsetHeight') |
1470 @DocsEditable() | 1496 @DocsEditable() |
1471 int get offsetHeight => JS('num', '#.offsetHeight', this).round(); | 1497 int get offsetHeight => JS('num', '#.offsetHeight', this).round(); |
1472 | 1498 |
1473 @DomName('Element.offsetLeft') | 1499 @DomName('Element.offsetLeft') |
1474 @DocsEditable() | 1500 @DocsEditable() |
1475 int get offsetLeft => JS('num', '#.offsetLeft', this).round(); | 1501 int get offsetLeft => JS('num', '#.offsetLeft', this).round(); |
1476 | 1502 |
1477 @DomName('Element.offsetTop') | 1503 @DomName('Element.offsetTop') |
(...skipping 23 matching lines...) Expand all Loading... |
1501 @DomName('Element.scrollHeight') | 1527 @DomName('Element.scrollHeight') |
1502 @DocsEditable() | 1528 @DocsEditable() |
1503 int get scrollHeight => JS('num', '#.scrollHeight', this).round(); | 1529 int get scrollHeight => JS('num', '#.scrollHeight', this).round(); |
1504 | 1530 |
1505 @DomName('Element.scrollLeft') | 1531 @DomName('Element.scrollLeft') |
1506 @DocsEditable() | 1532 @DocsEditable() |
1507 int get scrollLeft => JS('num', '#.scrollLeft', this).round(); | 1533 int get scrollLeft => JS('num', '#.scrollLeft', this).round(); |
1508 | 1534 |
1509 @DomName('Element.scrollLeft') | 1535 @DomName('Element.scrollLeft') |
1510 @DocsEditable() | 1536 @DocsEditable() |
1511 void set scrollLeft(int value) { | 1537 set scrollLeft(int value) { |
1512 JS("void", "#.scrollLeft = #", this, value.round()); | 1538 JS("void", "#.scrollLeft = #", this, value.round()); |
1513 } | 1539 } |
1514 | 1540 |
1515 @DomName('Element.scrollTop') | 1541 @DomName('Element.scrollTop') |
1516 @DocsEditable() | 1542 @DocsEditable() |
1517 int get scrollTop => JS('num', '#.scrollTop', this).round(); | 1543 int get scrollTop => JS('num', '#.scrollTop', this).round(); |
1518 | 1544 |
1519 @DomName('Element.scrollTop') | 1545 @DomName('Element.scrollTop') |
1520 @DocsEditable() | 1546 @DocsEditable() |
1521 void set scrollTop(int value) { | 1547 set scrollTop(int value) { |
1522 JS("void", "#.scrollTop = #", this, value.round()); | 1548 JS("void", "#.scrollTop = #", this, value.round()); |
1523 } | 1549 } |
1524 | 1550 |
1525 @DomName('Element.scrollWidth') | 1551 @DomName('Element.scrollWidth') |
1526 @DocsEditable() | 1552 @DocsEditable() |
1527 int get scrollWidth => JS('num', '#.scrollWidth', this).round(); | 1553 int get scrollWidth => JS('num', '#.scrollWidth', this).round(); |
1528 | 1554 |
1529 $else | 1555 $else |
1530 $if JSINTEROP | 1556 $if JSINTEROP |
1531 @DomName('Element.offsetHeight') | 1557 @DomName('Element.offsetHeight') |
(...skipping 31 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
1563 @DomName('Element.scrollHeight') | 1589 @DomName('Element.scrollHeight') |
1564 @DocsEditable() | 1590 @DocsEditable() |
1565 int get scrollHeight => _blink.BlinkElement.instance.scrollHeight_Getter_(unwr
ap_jso(this)).round(); | 1591 int get scrollHeight => _blink.BlinkElement.instance.scrollHeight_Getter_(unwr
ap_jso(this)).round(); |
1566 | 1592 |
1567 @DomName('Element.scrollLeft') | 1593 @DomName('Element.scrollLeft') |
1568 @DocsEditable() | 1594 @DocsEditable() |
1569 int get scrollLeft => _blink.BlinkElement.instance.scrollLeft_Getter_(unwrap_j
so(this)).round(); | 1595 int get scrollLeft => _blink.BlinkElement.instance.scrollLeft_Getter_(unwrap_j
so(this)).round(); |
1570 | 1596 |
1571 @DomName('Element.scrollLeft') | 1597 @DomName('Element.scrollLeft') |
1572 @DocsEditable() | 1598 @DocsEditable() |
1573 void set scrollLeft(int value) => _blink.BlinkElement.instance.scrollLeft_Sett
er_(unwrap_jso(this), value.round()); | 1599 set scrollLeft(int value) => _blink.BlinkElement.instance.scrollLeft_Setter_(u
nwrap_jso(this), value.round()); |
1574 | 1600 |
1575 @DomName('Element.scrollTop') | 1601 @DomName('Element.scrollTop') |
1576 @DocsEditable() | 1602 @DocsEditable() |
1577 int get scrollTop => _blink.BlinkElement.instance.scrollTop_Getter_(unwrap_jso
(this)).round(); | 1603 int get scrollTop => _blink.BlinkElement.instance.scrollTop_Getter_(unwrap_jso
(this)).round(); |
1578 | 1604 |
1579 @DomName('Element.scrollTop') | 1605 @DomName('Element.scrollTop') |
1580 @DocsEditable() | 1606 @DocsEditable() |
1581 void set scrollTop(int value) => _blink.BlinkElement.instance.scrollTop_Setter
_(unwrap_jso(this), value.round()); | 1607 set scrollTop(int value) => _blink.BlinkElement.instance.scrollTop_Setter_(unw
rap_jso(this), value.round()); |
1582 | 1608 |
1583 @DomName('Element.scrollWidth') | 1609 @DomName('Element.scrollWidth') |
1584 @DocsEditable() | 1610 @DocsEditable() |
1585 int get scrollWidth => _blink.BlinkElement.instance.scrollWidth_Getter_(unwrap
_jso(this)).round(); | 1611 int get scrollWidth => _blink.BlinkElement.instance.scrollWidth_Getter_(unwrap
_jso(this)).round(); |
1586 $else | 1612 $else |
1587 @DomName('Element.offsetHeight') | 1613 @DomName('Element.offsetHeight') |
1588 @DocsEditable() | 1614 @DocsEditable() |
1589 int get offsetHeight => _blink.BlinkElement.offsetHeight_Getter(this).round(); | 1615 int get offsetHeight => _blink.BlinkElement.offsetHeight_Getter(this).round(); |
1590 | 1616 |
1591 @DomName('Element.offsetLeft') | 1617 @DomName('Element.offsetLeft') |
(...skipping 27 matching lines...) Expand all Loading... |
1619 @DomName('Element.scrollHeight') | 1645 @DomName('Element.scrollHeight') |
1620 @DocsEditable() | 1646 @DocsEditable() |
1621 int get scrollHeight => _blink.BlinkElement.scrollHeight_Getter(this).round(); | 1647 int get scrollHeight => _blink.BlinkElement.scrollHeight_Getter(this).round(); |
1622 | 1648 |
1623 @DomName('Element.scrollLeft') | 1649 @DomName('Element.scrollLeft') |
1624 @DocsEditable() | 1650 @DocsEditable() |
1625 int get scrollLeft => _blink.BlinkElement.scrollLeft_Getter(this).round(); | 1651 int get scrollLeft => _blink.BlinkElement.scrollLeft_Getter(this).round(); |
1626 | 1652 |
1627 @DomName('Element.scrollLeft') | 1653 @DomName('Element.scrollLeft') |
1628 @DocsEditable() | 1654 @DocsEditable() |
1629 void set scrollLeft(int value) => _blink.BlinkElement.scrollLeft_Setter(this,
value.round()); | 1655 set scrollLeft(int value) => _blink.BlinkElement.scrollLeft_Setter(this, value
.round()); |
1630 | 1656 |
1631 @DomName('Element.scrollTop') | 1657 @DomName('Element.scrollTop') |
1632 @DocsEditable() | 1658 @DocsEditable() |
1633 int get scrollTop => _blink.BlinkElement.scrollTop_Getter(this).round(); | 1659 int get scrollTop => _blink.BlinkElement.scrollTop_Getter(this).round(); |
1634 | 1660 |
1635 @DomName('Element.scrollTop') | 1661 @DomName('Element.scrollTop') |
1636 @DocsEditable() | 1662 @DocsEditable() |
1637 void set scrollTop(int value) => _blink.BlinkElement.scrollTop_Setter(this, va
lue.round()); | 1663 set scrollTop(int value) => _blink.BlinkElement.scrollTop_Setter(this, value.r
ound()); |
1638 | 1664 |
1639 @DomName('Element.scrollWidth') | 1665 @DomName('Element.scrollWidth') |
1640 @DocsEditable() | 1666 @DocsEditable() |
1641 int get scrollWidth => _blink.BlinkElement.scrollWidth_Getter(this).round(); | 1667 int get scrollWidth => _blink.BlinkElement.scrollWidth_Getter(this).round(); |
1642 $endif | 1668 $endif |
1643 $endif | 1669 $endif |
1644 | 1670 |
1645 $!MEMBERS | 1671 $!MEMBERS |
1646 } | 1672 } |
1647 | 1673 |
(...skipping 32 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
1680 const ScrollAlignment._internal(this._value); | 1706 const ScrollAlignment._internal(this._value); |
1681 toString() => 'ScrollAlignment.$_value'; | 1707 toString() => 'ScrollAlignment.$_value'; |
1682 | 1708 |
1683 /// Attempt to align the element to the top of the scrollable area. | 1709 /// Attempt to align the element to the top of the scrollable area. |
1684 static const TOP = const ScrollAlignment._internal('TOP'); | 1710 static const TOP = const ScrollAlignment._internal('TOP'); |
1685 /// Attempt to center the element in the scrollable area. | 1711 /// Attempt to center the element in the scrollable area. |
1686 static const CENTER = const ScrollAlignment._internal('CENTER'); | 1712 static const CENTER = const ScrollAlignment._internal('CENTER'); |
1687 /// Attempt to align the element to the bottom of the scrollable area. | 1713 /// Attempt to align the element to the bottom of the scrollable area. |
1688 static const BOTTOM = const ScrollAlignment._internal('BOTTOM'); | 1714 static const BOTTOM = const ScrollAlignment._internal('BOTTOM'); |
1689 } | 1715 } |
OLD | NEW |