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