OLD | NEW |
| (Empty) |
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 | |
3 // BSD-style license that can be found in the LICENSE file. | |
4 | |
5 part of html; | |
6 | |
7 /** | |
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 | |
10 * improving performance for the typical cases where it is not required. | |
11 */ | |
12 class _ChildNodeListLazy implements List { | |
13 final Node _this; | |
14 | |
15 _ChildNodeListLazy(this._this); | |
16 | |
17 | |
18 $if DART2JS | |
19 Node get first => JS('Node', '#.firstChild', _this); | |
20 Node get last => JS('Node', '#.lastChild', _this); | |
21 $else | |
22 Node get first => _this.$dom_firstChild; | |
23 Node get last => _this.$dom_lastChild; | |
24 $endif | |
25 | |
26 void add(Node value) { | |
27 _this.$dom_appendChild(value); | |
28 } | |
29 | |
30 void addLast(Node value) { | |
31 _this.$dom_appendChild(value); | |
32 } | |
33 | |
34 | |
35 void addAll(Collection<Node> collection) { | |
36 for (Node node in collection) { | |
37 _this.$dom_appendChild(node); | |
38 } | |
39 } | |
40 | |
41 Node removeLast() { | |
42 final result = last; | |
43 if (result != null) { | |
44 _this.$dom_removeChild(result); | |
45 } | |
46 return result; | |
47 } | |
48 | |
49 Node removeAt(int index) { | |
50 var result = this[index]; | |
51 if (result != null) { | |
52 _this.$dom_removeChild(result); | |
53 } | |
54 return result; | |
55 } | |
56 | |
57 void clear() { | |
58 _this.text = ''; | |
59 } | |
60 | |
61 void operator []=(int index, Node value) { | |
62 _this.$dom_replaceChild(value, this[index]); | |
63 } | |
64 | |
65 Iterator<Node> iterator() => _this.$dom_childNodes.iterator(); | |
66 | |
67 // TODO(jacobr): We can implement these methods much more efficiently by | |
68 // looking up the nodeList only once instead of once per iteration. | |
69 bool contains(Node element) => Collections.contains(this, element); | |
70 | |
71 void forEach(void f(Node element)) => Collections.forEach(this, f); | |
72 | |
73 dynamic reduce(dynamic initialValue, | |
74 dynamic combine(dynamic previousValue, Node element)) { | |
75 return Collections.reduce(this, initialValue, combine); | |
76 } | |
77 | |
78 Collection map(f(Node element)) => Collections.map(this, [], f); | |
79 | |
80 Collection<Node> filter(bool f(Node element)) => | |
81 Collections.filter(this, <Node>[], f); | |
82 | |
83 bool every(bool f(Node element)) => Collections.every(this, f); | |
84 | |
85 bool some(bool f(Node element)) => Collections.some(this, f); | |
86 | |
87 bool get isEmpty => this.length == 0; | |
88 | |
89 // From List<Node>: | |
90 | |
91 // TODO(jacobr): this could be implemented for child node lists. | |
92 // The exception we throw here is misleading. | |
93 void sort([int compare(Node a, Node b)]) { | |
94 throw new UnsupportedError("Cannot sort immutable List."); | |
95 } | |
96 | |
97 int indexOf(Node element, [int start = 0]) => | |
98 Lists.indexOf(this, element, start, this.length); | |
99 | |
100 int lastIndexOf(Node element, [int start = 0]) => | |
101 Lists.lastIndexOf(this, element, start); | |
102 | |
103 // FIXME: implement these. | |
104 void setRange(int start, int rangeLength, List<Node> from, [int startFrom]) { | |
105 throw new UnsupportedError( | |
106 "Cannot setRange on immutable List."); | |
107 } | |
108 void removeRange(int start, int rangeLength) { | |
109 throw new UnsupportedError( | |
110 "Cannot removeRange on immutable List."); | |
111 } | |
112 void insertRange(int start, int rangeLength, [Node initialValue]) { | |
113 throw new UnsupportedError( | |
114 "Cannot insertRange on immutable List."); | |
115 } | |
116 List<Node> getRange(int start, int rangeLength) => | |
117 Lists.getRange(this, start, rangeLength, <Node>[]); | |
118 | |
119 // -- end List<Node> mixins. | |
120 | |
121 // TODO(jacobr): benchmark whether this is more efficient or whether caching | |
122 // a local copy of $dom_childNodes is more efficient. | |
123 int get length => _this.$dom_childNodes.length; | |
124 | |
125 void set length(int value) { | |
126 throw new UnsupportedError( | |
127 "Cannot set length on immutable List."); | |
128 } | |
129 | |
130 Node operator[](int index) => _this.$dom_childNodes[index]; | |
131 } | |
132 | |
133 /// @domName $DOMNAME | |
134 class $CLASSNAME$EXTENDS$IMPLEMENTS$NATIVESPEC { | |
135 List<Node> get nodes { | |
136 return new _ChildNodeListLazy(this); | |
137 } | |
138 | |
139 void set nodes(Collection<Node> value) { | |
140 // Copy list first since we don't want liveness during iteration. | |
141 // TODO(jacobr): there is a better way to do this. | |
142 List copy = new List.from(value); | |
143 text = ''; | |
144 for (Node node in copy) { | |
145 $dom_appendChild(node); | |
146 } | |
147 } | |
148 | |
149 /** | |
150 * Removes this node from the DOM. | |
151 * @domName Node.removeChild | |
152 */ | |
153 void remove() { | |
154 // TODO(jacobr): should we throw an exception if parent is already null? | |
155 // TODO(vsm): Use the native remove when available. | |
156 if (this.parentNode != null) { | |
157 final Node parent = this.parentNode; | |
158 parentNode.$dom_removeChild(this); | |
159 } | |
160 } | |
161 | |
162 /** | |
163 * Replaces this node with another node. | |
164 * @domName Node.replaceChild | |
165 */ | |
166 Node replaceWith(Node otherNode) { | |
167 try { | |
168 final Node parent = this.parentNode; | |
169 parent.$dom_replaceChild(otherNode, this); | |
170 } catch (e) { | |
171 | |
172 }; | |
173 return this; | |
174 } | |
175 | |
176 $!MEMBERS | |
177 } | |
OLD | NEW |