source: Dev/trunk/src/client/dojo/NodeList-traverse.js @ 501

Last change on this file since 501 was 483, checked in by hendrikvanantwerpen, 11 years ago

Added Dojo 1.9.3 release.

File size: 18.0 KB
Line 
1define(["./query", "./_base/lang", "./_base/array"], function(dquery, lang, array){
2
3// module:
4//              dojo/NodeList-traverse
5
6/*=====
7return function(){
8        // summary:
9        //              Adds chainable methods to dojo/query() / NodeList instances for traversing the DOM
10};
11=====*/
12
13var NodeList = dquery.NodeList;
14
15lang.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                //      |       require(["dojo/query", "dojo/NodeList-traverse"
89                //      |       ], function(query){
90                //      |               query(".container").children();
91                //      |       });
92                //              returns the four divs that are children of the container div.
93                //              Running this code:
94                //      |       dojo.query(".container").children(".red");
95                //              returns the two divs that have the class "red".
96                return this._getRelatedUniqueNodes(query, function(node, ary){
97                        return lang._toArray(node.childNodes);
98                }); // dojo/NodeList
99        },
100
101        closest: function(/*String*/ query, /*String|DOMNode?*/ root){
102                // summary:
103                //              Returns closest parent that matches query, including current node in this
104                //              dojo/NodeList if it matches the query.
105                // description:
106                //              .end() can be used on the returned dojo/NodeList to get back to the
107                //              original dojo/NodeList.
108                // query:
109                //              a CSS selector.
110                // root:
111                //              If specified, query is relative to "root" rather than document body.
112                // returns:
113                //              the closest parent that matches the query, including the current
114                //              node in this dojo/NodeList if it matches the query.
115                // example:
116                //              assume a DOM created by this markup:
117                //      |       <div class="container">
118                //      |               <div class="red">Red One</div>
119                //      |               Some Text
120                //      |               <div class="blue">Blue One</div>
121                //      |               <div class="red">Red Two</div>
122                //      |               <div class="blue">Blue Two</div>
123                //      |       </div>
124                //              Running this code:
125                //      |       require(["dojo/query", "dojo/NodeList-traverse"
126                //      |       ], function(query){
127                //      |               query(".red").closest(".container");
128                //      |       });
129                //              returns the div with class "container".
130                return this._getRelatedUniqueNodes(null, function(node, ary){
131                        do{
132                                if(dquery._filterResult([node], query, root).length){
133                                        return node;
134                                }
135                        }while(node != root && (node = node.parentNode) && node.nodeType == 1);
136                        return null; //To make rhino strict checking happy.
137                }); // dojo/NodeList
138        },
139
140        parent: function(/*String?*/ query){
141                // summary:
142                //              Returns immediate parent elements for nodes in this dojo/NodeList.
143                //              Optionally takes a query to filter the parent elements.
144                // description:
145                //              .end() can be used on the returned dojo/NodeList to get back to the
146                //              original dojo/NodeList.
147                // query:
148                //              a CSS selector.
149                // returns:
150                //              immediate parent elements for nodes in this dojo/NodeList.
151                // example:
152                //              assume a DOM created by this markup:
153                //      |       <div class="container">
154                //      |               <div class="red">Red One</div>
155                //      |               <div class="blue first"><span class="text">Blue One</span></div>
156                //      |               <div class="red">Red Two</div>
157                //      |               <div class="blue"><span class="text">Blue Two</span></div>
158                //      |       </div>
159                //              Running this code:
160                //      |       require(["dojo/query", "dojo/NodeList-traverse"
161                //      |       ], function(query){
162                //      |               query(".text").parent();
163                //      |       });
164                //              returns the two divs with class "blue".
165                //              Running this code:
166                //      |               query(".text").parent(".first");
167                //              returns the one div with class "blue" and "first".
168                return this._getRelatedUniqueNodes(query, function(node, ary){
169                        return node.parentNode;
170                }); // dojo/NodeList
171        },
172
173        parents: function(/*String?*/ query){
174                // summary:
175                //              Returns all parent elements for nodes in this dojo/NodeList.
176                //              Optionally takes a query to filter the child elements.
177                // description:
178                //              .end() can be used on the returned dojo/NodeList to get back to the
179                //              original dojo/NodeList.
180                // query:
181                //              a CSS selector.
182                // returns:
183                //              all parent elements for nodes in this dojo/NodeList.
184                // example:
185                //              assume a DOM created by this markup:
186                //      |       <div class="container">
187                //      |               <div class="red">Red One</div>
188                //      |               <div class="blue first"><span class="text">Blue One</span></div>
189                //      |               <div class="red">Red Two</div>
190                //      |               <div class="blue"><span class="text">Blue Two</span></div>
191                //      |       </div>
192                //              Running this code:
193                //      |       require(["dojo/query", "dojo/NodeList-traverse"
194                //      |       ], function(query){
195                //      |               query(".text").parents();
196                //      |       });
197                //              returns the two divs with class "blue", the div with class "container",
198                //      |       the body element and the html element.
199                //              Running this code:
200                //      |               query(".text").parents(".container");
201                //              returns the one div with class "container".
202                return this._getRelatedUniqueNodes(query, function(node, ary){
203                        var pary = [];
204                        while(node.parentNode){
205                                node = node.parentNode;
206                                pary.push(node);
207                        }
208                        return pary;
209                }); // dojo/NodeList
210        },
211
212        siblings: function(/*String?*/ query){
213                // summary:
214                //              Returns all sibling elements for nodes in this dojo/NodeList.
215                //              Optionally takes a query to filter the sibling elements.
216                // description:
217                //              .end() can be used on the returned dojo/NodeList to get back to the
218                //              original dojo/NodeList.
219                // query:
220                //              a CSS selector.
221                // returns:
222                //              all sibling elements for nodes in this dojo/NodeList.
223                // example:
224                //              assume a DOM created by this markup:
225                //      |       <div class="container">
226                //      |               <div class="red">Red One</div>
227                //      |               Some Text
228                //      |               <div class="blue first">Blue One</div>
229                //      |               <div class="red">Red Two</div>
230                //      |               <div class="blue">Blue Two</div>
231                //      |       </div>
232                //              Running this code:
233                //      |       require(["dojo/query", "dojo/NodeList-traverse"
234                //      |       ], function(query){
235                //      |               query(".first").siblings();
236                //      |       });
237                //              returns the two divs with class "red" and the other div
238                //      |       with class "blue" that does not have "first".
239                //              Running this code:
240                //      |               query(".first").siblings(".red");
241                //              returns the two div with class "red".
242                return this._getRelatedUniqueNodes(query, function(node, ary){
243                        var pary = [];
244                        var nodes = (node.parentNode && node.parentNode.childNodes);
245                        for(var i = 0; i < nodes.length; i++){
246                                if(nodes[i] != node){
247                                        pary.push(nodes[i]);
248                                }
249                        }
250                        return pary;
251                }); // dojo/NodeList
252        },
253
254        next: function(/*String?*/ query){
255                // summary:
256                //              Returns the next element for nodes in this dojo/NodeList.
257                //              Optionally takes a query to filter the next elements.
258                // description:
259                //              .end() can be used on the returned dojo/NodeList to get back to the
260                //              original dojo/NodeList.
261                // query:
262                //              a CSS selector.
263                // returns:
264                //              the next element for nodes in this dojo/NodeList.
265                // example:
266                //              assume a DOM created by this markup:
267                //      |       <div class="container">
268                //      |               <div class="red">Red One</div>
269                //      |               Some Text
270                //      |               <div class="blue first">Blue One</div>
271                //      |               <div class="red">Red Two</div>
272                //      |               <div class="blue last">Blue Two</div>
273                //      |       </div>
274                //              Running this code:
275                //      |       require(["dojo/query", "dojo/NodeList-traverse"
276                //      |       ], function(query){
277                //      |               query(".first").next();
278                //      |       });
279                //              returns the div with class "red" and has innerHTML of "Red Two".
280                //              Running this code:
281                //      |       dojo.query(".last").next(".red");
282                //              does not return any elements.
283                return this._getRelatedUniqueNodes(query, function(node, ary){
284                        var next = node.nextSibling;
285                        while(next && next.nodeType != 1){
286                                next = next.nextSibling;
287                        }
288                        return next;
289                }); // dojo/NodeList
290        },
291
292        nextAll: function(/*String?*/ query){
293                // summary:
294                //              Returns all sibling elements that come after the nodes in this dojo/NodeList.
295                //              Optionally takes a query to filter the sibling elements.
296                // description:
297                //              .end() can be used on the returned dojo/NodeList to get back to the
298                //              original dojo/NodeList.
299                // query:
300                //              a CSS selector.
301                // returns:
302                //              all sibling elements that come after the nodes in this dojo/NodeList.
303                // example:
304                //              assume a DOM created by this markup:
305                //      |       <div class="container">
306                //      |               <div class="red">Red One</div>
307                //      |               Some Text
308                //      |               <div class="blue first">Blue One</div>
309                //      |               <div class="red next">Red Two</div>
310                //      |               <div class="blue next">Blue Two</div>
311                //      |       </div>
312                //              Running this code:
313                //      |       require(["dojo/query", "dojo/NodeList-traverse"
314                //      |       ], function(query){
315                //      |               query(".first").nextAll();
316                //      |       });
317                //              returns the two divs with class of "next".
318                //              Running this code:
319                //      |               query(".first").nextAll(".red");
320                //              returns the one div with class "red" and innerHTML "Red Two".
321                return this._getRelatedUniqueNodes(query, function(node, ary){
322                        var pary = [];
323                        var next = node;
324                        while((next = next.nextSibling)){
325                                if(next.nodeType == 1){
326                                        pary.push(next);
327                                }
328                        }
329                        return pary;
330                }); // dojo/NodeList
331        },
332
333        prev: function(/*String?*/ query){
334                // summary:
335                //              Returns the previous element for nodes in this dojo/NodeList.
336                //              Optionally takes a query to filter the previous elements.
337                // description:
338                //              .end() can be used on the returned dojo/NodeList to get back to the
339                //              original dojo/NodeList.
340                // query:
341                //              a CSS selector.
342                // returns:
343                //              the previous element for nodes in this dojo/NodeList.
344                // example:
345                //              assume a DOM created by this markup:
346                //      |       <div class="container">
347                //      |               <div class="red">Red One</div>
348                //      |               Some Text
349                //      |               <div class="blue first">Blue One</div>
350                //      |               <div class="red">Red Two</div>
351                //      |               <div class="blue">Blue Two</div>
352                //      |       </div>
353                //              Running this code:
354                //      |       require(["dojo/query", "dojo/NodeList-traverse"
355                //      |       ], function(query){
356                //      |               query(".first").prev();
357                //      |       });
358                //              returns the div with class "red" and has innerHTML of "Red One".
359                //              Running this code:
360                //      |               query(".first").prev(".blue");
361                //              does not return any elements.
362                return this._getRelatedUniqueNodes(query, function(node, ary){
363                        var prev = node.previousSibling;
364                        while(prev && prev.nodeType != 1){
365                                prev = prev.previousSibling;
366                        }
367                        return prev;
368                }); // dojo/NodeList
369        },
370
371        prevAll: function(/*String?*/ query){
372                // summary:
373                //              Returns all sibling elements that come before the nodes in this dojo/NodeList.
374                //              Optionally takes a query to filter the sibling elements.
375                // description:
376                //              The returned nodes will be in reverse DOM order -- the first node in the list will
377                //              be the node closest to the original node/NodeList.
378                //              .end() can be used on the returned dojo/NodeList to get back to the
379                //              original dojo/NodeList.
380                // query:
381                //              a CSS selector.
382                // returns:
383                //              all sibling elements that come before the nodes in this dojo/NodeList.
384                // example:
385                //              assume a DOM created by this markup:
386                //      |       <div class="container">
387                //      |               <div class="red prev">Red One</div>
388                //      |               Some Text
389                //      |               <div class="blue prev">Blue One</div>
390                //      |               <div class="red second">Red Two</div>
391                //      |               <div class="blue">Blue Two</div>
392                //      |       </div>
393                //              Running this code:
394                //      |       require(["dojo/query", "dojo/NodeList-traverse"
395                //      |       ], function(query){
396                //      |               query(".second").prevAll();
397                //      |       });
398                //              returns the two divs with class of "prev".
399                //              Running this code:
400                //      |               query(".first").prevAll(".red");
401                //              returns the one div with class "red prev" and innerHTML "Red One".
402                return this._getRelatedUniqueNodes(query, function(node, ary){
403                        var pary = [];
404                        var prev = node;
405                        while((prev = prev.previousSibling)){
406                                if(prev.nodeType == 1){
407                                        pary.push(prev);
408                                }
409                        }
410                        return pary;
411                }); // dojo/NodeList
412        },
413
414        andSelf: function(){
415                // summary:
416                //              Adds the nodes from the previous dojo/NodeList to the current dojo/NodeList.
417                // description:
418                //              .end() can be used on the returned dojo/NodeList to get back to the
419                //              original dojo/NodeList.
420                // example:
421                //              assume a DOM created by this markup:
422                //      |       <div class="container">
423                //      |               <div class="red prev">Red One</div>
424                //      |               Some Text
425                //      |               <div class="blue prev">Blue One</div>
426                //      |               <div class="red second">Red Two</div>
427                //      |               <div class="blue">Blue Two</div>
428                //      |       </div>
429                //              Running this code:
430                //      |       require(["dojo/query", "dojo/NodeList-traverse"
431                //      |       ], function(query){
432                //      |               query(".second").prevAll().andSelf();
433                //      |       });
434                //              returns the two divs with class of "prev", as well as the div with class "second".
435                return this.concat(this._parent);       // dojo/NodeList
436        },
437
438        //Alternate methods for the :first/:last/:even/:odd pseudos.
439        first: function(){
440                // summary:
441                //              Returns the first node in this dojo/NodeList as a dojo/NodeList.
442                // description:
443                //              .end() can be used on the returned dojo/NodeList to get back to the
444                //              original dojo/NodeList.
445                // returns:
446                //              the first node in this dojo/NodeList
447                // example:
448                //              assume a DOM created by this markup:
449                //      |       <div class="container">
450                //      |               <div class="red">Red One</div>
451                //      |               <div class="blue first">Blue One</div>
452                //      |               <div class="red">Red Two</div>
453                //      |               <div class="blue last">Blue Two</div>
454                //      |       </div>
455                //              Running this code:
456                //      |       require(["dojo/query", "dojo/NodeList-traverse"
457                //      |       ], function(query){
458                //      |               query(".blue").first();
459                //      |       });
460                //              returns the div with class "blue" and "first".
461                return this._wrap(((this[0] && [this[0]]) || []), this); // dojo/NodeList
462        },
463
464        last: function(){
465                // summary:
466                //              Returns the last node in this dojo/NodeList as a dojo/NodeList.
467                // description:
468                //              .end() can be used on the returned dojo/NodeList to get back to the
469                //              original dojo/NodeList.
470                // returns:
471                //              the last node in this dojo/NodeList
472                // example:
473                //              assume a DOM created by this markup:
474                //      |       <div class="container">
475                //      |               <div class="red">Red One</div>
476                //      |               <div class="blue first">Blue One</div>
477                //      |               <div class="red">Red Two</div>
478                //      |               <div class="blue last">Blue Two</div>
479                //      |       </div>
480                //              Running this code:
481                //      |       require(["dojo/query", "dojo/NodeList-traverse"
482                //      |       ], function(query){
483                //      |       query(".blue").last();
484                //      |       });
485                //              returns the last div with class "blue",
486                return this._wrap((this.length ? [this[this.length - 1]] : []), this); // dojo/NodeList
487        },
488
489        even: function(){
490                // summary:
491                //              Returns the even nodes in this dojo/NodeList as a dojo/NodeList.
492                // description:
493                //              .end() can be used on the returned dojo/NodeList to get back to the
494                //              original dojo/NodeList.
495                // returns:
496                //              the even nodes in this dojo/NodeList
497                // example:
498                //              assume a DOM created by this markup:
499                //      |       <div class="container">
500                //      |               <div class="interior red">Red One</div>
501                //      |               <div class="interior blue">Blue One</div>
502                //      |               <div class="interior red">Red Two</div>
503                //      |               <div class="interior blue">Blue Two</div>
504                //      |       </div>
505                //              Running this code:
506                //      |       require(["dojo/query", "dojo/NodeList-traverse"
507                //      |       ], function(query){
508                //      |               query(".interior").even();
509                //      |       });
510                //              returns the two divs with class "blue"
511                return this.filter(function(item, i){
512                        return i % 2 != 0;
513                }); // dojo/NodeList
514        },
515
516        odd: function(){
517                // summary:
518                //              Returns the odd nodes in this dojo/NodeList as a dojo/NodeList.
519                // description:
520                //              .end() can be used on the returned dojo/NodeList to get back to the
521                //              original dojo/NodeList.
522                // returns:
523                //              the odd nodes in this dojo/NodeList
524                // example:
525                //              assume a DOM created by this markup:
526                //      |       <div class="container">
527                //      |               <div class="interior red">Red One</div>
528                //      |               <div class="interior blue">Blue One</div>
529                //      |               <div class="interior red">Red Two</div>
530                //      |               <div class="interior blue">Blue Two</div>
531                //      |       </div>
532                //              Running this code:
533                //      |       require(["dojo/query", "dojo/NodeList-traverse"
534                //      |       ], function(query){
535                //      |               query(".interior").odd();
536                //      |       });
537                //              returns the two divs with class "red"
538                return this.filter(function(item, i){
539                        return i % 2 == 0;
540                }); // dojo/NodeList
541        }
542});
543
544return NodeList;
545});
Note: See TracBrowser for help on using the repository browser.