source: Dev/branches/rest-dojo-ui/client/dojo/NodeList-traverse.js @ 274

Last change on this file since 274 was 256, checked in by hendrikvanantwerpen, 13 years ago

Reworked project structure based on REST interaction and Dojo library. As
soon as this is stable, the old jQueryUI branch can be removed (it's
kept for reference).

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