Index: tool/input_sdk/lib/html/html_common/filtered_element_list.dart |
diff --git a/tool/input_sdk/lib/html/html_common/filtered_element_list.dart b/tool/input_sdk/lib/html/html_common/filtered_element_list.dart |
new file mode 100644 |
index 0000000000000000000000000000000000000000..e9e47180fbdb26805ee503a5e413e5a639f70b88 |
--- /dev/null |
+++ b/tool/input_sdk/lib/html/html_common/filtered_element_list.dart |
@@ -0,0 +1,154 @@ |
+// Copyright (c) 2011, the Dart project authors. Please see the AUTHORS file |
+// for details. All rights reserved. Use of this source code is governed by a |
+// BSD-style license that can be found in the LICENSE file. |
+ |
+part of html_common; |
+ |
+/** |
+ * An indexable collection of a node's direct descendants in the document tree, |
+ * filtered so that only elements are in the collection. |
+ */ |
+class FilteredElementList extends ListBase<Element> implements NodeListWrapper { |
+ final Node _node; |
+ final List<Node> _childNodes; |
+ |
+ /** |
+ * Creates a collection of the elements that descend from a node. |
+ * |
+ * Example usage: |
+ * |
+ * var filteredElements = new FilteredElementList(query("#container")); |
+ * // filteredElements is [a, b, c]. |
+ */ |
+ FilteredElementList(Node node) |
+ : _childNodes = node.nodes, |
+ _node = node; |
+ |
+ // We can't memoize this, since it's possible that children will be messed |
+ // with externally to this class. |
+ // |
+ // We can't use where directly because the types don't agree and there's |
+ // no way to cast it, so take advantage of being in the SDK to construct |
+ // a WhereIterable directly. Even so it has to be of dynamic. |
+ Iterable<Element> get _iterable => |
+ new WhereIterable(_childNodes, (n) => n is Element); |
+ List<Element> get _filtered => |
+ new List<Element>.from(_iterable, growable: false); |
+ |
+ void forEach(void f(Element element)) { |
+ // This cannot use the iterator, because operations during iteration might |
+ // modify the collection, e.g. addAll might append a node to another parent. |
+ _filtered.forEach(f); |
+ } |
+ |
+ void operator []=(int index, Element value) { |
+ this[index].replaceWith(value); |
+ } |
+ |
+ set length(int newLength) { |
+ final len = this.length; |
+ if (newLength >= len) { |
+ return; |
+ } else if (newLength < 0) { |
+ throw new ArgumentError("Invalid list length"); |
+ } |
+ |
+ removeRange(newLength, len); |
+ } |
+ |
+ void add(Element value) { |
+ _childNodes.add(value); |
+ } |
+ |
+ void addAll(Iterable<Element> iterable) { |
+ for (Element element in iterable) { |
+ add(element); |
+ } |
+ } |
+ |
+ bool contains(Object needle) { |
+ if (needle is! Element) return false; |
+ Element element = needle; |
+ return element.parentNode == _node; |
+ } |
+ |
+ Iterable<Element> get reversed => _filtered.reversed; |
+ |
+ void sort([int compare(Element a, Element b)]) { |
+ throw new UnsupportedError('Cannot sort filtered list'); |
+ } |
+ |
+ void setRange(int start, int end, Iterable<Element> iterable, |
+ [int skipCount = 0]) { |
+ throw new UnsupportedError('Cannot setRange on filtered list'); |
+ } |
+ |
+ void fillRange(int start, int end, [Element fillValue]) { |
+ throw new UnsupportedError('Cannot fillRange on filtered list'); |
+ } |
+ |
+ void replaceRange(int start, int end, Iterable<Element> iterable) { |
+ throw new UnsupportedError('Cannot replaceRange on filtered list'); |
+ } |
+ |
+ void removeRange(int start, int end) { |
+ new List.from(_iterable.skip(start).take(end - start)) |
+ .forEach((el) => el.remove()); |
+ } |
+ |
+ void clear() { |
+ // Currently, ElementList#clear clears even non-element nodes, so we follow |
+ // that behavior. |
+ _childNodes.clear(); |
+ } |
+ |
+ Element removeLast() { |
+ final result = _iterable.last; |
+ if (result != null) { |
+ result.remove(); |
+ } |
+ return result; |
+ } |
+ |
+ void insert(int index, Element value) { |
+ if (index == length) { |
+ add(value); |
+ } else { |
+ var element = _iterable.elementAt(index); |
+ element.parentNode.insertBefore(value, element); |
+ } |
+ } |
+ |
+ void insertAll(int index, Iterable<Element> iterable) { |
+ if (index == length) { |
+ addAll(iterable); |
+ } else { |
+ var element = _iterable.elementAt(index); |
+ element.parentNode.insertAllBefore(iterable, element); |
+ } |
+ } |
+ |
+ Element removeAt(int index) { |
+ final result = this[index]; |
+ result.remove(); |
+ return result; |
+ } |
+ |
+ bool remove(Object element) { |
+ if (element is! Element) return false; |
+ if (contains(element)) { |
+ (element as Element).remove(); // Placate the type checker |
+ return true; |
+ } else { |
+ return false; |
+ } |
+ } |
+ |
+ int get length => _iterable.length; |
+ Element operator [](int index) => _iterable.elementAt(index); |
+ // This cannot use the iterator, because operations during iteration might |
+ // modify the collection, e.g. addAll might append a node to another parent. |
+ Iterator<Element> get iterator => _filtered.iterator; |
+ |
+ List<Node> get rawList => _node.childNodes; |
+} |