| OLD | NEW |
| 1 /// A simple tree API that results from parsing html. Intended to be compatible | 1 /// A simple tree API that results from parsing html. Intended to be compatible |
| 2 /// with dart:html, but right now it resembles the classic JS DOM. | 2 /// with dart:html, but right now it resembles the classic JS DOM. |
| 3 library dom; | 3 library dom; |
| 4 | 4 |
| 5 import 'dart:collection'; | 5 import 'dart:collection'; |
| 6 import 'package:source_maps/span.dart' show FileSpan; | 6 import 'package:source_maps/span.dart' show FileSpan; |
| 7 | 7 |
| 8 import 'src/constants.dart'; | 8 import 'src/constants.dart'; |
| 9 import 'src/list_proxy.dart'; | 9 import 'src/list_proxy.dart'; |
| 10 import 'src/token.dart'; | 10 import 'src/token.dart'; |
| (...skipping 633 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 644 | 644 |
| 645 Node _setParent(Node node) { | 645 Node _setParent(Node node) { |
| 646 // Note: we need to remove the node from its previous parent node, if any, | 646 // Note: we need to remove the node from its previous parent node, if any, |
| 647 // before updating its parent pointer to point at our parent. | 647 // before updating its parent pointer to point at our parent. |
| 648 node.remove(); | 648 node.remove(); |
| 649 node.parent = _parent; | 649 node.parent = _parent; |
| 650 return node; | 650 return node; |
| 651 } | 651 } |
| 652 | 652 |
| 653 void add(Node value) { | 653 void add(Node value) { |
| 654 super.add(_setParent(value)); | 654 if (value is DocumentFragment) { |
| 655 addAll(value.nodes); |
| 656 } else { |
| 657 super.add(_setParent(value)); |
| 658 } |
| 655 } | 659 } |
| 656 | 660 |
| 657 void addLast(Node value) => add(value); | 661 void addLast(Node value) => add(value); |
| 658 | 662 |
| 659 void addAll(Iterable<Node> collection) { | 663 void addAll(Iterable<Node> collection) { |
| 660 // Note: we need to be careful if collection is another NodeList. | 664 // Note: we need to be careful if collection is another NodeList. |
| 661 // In particular: | 665 // In particular: |
| 662 // 1. we need to copy the items before updating their parent pointers, | 666 // 1. we need to copy the items before updating their parent pointers, |
| 667 // _flattenDocFragments does a copy internally. |
| 663 // 2. we should update parent pointers in reverse order. That way they | 668 // 2. we should update parent pointers in reverse order. That way they |
| 664 // are removed from the original NodeList (if any) from the end, which | 669 // are removed from the original NodeList (if any) from the end, which |
| 665 // is faster. | 670 // is faster. |
| 666 var list = (collection is NodeList || collection is! List) | 671 var list = _flattenDocFragments(collection); |
| 667 ? collection.toList() : collection as List; | |
| 668 for (var node in list.reversed) _setParent(node); | 672 for (var node in list.reversed) _setParent(node); |
| 669 super.addAll(list); | 673 super.addAll(list); |
| 670 } | 674 } |
| 671 | 675 |
| 672 void insert(int index, Node value) { | 676 void insert(int index, Node value) { |
| 673 super.insert(index, _setParent(value)); | 677 if (value is DocumentFragment) { |
| 678 insertAll(index, value.nodes); |
| 679 } else { |
| 680 super.insert(index, _setParent(value)); |
| 681 } |
| 674 } | 682 } |
| 675 | 683 |
| 676 Node removeLast() => super.removeLast()..parent = null; | 684 Node removeLast() => super.removeLast()..parent = null; |
| 677 | 685 |
| 678 Node removeAt(int i) => super.removeAt(i)..parent = null; | 686 Node removeAt(int i) => super.removeAt(i)..parent = null; |
| 679 | 687 |
| 680 void clear() { | 688 void clear() { |
| 681 for (var node in this) node.parent = null; | 689 for (var node in this) node.parent = null; |
| 682 super.clear(); | 690 super.clear(); |
| 683 } | 691 } |
| 684 | 692 |
| 685 void operator []=(int index, Node value) { | 693 void operator []=(int index, Node value) { |
| 686 this[index].parent = null; | 694 if (value is DocumentFragment) { |
| 687 super[index] = _setParent(value); | 695 removeAt(index); |
| 696 insertAll(index, value.nodes); |
| 697 } else { |
| 698 this[index].parent = null; |
| 699 super[index] = _setParent(value); |
| 700 } |
| 688 } | 701 } |
| 689 | 702 |
| 690 // TODO(jmesserly): These aren't implemented in DOM _NodeListImpl, see | 703 // TODO(jmesserly): These aren't implemented in DOM _NodeListImpl, see |
| 691 // http://code.google.com/p/dart/issues/detail?id=5371 | 704 // http://code.google.com/p/dart/issues/detail?id=5371 |
| 692 void setRange(int start, int rangeLength, List<Node> from, | 705 void setRange(int start, int rangeLength, List<Node> from, |
| 693 [int startFrom = 0]) { | 706 [int startFrom = 0]) { |
| 694 if (from is NodeList) { | 707 if (from is NodeList) { |
| 695 // Note: this is presumed to make a copy | 708 // Note: this is presumed to make a copy |
| 696 from = from.sublist(startFrom, startFrom + rangeLength); | 709 from = from.sublist(startFrom, startFrom + rangeLength); |
| 697 } | 710 } |
| 698 // Note: see comment in [addAll]. We need to be careful about the order of | 711 // Note: see comment in [addAll]. We need to be careful about the order of |
| 699 // operations if [from] is also a NodeList. | 712 // operations if [from] is also a NodeList. |
| 700 for (int i = rangeLength - 1; i >= 0; i--) { | 713 for (int i = rangeLength - 1; i >= 0; i--) { |
| 701 this[start + i].parent = null; | 714 this[start + i] = from[startFrom + i]; |
| 702 super[start + i] = _setParent(from[startFrom + i]); | |
| 703 } | 715 } |
| 704 } | 716 } |
| 705 | 717 |
| 706 void replaceRange(int start, int end, Iterable<Node> newContents) { | 718 void replaceRange(int start, int end, Iterable<Node> newContents) { |
| 707 removeRange(start, end); | 719 removeRange(start, end); |
| 708 insertAll(start, newContents); | 720 insertAll(start, newContents); |
| 709 } | 721 } |
| 710 | 722 |
| 711 void removeRange(int start, int rangeLength) { | 723 void removeRange(int start, int rangeLength) { |
| 712 for (int i = start; i < rangeLength; i++) this[i].parent = null; | 724 for (int i = start; i < rangeLength; i++) this[i].parent = null; |
| 713 super.removeRange(start, rangeLength); | 725 super.removeRange(start, rangeLength); |
| 714 } | 726 } |
| 715 | 727 |
| 716 void removeWhere(bool test(Element e)) { | 728 void removeWhere(bool test(Element e)) { |
| 717 for (var node in where(test)) { | 729 for (var node in where(test)) { |
| 718 node.parent = null; | 730 node.parent = null; |
| 719 } | 731 } |
| 720 super.removeWhere(test); | 732 super.removeWhere(test); |
| 721 } | 733 } |
| 722 | 734 |
| 723 void retainWhere(bool test(Element e)) { | 735 void retainWhere(bool test(Element e)) { |
| 724 for (var node in where((n) => !test(n))) { | 736 for (var node in where((n) => !test(n))) { |
| 725 node.parent = null; | 737 node.parent = null; |
| 726 } | 738 } |
| 727 super.retainWhere(test); | 739 super.retainWhere(test); |
| 728 } | 740 } |
| 729 | 741 |
| 730 void insertAll(int index, List<Node> nodes) { | 742 void insertAll(int index, Iterable<Node> collection) { |
| 731 for (var node in nodes) _setParent(node); | 743 // Note: we need to be careful how we copy nodes. See note in addAll. |
| 732 super.insertAll(index, nodes); | 744 var list = _flattenDocFragments(collection); |
| 745 for (var node in list.reversed) _setParent(node); |
| 746 super.insertAll(index, list); |
| 747 } |
| 748 |
| 749 _flattenDocFragments(Iterable<Node> collection) { |
| 750 // Note: this function serves two purposes: |
| 751 // * it flattens document fragments |
| 752 // * it creates a copy of [collections] when `collection is NodeList`. |
| 753 var result = []; |
| 754 for (var node in collection) { |
| 755 if (node is DocumentFragment) { |
| 756 result.addAll(node.nodes); |
| 757 } else { |
| 758 result.add(node); |
| 759 } |
| 760 } |
| 761 return result; |
| 733 } | 762 } |
| 734 } | 763 } |
| 735 | 764 |
| 736 | 765 |
| 737 /// An indexable collection of a node's descendants in the document tree, | 766 /// An indexable collection of a node's descendants in the document tree, |
| 738 /// filtered so that only elements are in the collection. | 767 /// filtered so that only elements are in the collection. |
| 739 // TODO(jmesserly): this was copied from dart:html | 768 // TODO(jmesserly): this was copied from dart:html |
| 740 // TODO(jmesserly): "implements List<Element>" is a workaround for analyzer bug. | 769 // TODO(jmesserly): "implements List<Element>" is a workaround for analyzer bug. |
| 741 class FilteredElementList extends IterableBase<Element> with ListMixin<Element> | 770 class FilteredElementList extends IterableBase<Element> with ListMixin<Element> |
| 742 implements List<Element> { | 771 implements List<Element> { |
| (...skipping 184 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 927 | 956 |
| 928 class _ConcatTextVisitor extends TreeVisitor { | 957 class _ConcatTextVisitor extends TreeVisitor { |
| 929 final _str = new StringBuffer(); | 958 final _str = new StringBuffer(); |
| 930 | 959 |
| 931 String toString() => _str.toString(); | 960 String toString() => _str.toString(); |
| 932 | 961 |
| 933 visitText(Text node) { | 962 visitText(Text node) { |
| 934 _str.write(node.data); | 963 _str.write(node.data); |
| 935 } | 964 } |
| 936 } | 965 } |
| OLD | NEW |