]>
Commit | Line | Data |
---|---|---|
f0cfe83e AD |
1 | define("dojo/NodeList-traverse", ["./query", "./_base/lang", "./_base/array"], function(dquery, lang, array){ |
2 | ||
3 | // module: | |
4 | // dojo/NodeList-traverse | |
5 | ||
6 | /*===== | |
7 | return function(){ | |
8 | // summary: | |
9 | // Adds chainable methods to dojo.query() / NodeList instances for traversing the DOM | |
10 | }; | |
11 | =====*/ | |
12 | ||
13 | var NodeList = dquery.NodeList; | |
14 | ||
15 | lang.extend(NodeList, { | |
16 | _buildArrayFromCallback: function(/*Function*/ callback){ | |
17 | // summary: | |
18 | // builds a new array of possibly differing size based on the input list. | |
19 | // Since the returned array is likely of different size than the input array, | |
20 | // the array's map function cannot be used. | |
21 | var ary = []; | |
22 | for(var i = 0; i < this.length; i++){ | |
23 | var items = callback.call(this[i], this[i], ary); | |
24 | if(items){ | |
25 | ary = ary.concat(items); | |
26 | } | |
27 | } | |
28 | return ary; //Array | |
29 | }, | |
30 | ||
31 | _getUniqueAsNodeList: function(/*Array*/ nodes){ | |
32 | // summary: | |
33 | // given a list of nodes, make sure only unique | |
34 | // elements are returned as our NodeList object. | |
35 | // Does not call _stash(). | |
36 | var ary = []; | |
37 | //Using for loop for better speed. | |
38 | for(var i = 0, node; node = nodes[i]; i++){ | |
39 | //Should be a faster way to do this. dojo.query has a private | |
40 | //_zip function that may be inspirational, but there are pathways | |
41 | //in query that force nozip? | |
42 | if(node.nodeType == 1 && array.indexOf(ary, node) == -1){ | |
43 | ary.push(node); | |
44 | } | |
45 | } | |
46 | return this._wrap(ary, null, this._NodeListCtor); // dojo/NodeList | |
47 | }, | |
48 | ||
49 | _getUniqueNodeListWithParent: function(/*Array*/ nodes, /*String*/ query){ | |
50 | // summary: | |
51 | // gets unique element nodes, filters them further | |
52 | // with an optional query and then calls _stash to track parent NodeList. | |
53 | var ary = this._getUniqueAsNodeList(nodes); | |
54 | ary = (query ? dquery._filterResult(ary, query) : ary); | |
55 | return ary._stash(this); // dojo/NodeList | |
56 | }, | |
57 | ||
58 | _getRelatedUniqueNodes: function(/*String?*/ query, /*Function*/ callback){ | |
59 | // summary: | |
60 | // cycles over all the nodes and calls a callback | |
61 | // to collect nodes for a possible inclusion in a result. | |
62 | // The callback will get two args: callback(node, ary), | |
63 | // where ary is the array being used to collect the nodes. | |
64 | return this._getUniqueNodeListWithParent(this._buildArrayFromCallback(callback), query); // dojo/NodeList | |
65 | }, | |
66 | ||
67 | children: function(/*String?*/ query){ | |
68 | // summary: | |
69 | // Returns all immediate child elements for nodes in this dojo/NodeList. | |
70 | // Optionally takes a query to filter the child elements. | |
71 | // description: | |
72 | // .end() can be used on the returned dojo/NodeList to get back to the | |
73 | // original dojo/NodeList. | |
74 | // query: | |
75 | // a CSS selector. | |
76 | // returns: | |
77 | // all immediate child elements for the nodes in this dojo/NodeList. | |
78 | // example: | |
79 | // assume a DOM created by this markup: | |
80 | // | <div class="container"> | |
81 | // | <div class="red">Red One</div> | |
82 | // | Some Text | |
83 | // | <div class="blue">Blue One</div> | |
84 | // | <div class="red">Red Two</div> | |
85 | // | <div class="blue">Blue Two</div> | |
86 | // | </div> | |
87 | // Running this code: | |
88 | // | dojo.query(".container").children(); | |
89 | // returns the four divs that are children of the container div. | |
90 | // Running this code: | |
91 | // | dojo.query(".container").children(".red"); | |
92 | // returns the two divs that have the class "red". | |
93 | return this._getRelatedUniqueNodes(query, function(node, ary){ | |
94 | return lang._toArray(node.childNodes); | |
95 | }); // dojo/NodeList | |
96 | }, | |
97 | ||
98 | closest: function(/*String*/ query, /*String|DOMNode?*/ root){ | |
99 | // summary: | |
100 | // Returns closest parent that matches query, including current node in this | |
101 | // dojo/NodeList if it matches the query. | |
102 | // description: | |
103 | // .end() can be used on the returned dojo/NodeList to get back to the | |
104 | // original dojo/NodeList. | |
105 | // query: | |
106 | // a CSS selector. | |
107 | // root: | |
108 | // If specified, query is relative to "root" rather than document body. | |
109 | // returns: | |
110 | // the closest parent that matches the query, including the current | |
111 | // node in this dojo/NodeList if it matches the query. | |
112 | // example: | |
113 | // assume a DOM created by this markup: | |
114 | // | <div class="container"> | |
115 | // | <div class="red">Red One</div> | |
116 | // | Some Text | |
117 | // | <div class="blue">Blue One</div> | |
118 | // | <div class="red">Red Two</div> | |
119 | // | <div class="blue">Blue Two</div> | |
120 | // | </div> | |
121 | // Running this code: | |
122 | // | dojo.query(".red").closest(".container"); | |
123 | // returns the div with class "container". | |
124 | return this._getRelatedUniqueNodes(null, function(node, ary){ | |
125 | do{ | |
126 | if(dquery._filterResult([node], query, root).length){ | |
127 | return node; | |
128 | } | |
129 | }while(node != root && (node = node.parentNode) && node.nodeType == 1); | |
130 | return null; //To make rhino strict checking happy. | |
131 | }); // dojo/NodeList | |
132 | }, | |
133 | ||
134 | parent: function(/*String?*/ query){ | |
135 | // summary: | |
136 | // Returns immediate parent elements for nodes in this dojo/NodeList. | |
137 | // Optionally takes a query to filter the parent elements. | |
138 | // description: | |
139 | // .end() can be used on the returned dojo/NodeList to get back to the | |
140 | // original dojo/NodeList. | |
141 | // query: | |
142 | // a CSS selector. | |
143 | // returns: | |
144 | // immediate parent elements for nodes in this dojo/NodeList. | |
145 | // example: | |
146 | // assume a DOM created by this markup: | |
147 | // | <div class="container"> | |
148 | // | <div class="red">Red One</div> | |
149 | // | <div class="blue first"><span class="text">Blue One</span></div> | |
150 | // | <div class="red">Red Two</div> | |
151 | // | <div class="blue"><span class="text">Blue Two</span></div> | |
152 | // | </div> | |
153 | // Running this code: | |
154 | // | dojo.query(".text").parent(); | |
155 | // returns the two divs with class "blue". | |
156 | // Running this code: | |
157 | // | dojo.query(".text").parent(".first"); | |
158 | // returns the one div with class "blue" and "first". | |
159 | return this._getRelatedUniqueNodes(query, function(node, ary){ | |
160 | return node.parentNode; | |
161 | }); // dojo/NodeList | |
162 | }, | |
163 | ||
164 | parents: function(/*String?*/ query){ | |
165 | // summary: | |
166 | // Returns all parent elements for nodes in this dojo/NodeList. | |
167 | // Optionally takes a query to filter the child elements. | |
168 | // description: | |
169 | // .end() can be used on the returned dojo/NodeList to get back to the | |
170 | // original dojo/NodeList. | |
171 | // query: | |
172 | // a CSS selector. | |
173 | // returns: | |
174 | // all parent elements for nodes in this dojo/NodeList. | |
175 | // example: | |
176 | // assume a DOM created by this markup: | |
177 | // | <div class="container"> | |
178 | // | <div class="red">Red One</div> | |
179 | // | <div class="blue first"><span class="text">Blue One</span></div> | |
180 | // | <div class="red">Red Two</div> | |
181 | // | <div class="blue"><span class="text">Blue Two</span></div> | |
182 | // | </div> | |
183 | // Running this code: | |
184 | // | dojo.query(".text").parents(); | |
185 | // returns the two divs with class "blue", the div with class "container", | |
186 | // | the body element and the html element. | |
187 | // Running this code: | |
188 | // | dojo.query(".text").parents(".container"); | |
189 | // returns the one div with class "container". | |
190 | return this._getRelatedUniqueNodes(query, function(node, ary){ | |
191 | var pary = []; | |
192 | while(node.parentNode){ | |
193 | node = node.parentNode; | |
194 | pary.push(node); | |
195 | } | |
196 | return pary; | |
197 | }); // dojo/NodeList | |
198 | }, | |
199 | ||
200 | siblings: function(/*String?*/ query){ | |
201 | // summary: | |
202 | // Returns all sibling elements for nodes in this dojo/NodeList. | |
203 | // Optionally takes a query to filter the sibling elements. | |
204 | // description: | |
205 | // .end() can be used on the returned dojo/NodeList to get back to the | |
206 | // original dojo/NodeList. | |
207 | // query: | |
208 | // a CSS selector. | |
209 | // returns: | |
210 | // all sibling elements for nodes in this dojo/NodeList. | |
211 | // example: | |
212 | // assume a DOM created by this markup: | |
213 | // | <div class="container"> | |
214 | // | <div class="red">Red One</div> | |
215 | // | Some Text | |
216 | // | <div class="blue first">Blue One</div> | |
217 | // | <div class="red">Red Two</div> | |
218 | // | <div class="blue">Blue Two</div> | |
219 | // | </div> | |
220 | // Running this code: | |
221 | // | dojo.query(".first").siblings(); | |
222 | // returns the two divs with class "red" and the other div | |
223 | // | with class "blue" that does not have "first". | |
224 | // Running this code: | |
225 | // | dojo.query(".first").siblings(".red"); | |
226 | // returns the two div with class "red". | |
227 | return this._getRelatedUniqueNodes(query, function(node, ary){ | |
228 | var pary = []; | |
229 | var nodes = (node.parentNode && node.parentNode.childNodes); | |
230 | for(var i = 0; i < nodes.length; i++){ | |
231 | if(nodes[i] != node){ | |
232 | pary.push(nodes[i]); | |
233 | } | |
234 | } | |
235 | return pary; | |
236 | }); // dojo/NodeList | |
237 | }, | |
238 | ||
239 | next: function(/*String?*/ query){ | |
240 | // summary: | |
241 | // Returns the next element for nodes in this dojo/NodeList. | |
242 | // Optionally takes a query to filter the next elements. | |
243 | // description: | |
244 | // .end() can be used on the returned dojo/NodeList to get back to the | |
245 | // original dojo/NodeList. | |
246 | // query: | |
247 | // a CSS selector. | |
248 | // returns: | |
249 | // the next element for nodes in this dojo/NodeList. | |
250 | // example: | |
251 | // assume a DOM created by this markup: | |
252 | // | <div class="container"> | |
253 | // | <div class="red">Red One</div> | |
254 | // | Some Text | |
255 | // | <div class="blue first">Blue One</div> | |
256 | // | <div class="red">Red Two</div> | |
257 | // | <div class="blue last">Blue Two</div> | |
258 | // | </div> | |
259 | // Running this code: | |
260 | // | dojo.query(".first").next(); | |
261 | // returns the div with class "red" and has innerHTML of "Red Two". | |
262 | // Running this code: | |
263 | // | dojo.query(".last").next(".red"); | |
264 | // does not return any elements. | |
265 | return this._getRelatedUniqueNodes(query, function(node, ary){ | |
266 | var next = node.nextSibling; | |
267 | while(next && next.nodeType != 1){ | |
268 | next = next.nextSibling; | |
269 | } | |
270 | return next; | |
271 | }); // dojo/NodeList | |
272 | }, | |
273 | ||
274 | nextAll: function(/*String?*/ query){ | |
275 | // summary: | |
276 | // Returns all sibling elements that come after the nodes in this dojo/NodeList. | |
277 | // Optionally takes a query to filter the sibling elements. | |
278 | // description: | |
279 | // .end() can be used on the returned dojo/NodeList to get back to the | |
280 | // original dojo/NodeList. | |
281 | // query: | |
282 | // a CSS selector. | |
283 | // returns: | |
284 | // all sibling elements that come after the nodes in this dojo/NodeList. | |
285 | // example: | |
286 | // assume a DOM created by this markup: | |
287 | // | <div class="container"> | |
288 | // | <div class="red">Red One</div> | |
289 | // | Some Text | |
290 | // | <div class="blue first">Blue One</div> | |
291 | // | <div class="red next">Red Two</div> | |
292 | // | <div class="blue next">Blue Two</div> | |
293 | // | </div> | |
294 | // Running this code: | |
295 | // | dojo.query(".first").nextAll(); | |
296 | // returns the two divs with class of "next". | |
297 | // Running this code: | |
298 | // | dojo.query(".first").nextAll(".red"); | |
299 | // returns the one div with class "red" and innerHTML "Red Two". | |
300 | return this._getRelatedUniqueNodes(query, function(node, ary){ | |
301 | var pary = []; | |
302 | var next = node; | |
303 | while((next = next.nextSibling)){ | |
304 | if(next.nodeType == 1){ | |
305 | pary.push(next); | |
306 | } | |
307 | } | |
308 | return pary; | |
309 | }); // dojo/NodeList | |
310 | }, | |
311 | ||
312 | prev: function(/*String?*/ query){ | |
313 | // summary: | |
314 | // Returns the previous element for nodes in this dojo/NodeList. | |
315 | // Optionally takes a query to filter the previous elements. | |
316 | // description: | |
317 | // .end() can be used on the returned dojo/NodeList to get back to the | |
318 | // original dojo/NodeList. | |
319 | // query: | |
320 | // a CSS selector. | |
321 | // returns: | |
322 | // the previous element for nodes in this dojo/NodeList. | |
323 | // example: | |
324 | // assume a DOM created by this markup: | |
325 | // | <div class="container"> | |
326 | // | <div class="red">Red One</div> | |
327 | // | Some Text | |
328 | // | <div class="blue first">Blue One</div> | |
329 | // | <div class="red">Red Two</div> | |
330 | // | <div class="blue">Blue Two</div> | |
331 | // | </div> | |
332 | // Running this code: | |
333 | // | dojo.query(".first").prev(); | |
334 | // returns the div with class "red" and has innerHTML of "Red One". | |
335 | // Running this code: | |
336 | // | dojo.query(".first").prev(".blue"); | |
337 | // does not return any elements. | |
338 | return this._getRelatedUniqueNodes(query, function(node, ary){ | |
339 | var prev = node.previousSibling; | |
340 | while(prev && prev.nodeType != 1){ | |
341 | prev = prev.previousSibling; | |
342 | } | |
343 | return prev; | |
344 | }); // dojo/NodeList | |
345 | }, | |
346 | ||
347 | prevAll: function(/*String?*/ query){ | |
348 | // summary: | |
349 | // Returns all sibling elements that come before the nodes in this dojo/NodeList. | |
350 | // Optionally takes a query to filter the sibling elements. | |
351 | // description: | |
352 | // The returned nodes will be in reverse DOM order -- the first node in the list will | |
353 | // be the node closest to the original node/NodeList. | |
354 | // .end() can be used on the returned dojo/NodeList to get back to the | |
355 | // original dojo/NodeList. | |
356 | // query: | |
357 | // a CSS selector. | |
358 | // returns: | |
359 | // all sibling elements that come before the nodes in this dojo/NodeList. | |
360 | // example: | |
361 | // assume a DOM created by this markup: | |
362 | // | <div class="container"> | |
363 | // | <div class="red prev">Red One</div> | |
364 | // | Some Text | |
365 | // | <div class="blue prev">Blue One</div> | |
366 | // | <div class="red second">Red Two</div> | |
367 | // | <div class="blue">Blue Two</div> | |
368 | // | </div> | |
369 | // Running this code: | |
370 | // | dojo.query(".second").prevAll(); | |
371 | // returns the two divs with class of "prev". | |
372 | // Running this code: | |
373 | // | dojo.query(".first").prevAll(".red"); | |
374 | // returns the one div with class "red prev" and innerHTML "Red One". | |
375 | return this._getRelatedUniqueNodes(query, function(node, ary){ | |
376 | var pary = []; | |
377 | var prev = node; | |
378 | while((prev = prev.previousSibling)){ | |
379 | if(prev.nodeType == 1){ | |
380 | pary.push(prev); | |
381 | } | |
382 | } | |
383 | return pary; | |
384 | }); // dojo/NodeList | |
385 | }, | |
386 | ||
387 | andSelf: function(){ | |
388 | // summary: | |
389 | // Adds the nodes from the previous dojo/NodeList to the current dojo/NodeList. | |
390 | // description: | |
391 | // .end() can be used on the returned dojo/NodeList to get back to the | |
392 | // original dojo/NodeList. | |
393 | // example: | |
394 | // assume a DOM created by this markup: | |
395 | // | <div class="container"> | |
396 | // | <div class="red prev">Red One</div> | |
397 | // | Some Text | |
398 | // | <div class="blue prev">Blue One</div> | |
399 | // | <div class="red second">Red Two</div> | |
400 | // | <div class="blue">Blue Two</div> | |
401 | // | </div> | |
402 | // Running this code: | |
403 | // | dojo.query(".second").prevAll().andSelf(); | |
404 | // returns the two divs with class of "prev", as well as the div with class "second". | |
405 | return this.concat(this._parent); // dojo/NodeList | |
406 | }, | |
407 | ||
408 | //Alternate methods for the :first/:last/:even/:odd pseudos. | |
409 | first: function(){ | |
410 | // summary: | |
411 | // Returns the first node in this dojo/NodeList as a dojo/NodeList. | |
412 | // description: | |
413 | // .end() can be used on the returned dojo/NodeList to get back to the | |
414 | // original dojo/NodeList. | |
415 | // returns: | |
416 | // the first node in this dojo/NodeList | |
417 | // example: | |
418 | // assume a DOM created by this markup: | |
419 | // | <div class="container"> | |
420 | // | <div class="red">Red One</div> | |
421 | // | <div class="blue first">Blue One</div> | |
422 | // | <div class="red">Red Two</div> | |
423 | // | <div class="blue last">Blue Two</div> | |
424 | // | </div> | |
425 | // Running this code: | |
426 | // | dojo.query(".blue").first(); | |
427 | // returns the div with class "blue" and "first". | |
428 | return this._wrap(((this[0] && [this[0]]) || []), this); // dojo/NodeList | |
429 | }, | |
430 | ||
431 | last: function(){ | |
432 | // summary: | |
433 | // Returns the last node in this dojo/NodeList as a dojo/NodeList. | |
434 | // description: | |
435 | // .end() can be used on the returned dojo/NodeList to get back to the | |
436 | // original dojo/NodeList. | |
437 | // returns: | |
438 | // the last node in this dojo/NodeList | |
439 | // example: | |
440 | // assume a DOM created by this markup: | |
441 | // | <div class="container"> | |
442 | // | <div class="red">Red One</div> | |
443 | // | <div class="blue first">Blue One</div> | |
444 | // | <div class="red">Red Two</div> | |
445 | // | <div class="blue last">Blue Two</div> | |
446 | // | </div> | |
447 | // Running this code: | |
448 | // | dojo.query(".blue").last(); | |
449 | // returns the last div with class "blue", | |
450 | return this._wrap((this.length ? [this[this.length - 1]] : []), this); // dojo/NodeList | |
451 | }, | |
452 | ||
453 | even: function(){ | |
454 | // summary: | |
455 | // Returns the even nodes in this dojo/NodeList as a dojo/NodeList. | |
456 | // description: | |
457 | // .end() can be used on the returned dojo/NodeList to get back to the | |
458 | // original dojo/NodeList. | |
459 | // returns: | |
460 | // the even nodes in this dojo/NodeList | |
461 | // example: | |
462 | // assume a DOM created by this markup: | |
463 | // | <div class="container"> | |
464 | // | <div class="interior red">Red One</div> | |
465 | // | <div class="interior blue">Blue One</div> | |
466 | // | <div class="interior red">Red Two</div> | |
467 | // | <div class="interior blue">Blue Two</div> | |
468 | // | </div> | |
469 | // Running this code: | |
470 | // | dojo.query(".interior").even(); | |
471 | // returns the two divs with class "blue" | |
472 | return this.filter(function(item, i){ | |
473 | return i % 2 != 0; | |
474 | }); // dojo/NodeList | |
475 | }, | |
476 | ||
477 | odd: function(){ | |
478 | // summary: | |
479 | // Returns the odd nodes in this dojo/NodeList as a dojo/NodeList. | |
480 | // description: | |
481 | // .end() can be used on the returned dojo/NodeList to get back to the | |
482 | // original dojo/NodeList. | |
483 | // returns: | |
484 | // the odd nodes in this dojo/NodeList | |
485 | // example: | |
486 | // assume a DOM created by this markup: | |
487 | // | <div class="container"> | |
488 | // | <div class="interior red">Red One</div> | |
489 | // | <div class="interior blue">Blue One</div> | |
490 | // | <div class="interior red">Red Two</div> | |
491 | // | <div class="interior blue">Blue Two</div> | |
492 | // | </div> | |
493 | // Running this code: | |
494 | // | dojo.query(".interior").odd(); | |
495 | // returns the two divs with class "red" | |
496 | return this.filter(function(item, i){ | |
497 | return i % 2 == 0; | |
498 | }); // dojo/NodeList | |
499 | } | |
500 | }); | |
501 | ||
502 | return NodeList; | |
503 | }); |