Chromium Code Reviews| 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 /** | 7 /** |
| 8 * Lazy implementation of the child nodes of an element that does not request | 8 * Lazy implementation of the child nodes of an element that does not request |
| 9 * the actual child nodes of an element until strictly necessary greatly | 9 * the actual child nodes of an element until strictly necessary greatly |
| 10 * improving performance for the typical cases where it is not required. | 10 * improving performance for the typical cases where it is not required. |
| 11 */ | 11 */ |
| 12 class _ChildNodeListLazy implements List { | 12 class _ChildNodeListLazy extends ListBase<Node> { |
| 13 final Node _this; | 13 final Node _this; |
| 14 | 14 |
| 15 _ChildNodeListLazy(this._this); | 15 _ChildNodeListLazy(this._this); |
| 16 | 16 |
| 17 | 17 |
| 18 $if DART2JS | 18 $if DART2JS |
| 19 Node get first { | 19 Node get first { |
| 20 Node result = JS('Node|Null', '#.firstChild', _this); | 20 Node result = JS('Node|Null', '#.firstChild', _this); |
| 21 if (result == null) throw new StateError("No elements"); | 21 if (result == null) throw new StateError("No elements"); |
| 22 return result; | 22 return result; |
| (...skipping 21 matching lines...) Expand all Loading... | |
| 44 return result; | 44 return result; |
| 45 } | 45 } |
| 46 Node get single { | 46 Node get single { |
| 47 int l = this.length; | 47 int l = this.length; |
| 48 if (l == 0) throw new StateError("No elements"); | 48 if (l == 0) throw new StateError("No elements"); |
| 49 if (l > 1) throw new StateError("More than one element"); | 49 if (l > 1) throw new StateError("More than one element"); |
| 50 return _this.$dom_firstChild; | 50 return _this.$dom_firstChild; |
| 51 } | 51 } |
| 52 $endif | 52 $endif |
| 53 | 53 |
| 54 Node min([int compare(Node a, Node b)]) { | |
| 55 return IterableMixinWorkaround.min(this, compare); | |
| 56 } | |
| 57 | |
| 58 Node max([int compare(Node a, Node b)]) { | |
| 59 return IterableMixinWorkaround.max(this, compare); | |
| 60 } | |
| 61 | |
| 62 void add(Node value) { | 54 void add(Node value) { |
| 63 _this.append(value); | 55 _this.append(value); |
| 64 } | 56 } |
| 65 | 57 |
| 66 void addAll(Iterable<Node> iterable) { | 58 void addAll(Iterable<Node> iterable) { |
| 67 if (iterable is _ChildNodeListLazy) { | 59 if (iterable is _ChildNodeListLazy) { |
| 68 if (!identical(iterable._this, _this)) { | 60 if (!identical(iterable._this, _this)) { |
| 69 // Optimized route for copying between nodes. | 61 // Optimized route for copying between nodes. |
| 70 for (var i = 0, len = iterable.length; i < len; ++i) { | 62 for (var i = 0, len = iterable.length; i < len; ++i) { |
| 71 // Should use $dom_firstChild, Bug 8886. | 63 // Should use $dom_firstChild, Bug 8886. |
| (...skipping 34 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... | |
| 106 return result; | 98 return result; |
| 107 } | 99 } |
| 108 | 100 |
| 109 void remove(Object object) { | 101 void remove(Object object) { |
| 110 if (object is! Node) return; | 102 if (object is! Node) return; |
| 111 Node node = object; | 103 Node node = object; |
| 112 if (!identical(_this, node.parentNode)) return; | 104 if (!identical(_this, node.parentNode)) return; |
| 113 _this.$dom_removeChild(node); | 105 _this.$dom_removeChild(node); |
| 114 } | 106 } |
| 115 | 107 |
| 116 void removeAll(Iterable elements) { | 108 void removeAll(Iterable elements) { |
|
floitsch
2013/04/08 15:33:14
Explain why this doesn't come from the ListBase.
Lasse Reichstein Nielsen
2013/04/11 07:28:19
Done.
| |
| 117 IterableMixinWorkaround.removeAll(this, elements); | 109 for (var element in elements) { |
| 110 remove(element); | |
| 111 } | |
| 112 } | |
| 113 | |
| 114 void _filter(bool test(Node node), bool removeMatching) { | |
| 115 Node child = _this.$dom_firstChild; | |
| 116 while (child != null) { | |
| 117 Node nextChild = child.nextSibling; | |
| 118 if (test(child) == removeMatching) { | |
| 119 _this.$dom_removeChild(child); | |
| 120 } | |
| 121 child = nextChild; | |
| 122 } | |
| 118 } | 123 } |
| 119 | 124 |
| 120 void retainAll(Iterable elements) { | 125 void retainAll(Iterable elements) { |
| 121 IterableMixinWorkaround.retainAll(this, elements); | 126 Set retainSet = (elements is Set) ? elements : elements.toSet(); |
| 127 _filter(retainSet.contains, false); | |
| 122 } | 128 } |
| 123 | 129 |
| 124 void removeWhere(bool test(Node node)) { | 130 void removeWhere(bool test(Node node)) { |
| 125 IterableMixinWorkaround.removeWhere(this, test); | 131 _filter(test, true); |
|
floitsch
2013/04/08 15:33:14
ditto.
Lasse Reichstein Nielsen
2013/04/11 07:28:19
Done.
| |
| 126 } | 132 } |
| 127 | 133 |
| 128 void retainWhere(bool test(Node node)) { | 134 void retainWhere(bool test(Node node)) { |
| 129 IterableMixinWorkaround.retainWhere(this, test); | 135 _filter(test, false); |
| 130 } | 136 } |
| 131 | 137 |
| 132 void clear() { | 138 void clear() { |
| 133 _this.text = ''; | 139 _this.text = ''; |
| 134 } | 140 } |
| 135 | 141 |
| 136 void operator []=(int index, Node value) { | 142 void operator []=(int index, Node value) { |
| 137 _this.$dom_replaceChild(value, this[index]); | 143 _this.$dom_replaceChild(value, this[index]); |
| 138 } | 144 } |
| 139 | 145 |
| 140 Iterator<Node> get iterator => _this.$dom_childNodes.iterator; | 146 Iterator<Node> get iterator => _this.$dom_childNodes.iterator; |
| 141 | 147 |
| 142 // TODO(jacobr): We can implement these methods much more efficiently by | |
| 143 // looking up the nodeList only once instead of once per iteration. | |
| 144 bool contains(Node element) => IterableMixinWorkaround.contains(this, element) ; | |
| 145 | |
| 146 void forEach(void f(Node element)) => IterableMixinWorkaround.forEach(this, f) ; | |
| 147 | |
| 148 dynamic reduce(dynamic initialValue, | |
| 149 dynamic combine(dynamic previousValue, Node element)) { | |
| 150 return IterableMixinWorkaround.reduce(this, initialValue, combine); | |
| 151 } | |
| 152 | |
| 153 dynamic fold(dynamic initialValue, | |
| 154 dynamic combine(dynamic previousValue, Node element)) { | |
| 155 return IterableMixinWorkaround.fold(this, initialValue, combine); | |
| 156 } | |
| 157 | |
| 158 String join([String separator]) { | |
| 159 return IterableMixinWorkaround.joinList(this, separator); | |
| 160 } | |
| 161 | |
| 162 Iterable map(f(Node element)) { | |
| 163 return IterableMixinWorkaround.mapList(this, f); | |
| 164 } | |
| 165 | |
| 166 Iterable<Node> where(bool f(Node element)) { | |
| 167 return IterableMixinWorkaround.where(this, f); | |
| 168 } | |
| 169 | |
| 170 Iterable expand(Iterable f(Node element)) { | |
| 171 return IterableMixinWorkaround.expand(this, f); | |
| 172 } | |
| 173 | |
| 174 bool every(bool f(Node element)) => IterableMixinWorkaround.every(this, f); | |
| 175 | |
| 176 bool any(bool f(Node element)) => IterableMixinWorkaround.any(this, f); | |
| 177 | |
| 178 List<Node> toList({ bool growable: true }) => | 148 List<Node> toList({ bool growable: true }) => |
| 179 new List<Node>.from(this, growable: growable); | 149 new List<Node>.from(this, growable: growable); |
| 180 Set<Node> toSet() => new Set<Node>.from(this); | 150 Set<Node> toSet() => new Set<Node>.from(this); |
| 181 | 151 |
| 182 bool get isEmpty => this.length == 0; | 152 bool get isEmpty => this.length == 0; |
| 183 | 153 |
| 184 // From List<Node>: | 154 // From List<Node>: |
| 185 | 155 |
| 186 Iterable<Node> take(int n) { | |
| 187 return IterableMixinWorkaround.takeList(this, n); | |
| 188 } | |
| 189 | |
| 190 Iterable<Node> takeWhile(bool test(Node value)) { | |
| 191 return IterableMixinWorkaround.takeWhile(this, test); | |
| 192 } | |
| 193 | |
| 194 Iterable<Node> skip(int n) { | |
| 195 return IterableMixinWorkaround.skipList(this, n); | |
| 196 } | |
| 197 | |
| 198 Iterable<Node> skipWhile(bool test(Node value)) { | |
| 199 return IterableMixinWorkaround.skipWhile(this, test); | |
| 200 } | |
| 201 | |
| 202 Node firstWhere(bool test(Node value), {Node orElse()}) { | |
| 203 return IterableMixinWorkaround.firstWhere(this, test, orElse); | |
| 204 } | |
| 205 | |
| 206 Node lastWhere(bool test(Node value), {Node orElse()}) { | |
| 207 return IterableMixinWorkaround.lastWhereList(this, test, orElse); | |
| 208 } | |
| 209 | |
| 210 Node singleWhere(bool test(Node value)) { | |
| 211 return IterableMixinWorkaround.singleWhere(this, test); | |
| 212 } | |
| 213 | |
| 214 Node elementAt(int index) { | |
| 215 return this[index]; | |
| 216 } | |
| 217 | |
| 218 Iterable<Node> get reversed { | |
| 219 return IterableMixinWorkaround.reversedList(this); | |
| 220 } | |
| 221 | |
| 222 // TODO(jacobr): this could be implemented for child node lists. | 156 // TODO(jacobr): this could be implemented for child node lists. |
| 223 // The exception we throw here is misleading. | 157 // The exception we throw here is misleading. |
| 224 void sort([int compare(Node a, Node b)]) { | 158 void sort([int compare(Node a, Node b)]) { |
| 225 throw new UnsupportedError("Cannot sort immutable List."); | 159 throw new UnsupportedError("Cannot sort immutable List."); |
| 226 } | 160 } |
| 227 | 161 |
| 228 int indexOf(Node element, [int start = 0]) => | |
| 229 Lists.indexOf(this, element, start, this.length); | |
| 230 | |
| 231 int lastIndexOf(Node element, [int start = 0]) => | |
| 232 Lists.lastIndexOf(this, element, start); | |
| 233 | |
| 234 // FIXME: implement these. | 162 // FIXME: implement these. |
| 235 void setRange(int start, int rangeLength, List<Node> from, [int startFrom]) { | 163 void setRange(int start, int rangeLength, List<Node> from, [int startFrom]) { |
| 236 throw new UnsupportedError( | 164 throw new UnsupportedError( |
| 237 "Cannot setRange on immutable List."); | 165 "Cannot setRange on immutable List."); |
| 238 } | 166 } |
| 239 void removeRange(int start, int rangeLength) { | 167 void removeRange(int start, int rangeLength) { |
| 240 throw new UnsupportedError( | 168 throw new UnsupportedError( |
| 241 "Cannot removeRange on immutable List."); | 169 "Cannot removeRange on immutable List."); |
| 242 } | 170 } |
| 243 void insertRange(int start, int rangeLength, [Node initialValue]) { | 171 void insertRange(int start, int rangeLength, [Node initialValue]) { |
| (...skipping 19 matching lines...) Expand all Loading... | |
| 263 // TODO(jacobr): benchmark whether this is more efficient or whether caching | 191 // TODO(jacobr): benchmark whether this is more efficient or whether caching |
| 264 // a local copy of $dom_childNodes is more efficient. | 192 // a local copy of $dom_childNodes is more efficient. |
| 265 int get length => _this.$dom_childNodes.length; | 193 int get length => _this.$dom_childNodes.length; |
| 266 | 194 |
| 267 void set length(int value) { | 195 void set length(int value) { |
| 268 throw new UnsupportedError( | 196 throw new UnsupportedError( |
| 269 "Cannot set length on immutable List."); | 197 "Cannot set length on immutable List."); |
| 270 } | 198 } |
| 271 | 199 |
| 272 Node operator[](int index) => _this.$dom_childNodes[index]; | 200 Node operator[](int index) => _this.$dom_childNodes[index]; |
| 273 | |
| 274 Map<int, Node> asMap() => IterableMixinWorkaround.asMapList(this); | |
| 275 } | 201 } |
| 276 | 202 |
| 277 $(ANNOTATIONS)class $CLASSNAME$EXTENDS$IMPLEMENTS$NATIVESPEC { | 203 $(ANNOTATIONS)class $CLASSNAME$EXTENDS$IMPLEMENTS$NATIVESPEC { |
| 278 List<Node> get nodes { | 204 List<Node> get nodes { |
| 279 return new _ChildNodeListLazy(this); | 205 return new _ChildNodeListLazy(this); |
| 280 } | 206 } |
| 281 | 207 |
| 282 void set nodes(Collection<Node> value) { | 208 void set nodes(Collection<Node> value) { |
| 283 // Copy list first since we don't want liveness during iteration. | 209 // Copy list first since we don't want liveness during iteration. |
| 284 // TODO(jacobr): there is a better way to do this. | 210 // TODO(jacobr): there is a better way to do this. |
| (...skipping 134 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... | |
| 419 if (_modelChangedStream == null) { | 345 if (_modelChangedStream == null) { |
| 420 // Ensure the model is cached locally to minimize change notifications. | 346 // Ensure the model is cached locally to minimize change notifications. |
| 421 _model = model; | 347 _model = model; |
| 422 _modelChangedStream = new StreamController.broadcast(); | 348 _modelChangedStream = new StreamController.broadcast(); |
| 423 } | 349 } |
| 424 return _modelChangedStream.stream; | 350 return _modelChangedStream.stream; |
| 425 } | 351 } |
| 426 | 352 |
| 427 $!MEMBERS | 353 $!MEMBERS |
| 428 } | 354 } |
| OLD | NEW |