source: Dev/branches/rest-dojo-ui/client/dojo/query.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: 27.2 KB
Line 
1define(["./_base/kernel", "./has", "./dom", "./on", "./_base/array", "./_base/lang", "./selector/_loader", "./selector/_loader!default"],
2        function(dojo, has, dom, on, array, lang, loader, defaultEngine){
3"use strict";
4
5        has.add("array-extensible", function(){
6                // test to see if we can extend an array (not supported in old IE)
7                return lang.delegate([], {length: 1}).length == 1 && !has("bug-for-in-skips-shadowed");
8        });
9       
10        var ap = Array.prototype, aps = ap.slice, apc = ap.concat, forEach = array.forEach;
11
12        var tnl = function(/*Array*/ a, /*dojo.NodeList?*/ parent, /*Function?*/ NodeListCtor){
13                // summary:
14                //              decorate an array to make it look like a `dojo.NodeList`.
15                // a:
16                //              Array of nodes to decorate.
17                // parent:
18                //              An optional parent NodeList that generated the current
19                //              list of nodes. Used to call _stash() so the parent NodeList
20                //              can be accessed via end() later.
21                // NodeListCtor:
22                //              An optional constructor function to use for any
23                //              new NodeList calls. This allows a certain chain of
24                //              NodeList calls to use a different object than dojo.NodeList.
25                var nodeList = new (NodeListCtor || this._NodeListCtor || nl)(a);
26                return parent ? nodeList._stash(parent) : nodeList;
27        };
28
29        var loopBody = function(f, a, o){
30                a = [0].concat(aps.call(a, 0));
31                o = o || dojo.global;
32                return function(node){
33                        a[0] = node;
34                        return f.apply(o, a);
35                };
36        };
37
38        // adapters
39
40        var adaptAsForEach = function(f, o){
41                // summary:
42                //              adapts a single node function to be used in the forEach-type
43                //              actions. The initial object is returned from the specialized
44                //              function.
45                // f: Function
46                //              a function to adapt
47                // o: Object?
48                //              an optional context for f
49                return function(){
50                        this.forEach(loopBody(f, arguments, o));
51                        return this;    // Object
52                };
53        };
54
55        var adaptAsMap = function(f, o){
56                // summary:
57                //              adapts a single node function to be used in the map-type
58                //              actions. The return is a new array of values, as via `dojo.map`
59                // f: Function
60                //              a function to adapt
61                // o: Object?
62                //              an optional context for f
63                return function(){
64                        return this.map(loopBody(f, arguments, o));
65                };
66        };
67
68        var adaptAsFilter = function(f, o){
69                // summary:
70                //              adapts a single node function to be used in the filter-type actions
71                // f: Function
72                //              a function to adapt
73                // o: Object?
74                //              an optional context for f
75                return function(){
76                        return this.filter(loopBody(f, arguments, o));
77                };
78        };
79
80        var adaptWithCondition = function(f, g, o){
81                // summary:
82                //              adapts a single node function to be used in the map-type
83                //              actions, behaves like forEach() or map() depending on arguments
84                // f: Function
85                //              a function to adapt
86                // g: Function
87                //              a condition function, if true runs as map(), otherwise runs as forEach()
88                // o: Object?
89                //              an optional context for f and g
90                return function(){
91                        var a = arguments, body = loopBody(f, a, o);
92                        if(g.call(o || dojo.global, a)){
93                                return this.map(body);  // self
94                        }
95                        this.forEach(body);
96                        return this;    // self
97                };
98        };
99
100        var NodeList = function(array){
101                // summary:
102                //              dojo.NodeList is an of Array-like object which adds syntactic
103                //              sugar for chaining, common iteration operations, animation, and
104                //              node manipulation. NodeLists are most often returned as the
105                //              result of dojo.query() calls.
106                // description:
107                //              dojo.NodeList instances provide many utilities that reflect
108                //              core Dojo APIs for Array iteration and manipulation, DOM
109                //              manipulation, and event handling. Instead of needing to dig up
110                //              functions in the dojo.* namespace, NodeLists generally make the
111                //              full power of Dojo available for DOM manipulation tasks in a
112                //              simple, chainable way.
113                // example:
114                //              create a node list from a node
115                //              |       new dojo.NodeList(dojo.byId("foo"));
116                // example:
117                //              get a NodeList from a CSS query and iterate on it
118                //              |       var l = dojo.query(".thinger");
119                //              |       l.forEach(function(node, index, nodeList){
120                //              |               console.log(index, node.innerHTML);
121                //              |       });
122                // example:
123                //              use native and Dojo-provided array methods to manipulate a
124                //              NodeList without needing to use dojo.* functions explicitly:
125                //              |       var l = dojo.query(".thinger");
126                //              |       // since NodeLists are real arrays, they have a length
127                //              |       // property that is both readable and writable and
128                //              |       // push/pop/shift/unshift methods
129                //              |       console.log(l.length);
130                //              |       l.push(dojo.create("span"));
131                //              |
132                //              |       // dojo's normalized array methods work too:
133                //              |       console.log( l.indexOf(dojo.byId("foo")) );
134                //              |       // ...including the special "function as string" shorthand
135                //              |       console.log( l.every("item.nodeType == 1") );
136                //              |
137                //              |       // NodeLists can be [..] indexed, or you can use the at()
138                //              |       // function to get specific items wrapped in a new NodeList:
139                //              |       var node = l[3]; // the 4th element
140                //              |       var newList = l.at(1, 3); // the 2nd and 4th elements
141                // example:
142                //              the style functions you expect are all there too:
143                //              |       // style() as a getter...
144                //              |       var borders = dojo.query(".thinger").style("border");
145                //              |       // ...and as a setter:
146                //              |       dojo.query(".thinger").style("border", "1px solid black");
147                //              |       // class manipulation
148                //              |       dojo.query("li:nth-child(even)").addClass("even");
149                //              |       // even getting the coordinates of all the items
150                //              |       var coords = dojo.query(".thinger").coords();
151                // example:
152                //              DOM manipulation functions from the dojo.* namespace area also
153                //              available:
154                //              |       // remove all of the elements in the list from their
155                //              |       // parents (akin to "deleting" them from the document)
156                //              |       dojo.query(".thinger").orphan();
157                //              |       // place all elements in the list at the front of #foo
158                //              |       dojo.query(".thinger").place("foo", "first");
159                // example:
160                //              Event handling couldn't be easier. `dojo.connect` is mapped in,
161                //              and shortcut handlers are provided for most DOM events:
162                //              |       // like dojo.connect(), but with implicit scope
163                //              |       dojo.query("li").connect("onclick", console, "log");
164                //              |
165                //              |       // many common event handlers are already available directly:
166                //              |       dojo.query("li").onclick(console, "log");
167                //              |       var toggleHovered = dojo.hitch(dojo, "toggleClass", "hovered");
168                //              |       dojo.query("p")
169                //              |               .onmouseenter(toggleHovered)
170                //              |               .onmouseleave(toggleHovered);
171                // example:
172                //              chainability is a key advantage of NodeLists:
173                //              |       dojo.query(".thinger")
174                //              |               .onclick(function(e){ /* ... */ })
175                //              |               .at(1, 3, 8) // get a subset
176                //              |                       .style("padding", "5px")
177                //              |                       .forEach(console.log);
178                var isNew = this instanceof nl && has("array-extensible");
179                if(typeof array == "number"){
180                        array = Array(array);
181                }
182                var nodeArray = (array && "length" in array) ? array : arguments;
183                if(isNew || !nodeArray.sort){
184                        // make sure it's a real array before we pass it on to be wrapped
185                        var target = isNew ? this : [],
186                                l = target.length = nodeArray.length;
187                        for(var i = 0; i < l; i++){
188                                target[i] = nodeArray[i];
189                        }
190                        if(isNew){
191                                // called with new operator, this means we are going to use this instance and push
192                                // the nodes on to it. This is usually much faster since the NodeList properties
193                                //      don't need to be copied (unless the list of nodes is extremely large).
194                                return target;
195                        }
196                        nodeArray = target;
197                }
198                // called without new operator, use a real array and copy prototype properties,
199                // this is slower and exists for back-compat. Should be removed in 2.0.
200                lang._mixin(nodeArray, nlp);
201                nodeArray._NodeListCtor = function(array){
202                        // call without new operator to preserve back-compat behavior
203                        return nl(array);
204                };
205                return nodeArray;
206        };
207       
208        var nl = NodeList, nlp = nl.prototype =
209                has("array-extensible") ? [] : {};// extend an array if it is extensible
210
211        // expose adapters and the wrapper as private functions
212
213        nl._wrap = nlp._wrap = tnl;
214        nl._adaptAsMap = adaptAsMap;
215        nl._adaptAsForEach = adaptAsForEach;
216        nl._adaptAsFilter  = adaptAsFilter;
217        nl._adaptWithCondition = adaptWithCondition;
218
219        // mass assignment
220
221        // add array redirectors
222        forEach(["slice", "splice"], function(name){
223                var f = ap[name];
224                //Use a copy of the this array via this.slice() to allow .end() to work right in the splice case.
225                // CANNOT apply ._stash()/end() to splice since it currently modifies
226                // the existing this array -- it would break backward compatibility if we copy the array before
227                // the splice so that we can use .end(). So only doing the stash option to this._wrap for slice.
228                nlp[name] = function(){ return this._wrap(f.apply(this, arguments), name == "slice" ? this : null); };
229        });
230        // concat should be here but some browsers with native NodeList have problems with it
231
232        // add array.js redirectors
233        forEach(["indexOf", "lastIndexOf", "every", "some"], function(name){
234                var f = array[name];
235                nlp[name] = function(){ return f.apply(dojo, [this].concat(aps.call(arguments, 0))); };
236        });
237
238        /*===== var NodeList = dojo.NodeList; =====*/
239        lang.extend(NodeList, {
240                // copy the constructors
241                constructor: nl,
242                _NodeListCtor: nl,
243                toString: function(){
244                        // Array.prototype.toString can't be applied to objects, so we use join
245                        return this.join(",");
246                },
247                _stash: function(parent){
248                        // summary:
249                        //              private function to hold to a parent NodeList. end() to return the parent NodeList.
250                        //
251                        // example:
252                        // How to make a `dojo.NodeList` method that only returns the third node in
253                        // the dojo.NodeList but allows access to the original NodeList by using this._stash:
254                        //      |       dojo.extend(dojo.NodeList, {
255                        //      |               third: function(){
256                        //      |                       var newNodeList = dojo.NodeList(this[2]);
257                        //      |                       return newNodeList._stash(this);
258                        //      |               }
259                        //      |       });
260                        //      |       // then see how _stash applies a sub-list, to be .end()'ed out of
261                        //      |       dojo.query(".foo")
262                        //      |               .third()
263                        //      |                       .addClass("thirdFoo")
264                        //      |               .end()
265                        //      |               // access to the orig .foo list
266                        //      |               .removeClass("foo")
267                        //      |
268                        //
269                        this._parent = parent;
270                        return this; //dojo.NodeList
271                },
272
273                on: function(eventName, listener){
274                        // summary:
275                        //              Listen for events on the nodes in the NodeList. Basic usage is:
276                        //              | query(".my-class").on("click", listener);
277                        //              This supports event delegation by using selectors as the first argument with the event names as
278                        //              pseudo selectors. For example:
279                        //              | dojo.query("#my-list").on("li:click", listener);
280                        //              This will listen for click events within <li> elements that are inside the #my-list element.
281                        //              Because on supports CSS selector syntax, we can use comma-delimited events as well:
282                        //              | dojo.query("#my-list").on("li button:mouseover, li:click", listener);
283                        var handles = this.map(function(node){
284                                return on(node, eventName, listener); // TODO: apply to the NodeList so the same selector engine is used for matches
285                        });
286                        handles.remove = function(){
287                                for(var i = 0; i < handles.length; i++){
288                                        handles[i].remove();
289                                }
290                        };
291                        return handles;
292                },
293
294                end: function(){
295                        // summary:
296                        //              Ends use of the current `dojo.NodeList` by returning the previous dojo.NodeList
297                        //              that generated the current dojo.NodeList.
298                        // description:
299                        //              Returns the `dojo.NodeList` that generated the current `dojo.NodeList`. If there
300                        //              is no parent dojo.NodeList, an empty dojo.NodeList is returned.
301                        // example:
302                        //      |       dojo.query("a")
303                        //      |               .filter(".disabled")
304                        //      |                       // operate on the anchors that only have a disabled class
305                        //      |                       .style("color", "grey")
306                        //      |               .end()
307                        //      |               // jump back to the list of anchors
308                        //      |               .style(...)
309                        //
310                        if(this._parent){
311                                return this._parent;
312                        }else{
313                                //Just return empty list.
314                                return new this._NodeListCtor(0);
315                        }
316                },
317
318                // http://developer.mozilla.org/en/docs/Core_JavaScript_1.5_Reference:Global_Objects:Array#Methods
319
320                // FIXME: handle return values for #3244
321                //              http://trac.dojotoolkit.org/ticket/3244
322
323                // FIXME:
324                //              need to wrap or implement:
325                //                      join (perhaps w/ innerHTML/outerHTML overload for toString() of items?)
326                //                      reduce
327                //                      reduceRight
328
329                /*=====
330                slice: function(begin, end){
331                        // summary:
332                        //              Returns a new NodeList, maintaining this one in place
333                        // description:
334                        //              This method behaves exactly like the Array.slice method
335                        //              with the caveat that it returns a dojo.NodeList and not a
336                        //              raw Array. For more details, see Mozilla's (slice
337                        //              documentation)[http://developer.mozilla.org/en/docs/Core_JavaScript_1.5_Reference:Global_Objects:Array:slice]
338                        // begin: Integer
339                        //              Can be a positive or negative integer, with positive
340                        //              integers noting the offset to begin at, and negative
341                        //              integers denoting an offset from the end (i.e., to the left
342                        //              of the end)
343                        // end: Integer?
344                        //              Optional parameter to describe what position relative to
345                        //              the NodeList's zero index to end the slice at. Like begin,
346                        //              can be positive or negative.
347                        return this._wrap(a.slice.apply(this, arguments));
348                },
349
350                splice: function(index, howmany, item){
351                        // summary:
352                        //              Returns a new NodeList, manipulating this NodeList based on
353                        //              the arguments passed, potentially splicing in new elements
354                        //              at an offset, optionally deleting elements
355                        // description:
356                        //              This method behaves exactly like the Array.splice method
357                        //              with the caveat that it returns a dojo.NodeList and not a
358                        //              raw Array. For more details, see Mozilla's (splice
359                        //              documentation)[http://developer.mozilla.org/en/docs/Core_JavaScript_1.5_Reference:Global_Objects:Array:splice]
360                        //              For backwards compatibility, calling .end() on the spliced NodeList
361                        //              does not return the original NodeList -- splice alters the NodeList in place.
362                        // index: Integer
363                        //              begin can be a positive or negative integer, with positive
364                        //              integers noting the offset to begin at, and negative
365                        //              integers denoting an offset from the end (i.e., to the left
366                        //              of the end)
367                        // howmany: Integer?
368                        //              Optional parameter to describe what position relative to
369                        //              the NodeList's zero index to end the slice at. Like begin,
370                        //              can be positive or negative.
371                        // item: Object...?
372                        //              Any number of optional parameters may be passed in to be
373                        //              spliced into the NodeList
374                        // returns:
375                        //              dojo.NodeList
376                        return this._wrap(a.splice.apply(this, arguments));
377                },
378
379                indexOf: function(value, fromIndex){
380                        // summary:
381                        //              see dojo.indexOf(). The primary difference is that the acted-on
382                        //              array is implicitly this NodeList
383                        // value: Object:
384                        //              The value to search for.
385                        // fromIndex: Integer?:
386                        //              The location to start searching from. Optional. Defaults to 0.
387                        // description:
388                        //              For more details on the behavior of indexOf, see Mozilla's
389                        //              (indexOf
390                        //              docs)[http://developer.mozilla.org/en/docs/Core_JavaScript_1.5_Reference:Global_Objects:Array:indexOf]
391                        // returns:
392                        //              Positive Integer or 0 for a match, -1 of not found.
393                        return d.indexOf(this, value, fromIndex); // Integer
394                },
395
396                lastIndexOf: function(value, fromIndex){
397                        // summary:
398                        //              see dojo.lastIndexOf(). The primary difference is that the
399                        //              acted-on array is implicitly this NodeList
400                        // description:
401                        //              For more details on the behavior of lastIndexOf, see
402                        //              Mozilla's (lastIndexOf
403                        //              docs)[http://developer.mozilla.org/en/docs/Core_JavaScript_1.5_Reference:Global_Objects:Array:lastIndexOf]
404                        // value: Object
405                        //              The value to search for.
406                        // fromIndex: Integer?
407                        //              The location to start searching from. Optional. Defaults to 0.
408                        // returns:
409                        //              Positive Integer or 0 for a match, -1 of not found.
410                        return d.lastIndexOf(this, value, fromIndex); // Integer
411                },
412
413                every: function(callback, thisObject){
414                        // summary:
415                        //              see `dojo.every()` and the (Array.every
416                        //              docs)[http://developer.mozilla.org/en/docs/Core_JavaScript_1.5_Reference:Global_Objects:Array:every].
417                        //              Takes the same structure of arguments and returns as
418                        //              dojo.every() with the caveat that the passed array is
419                        //              implicitly this NodeList
420                        // callback: Function: the callback
421                        // thisObject: Object?: the context
422                        return d.every(this, callback, thisObject); // Boolean
423                },
424
425                some: function(callback, thisObject){
426                        // summary:
427                        //              Takes the same structure of arguments and returns as
428                        //              `dojo.some()` with the caveat that the passed array is
429                        //              implicitly this NodeList.  See `dojo.some()` and Mozilla's
430                        //              (Array.some
431                        //              documentation)[http://developer.mozilla.org/en/docs/Core_JavaScript_1.5_Reference:Global_Objects:Array:some].
432                        // callback: Function: the callback
433                        // thisObject: Object?: the context
434                        return d.some(this, callback, thisObject); // Boolean
435                },
436                =====*/
437
438                concat: function(item){
439                        // summary:
440                        //              Returns a new NodeList comprised of items in this NodeList
441                        //              as well as items passed in as parameters
442                        // description:
443                        //              This method behaves exactly like the Array.concat method
444                        //              with the caveat that it returns a `dojo.NodeList` and not a
445                        //              raw Array. For more details, see the (Array.concat
446                        //              docs)[http://developer.mozilla.org/en/docs/Core_JavaScript_1.5_Reference:Global_Objects:Array:concat]
447                        // item: Object?
448                        //              Any number of optional parameters may be passed in to be
449                        //              spliced into the NodeList
450                        // returns:
451                        //              dojo.NodeList
452
453                        //return this._wrap(apc.apply(this, arguments));
454                        // the line above won't work for the native NodeList :-(
455
456                        // implementation notes:
457                        // 1) Native NodeList is not an array, and cannot be used directly
458                        // in concat() --- the latter doesn't recognize it as an array, and
459                        // does not inline it, but append as a single entity.
460                        // 2) On some browsers (e.g., Safari) the "constructor" property is
461                        // read-only and cannot be changed. So we have to test for both
462                        // native NodeList and dojo.NodeList in this property to recognize
463                        // the node list.
464
465                        var t = lang.isArray(this) ? this : aps.call(this, 0),
466                                m = array.map(arguments, function(a){
467                                        return a && !lang.isArray(a) &&
468                                                (typeof NodeList != "undefined" && a.constructor === NodeList || a.constructor === this._NodeListCtor) ?
469                                                        aps.call(a, 0) : a;
470                                });
471                        return this._wrap(apc.apply(t, m), this);       // dojo.NodeList
472                },
473
474                map: function(/*Function*/ func, /*Function?*/ obj){
475                        // summary:
476                        //              see dojo.map(). The primary difference is that the acted-on
477                        //              array is implicitly this NodeList and the return is a
478                        //              dojo.NodeList (a subclass of Array)
479                        ///return d.map(this, func, obj, d.NodeList); // dojo.NodeList
480                        return this._wrap(array.map(this, func, obj), this); // dojo.NodeList
481                },
482
483                forEach: function(callback, thisObj){
484                        // summary:
485                        //              see `dojo.forEach()`. The primary difference is that the acted-on
486                        //              array is implicitly this NodeList. If you want the option to break out
487                        //              of the forEach loop, use every() or some() instead.
488                        forEach(this, callback, thisObj);
489                        // non-standard return to allow easier chaining
490                        return this; // dojo.NodeList
491                },
492                filter: function(/*String|Function*/ filter){
493                        // summary:
494                        //              "masks" the built-in javascript filter() method (supported
495                        //              in Dojo via `dojo.filter`) to support passing a simple
496                        //              string filter in addition to supporting filtering function
497                        //              objects.
498                        // filter:
499                        //              If a string, a CSS rule like ".thinger" or "div > span".
500                        // example:
501                        //              "regular" JS filter syntax as exposed in dojo.filter:
502                        //              |       dojo.query("*").filter(function(item){
503                        //              |               // highlight every paragraph
504                        //              |               return (item.nodeName == "p");
505                        //              |       }).style("backgroundColor", "yellow");
506                        // example:
507                        //              the same filtering using a CSS selector
508                        //              |       dojo.query("*").filter("p").styles("backgroundColor", "yellow");
509
510                        var a = arguments, items = this, start = 0;
511                        if(typeof filter == "string"){ // inline'd type check
512                                items = query._filterResult(this, a[0]);
513                                if(a.length == 1){
514                                        // if we only got a string query, pass back the filtered results
515                                        return items._stash(this); // dojo.NodeList
516                                }
517                                // if we got a callback, run it over the filtered items
518                                start = 1;
519                        }
520                        return this._wrap(array.filter(items, a[start], a[start + 1]), this);   // dojo.NodeList
521                },
522                instantiate: function(/*String|Object*/ declaredClass, /*Object?*/ properties){
523                        // summary:
524                        //              Create a new instance of a specified class, using the
525                        //              specified properties and each node in the nodeList as a
526                        //              srcNodeRef.
527                        // example:
528                        //              Grabs all buttons in the page and converts them to diji.form.Buttons.
529                        //      |       var buttons = dojo.query("button").instantiate("dijit.form.Button", {showLabel: true});
530                        var c = lang.isFunction(declaredClass) ? declaredClass : lang.getObject(declaredClass);
531                        properties = properties || {};
532                        return this.forEach(function(node){
533                                new c(properties, node);
534                        });     // dojo.NodeList
535                },
536                at: function(/*===== index =====*/){
537                        // summary:
538                        //              Returns a new NodeList comprised of items in this NodeList
539                        //              at the given index or indices.
540                        //
541                        // index: Integer...
542                        //              One or more 0-based indices of items in the current
543                        //              NodeList. A negative index will start at the end of the
544                        //              list and go backwards.
545                        //
546                        // example:
547                        //      Shorten the list to the first, second, and third elements
548                        //      |       dojo.query("a").at(0, 1, 2).forEach(fn);
549                        //
550                        // example:
551                        //      Retrieve the first and last elements of a unordered list:
552                        //      |       dojo.query("ul > li").at(0, -1).forEach(cb);
553                        //
554                        // example:
555                        //      Do something for the first element only, but end() out back to
556                        //      the original list and continue chaining:
557                        //      |       dojo.query("a").at(0).onclick(fn).end().forEach(function(n){
558                        //      |               console.log(n); // all anchors on the page.
559                        //      |       })
560                        //
561                        // returns:
562                        //              dojo.NodeList
563                        var t = new this._NodeListCtor(0);
564                        forEach(arguments, function(i){
565                                if(i < 0){ i = this.length + i; }
566                                if(this[i]){ t.push(this[i]); }
567                        }, this);
568                        return t._stash(this); // dojo.NodeList
569                }
570        });
571
572
573/*=====
574dojo.query = function(selector, context){
575        // summary:
576        //              This modules provides DOM querying functionality. The module export is a function
577        //              that can be used to query for DOM nodes by CSS selector and returns a dojo.NodeList
578        //              representing the matching nodes.
579        //
580        // selector: String
581        //              A CSS selector to search for.
582        // context: String|DomNode?
583        //              An optional context to limit the searching scope. Only nodes under `context` will be
584        //              scanned.
585        //
586        //      example:
587        //              add an onclick handler to every submit button in the document
588        //              which causes the form to be sent via Ajax instead:
589        //      |       define(["dojo/query"], function(query){
590        //      |       query("input[type='submit']").on("click", function(e){
591        //      |               dojo.stopEvent(e); // prevent sending the form
592        //      |               var btn = e.target;
593        //      |               dojo.xhrPost({
594        //      |                       form: btn.form,
595        //      |                       load: function(data){
596        //      |                               // replace the form with the response
597        //      |                               var div = dojo.doc.createElement("div");
598        //      |                               dojo.place(div, btn.form, "after");
599        //      |                               div.innerHTML = data;
600        //      |                               dojo.style(btn.form, "display", "none");
601        //      |                       }
602        //      |               });
603        //      |       });
604        //
605        // description:
606        //              dojo/query is responsible for loading the appropriate query engine and wrapping
607        //              its results with a `dojo.NodeList`. You can use dojo/query with a specific selector engine
608        //              by using it as a plugin. For example, if you installed the sizzle package, you could
609        //              use it as the selector engine with:
610        //              |       define("dojo/query!sizzle", function(query){
611        //              |               query("div")...
612        //
613        //              The id after the ! can be a module id of the selector engine or one of the following values:
614        //              |       + acme: This is the default engine used by Dojo base, and will ensure that the full
615        //              |       Acme engine is always loaded.
616        //              |       
617        //              |       + css2: If the browser has a native selector engine, this will be used, otherwise a
618        //              |       very minimal lightweight selector engine will be loaded that can do simple CSS2 selectors
619        //              |       (by #id, .class, tag, and [name=value] attributes, with standard child or descendant (>)
620        //              |       operators) and nothing more.
621        //              |
622        //              |       + css2.1: If the browser has a native selector engine, this will be used, otherwise the
623        //              |       full Acme engine will be loaded.
624        //              |       
625        //              |       + css3: If the browser has a native selector engine with support for CSS3 pseudo
626        //              |       selectors (most modern browsers except IE8), this will be used, otherwise the
627        //              |       full Acme engine will be loaded.
628        //              |       
629        //              |       + Or the module id of a selector engine can be used to explicitly choose the selector engine
630        //             
631        //              For example, if you are using CSS3 pseudo selectors in module, you can specify that
632        //              you will need support them with:
633        //              |       define("dojo/query!css3", function(query){
634        //              |               query('#t > h3:nth-child(odd)')...
635        //
636        //              You can also choose the selector engine/load configuration by setting the <FIXME:what is the configuration setting?>.
637        //              For example:
638        //              |       <script data-dojo-config="query-selector:'css3'" src="dojo.js"></script>
639        //             
640        return new dojo.NodeList(); // dojo.NodeList
641};
642=====*/
643
644function queryForEngine(engine, NodeList){
645        var query = function(/*String*/ query, /*String|DOMNode?*/ root){
646                //      summary:
647                //              Returns nodes which match the given CSS selector, searching the
648                //              entire document by default but optionally taking a node to scope
649                //              the search by. Returns an instance of dojo.NodeList.
650                if(typeof root == "string"){
651                        root = dom.byId(root);
652                        if(!root){
653                                return new NodeList([]);
654                        }
655                }
656                var results = typeof query == "string" ? engine(query, root) : query.orphan ? query : [query];
657                if(results.orphan){
658                        // already wrapped
659                        return results;
660                }
661                return new NodeList(results);
662        };
663        query.matches = engine.match || function(node, selector, root){
664                // summary:
665                //              Test to see if a node matches a selector
666                return query.filter([node], selector, root).length > 0;
667        };
668        // the engine provides a filtering function, use it to for matching
669        query.filter = engine.filter || function(nodes, selector, root){
670                // summary:
671                //              Filters an array of nodes. Note that this does not guarantee to return a dojo.NodeList, just an array.
672                return query(selector, root).filter(function(node){
673                        return array.indexOf(nodes, node) > -1;
674                });
675        };
676        if(typeof engine != "function"){
677                var search = engine.search;
678                engine = function(selector, root){
679                        // Slick does it backwards (or everyone else does it backwards, probably the latter)
680                        return search(root || document, selector);
681                };
682        }
683        return query;
684}
685var query = queryForEngine(defaultEngine, NodeList);
686// the query that is returned from this module is slightly different than dojo.query,
687// because dojo.query has to maintain backwards compatibility with returning a
688// true array which has performance problems. The query returned from the module
689// does not use true arrays, but rather inherits from Array, making it much faster to
690// instantiate.
691dojo.query = queryForEngine(defaultEngine, function(array){
692        // call it without the new operator to invoke the back-compat behavior that returns a true array
693        return NodeList(array);
694});
695
696query.load = /*===== dojo.query.load= ======*/ function(id, parentRequire, loaded, config){
697        // summary: can be used as AMD plugin to conditionally load new query engine
698        // example:
699        //      |       define(["dojo/query!custom"], function(qsa){
700        //      |               // loaded selector/custom.js as engine
701        //      |               qsa("#foobar").forEach(...);
702        //      |       });
703        loader.load(id, parentRequire, function(engine){
704                loaded(queryForEngine(engine, NodeList));
705        });
706};
707
708dojo._filterQueryResult = query._filterResult = function(nodes, selector, root){
709        return new NodeList(query.filter(nodes, selector, root));
710};
711dojo.NodeList = query.NodeList = NodeList;
712return query;
713});
Note: See TracBrowser for help on using the repository browser.