OLD | NEW |
(Empty) | |
| 1 // Copyright (c) 2011, the Dart project authors. Please see the AUTHORS file |
| 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. |
| 4 |
| 5 part of html_common; |
| 6 |
| 7 /** |
| 8 * An indexable collection of a node's direct descendants in the document tree, |
| 9 * filtered so that only elements are in the collection. |
| 10 */ |
| 11 class FilteredElementList extends ListBase<Element> implements NodeListWrapper { |
| 12 final Node _node; |
| 13 final List<Node> _childNodes; |
| 14 |
| 15 /** |
| 16 * Creates a collection of the elements that descend from a node. |
| 17 * |
| 18 * Example usage: |
| 19 * |
| 20 * var filteredElements = new FilteredElementList(query("#container")); |
| 21 * // filteredElements is [a, b, c]. |
| 22 */ |
| 23 FilteredElementList(Node node) |
| 24 : _childNodes = node.nodes, |
| 25 _node = node; |
| 26 |
| 27 // We can't memoize this, since it's possible that children will be messed |
| 28 // with externally to this class. |
| 29 // |
| 30 // We can't use where directly because the types don't agree and there's |
| 31 // no way to cast it, so take advantage of being in the SDK to construct |
| 32 // a WhereIterable directly. Even so it has to be of dynamic. |
| 33 Iterable<Element> get _iterable => |
| 34 new WhereIterable(_childNodes, (n) => n is Element); |
| 35 List<Element> get _filtered => |
| 36 new List<Element>.from(_iterable, growable: false); |
| 37 |
| 38 void forEach(void f(Element element)) { |
| 39 // This cannot use the iterator, because operations during iteration might |
| 40 // modify the collection, e.g. addAll might append a node to another parent. |
| 41 _filtered.forEach(f); |
| 42 } |
| 43 |
| 44 void operator []=(int index, Element value) { |
| 45 this[index].replaceWith(value); |
| 46 } |
| 47 |
| 48 set length(int newLength) { |
| 49 final len = this.length; |
| 50 if (newLength >= len) { |
| 51 return; |
| 52 } else if (newLength < 0) { |
| 53 throw new ArgumentError("Invalid list length"); |
| 54 } |
| 55 |
| 56 removeRange(newLength, len); |
| 57 } |
| 58 |
| 59 void add(Element value) { |
| 60 _childNodes.add(value); |
| 61 } |
| 62 |
| 63 void addAll(Iterable<Element> iterable) { |
| 64 for (Element element in iterable) { |
| 65 add(element); |
| 66 } |
| 67 } |
| 68 |
| 69 bool contains(Object needle) { |
| 70 if (needle is! Element) return false; |
| 71 Element element = needle; |
| 72 return element.parentNode == _node; |
| 73 } |
| 74 |
| 75 Iterable<Element> get reversed => _filtered.reversed; |
| 76 |
| 77 void sort([int compare(Element a, Element b)]) { |
| 78 throw new UnsupportedError('Cannot sort filtered list'); |
| 79 } |
| 80 |
| 81 void setRange(int start, int end, Iterable<Element> iterable, |
| 82 [int skipCount = 0]) { |
| 83 throw new UnsupportedError('Cannot setRange on filtered list'); |
| 84 } |
| 85 |
| 86 void fillRange(int start, int end, [Element fillValue]) { |
| 87 throw new UnsupportedError('Cannot fillRange on filtered list'); |
| 88 } |
| 89 |
| 90 void replaceRange(int start, int end, Iterable<Element> iterable) { |
| 91 throw new UnsupportedError('Cannot replaceRange on filtered list'); |
| 92 } |
| 93 |
| 94 void removeRange(int start, int end) { |
| 95 new List.from(_iterable.skip(start).take(end - start)) |
| 96 .forEach((el) => el.remove()); |
| 97 } |
| 98 |
| 99 void clear() { |
| 100 // Currently, ElementList#clear clears even non-element nodes, so we follow |
| 101 // that behavior. |
| 102 _childNodes.clear(); |
| 103 } |
| 104 |
| 105 Element removeLast() { |
| 106 final result = _iterable.last; |
| 107 if (result != null) { |
| 108 result.remove(); |
| 109 } |
| 110 return result; |
| 111 } |
| 112 |
| 113 void insert(int index, Element value) { |
| 114 if (index == length) { |
| 115 add(value); |
| 116 } else { |
| 117 var element = _iterable.elementAt(index); |
| 118 element.parentNode.insertBefore(value, element); |
| 119 } |
| 120 } |
| 121 |
| 122 void insertAll(int index, Iterable<Element> iterable) { |
| 123 if (index == length) { |
| 124 addAll(iterable); |
| 125 } else { |
| 126 var element = _iterable.elementAt(index); |
| 127 element.parentNode.insertAllBefore(iterable, element); |
| 128 } |
| 129 } |
| 130 |
| 131 Element removeAt(int index) { |
| 132 final result = this[index]; |
| 133 result.remove(); |
| 134 return result; |
| 135 } |
| 136 |
| 137 bool remove(Object element) { |
| 138 if (element is! Element) return false; |
| 139 if (contains(element)) { |
| 140 (element as Element).remove(); // Placate the type checker |
| 141 return true; |
| 142 } else { |
| 143 return false; |
| 144 } |
| 145 } |
| 146 |
| 147 int get length => _iterable.length; |
| 148 Element operator [](int index) => _iterable.elementAt(index); |
| 149 // This cannot use the iterator, because operations during iteration might |
| 150 // modify the collection, e.g. addAll might append a node to another parent. |
| 151 Iterator<Element> get iterator => _filtered.iterator; |
| 152 |
| 153 List<Node> get rawList => _node.childNodes; |
| 154 } |
OLD | NEW |