| 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 it is missing many types and APIs. | 2 /// with dart:html, but it is missing many types and APIs. |
| 3 library dom; | 3 library dom; |
| 4 | 4 |
| 5 // TODO(jmesserly): lots to do here. Originally I wanted to generate this using | 5 // TODO(jmesserly): lots to do here. Originally I wanted to generate this using |
| 6 // our Blink IDL generator, but another idea is to directly use the excellent | 6 // our Blink IDL generator, but another idea is to directly use the excellent |
| 7 // http://dom.spec.whatwg.org/ and http://html.spec.whatwg.org/ and just | 7 // http://dom.spec.whatwg.org/ and http://html.spec.whatwg.org/ and just |
| 8 // implement that. | 8 // implement that. |
| 9 | 9 |
| 10 import 'dart:collection'; | 10 import 'dart:collection'; |
| (...skipping 724 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 735 removeAt(index); | 735 removeAt(index); |
| 736 insertAll(index, value.nodes); | 736 insertAll(index, value.nodes); |
| 737 } else { | 737 } else { |
| 738 this[index].parentNode = null; | 738 this[index].parentNode = null; |
| 739 super[index] = _setParent(value); | 739 super[index] = _setParent(value); |
| 740 } | 740 } |
| 741 } | 741 } |
| 742 | 742 |
| 743 // TODO(jmesserly): These aren't implemented in DOM _NodeListImpl, see | 743 // TODO(jmesserly): These aren't implemented in DOM _NodeListImpl, see |
| 744 // http://code.google.com/p/dart/issues/detail?id=5371 | 744 // http://code.google.com/p/dart/issues/detail?id=5371 |
| 745 void setRange(int start, int rangeLength, List<Node> from, | 745 void setRange(int start, int rangeLength, Iterable<Node> from, |
| 746 [int startFrom = 0]) { | 746 [int startFrom = 0]) { |
| 747 if (from is NodeList) { | 747 List<Node> from_ = from as List<Node>; |
| 748 if (from_ is NodeList) { |
| 748 // Note: this is presumed to make a copy | 749 // Note: this is presumed to make a copy |
| 749 from = from.sublist(startFrom, startFrom + rangeLength); | 750 from_ = from_.sublist(startFrom, startFrom + rangeLength); |
| 750 } | 751 } |
| 751 // Note: see comment in [addAll]. We need to be careful about the order of | 752 // Note: see comment in [addAll]. We need to be careful about the order of |
| 752 // operations if [from] is also a NodeList. | 753 // operations if [from] is also a NodeList. |
| 753 for (int i = rangeLength - 1; i >= 0; i--) { | 754 for (int i = rangeLength - 1; i >= 0; i--) { |
| 754 this[start + i] = from[startFrom + i]; | 755 this[start + i] = from_[startFrom + i]; |
| 755 } | 756 } |
| 756 } | 757 } |
| 757 | 758 |
| 758 void replaceRange(int start, int end, Iterable<Node> newContents) { | 759 void replaceRange(int start, int end, Iterable<Node> newContents) { |
| 759 removeRange(start, end); | 760 removeRange(start, end); |
| 760 insertAll(start, newContents); | 761 insertAll(start, newContents); |
| 761 } | 762 } |
| 762 | 763 |
| 763 void removeRange(int start, int rangeLength) { | 764 void removeRange(int start, int rangeLength) { |
| 764 for (int i = start; i < rangeLength; i++) this[i].parentNode = null; | 765 for (int i = start; i < rangeLength; i++) this[i].parentNode = null; |
| 765 super.removeRange(start, rangeLength); | 766 super.removeRange(start, rangeLength); |
| 766 } | 767 } |
| 767 | 768 |
| 768 void removeWhere(bool test(Element e)) { | 769 void removeWhere(bool test(Node e)) { |
| 769 for (var node in where(test)) { | 770 for (var node in where(test)) { |
| 770 node.parentNode = null; | 771 node.parentNode = null; |
| 771 } | 772 } |
| 772 super.removeWhere(test); | 773 super.removeWhere(test); |
| 773 } | 774 } |
| 774 | 775 |
| 775 void retainWhere(bool test(Element e)) { | 776 void retainWhere(bool test(Node e)) { |
| 776 for (var node in where((n) => !test(n))) { | 777 for (var node in where((n) => !test(n))) { |
| 777 node.parentNode = null; | 778 node.parentNode = null; |
| 778 } | 779 } |
| 779 super.retainWhere(test); | 780 super.retainWhere(test); |
| 780 } | 781 } |
| 781 | 782 |
| 782 void insertAll(int index, Iterable<Node> collection) { | 783 void insertAll(int index, Iterable<Node> collection) { |
| 783 // Note: we need to be careful how we copy nodes. See note in addAll. | 784 // Note: we need to be careful how we copy nodes. See note in addAll. |
| 784 var list = _flattenDocFragments(collection); | 785 var list = _flattenDocFragments(collection); |
| 785 for (var node in list.reversed) _setParent(node); | 786 for (var node in list.reversed) _setParent(node); |
| 786 super.insertAll(index, list); | 787 super.insertAll(index, list); |
| 787 } | 788 } |
| 788 | 789 |
| 789 _flattenDocFragments(Iterable<Node> collection) { | 790 List<Node> _flattenDocFragments(Iterable<Node> collection) { |
| 790 // Note: this function serves two purposes: | 791 // Note: this function serves two purposes: |
| 791 // * it flattens document fragments | 792 // * it flattens document fragments |
| 792 // * it creates a copy of [collections] when `collection is NodeList`. | 793 // * it creates a copy of [collections] when `collection is NodeList`. |
| 793 var result = []; | 794 var result = <Node>[]; |
| 794 for (var node in collection) { | 795 for (var node in collection) { |
| 795 if (node is DocumentFragment) { | 796 if (node is DocumentFragment) { |
| 796 result.addAll(node.nodes); | 797 result.addAll(node.nodes); |
| 797 } else { | 798 } else { |
| 798 result.add(node); | 799 result.add(node); |
| 799 } | 800 } |
| 800 } | 801 } |
| 801 return result; | 802 return result; |
| 802 } | 803 } |
| 803 } | 804 } |
| 804 | 805 |
| 805 /// An indexable collection of a node's descendants in the document tree, | 806 /// An indexable collection of a node's descendants in the document tree, |
| 806 /// filtered so that only elements are in the collection. | 807 /// filtered so that only elements are in the collection. |
| 807 // TODO(jmesserly): this was copied from dart:html | 808 // TODO(jmesserly): this was copied from dart:html |
| 808 // TODO(jmesserly): "implements List<Element>" is a workaround for analyzer bug. | 809 // TODO(jmesserly): "implements List<Element>" is a workaround for analyzer bug. |
| 809 class FilteredElementList extends IterableBase<Element> with ListMixin<Element> | 810 class FilteredElementList extends IterableBase<Element> with ListMixin<Element> |
| 810 implements List<Element> { | 811 implements List<Element> { |
| 811 final Node _node; | |
| 812 final List<Node> _childNodes; | 812 final List<Node> _childNodes; |
| 813 | 813 |
| 814 /// Creates a collection of the elements that descend from a node. | 814 /// Creates a collection of the elements that descend from a node. |
| 815 /// | 815 /// |
| 816 /// Example usage: | 816 /// Example usage: |
| 817 /// | 817 /// |
| 818 /// var filteredElements = new FilteredElementList(query("#container")); | 818 /// var filteredElements = new FilteredElementList(query("#container")); |
| 819 /// // filteredElements is [a, b, c]. | 819 /// // filteredElements is [a, b, c]. |
| 820 FilteredElementList(Node node) | 820 FilteredElementList(Node node) |
| 821 : _childNodes = node.nodes, | 821 : _childNodes = node.nodes; |
| 822 _node = node; | 822 |
| 823 | 823 |
| 824 // We can't memoize this, since it's possible that children will be messed | 824 // We can't memoize this, since it's possible that children will be messed |
| 825 // with externally to this class. | 825 // with externally to this class. |
| 826 // | 826 // |
| 827 // TODO(nweiz): we don't always need to create a new list. For example | 827 // TODO(nweiz): we don't always need to create a new list. For example |
| 828 // forEach, every, any, ... could directly work on the _childNodes. | 828 // forEach, every, any, ... could directly work on the _childNodes. |
| 829 List<Element> get _filtered => | 829 List<Element> get _filtered => |
| 830 new List<Element>.from(_childNodes.where((n) => n is Element)); | 830 new List<Element>.from(_childNodes.where((n) => n is Element)); |
| 831 | 831 |
| 832 void forEach(void f(Element element)) { | 832 void forEach(void f(Element element)) { |
| (...skipping 20 matching lines...) Expand all Loading... |
| 853 void add(Element value) { | 853 void add(Element value) { |
| 854 _childNodes.add(value); | 854 _childNodes.add(value); |
| 855 } | 855 } |
| 856 | 856 |
| 857 void addAll(Iterable<Element> iterable) { | 857 void addAll(Iterable<Element> iterable) { |
| 858 for (Element element in iterable) { | 858 for (Element element in iterable) { |
| 859 add(element); | 859 add(element); |
| 860 } | 860 } |
| 861 } | 861 } |
| 862 | 862 |
| 863 bool contains(Element element) { | 863 bool contains(Object element) { |
| 864 return element is Element && _childNodes.contains(element); | 864 return element is Element && _childNodes.contains(element); |
| 865 } | 865 } |
| 866 | 866 |
| 867 Iterable<Element> get reversed => _filtered.reversed; | 867 Iterable<Element> get reversed => _filtered.reversed; |
| 868 | 868 |
| 869 void sort([int compare(Element a, Element b)]) { | 869 void sort([int compare(Element a, Element b)]) { |
| 870 throw new UnsupportedError('TODO(jacobr): should we impl?'); | 870 throw new UnsupportedError('TODO(jacobr): should we impl?'); |
| 871 } | 871 } |
| 872 | 872 |
| 873 void setRange(int start, int end, Iterable<Element> iterable, | 873 void setRange(int start, int end, Iterable<Element> iterable, |
| (...skipping 20 matching lines...) Expand all Loading... |
| 894 } | 894 } |
| 895 | 895 |
| 896 Element removeLast() { | 896 Element removeLast() { |
| 897 final result = this.last; | 897 final result = this.last; |
| 898 if (result != null) { | 898 if (result != null) { |
| 899 result.remove(); | 899 result.remove(); |
| 900 } | 900 } |
| 901 return result; | 901 return result; |
| 902 } | 902 } |
| 903 | 903 |
| 904 Iterable map(f(Element element)) => _filtered.map(f); | 904 Iterable/*<T>*/ map/*<T>*/(/*=T*/ f(Element element)) => _filtered.map(f); |
| 905 Iterable<Element> where(bool f(Element element)) => _filtered.where(f); | 905 Iterable<Element> where(bool f(Element element)) => _filtered.where(f); |
| 906 Iterable expand(Iterable f(Element element)) => _filtered.expand(f); | 906 Iterable/*<T>*/ expand/*<T>*/(Iterable/*<T>*/ f(Element element)) => |
| 907 _filtered.expand(f); |
| 907 | 908 |
| 908 void insert(int index, Element value) { | 909 void insert(int index, Element value) { |
| 909 _childNodes.insert(index, value); | 910 _childNodes.insert(index, value); |
| 910 } | 911 } |
| 911 | 912 |
| 912 void insertAll(int index, Iterable<Element> iterable) { | 913 void insertAll(int index, Iterable<Element> iterable) { |
| 913 _childNodes.insertAll(index, iterable); | 914 _childNodes.insertAll(index, iterable); |
| 914 } | 915 } |
| 915 | 916 |
| 916 Element removeAt(int index) { | 917 Element removeAt(int index) { |
| (...skipping 11 matching lines...) Expand all Loading... |
| 928 return true; | 929 return true; |
| 929 } | 930 } |
| 930 } | 931 } |
| 931 return false; | 932 return false; |
| 932 } | 933 } |
| 933 | 934 |
| 934 Element reduce(Element combine(Element value, Element element)) { | 935 Element reduce(Element combine(Element value, Element element)) { |
| 935 return _filtered.reduce(combine); | 936 return _filtered.reduce(combine); |
| 936 } | 937 } |
| 937 | 938 |
| 938 dynamic fold(dynamic initialValue, | 939 dynamic/*=T*/ fold/*<T>*/(var/*=T*/ initialValue, |
| 939 dynamic combine(dynamic previousValue, Element element)) { | 940 dynamic/*=T*/ combine(var/*=T*/ previousValue, Element element)) { |
| 940 return _filtered.fold(initialValue, combine); | 941 return _filtered.fold(initialValue, combine); |
| 941 } | 942 } |
| 942 | 943 |
| 943 bool every(bool f(Element element)) => _filtered.every(f); | 944 bool every(bool f(Element element)) => _filtered.every(f); |
| 944 bool any(bool f(Element element)) => _filtered.any(f); | 945 bool any(bool f(Element element)) => _filtered.any(f); |
| 945 List<Element> toList({bool growable: true}) => | 946 List<Element> toList({bool growable: true}) => |
| 946 new List<Element>.from(this, growable: growable); | 947 new List<Element>.from(this, growable: growable); |
| 947 Set<Element> toSet() => new Set<Element>.from(this); | 948 Set<Element> toSet() => new Set<Element>.from(this); |
| 948 Element firstWhere(bool test(Element value), {Element orElse()}) { | 949 Element firstWhere(bool test(Element value), {Element orElse()}) { |
| 949 return _filtered.firstWhere(test, orElse: orElse); | 950 return _filtered.firstWhere(test, orElse: orElse); |
| (...skipping 11 matching lines...) Expand all Loading... |
| 961 return this[index]; | 962 return this[index]; |
| 962 } | 963 } |
| 963 | 964 |
| 964 bool get isEmpty => _filtered.isEmpty; | 965 bool get isEmpty => _filtered.isEmpty; |
| 965 int get length => _filtered.length; | 966 int get length => _filtered.length; |
| 966 Element operator [](int index) => _filtered[index]; | 967 Element operator [](int index) => _filtered[index]; |
| 967 Iterator<Element> get iterator => _filtered.iterator; | 968 Iterator<Element> get iterator => _filtered.iterator; |
| 968 List<Element> sublist(int start, [int end]) => _filtered.sublist(start, end); | 969 List<Element> sublist(int start, [int end]) => _filtered.sublist(start, end); |
| 969 Iterable<Element> getRange(int start, int end) => | 970 Iterable<Element> getRange(int start, int end) => |
| 970 _filtered.getRange(start, end); | 971 _filtered.getRange(start, end); |
| 971 int indexOf(Element element, [int start = 0]) => | 972 // TODO(sigmund): this should be typed Element, but we currently run into a |
| 973 // bug where ListMixin<E>.indexOf() expects Object as the argument. |
| 974 int indexOf(element, [int start = 0]) => |
| 972 _filtered.indexOf(element, start); | 975 _filtered.indexOf(element, start); |
| 973 | 976 |
| 974 int lastIndexOf(Element element, [int start = null]) { | 977 // TODO(sigmund): this should be typed Element, but we currently run into a |
| 978 // bug where ListMixin<E>.lastIndexOf() expects Object as the argument. |
| 979 int lastIndexOf(element, [int start = null]) { |
| 975 if (start == null) start = length - 1; | 980 if (start == null) start = length - 1; |
| 976 return _filtered.lastIndexOf(element, start); | 981 return _filtered.lastIndexOf(element, start); |
| 977 } | 982 } |
| 978 | 983 |
| 979 Element get first => _filtered.first; | 984 Element get first => _filtered.first; |
| 980 | 985 |
| 981 Element get last => _filtered.last; | 986 Element get last => _filtered.last; |
| 982 | 987 |
| 983 Element get single => _filtered.single; | 988 Element get single => _filtered.single; |
| 984 } | 989 } |
| (...skipping 10 matching lines...) Expand all Loading... |
| 995 | 1000 |
| 996 class _ConcatTextVisitor extends TreeVisitor { | 1001 class _ConcatTextVisitor extends TreeVisitor { |
| 997 final _str = new StringBuffer(); | 1002 final _str = new StringBuffer(); |
| 998 | 1003 |
| 999 String toString() => _str.toString(); | 1004 String toString() => _str.toString(); |
| 1000 | 1005 |
| 1001 visitText(Text node) { | 1006 visitText(Text node) { |
| 1002 _str.write(node.data); | 1007 _str.write(node.data); |
| 1003 } | 1008 } |
| 1004 } | 1009 } |
| OLD | NEW |