source: Dev/trunk/src/client/dojox/jq.js @ 531

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

Added Dojo 1.9.3 release.

File size: 50.9 KB
Line 
1//For jQuery 1.3.2
2
3dojo.provide("dojox.jq");
4dojo.require("dojo.NodeList-traverse");
5dojo.require("dojo.NodeList-manipulate");
6dojo.require("dojo.io.script");
7
8/*
9To get jquery tests to pass:
10- add spaces between span>form selectors, other ones like one,two
11- .last() instead of :last
12- $("<div>").find("#foo") does not work unless the div is attached to the body.
13
14- trigger .test not work
15- No jquery.Event thing.
16
17- jQuery.ajax() modifies incoming arguments?
18- test framework not good for our io methods, async, poll.
19- Dojo ajax is async: we fire ajaxStop more than jquery.
20
21- jquery makes assumptions of a value to set for an element
22by inserting an element and checking display. Does not seem to
23account for nested styles, only captures generic tag name style off
24of body. Why can't we just set display to empty?
25
26
27
28
29
30OK for failures:
31- test("jQuery.ajax - beforeSend, cancel request (#2688)"
32  We cancel the deferred which triggers error and complete callbacks.
33
34
35Looked at jquery code for:
36- how it handled text(): did not use textContent/innerText, but use recursive look over childNodes and nodeValue,
37so it may have impact on how <br> is serialized, but it has uniform behavior across browsers.
38- Looked at trigger: how it triggered actions on dom nodes. This seemed unsafe.
39*/
40
41/*
42dojo.query differences that cause some tests to fail:
43- does not support XML queries
44- $("#sap>form") does not find a match but $("#sap > form") does. Similar issue with comma instead of > (see is() tests)
45- "$("form:last") should return the last form object, not if that particular form is that last related
46  to its siblings? Same issue with :first?
47- $("p").filter("#ap, #sndp"): filter does not work.
48- dojo.NodeList uses d.NodeList a few places in the code. Would be nice to use a ctor that can be configured.
49  That would make the filter function operate better.
50- filterQueryResult, cannot handle queries like "p, div"? See andSelf test with parents().
51- adjacent "p + p" not supported?
52= a:only-child not supported?
53- nth(1)
54- even/odd
55- eq/gt/lt
56- #form :radio:checked does not run the first :radio psuedo selector? Seems to be a general issue where only the last pseud
57  is run. For example, "#form :checked:radio" does only the radio pseudo.
58*/
59
60(function(){
61        //Enable io topic publishing.   But don't mask the original definition of ioPublish from the doc parser.
62        /*===== var ioPublish = dojo.config.ioPublish; =====*/
63        dojo.config.ioPublish = true;
64        /*===== dojo.config.ioPublish = ioPublish; =====*/
65
66        //Support stuff for toDom
67        var selfClosedTags = "|img|meta|hr|br|input|";
68
69        function toDom(/*String*/html, /*Document?*/doc){
70                //summary converts HTML string into DOM nodes.
71                //Make sure html is a string.
72                html += "";
73
74                //Convert <tag/> into <tag></tag>
75                html = html.replace(/<\s*(\w+)([^\/\>]*)\/\s*>/g, function(tag, name, contents){
76                        if(selfClosedTags.indexOf("|" + name + "|") == -1){
77                                return "<" + name + contents + "></" + name + ">";
78                        }else{
79                                return tag;
80                        }
81                });
82
83                return dojo._toDom(html, doc);
84        }
85
86        function cssNameToJs(name){
87                var index = name.indexOf("-");
88                if(index != -1){
89                        //Strip off beginning dash
90                        if(index == 0){
91                                name = name.substring(1);
92                        }
93                        name = name.replace(/-(\w)/g, function(match, match1){
94                                return match1.toUpperCase();
95                        });
96                }
97                return name;
98        }
99
100        var _old$ = dojo.global.$;
101        var _oldJQuery = dojo.global.jQuery;
102
103        var $ = dojo.global.$ = dojo.global.jQuery = function(){
104                var arg = arguments[0];
105                if(!arg){
106                        return $._wrap([], null, $);
107                }else if(dojo.isString(arg)){
108                        if(arg.charAt(0) == "<"){
109                                //String of html that needs nodes created.
110                                arg = toDom(arg);
111                                //If a DocumentFragment, convert to use its children
112                                //since we want to treat all top level nodes as elements
113                                //in the NodeList array.
114                                if(arg.nodeType == 11){
115                                        arg = arg.childNodes;
116                                }else{
117                                        return $._wrap([arg], null, $);
118                                }
119                                //Use end case of nodelist to finish work.
120                        }else{
121                                //Normal dojo.query selector.
122                                //Switch out query's NodeList constructor to be our specialized
123                                //NodeList constructor.
124                                var listCtor = dojo._NodeListCtor;
125                                dojo._NodeListCtor = $;
126
127                                //If the second arg is one of our fake NodeLists then
128                                //use the first parent for the call.
129                                var arg2 = arguments[1];
130                                if(arg2 && arg2._is$){
131                                        arg2 = arg2[0];
132                                }else if(dojo.isString(arg2)){
133                                        arg2 = dojo.query(arg2)[0];
134                                }
135
136                                var nl = dojo.query.call(this, arg, arg2);
137                                dojo._NodeListCtor = listCtor;
138                                return nl;
139                        }
140                }else if(dojo.isFunction(arg)){
141                        //The addOnLoad case
142                        $.ready(arg);
143                        return $;
144                }else if(arg == document || arg == window){
145                        //If the arg is the document or window,
146                        //then just use it directly.
147                        return $._wrap([arg], null, $);
148                }else if(dojo.isArray(arg)){
149                        //Input is a plain array.
150                        //Filter out duplicates.
151                        var ary = [];
152                        for(var i = 0; i < arg.length; i++){
153                                if(dojo.indexOf(ary, arg[i]) == -1){
154                                        ary.push(arg[i]);
155                                }
156                        }
157                        return $._wrap(arg, null, $);
158                }else if("nodeType" in arg){
159                        //A DOM Node
160                        return $._wrap([arg], null, $);
161                }
162
163                //A native NodeList that does not conform to dojo.isArray().
164                //Convert it to a workable array and create new NodeList.
165                return $._wrap(dojo._toArray(arg), null, $);
166
167        };
168
169        //Set up plugin extension point.
170        var nlProto = dojo.NodeList.prototype;
171
172        //Need a delegate, because at least one method conflicts with jquery
173        //API: attr(name) in jQuery only returns a single, first value, where
174        //dojo.attr will return an array.
175        var f = $.fn = $.prototype = dojo.delegate(nlProto);
176
177        //_wrap is required for proper use in dojo.query, but the _adaptAs* methods
178        //do not have to placed on $ -- they can be used directly off dojo.NodeList.
179        $._wrap = dojo.NodeList._wrap;
180
181        //Add in some pseudos selectors
182        var headerRegExp = /^H\d/i;
183        var pseudos = dojo.query.pseudos;
184        dojo.mixin(pseudos, {
185                has: function(name, condition){
186                        return function(elem){
187                                return $(condition, elem).length;
188                        }
189                },
190                visible: function(name, condition){
191                        return function(elem){
192                                return dojo.style(elem, "visible") != "hidden" && dojo.style(elem, "display") != "none";
193                        }
194                },
195                hidden: function(name, condition){
196                        return function(elem){
197                                return elem.type == "hidden" || dojo.style(elem, "visible") == "hidden" || dojo.style(elem, "display") == "none";
198                        }
199                },
200                selected: function(name, condition){
201                        return function(elem){
202                                return elem.selected;
203                        }
204                },
205                checked: function(name, condition){
206                        return function(elem){
207                                return elem.nodeName.toUpperCase() == "INPUT" && elem.checked;
208                        }
209                },
210                disabled: function(name, condition){
211                        return function(elem){
212                                return elem.getAttribute("disabled");
213                        }
214                },
215                enabled: function(name, condition){
216                        return function(elem){
217                                return !elem.getAttribute("disabled");
218                        }
219                },
220                input: function(name, condition){
221                        return function(elem){
222                                var n = elem.nodeName.toUpperCase();
223                                return n == "INPUT" || n == "SELECT" || n == "TEXTAREA" || n == "BUTTON";
224                        }
225                },
226                button: function(name, condition){
227                        return function(elem){
228                                return (elem.nodeName.toUpperCase() == "INPUT" && elem.type == "button") || elem.nodeName.toUpperCase() == "BUTTON";
229                        }
230                },
231                header: function(name, condition){
232                        return function(elem){
233                                return elem.nodeName.match(headerRegExp);
234                        }
235                }
236                //TODO: implement :animated
237        });
238
239
240        //Add the input type selectors to pseudos
241        var inputPseudos = {};
242        dojo.forEach([
243                "text", "password", "radio", "checkbox", "submit", "image", "reset", "file"
244        ], function(type) {
245                inputPseudos[type] = function(name, condition){
246                        return function(elem){
247                                return elem.nodeName.toUpperCase() == "INPUT" && elem.type == type;
248                        }
249                };
250        });
251        dojo.mixin(pseudos, inputPseudos);
252
253        //Set up browser sniff.
254        $.browser = {
255                mozilla: dojo.isMoz,
256                msie: dojo.isIE,
257                opera: dojo.isOpera,
258                safari: dojo.isSafari
259        };
260        $.browser.version = dojo.isIE || dojo.isMoz || dojo.isOpera || dojo.isSafari || dojo.isWebKit;
261       
262        //Map back into dojo
263        //Hmm maybe this is not so good. Dojo
264        //modules may still be holding on to old
265        //dojo (example: the d._NodeListCtor in query.js)
266        //dojo = dojo.mixin($, dojo);
267
268        // Add $.ready
269        $.ready = $.fn.ready = function(callback){
270                dojo.addOnLoad(dojo.hitch(null, callback, $));
271                return this;
272        }
273
274        //START jquery Core API methods
275        //http://docs.jquery.com/Core
276        f._is$ = true;
277        f.size = function(){return this.length; };
278
279        $.prop = function(node, propCheck){
280                //TODO: not sure about this one, could not find the docs?
281                if(dojo.isFunction(propCheck)){
282                        return propCheck.call(node);
283                }else{
284                        return propCheck;
285                }
286        }
287
288        $.className = {
289                add: dojo.addClass,
290                remove: dojo.removeClass,
291                has: dojo.hasClass
292        };
293
294        $.makeArray = function(thing){
295                if(typeof thing == "undefined"){
296                        return [];
297                }else if(thing.length && !dojo.isString(thing) && !("location" in thing)){
298                        //Location check was for excluding window objects that have a length.
299                        return dojo._toArray(thing);
300                }else{
301                        return [thing];
302                }
303        }
304       
305        $.merge = function(ary1, ary2){
306                //Alters first array by adding in the element.
307                var args = [ary1.length, 0];
308                args = args.concat(ary2);
309                ary1.splice.apply(ary1, args);
310                return ary1;
311        }
312
313        $.each = function(/*Array||ArrayLike*/list, /*Function*/cb){
314                //each differs from dojo.NodeList.forEach in that
315                //"this" is the current cycled node. Breaking
316                //the loop is also possible. Also, index is first arg
317                //to the callback.
318                if(dojo.isArrayLike(list)){
319                        for(var i = 0; i < list.length; i++){
320                                if(cb.call(list[i], i, list[i]) === false){
321                                        break;
322                                }
323                        }
324                }else if(dojo.isObject(list)){
325                        for(var param in list){
326                                if(cb.call(list[param], param, list[param]) === false){
327                                        break;
328                                }
329                        }
330                }
331                return this;
332        };
333        f.each = function(/*Function*/cb){
334                return $.each.call(this, this, cb);
335        };
336        //f.length already implemented by NodeList
337        f.eq = function(){
338                //Direct copy of dojo.NodeList.at, but want
339                //to use our NodeList class.
340                var nl = $();
341                dojo.forEach(arguments, function(i) { if(this[i]) { nl.push(this[i]); } }, this);
342                return nl; // dojo.NodeList
343        };
344        f.get = function(/*Number*/index){
345                if(index || index == 0){
346                        return this[index];
347                }
348                return this;
349        };
350        f.index = function(arg){
351                //Hmm, allows passing in a $ nodelist. Apparently in that
352                //case take the first item in that array and match
353                if(arg._is$){
354                        arg = arg[0];
355                }
356                return this.indexOf(arg);
357        }
358
359        //.data implementation
360        var dataStore = [];
361        var dataId = 0;
362        var dataAttr = dojo._scopeName + "DataId";
363       
364        var getDataId = function(node){
365                var id = node.getAttribute(dataAttr);
366                if(!id){
367                        id = dataId++;
368                        node.setAttribute(dataAttr, id);
369                }
370        }
371       
372        var getData = function(node){
373                var data = {};
374                if(node.nodeType == 1){
375                        var id = getDataId(node);
376                        data = dataStore[id];
377                        if(!data){
378                                data = dataStore[id] = {};
379                        }
380                }
381                return data;
382        }
383
384        $.data = function(/*DOMNode*/node, /*String*/name, /*String*/value){
385                var result = null;
386                if(name == "events"){
387                        //Special case "events", since jquery tests seem to use it to
388                        //get the event handler storage for jquery. So for jquery apps
389                        //"events" is probably a reserved word anyway.
390                        result = listeners[node.getAttribute(eventAttr)];
391                        var isEmpty = true;
392                        if(result){
393                                for(var param in result){
394                                        isEmpty = false;
395                                        break;
396                                }
397                        }
398                        return isEmpty ? null : result;
399                }
400
401                var data = getData(node);
402                if(typeof value != "undefined"){
403                        data[name] = value;
404                }else{
405                        result = data[name];
406                }
407                return value ? this : result;
408        }
409
410        $.removeData = function(/*DOMNode*/node, /*String*/name){
411                var data = getData(node);
412                delete data[name];
413                if(node.nodeType == 1){
414                        var isEmpty = true;
415                        for(var param in data){
416                                isEmpty = false;
417                                break;
418                        }
419                        if(isEmpty){
420                                node.removeAttribute(dataAttr);
421                        }
422                }
423                return this;
424        }
425
426        f.data = function(/*String*/name, /*String*/value){
427                var result = null;
428                this.forEach(function(node){
429                        result = $.data(node, name, value);
430                });
431
432                return value ? this : result;
433        }
434
435        f.removeData = function(/*String*/name){
436                this.forEach(function(node){
437                        $.removeData(node, name);
438                });
439                return this;
440        }
441       
442        function jqMix(obj, props){
443                // summary:
444                //              an attempt at a mixin that follows
445                //              jquery's .extend rules. Seems odd. Not sure how
446                //              to resolve this with dojo.mixin and what the use
447                //              cases are for the jquery version.
448                //              Copying some code from dojo._mixin.
449                if(obj == props){
450                        return obj;
451                }
452                var tobj = {};
453                for(var x in props){
454                        // the "tobj" condition avoid copying properties in "props"
455                        // inherited from Object.prototype.  For example, if obj has a custom
456                        // toString() method, don't overwrite it with the toString() method
457                        // that props inherited from Object.prototype
458                        if((tobj[x] === undefined || tobj[x] != props[x]) && props[x] !== undefined && obj != props[x]){
459                                if(dojo.isObject(obj[x]) && dojo.isObject(props[x])){
460                                        if(dojo.isArray(props[x])){
461                                                obj[x] = props[x];
462                                        }else{
463                                                obj[x] = jqMix(obj[x], props[x]);
464                                        }
465                                }else{
466                                        obj[x] = props[x];
467                                }
468                        }
469                }
470                // IE doesn't recognize custom toStrings in for..in
471                if(dojo.isIE && props){
472                        var p = props.toString;
473                        if(typeof p == "function" && p != obj.toString && p != tobj.toString &&
474                                p != "\nfunction toString() {\n    [native code]\n}\n"){
475                                        obj.toString = props.toString;
476                        }
477                }
478                return obj; // Object
479        }
480
481        f.extend = function(){
482                var args = [this];
483                args = args.concat(arguments);
484                return $.extend.apply($, args);
485        }
486
487        $.extend = function(){
488                //Could have multiple args to mix in. Similar to dojo.mixin,
489                //but has some different rules, and the mixins all get applied
490                //to the first arg.
491                var args = arguments, finalObj;
492                for(var i = 0; i < args.length; i++){
493                        var obj = args[i];
494                        if(obj && dojo.isObject(obj)){
495                                if(!finalObj){
496                                        finalObj = obj;
497                                }else{
498                                        jqMix(finalObj, obj);
499                                }
500                        }
501                }
502                return finalObj;
503        }
504
505        $.noConflict = function(/*Boolean*/extreme){
506                var me = $;
507                dojo.global.$ = _old$;
508                if(extreme){
509                        dojo.global.jQuery = _oldJQuery;
510                }
511                return me;
512        }
513        //END jquery Core API methods
514       
515        //START jquery Attribute API methods
516        //http://docs.jquery.com/Attributes
517        f.attr = function(name, value){
518                //The isObject tests below are to weed out where something
519                //like a form node has an input called "action" but we really
520                //want to get the attribute "action". But in general, favor
521                //a property value over a DOM attribute value.
522                if(arguments.length == 1 && dojo.isString(arguments[0])){
523                        //The get case, return first match.
524                        var first = this[0];
525                       
526                        //Weed out empty nodes
527                        if(!first){
528                                return null;
529                        }
530
531                        var arg = arguments[0];
532                        //favor properties over attributes.
533                        var attr = dojo.attr(first, arg);
534                        var prop = first[arg];
535                        if((arg in first) && !dojo.isObject(prop) && name != "href"){
536                                return prop;
537                        }else{
538                                return attr || prop;
539                        }
540                }else if(dojo.isObject(name)){
541                        //A setter, using an object.
542                        for(var param in name){
543                                this.attr(param, name[param]);
544                        }
545                        return this;
546                }else{
547                        //The setter case. Figure out if value is a function.
548                        var isFunc = dojo.isFunction(value);
549                        this.forEach(function(node, index){
550                                var prop = node[name];
551                                if((name in node) && !dojo.isObject(prop) && name != "href"){
552                                        node[name] = (isFunc ? value.call(node, index) : value);
553                                }else if(node.nodeType == 1){
554                                        dojo.attr(node, name, (isFunc ? value.call(node, index) : value));
555                                }
556                        });
557                        return this;
558                }
559        }
560
561        f.removeAttr = function(name){
562                this.forEach(function(node, index){
563                        var prop = node[name];
564                        if((name in node) && !dojo.isObject(prop) && name != "href"){
565                                delete node[name];
566                        }else if(node.nodeType == 1){
567                                if(name == "class"){
568                                        //TODO: push this fix into dojo.removeAttr
569                                        node.removeAttribute(name);
570                                }else{
571                                        dojo.removeAttr(node, name);
572                                }
573                        }
574                });
575                return this;
576        }
577
578        //addClass, removeClass exist in dojo.NodeList. toggleClass in jQuery case
579        //just means add/remove the classname if it missing/exists. So need custom override.
580        f.toggleClass = function(/*String*/name, /*Expression?*/condition){
581                var hasCondition = arguments.length > 1;
582                this.forEach(function(node){
583                        dojo.toggleClass(node, name,  hasCondition ? condition : !dojo.hasClass(node, name));
584                });
585                return this;
586        }
587
588        //Action depends on arguments: if an array of functions do one thing,
589        //If no args, do a display toggle,
590        //If an expression, something that evaluates to true or false,
591        //then toggle display accordingly.
592        //If first arg is a String/Number, then do animation. Second arg
593        //is an optional callback.
594        f.toggle = function(){
595                //If more than two args and we have a function as first arg, then
596                //probably the onclick toggle variant: takes variable args that are
597                //functions and cycles through them on click actions.
598                var args = arguments;
599                if(arguments.length > 1 && dojo.isFunction(arguments[0])){
600                        var index = 0;
601                        var func = function(){
602                                var result = args[index].apply(this, arguments);
603                                index += 1;
604                                if(index > args.length - 1){
605                                        index = 0;
606                                }
607                        };
608                        return this.bind("click", func);
609                }else{
610                        //The display/hide/show case.
611                        var condition = arguments.length == 1 ? arguments[0] : undefined;
612                        this.forEach(function(node){
613                                var result = typeof condition == "undefined" ? dojo.style(node, "display") == "none" : condition;
614                                var action = (result ? "show" : "hide");
615                                var nl = $(node);
616                                nl[action].apply(nl, args);
617                        });
618                        return this;
619                }
620        }
621
622        //hasClass just returns true if any of the nodes has the class.
623        f.hasClass = function(/*String*/name){
624                return this.some(function(node){
625                        return dojo.hasClass(node, name);
626                });
627        }
628
629        //use the html method from dojo.NodeList-manipulate.
630        f.html = f.innerHTML;
631
632        //END jquery Attribute API methods
633
634       
635        //START jquery Traversing API methods
636        //http://docs.jquery.com/Traversing
637        dojo.forEach(["filter", "slice"], function(item){
638                f[item] = function(){
639                        //Convert the "this" value for functions passed in:
640                        var nl;
641                        if(dojo.isFunction(arguments[0])){
642                                var origFunc = arguments[0];
643                                arguments[0] = function(item, index){
644                                        return origFunc.call(item, item, index);
645                                }
646                        }
647                       
648                        if(item == "filter" && dojo.isString(arguments[0])){
649                                var nl = this._filterQueryResult(this, arguments[0]);
650                        }else{
651                                var oldCtor = dojo._NodeListCtor;
652                                dojo._NodeListCtor = f;
653                                //Need to wrap in a $() call since internally some
654                                //dojo.NodeList functions reference dojo.NodeList directly.
655                                //Need to get a configurable constructor for dojo.NodeList.
656                                nl = $(nlProto[item].apply(this, arguments));
657                                dojo._NodeListCtor = oldCtor;
658                        }
659
660                        return nl._stash(this);
661                }
662        });
663
664        f.map = function(/*Function*/callback){
665                //Hmm, this is not like array map/dojo.map where you get one item back for
666                //each input.
667                return this._buildArrayFromCallback(callback);
668        }
669        $.map = function(/*Array*/ary, /*Function*/callback){
670                //Hmm, this is not like array map/dojo.map where you get one item back for
671                //each input.
672                return f._buildArrayFromCallback.call(ary, callback);
673        }
674
675        $.inArray = function(value, /*Array*/ary){
676                return dojo.indexOf(ary, value);
677        }
678
679        f.is = function(query){
680                return (query ? !!this.filter(query).length : false);
681        }
682
683        //TODO: probably a better way to do this.
684        f.not = function(){
685                var notList = $.apply($, arguments);
686                //TODO: another place where if dojo.NodeList can configure a constructor,
687                //then we could avoid the $() wrapper below.
688                var nl = $(nlProto.filter.call(this, function(node){
689                        return notList.indexOf(node) == -1;
690                }));
691                return nl._stash(this);
692        }
693
694        f.add = function(){
695                return this.concat.apply(this, arguments);
696        }
697
698        function iframeDoc(/*DOMNode*/iframeNode){
699                // summary:
700                //              Returns the document object associated with the iframe DOM Node argument.
701
702                //Taken from dojo.io.iframe.doc(). Needed for contents() function below.
703
704                var doc = iframeNode.contentDocument || // W3
705                        (
706                                (
707                                        (iframeNode.name) && (iframeNode.document) &&
708                                        (document.getElementsByTagName("iframe")[iframeNode.name].contentWindow) &&
709                                        (document.getElementsByTagName("iframe")[iframeNode.name].contentWindow.document)
710                                )
711                        ) ||  // IE
712                        (
713                                (iframeNode.name)&&(document.frames[iframeNode.name])&&
714                                (document.frames[iframeNode.name].document)
715                        ) || null;
716                return doc;
717        }
718
719        f.contents = function(){
720                var ary = [];
721                this.forEach(function(node){
722                        if(node.nodeName.toUpperCase() == "IFRAME"){
723                                var doc = iframeDoc(node);
724                                if(doc){
725                                        ary.push(doc);
726                                }
727                        }else{
728                                //TODO: code similar to children() function. Refactor?
729                                var children = node.childNodes;
730                                //Using for loop for better speed.
731                                for(var i = 0; i < children.length; i++){
732                                        ary.push(children[i]);
733                                }
734                        }
735                });
736                return this._wrap(ary)._stash(this);
737        }
738
739        f.find = function(/*String*/query){
740                var ary = [];
741                this.forEach(function(node){
742                        if(node.nodeType == 1){
743                                ary = ary.concat(dojo._toArray($(query, node)));
744                        }
745                });
746                return this._getUniqueAsNodeList(ary)._stash(this);
747        }
748
749        f.andSelf = function(){
750                return this.add(this._parent);
751        }
752
753        //END jquery Traversing API methods
754
755        //START jquery Manipulation API methods
756        //http://docs.jquery.com/Manipulation
757
758        f.remove = function(/*String?*/query){
759                //Override NodeList-manipulate's remove so we can remove data.
760                var nl = (query ? this._filterQueryResult(this, query) : this);
761               
762                //Remove data
763                nl.removeData();
764               
765                //Remove event listeners.
766                //TODO! do this, once event stuff is built out.
767               
768                //Remove the items from the DOM, but keep them in this
769                //node list.
770                nl.forEach(function(node){
771                        node.parentNode.removeChild(node);
772                });
773               
774                return this;
775        }
776
777        //START jquery CSS API methods
778        //http://docs.jquery.com/CSS
779        $.css = function(/*DOMNode*/node, /*String|Object*/name, /*String|Number?*/value){
780                name = cssNameToJs(name);
781               
782                //Hmm, dojo.style does an arguments. length check.
783                var result = (value ? dojo.style(node, name, value) : dojo.style(node, name));
784                return result;
785        }
786
787        f.css = function(/*String|Object*/name, /*String|Number?*/value){
788                if(dojo.isString(name)){
789                        //Convert name to JS name if needed.
790                        name = cssNameToJs(name);
791                        if(arguments.length == 2){
792                                //set the value. Cannot directly delegate to
793                                //this.style, since non-element nodes may be in the mix?
794                                //this.contents() in particular will return some funky stuff.
795                               
796                                //Need to be sure to add "px" if appropriate.
797                                if(!dojo.isString(value) && name != "zIndex"){
798                                        value = value + "px";
799                                }
800
801                                this.forEach(function(node){
802                                        if(node.nodeType == 1){
803                                                dojo.style(node, name, value);
804                                        }
805                                });
806                                return this;
807                        }else{
808                                //return the value
809                                value = dojo.style(this[0], name);
810                                //Need to be sure to add "px" if appropriate.
811                                if(!dojo.isString(value) && name != "zIndex"){
812                                        value = value + "px";
813                                }
814                                return value;
815                        }
816                }else{
817                        for(var param in name){
818                                this.css(param, name[param]);
819                        }
820                        return this;
821                }
822        }
823       
824        function doBox(/*NodeList*/nl, /*String*/boxType, /*String*/prop, /*String||Number*/value){;
825                if(value){
826                        //Set height for all elements.
827                        var mod = {};
828                        mod[prop] = value;
829                        nl.forEach(function(node){
830                                dojo[boxType](node, mod);
831                        });
832                        return nl;
833                }else{
834                        //Just get first node's height.
835                        //Hmm. width is negative when element is display none in FF3?
836                        return Math.abs(Math.round(dojo[boxType](nl[0])[prop]));
837                }
838        }
839
840        f.height = function(value){
841                return doBox(this, "contentBox", "h", value);
842        }
843
844        f.width = function(value){
845                return doBox(this, "contentBox", "w", value);
846        }
847
848        function getDimensions(/*DOMNode*/node, /*String*/type, /*Boolean*/usePadding, /*Boolean*/useBorder, /*Boolean*/useMargin){
849                // summary:
850                //              sums up the different parts of the width/height based on arguments.
851
852                //If hidden, temporarily show it, do measurements then close.
853                var rehide = false;
854                if((rehide = node.style.display == "none")){
855                        node.style.display = "block";
856                }
857
858                var cs = dojo.getComputedStyle(node);
859                var content = Math.abs(Math.round(dojo._getContentBox(node, cs)[type]));
860                var pad = usePadding ? Math.abs(Math.round(dojo._getPadExtents(node, cs)[type])) : 0;
861                var border = useBorder ? Math.abs(Math.round(dojo._getBorderExtents(node, cs)[type])) : 0;
862                var margin = useMargin ? Math.abs(Math.round(dojo._getMarginExtents(node, cs)[type])) : 0;
863               
864                if(rehide){
865                        node.style.display = "none";
866                }
867
868                return pad + content + border + margin;
869        }
870
871        f.innerHeight = function(){
872                return getDimensions(this[0], "h", true);
873        }
874
875        f.innerWidth = function(){
876                return getDimensions(this[0], "w", true);
877        }
878
879        f.outerHeight = function(useMargin){
880                return getDimensions(this[0], "h", true, true, useMargin);
881        }
882
883        f.outerWidth = function(useMargin){
884                return getDimensions(this[0], "w", true, true, useMargin);
885        }
886
887        //END jquery CSS API methods
888
889
890        //START jquery Events API methods
891        //http://docs.jquery.com/Events
892       
893        //ready() already defined above.
894
895        //Event plumbing.
896        var listeners = [];
897        var listenId = 1;
898        var eventAttr = dojo._scopeName + "eventid";
899        var currentEvtData;
900
901        function getNonNamespacedName(/*String*/evtName){
902                // summary:
903                //              gets name of the event before the first ".".
904
905                //The $$ stuff is special ids used to create unique names
906                //for bound functions that did not have a unique namespace name.
907                evtName = evtName.split("$$")[0];
908                var dotIndex = evtName.indexOf(".");
909                if(dotIndex != -1){
910                        evtName = evtName.substring(0, dotIndex);
911                }
912                return evtName;
913        }
914
915        function domConnect(/*DOMNode*/node, /*String*/evtName){
916                // summary:
917                //              handles creating the connection with a real DOM event.
918
919                //This work should only be done one time per evName type.
920                //If the event if an ajax event, use dojo.subscribe instead.
921                if(evtName.indexOf("ajax") == 0){
922                        return dojo.subscribe(topics[evtName], function(dfd, res){
923                                var fakeEvt = new $.Event(evtName);
924                                if("ajaxComplete|ajaxSend|ajaxSuccess".indexOf(evtName) != -1){
925                                        triggerHandlers(node, [fakeEvt, dfd.ioArgs.xhr, dfd.ioArgs.args]);
926                                }else if(evtName == "ajaxError"){
927                                        triggerHandlers(node, [fakeEvt, dfd.ioArgs.xhr, dfd.ioArgs.args, res]);
928                                }else{
929                                        //ajaxStart|ajaxStop
930                                        triggerHandlers(node, [fakeEvt]);
931                                }
932                        });
933                }else{
934                        return dojo.connect(node, "on" + evtName, function(e){
935                                triggerHandlers(node, arguments);
936                        }); //Object
937                }
938        }
939
940        //Event object for compatibility for some tests.
941        $.Event = function(/*String*/type){
942                //Allow for calling function without "new"
943                if(this == $){
944                        return new $.Event(type);
945                }
946                if(typeof type == "string"){
947                        this.type = type.replace(/!/, "");
948                }else{
949                        dojo.mixin(this, type);
950                }
951                this.timeStamp = (new Date()).getTime();
952                this._isFake = true;
953                this._isStrict = (this.type.indexOf("!") != -1);
954               
955        }
956       
957        var ep = $.Event.prototype = {
958                preventDefault: function(){
959                        this.isDefaultPrevented = this._true;
960                },
961                stopPropagation: function(){
962                        this.isPropagationStopped = this._true;
963                },
964                stopImmediatePropagation: function(){
965                        this.isPropagationStopped = this._true;
966                        this.isImmediatePropagationStopped = this._true;
967                },
968                _true: function(){ return true; },
969                _false: function(){ return false; }
970        }
971        dojo.mixin(ep, {
972                isPropagationStopped: ep._false,
973                isImmediatePropagationStopped: ep._false,
974                isDefaultPrevented: ep._false
975        });
976
977        function makeTriggerData(data, type){
978                // summary:
979                //              makes sure that the data array is copied
980                //              and has an event as the first arg. If this function generates
981                //              a fake event (known by the data[0]._isFake property being true)
982                //              then the data[0].target needs to be set by the consumer of this function.
983               
984                data = data || [];
985                data = [].concat(data);
986
987                //If first data item is not an event, make one up.
988                //Need to set up target: prop in the consumers of this
989                //function.
990                var evt = data[0];
991                if(!evt || !evt.preventDefault){
992                        evt = type && type.preventDefault ? type : new $.Event(type);
993                        data.unshift(evt);
994                }
995                return data;
996        }
997       
998        var triggerHandlersCalled = false;
999
1000        function triggerHandlers(/*DOMNode*/node, /*Array*/data, /*Function?*/extraFunc){
1001                // summary:
1002                //              handles the actual callbacks to the handlers.
1003               
1004                //Indicate triggerHandlers was called.
1005                triggerHandlersCalled = true;
1006               
1007                //Uses currentEvtData if this is a simulated event.
1008                data = data || currentEvtData;
1009                extraFunc = extraFunc;
1010
1011                //Normalize on a real element if dealing with a document.
1012                if(node.nodeType == 9){
1013                        node = node.documentElement;
1014                }
1015
1016                var nodeId = node.getAttribute(eventAttr);
1017                if(!nodeId){
1018                        return;
1019                }
1020
1021                var evt = data[0];
1022                var evtFullName = evt.type;
1023                var evtName = getNonNamespacedName(evtFullName);
1024
1025                var cbs = listeners[nodeId][evtName];
1026
1027                var result;
1028                //Apply the extra function. What is that about? Not mentioned in the
1029                //public APIs?
1030                if(extraFunc){
1031                        result = extraFunc.apply(node, data);
1032                }
1033
1034                if (result !== false){
1035                        for(var param in cbs){
1036                                if(param != "_connectId" && (!evt._isStrict && (param.indexOf(evtFullName) == 0) || (evt._isStrict && param == evtFullName))){
1037                                        //Store the callback ID in case unbind is called with this event
1038                                        //so we can only unbind that one callback.
1039                                        evt[dojo._scopeName + "callbackId"] = param;
1040
1041                                        var cb = cbs[param];
1042                                        if(typeof cb.data != "undefined"){
1043                                                evt.data = cb.data;
1044                                        }else{
1045                                                evt.data = null;
1046                                        }
1047       
1048                                        //Do the actual callback.
1049                                        if ((result = cb.fn.apply(evt.target, data)) === false && !evt._isFake){
1050                                                dojo.stopEvent(evt);
1051                                        }
1052                                        evt.result = result;
1053                                }
1054                        }
1055                }
1056
1057                return result;
1058        }
1059
1060        f.triggerHandler = function(/*String*/type, /*Array?*/data, /*Function?*/extraFunc){
1061                //Only triggers handlers on the first node. Huh.
1062                var node = this[0];
1063                if(node && node.nodeType != 3 && node.nodeType != 8){
1064                        data = makeTriggerData(data, type);
1065                        return triggerHandlers(node, data, extraFunc);
1066                }else{
1067                        return undefined;
1068                }
1069        }
1070
1071        f.trigger = function(/*String*/type, /*Array?*/data, /*Function?*/extraFunc){
1072                //Copy data since we may need to modify by adding a
1073                data = makeTriggerData(data, type);
1074                var evt = data[0];
1075                var type = getNonNamespacedName(evt.type);
1076               
1077                //Store the current event data in case handlers need
1078                //to reference it because of a simulated event.
1079                currentEvtData = data;
1080                currentExtraFunc = extraFunc;
1081
1082                var result = null;
1083                var needTarget = !evt.target;
1084                this.forEach(function(node){
1085                        //Only handle non text/comment nodes.
1086                        if(node.nodeType != 3 && node.nodeType != 8){
1087
1088                                //Normalize on a real element if dealing with a document.
1089                                if(node.nodeType == 9){
1090                                        node = node.documentElement;
1091                                }
1092
1093                                //Set the node target appropriately for fake events.
1094                                if(evt._isFake){
1095                                        evt.currentTarget = node;
1096                                        if(needTarget){
1097                                                evt.target = node;
1098                                        }
1099                                }
1100
1101                                //Bizarre extra function thing. Not really demonstrated in public
1102                                //API docs.
1103                                if(extraFunc){
1104                                        var funcData = data.slice(1);
1105                                        result = extraFunc.apply(node, (result = null ? funcData : funcData.concat(result)));
1106                                }
1107
1108                                if(result !== false){
1109                                        //Trigger DOM event. onclick is handled differently than
1110                                        //others.
1111                                        /*
1112                                        if(type == 'click' && node.onclick && node.nodeName.toUpperCase() == "A"){
1113                                                result = node.onclick.apply(node, data);
1114                                        }
1115                                        */
1116                                       
1117                                        //Set the "global" flag that indicates if triggerHandlers was called.
1118                                        //If the direct node.event/onevent does not trigger the handlers, do so
1119                                        //manually at the end.
1120                                        triggerHandlersCalled = false;
1121                                       
1122                                        //Trigger functions registered directly on the DOM node.
1123                                        if(node[type]){
1124                                                try{
1125                                                        result = node[type]();
1126                                                }catch(e){
1127                                                        //Apparently IE throws on some hidden elements. Just eat it.
1128                                                }
1129                                        }else if(node["on" + type]){
1130                                                try{
1131                                                        result = node["on" + type]();
1132                                                }catch(e){
1133                                                        //Apparently IE throws on some hidden elements. Just eat it.
1134                                                }
1135                                        }
1136                                       
1137                                        if(!triggerHandlersCalled){
1138                                                //Finally triggerHandlers directly if the above code did not trigger it yet.
1139                                                result = triggerHandlers(node, data);
1140                                        }
1141
1142                                        //Bubble the event up.
1143                                        //TODO: optimize this path so we don't have to do forEach and NodeList work.
1144                                        var parentNode = node.parentNode;
1145                                        if(result !== false && !evt.isImmediatePropagationStopped() && !evt.isPropagationStopped() && parentNode && parentNode.nodeType == 1){
1146                                                $(parentNode).trigger(type, data, extraFunc);
1147                                        }
1148                                }
1149                        }
1150                });
1151
1152                //Clear current event data.
1153                currentEvtData = null;
1154                currentExtraFunc = null;
1155
1156                return this;
1157        }
1158
1159        var bindIdCounter = 0;
1160
1161        f.bind = function(/*String*/type, /*Array||Function?*/data, /*Function*/fn){
1162                //Type can be space separated values.
1163                type = type.split(" ");
1164               
1165                //May not have data argument.
1166                if(!fn){
1167                        fn = data;
1168                        data = null;
1169                }
1170
1171                this.forEach(function(node){
1172                        //Only handle non text/comment nodes.
1173                        if(node.nodeType != 3 && node.nodeType != 8){
1174                       
1175                                //If document, bind to documentElement
1176                                if(node.nodeType == 9){
1177                                        node = node.documentElement;
1178                                }
1179
1180                                //If no nodeId, then create one and attach it to the DOM node.
1181                                var nodeId = node.getAttribute(eventAttr);
1182                                if(!nodeId){
1183                                        nodeId = listenId++;
1184                                        node.setAttribute(eventAttr, nodeId);
1185                                        listeners[nodeId] = {};
1186                                }
1187       
1188                                //Process each event type.
1189                                for(var i = 0; i < type.length; i++){
1190                                        //Get event name, if have a dot on it, it is namespaced,
1191                                        //be sure to get the core event name.
1192                                        var evtFullName = type[i];
1193                                        var evtName = getNonNamespacedName(evtFullName);
1194                                        if(evtName == evtFullName){
1195                                                //Generate a unique ID for this function binding
1196                                                evtFullName = evtName + "$$" + (bindIdCounter++);
1197                                        }
1198       
1199                                        //Get the event listeners for the event name, the complete name.
1200                                        var lls = listeners[nodeId];
1201                                        if(!lls[evtName]){
1202                                                lls[evtName] = {
1203                                                        _connectId: domConnect(node, evtName)
1204                                                };
1205                                        }
1206       
1207                                        //Add the callback to the list of listeners.
1208                                        lls[evtName][evtFullName] = {
1209                                                fn: fn,
1210                                                data: data
1211                                        };
1212                                }
1213                        }
1214                });
1215               
1216                return this;
1217        }
1218
1219        function copyEventHandlers(/*DOMNode*/ src, /*DOMNode*/ target){
1220                // summary:
1221                //              copies the event handlers from onne src *element* node to
1222                //              another target *element* node. Assumes that target had
1223                //              no previous events on it, and is a clone of the src node.
1224
1225                //Get src listeners.
1226                var srcNodeId = target.getAttribute(eventAttr);
1227                var sls = listeners[srcNodeId];
1228                if(!sls){
1229                        return;
1230                }
1231
1232                //Generate listeners area for target.
1233                var nodeId = nodeId = listenId++;
1234                target.setAttribute(eventAttr, nodeId);
1235                var tls = listeners[nodeId] = {};
1236
1237                //Loope through events in source. Protect against bad
1238                //code modifying Object.prototype.
1239                var empty = {};
1240                for (var evtName in sls){
1241                        var tEvtData = tls[evtName] = {
1242                                _connectId: domConnect(target, evtName)
1243                        };
1244                        var sEvtData = sls[evtName];
1245
1246                        for (var evtFullName in sEvtData){
1247                                tEvtData[evtFullName] = {
1248                                        fn: sEvtData[evtFullName].fn,
1249                                        data: sEvtData[evtFullName].data
1250                                };
1251                        }
1252                }
1253        }
1254
1255        function listenerUnbind(lls, evtName, evtFullName, callbackId, fn){
1256                //Handles the real remove of an event and dojo.disconnects DOM handler if necessary.
1257                //This has to be broken out of the main unbind function because we have to support
1258                //things like unbind(".test") that go across major event names. Yuck.
1259                var handles = lls[evtName];
1260                if(handles){
1261                        var hasDot = evtFullName.indexOf(".") != -1;
1262                        var forceDelete = false;
1263
1264                        if(callbackId){
1265                                //Only need to unbind that one callback
1266                                delete handles[callbackId];
1267                        }else if(!hasDot && !fn){
1268                                forceDelete = true;
1269                        }else if(hasDot){
1270                                //A namespaced event.
1271                                //Problem is the namespaced event could be something like
1272                                //".test" which means remove all that end in .test. Yuck.
1273                                if(evtFullName.charAt(0) == "."){
1274                                        for(var param in handles){
1275                                                if(param.indexOf(evtFullName) == param.length - evtFullName.length){
1276                                                        delete handles[param];
1277                                                }
1278                                        }
1279                                }else{
1280                                        delete handles[evtFullName];
1281                                }
1282                        }else{
1283                                //Not a namespaced event. Cycle through the $$ names
1284                                //to find a function match.
1285                                for(var param in handles){
1286                                        if(param.indexOf("$$") != -1 && handles[param].fn == fn){
1287                                                delete handles[param];
1288                                                break;
1289                                        }
1290                                }
1291                        }
1292
1293                        //Remove handles/disconnect dom if no other params.
1294                        var allDone = true;
1295                        for(var param in handles){
1296                                if(param != "_connectId"){
1297                                        allDone = false;
1298                                        break;
1299                                }
1300                        }
1301                        if(forceDelete || allDone){
1302                                if(evtName.indexOf("ajax") != -1){
1303                                        dojo.unsubscribe(handles._connectId);
1304                                }else{
1305                                        dojo.disconnect(handles._connectId);
1306                                }
1307                                delete lls[evtName];
1308                        }
1309                }
1310        }
1311
1312        f.unbind = function(/*String*/type, /*Function*/fn){
1313               
1314                //See if event has a callbackId, if so, then we only unbind
1315                //that one callback.
1316                var callbackId = type ? type[dojo._scopeName + "callbackId"] : null;
1317
1318                //Type can be space separated values.
1319                type = type && type.type ? type.type : type;
1320                type = type ? type.split(" ") : type;
1321
1322                this.forEach(function(node){
1323                        //Only handle non text/comment nodes.
1324                        if(node.nodeType != 3 && node.nodeType != 8){
1325                                //If document, bind to documentElement
1326                                if(node.nodeType == 9){
1327                                        node = node.documentElement;
1328                                }
1329
1330                                //If no nodeId, then create one and attach it to the DOM node.
1331                                var nodeId = node.getAttribute(eventAttr);
1332                               
1333                                if(nodeId){
1334                                        //Get the event listeners for the event name, the complete name.
1335                                        var lls = listeners[nodeId];
1336                                        if(lls){
1337                                                //If no type, then it means do all bound types. Make a list of them.
1338                                                var etypes = type;
1339                                                if(!etypes){
1340                                                        etypes = [];
1341                                                        for(var param in lls){
1342                                                                etypes.push(param);
1343                                                        }
1344                                                }
1345
1346                                                //Process each event type.
1347                                                for(var i = 0; i < etypes.length; i++){
1348                                                        //Get event name, if have a dot on it, it is namespaced,
1349                                                        //be sure to get the core event name.
1350                                                        var evtFullName = etypes[i];
1351                                                        var evtName = getNonNamespacedName(evtFullName);
1352                       
1353                                                        //Problem is the namespaced event could be something like
1354                                                        //".test" which means remove all that end in .test. Yuck.
1355                                                        if(evtFullName.charAt(0) == "."){
1356                                                                for(var param in lls) {
1357                                                                        listenerUnbind(lls, param, evtFullName, callbackId, fn);
1358                                                                }
1359                                                        }else{
1360                                                                listenerUnbind(lls, evtName, evtFullName, callbackId, fn);
1361                                                        }
1362                                                }
1363                                        }
1364                                }
1365                        }
1366                });
1367
1368                return this;
1369        }
1370
1371        f.one = function(/*String*/evtName, /*Function*/func){
1372                var oneFunc = function(){
1373                        $(this).unbind(evtName, arguments.callee);
1374                        return func.apply(this, arguments);
1375                }
1376
1377                return this.bind(evtName, oneFunc);
1378        };
1379
1380        f._cloneNode = function(/*DOMNode*/ src){
1381                // summary:
1382                //              private utiltity to clone a node. Copies event handlers too.
1383                var target = src.cloneNode(true);
1384
1385                if(src.nodeType == 1){
1386                        //Look for event handlers in target.
1387                        var evNodes = dojo.query("[" + eventAttr + "]", target);
1388                        for(var i = 0, newNode; newNode = evNodes[i]; i++){
1389                                var oldNode = dojo.query('[' + eventAttr + '="' + newNode.getAttribute(eventAttr) + '"]', src)[0];
1390                                if(oldNode){
1391                                        copyEventHandlers(oldNode, newNode);
1392                                }
1393                        }
1394                }
1395                return target;
1396        };
1397
1398        //Temporary testing shim to get past jquery test setup errors.
1399        dojo.getObject("$.event.global", true);
1400
1401        //Set up event handlers
1402        dojo.forEach([
1403                "blur", "focus", "dblclick", "click", "error", "keydown", "keypress", "keyup", "load", "mousedown",
1404                "mouseenter", "mouseleave", "mousemove", "mouseout", "mouseover", "mouseup", "submit",
1405                "ajaxStart", "ajaxSend", "ajaxSuccess", "ajaxError", "ajaxComplete", "ajaxStop"
1406                ], function(evt){
1407                        f[evt] = function(callback){
1408                                if(callback){
1409                                        this.bind(evt, callback);
1410                                }else{
1411                                        this.trigger(evt);
1412                                }
1413                                return this;
1414                        }
1415                }
1416        );
1417
1418        //END jquery Events API methods
1419
1420
1421        //START jquery Effects API methods
1422        //http://docs.jquery.com/Effects
1423        function speedInt(speed){
1424                //Fix speed setting, translate string values to numbers.
1425                if(dojo.isString(speed)){
1426                        if(speed == "slow"){
1427                                speed = 700;
1428                        }else if(speed == "fast"){
1429                                speed = 300;
1430                        }else{
1431                                //Everything else is considered normal speed.
1432                                speed = 500;
1433                        }
1434                }
1435                return speed;
1436        }
1437       
1438        f.hide = function(/*String||Number*/speed, /*Function?*/callback){
1439                //Fix speed setting, translate string values to numbers.
1440                speed = speedInt(speed);
1441
1442                this.forEach(function(node){
1443                        var style = node.style;
1444                       
1445                        //Skip if already hidden
1446                        var cs = dojo.getComputedStyle(node);
1447                        if(cs.display == "none"){
1448                                return;
1449                        }
1450
1451                        style.overflow = "hidden";
1452                        style.display = "block";
1453                       
1454                        if(speed){
1455                                //It is alive!
1456                                dojo.anim(
1457                                        node,
1458                                        {
1459                                                width: 0,
1460                                                height: 0,
1461                                                opacity: 0
1462                                        },
1463                                        speed,
1464                                        null,
1465                                        function(){
1466                                                style.width = "";
1467                                                style.height = "";
1468                                                style.display = "none";
1469                                                return callback && callback.call(node);
1470                                        }
1471                                );
1472                        }else{
1473                                //No need for animation, fast path it.
1474                                dojo.style(node, "display", "none");
1475                                if(callback){
1476                                        callback.call(node);
1477                                }
1478                        }
1479                });
1480                return this;
1481        }
1482
1483        f.show = function(/*String||Number*/speed, /*Function?*/callback){
1484                //Fix speed setting, translate string values to numbers.
1485                speed = speedInt(speed);
1486
1487                this.forEach(function(node){
1488                        var style = node.style;
1489                        //Skip if the node is already showing.
1490                        var cs = dojo.getComputedStyle(node);
1491                        if(cs.display != "none"){
1492                                return;
1493                        }
1494
1495                        if(speed){
1496                                //Figure out size of element
1497                                //so we know when to stop animation.
1498                                //Try the easy path first.
1499                                var width = parseFloat(style.width);
1500                                var height = parseFloat(style.height);
1501                                if(!width || !height){
1502                                        //temporarily show the element to get
1503                                        //dimensions
1504                                        style.display = "block";
1505                                        var box = dojo.marginBox(node);
1506                                        width = box.w;
1507                                        height = box.h;
1508                                }
1509
1510                                //Make sure values are set to hidden state.
1511                                style.width = 0;
1512                                style.height = 0;
1513                                style.overflow = "hidden";
1514                                dojo.attr(node, "opacity", 0);
1515                                style.display = "block";
1516
1517                                //It is alive!
1518                                dojo.anim(
1519                                        node,
1520                                        {
1521                                                width: width,
1522                                                height: height,
1523                                                opacity: 1
1524                                        },
1525                                        speed,
1526                                        null,
1527                                        callback ? dojo.hitch(node, callback) : undefined
1528                                );
1529                        }else{
1530                                dojo.style(node, "display", "block");
1531                                if(callback){
1532                                        callback.call(node);
1533                                }
1534                        }
1535                });
1536                return this;
1537        }
1538
1539
1540        //END jquery Effects API methods
1541
1542
1543        //START jquery Ajax API methods
1544        //http://docs.jquery.com/Ajax
1545       
1546        $.ajaxSettings = {
1547        };
1548
1549        $.ajaxSetup = function(/*Object*/args){
1550                dojo.mixin($.ajaxSettings, args);
1551        }
1552
1553        var topics = {
1554                "ajaxStart": "/dojo/io/start",
1555                "ajaxSend": "/dojo/io/send",
1556                "ajaxSuccess": "/dojo/io/load",
1557                "ajaxError": "/dojo/io/error",
1558                "ajaxComplete": "/dojo/io/done",
1559                "ajaxStop": "/dojo/io/stop"
1560        };
1561
1562        for(var fnName in topics){
1563                //Make sure we are dealing with properties
1564                //we care about and not something another toolkit added.
1565                if(fnName.indexOf("ajax") == 0){
1566                        ;(function(fnName){
1567                                f[fnName] = function(callback){
1568                                        this.forEach(function(node){
1569                                                dojo.subscribe(topics[fnName], function(){
1570                                                        var fakeEvt = new $.Event(fnName);
1571                                                        var ioArgs = arguments[0] && arguments[0].ioArgs;
1572                                                        var xhr = ioArgs && ioArgs.xhr;
1573                                                        var args = ioArgs && ioArgs.args;
1574                                                        var res = arguments[1];
1575                                                        if("ajaxComplete|ajaxSend|ajaxSuccess".indexOf(fnName) != -1){
1576                                                                return callback.call(node, fakeEvt, xhr, args);
1577                                                        }else if(fnName == "ajaxError"){
1578                                                                return callback.call(node, fakeEvt, xhr, args, res);
1579                                                        }else{
1580                                                                //ajaxStart|ajaxStop
1581                                                                return callback.call(node, fakeEvt);
1582                                                        }
1583                                                });
1584                                        });
1585                                        return this;
1586                                }
1587                        })(fnName);
1588                }
1589        };
1590
1591        //Override dojo._xhrObj(dfd.ioArgs.args) to support beforeSend
1592        //Do not understand the reason for beforeSend, particularly
1593        //returning false stops the request.
1594        //WARNING: even with this code, the error and complete callbacks
1595        //will be fired because the deferred is cancelled. I feel this is
1596        //correct behavior for dojo, and not sure why beforeSend is needed.
1597        var _oldXhrObj = dojo._xhrObj;
1598        dojo._xhrObj = function(args){
1599                var xhr = _oldXhrObj.apply(dojo, arguments);
1600                if(args && args.beforeSend){
1601                        if(args.beforeSend(xhr) === false){
1602                                return false;
1603                        }
1604                }
1605                return xhr;
1606        }
1607
1608        $.ajax = function(/*Object*/args){
1609                //Not sure if the args are considered mutable.
1610                //Copy them to be safe.
1611                var temp = dojo.delegate($.ajaxSettings);
1612                for(var param in args){
1613                        //For data objects merge the data do not overwrite.
1614                        if(param == "data" && dojo.isObject(args[param]) && dojo.isObject(temp.data)){
1615                                for(var prop in args[param]){
1616                                        temp.data[prop] = args[param][prop];
1617                                }
1618                        }else{
1619                                temp[param] = args[param];
1620                        }
1621                }
1622                args = temp;
1623                var url = args.url;
1624
1625                if("async" in args){
1626                        args.sync = !args.async;
1627                }
1628
1629                //Turn off topic publications
1630                if(args.global === false){
1631                        args.ioPublish = false;
1632                }
1633
1634                if(args.data){
1635                        var data = args.data;
1636                        if(dojo.isString(data)){
1637                                //convert to an object.
1638                                args.content = dojo.queryToObject(data);
1639                        }else{
1640                                //data property values could be a function, be sure to call them if so.
1641                                //Hmm, this seems to be of dubious value.
1642                                for(var param in data){
1643                                        if(dojo.isFunction(data[param])){
1644                                                data[param] = data[param]();
1645                                        }
1646                                }
1647                                args.content = data;
1648                        }
1649                }
1650
1651                //dataType
1652                var dataType = args.dataType;
1653                if("dataType" in args){
1654                        if(dataType == "script"){
1655                                dataType = "javascript";
1656                        }else if(dataType == "html"){
1657                                dataType = "text";
1658                        }
1659                        args.handleAs = dataType;
1660                }else{
1661                        //Make a guess based on the URL.
1662                        dataType = args.handleAs = "text";
1663                        args.guessedType = true;
1664                }
1665
1666                //cache:
1667                if("cache" in args){
1668                        args.preventCache = !args.cache;
1669                }else{
1670                        if(args.dataType == "script" || args.dataType == "jsonp"){
1671                                args.preventCache = true;
1672                        }
1673                }
1674
1675                //Hide error since dojo treats it different.
1676                if(args.error){
1677                        args._jqueryError = args.error;
1678                        delete args.error;
1679                }
1680               
1681                //TODO: dataFilter
1682
1683                //Set up callbacks.
1684                args.handle = function(result, ioArgs){
1685                        var textStatus = "success";
1686                        if(result instanceof Error){
1687                                textStatus = (result.dojoType == "timeout" ? "timeout" : "error");
1688                                if(args._jqueryError){
1689                                        args._jqueryError(ioArgs.xhr, textStatus, result);
1690                                }
1691                        }else{
1692                                //If we guessed the type, see if it should be XML.
1693                                var xml = (ioArgs.args.guessedType && ioArgs.xhr && ioArgs.xhr.responseXML);
1694                                if(xml){
1695                                        result = xml;
1696                                }
1697
1698                                if(args.success){
1699                                        args.success(result, textStatus, ioArgs.xhr);
1700                                }
1701                        }
1702                        if(args.complete){
1703                                args.complete(result, textStatus, ioArgs.xhr);
1704                        }
1705                       
1706                        return result;
1707                };
1708               
1709                //Use a script tag if the request is xdomain or a jsonp thing.
1710                var useScript = (dataType == "jsonp");
1711                if(dataType == "javascript"){
1712                        //Get protocol and domain.
1713                        var colonIndex = url.indexOf(":");
1714                        var slashIndex = url.indexOf("/");
1715                        if(colonIndex > 0 && colonIndex < slashIndex){
1716                                //Possibly xdomain. Peel off protocol and hostname to find out.
1717                                var lastSlash = url.indexOf("/", slashIndex + 2);
1718                                if(lastSlash == -1){
1719                                        lastSlash = url.length;
1720                                }
1721                                if(location.protocol != url.substring(0, colonIndex + 1) ||
1722                                        location.hostname != url.substring(slashIndex + 2, lastSlash)){
1723                                        useScript = true;
1724                                }
1725                        }
1726                }
1727
1728                if(useScript){
1729                        if(dataType == "jsonp"){
1730                                //Look for callback param
1731                                var cb = args.jsonp;
1732                                if(!cb){
1733                                        //Look in the URL
1734                                        var params = args.url.split("?")[1];
1735                                        if(params && (params = dojo.queryToObject(params))){
1736                                                cb = findJsonpCallback(params);
1737                                                if(cb){
1738                                                        //Remove the cb from the url.
1739                                                        var regex = new RegExp("([&\\?])?" + cb + "=?");
1740                                                        args.url = args.url.replace(regex + "=?");
1741                                                }
1742                                        }
1743                                        //Look in the content.
1744                                        if(!cb){
1745                                                cb = findJsonpCallback(args.content);
1746                                                if(cb){
1747                                                        delete args.content[cb];
1748                                                }
1749                                        }
1750                                }
1751                                args.jsonp = cb || "callback";
1752                        }
1753                        var dfd = dojo.io.script.get(args);
1754                        return dfd;
1755                }else{
1756                        var dfd = dojo.xhr(args.type || "GET", args);
1757                        //If the XHR object is false, it means beforeSend canceled the request.
1758                        return dfd.ioArgs.xhr === false ? false : dfd.ioArgs.xhr;
1759                }
1760        }
1761
1762        function findJsonpCallback(obj){
1763                for(var prop in obj){
1764                        if(prop.indexOf("callback") == prop.length - 8){
1765                                return prop;
1766                        }
1767                }
1768                return null;
1769        }
1770       
1771        $.getpost = function(httpType, url, data, callback, dataType){
1772                var args = {
1773                        url: url,
1774                        type: httpType
1775                };
1776
1777                //Normalize data, considering it may be the real
1778                //callback.
1779                if(data){
1780                        if(dojo.isFunction(data) && !callback){
1781                                args.complete = data;
1782                        }else{
1783                                args.data = data;
1784                        }
1785                }
1786
1787                //Normalize callback, considering it may be
1788                //the datatype.
1789                if(callback){
1790                        if(dojo.isString(callback) && !dataType){
1791                                dataType = callback;
1792                        }else{
1793                                args.complete = callback;
1794                        }
1795                }
1796
1797                if(dataType){
1798                        args.dataType = dataType;
1799                }
1800
1801                return $.ajax(args);
1802        };
1803
1804        $.get = dojo.hitch($, "getpost", "GET");
1805        $.post = dojo.hitch($, "getpost", "POST");
1806        $.getJSON = function(url, data, callback){
1807                return $.getpost("GET", url, data, callback, "json");
1808        }
1809        $.getScript = function(url, callback){
1810                return $.ajax({
1811                        url: url,
1812                        success: callback,
1813                        dataType: "script"
1814                });
1815        }
1816
1817        f.load = function(url, data, callback){
1818               
1819                //See if this is a window or document. If so, then want to
1820                //register onload handler.
1821                var node = this[0];
1822                if(!node || !node.nodeType || node.nodeType == 9){
1823                        dojo.addOnLoad(url);
1824                        return this;
1825                }
1826
1827                //The rest of this function is the ajax HTML load case.
1828                //Pull off selector if it is on the url.
1829                var parts = url.split(/\s+/);
1830                url = parts[0];
1831                var query = parts[1];
1832               
1833                var finalCb = callback || data;
1834
1835                var cb = dojo.hitch(this, function(result, textStatus, xhr){
1836                        //Try to find all the body content.
1837                        var match = result.match(/\<\s*body[^>]+>.*<\/body\s*>/i);
1838                        if(match){
1839                                result = match;
1840                        }
1841
1842                        //Convert to DOM nodes.
1843                        var nodes = dojo._toDom(result);
1844
1845                        //Apply query, using a temp div to do the filtering.
1846                        if(query){
1847                                var temp = $(dojo.create("div"));
1848                                temp.append(nodes);
1849                                nodes = temp.find(query);
1850                        }else{
1851                                nodes = $(nodes.nodeType == 11 ? nodes.childNodes : nodes);
1852                        }
1853
1854                        //Add the HTML to all nodes in this node list.
1855                        this.html(nodes);
1856
1857                        //Call the user's callback.
1858                        //Use a timeout to allow any embedded scripts that
1859                        //were just inserted to run.
1860                        if(finalCb){
1861                                setTimeout(dojo.hitch(this, function(){
1862                                        this.forEach(function(node){
1863                                                finalCb.call(node, result, textStatus, xhr);
1864                                        });
1865                                }), 10);
1866                        }
1867                });
1868
1869                //Adjust parameters since they are variable.
1870                if(!callback){
1871                        data = cb;
1872                }else{
1873                        callback = cb;
1874                }
1875
1876                //Set HTTP method. If the data is a string, use get, if it is an object,
1877                //use post.
1878                var method = "GET";
1879                if(data && dojo.isObject(data)){
1880                        method = "POST";
1881                }
1882
1883                $.getpost(method, url, data, callback, "html");
1884                return this;
1885        }
1886
1887        var serializeExclude = "file|submit|image|reset|button|";
1888        f.serialize = function(){
1889                var ret = "";
1890                var strs = this.map(function(node){
1891                        if(node.nodeName.toUpperCase() == "FORM"){
1892                                return dojo.formToQuery(node);
1893                        }else{
1894                                var type = (node.type||"").toLowerCase();
1895                                if(serializeExclude.indexOf(type) == -1){
1896                                        var val = dojo.fieldToObject(node);
1897                                        if(node.name && val != null){
1898                                                var q = {};
1899                                                q[node.name] = val;
1900                                                return dojo.objectToQuery(q);
1901                                        }
1902                                }
1903                        }
1904                });
1905                return ret + strs.join("&");
1906        }
1907
1908        $.param = function(obj){
1909                if(obj._is$ && obj.serialize){
1910                        return obj.serialize();
1911                }else if(dojo.isArray(obj)){
1912                        return dojo.map(obj, function(item){
1913                                return $.param(item);
1914                        }).join("&");
1915                }else{
1916                        return dojo.objectToQuery(obj);
1917                }
1918        }
1919       
1920        //END jquery Ajax API methods
1921
1922        //START jquery Utilities API methods
1923        //http://docs.jquery.com/Utilities
1924        //TODO:
1925       
1926        $.isFunction = function(){
1927                var result = dojo.isFunction.apply(dojo, arguments);
1928                //Make sure Object does not return true
1929                if(result){
1930                        result = (typeof(arguments[0]) != "object");
1931                }
1932                return result;
1933        }
1934
1935        //END jquery Utilities API methods
1936
1937       
1938})();
1939
Note: See TracBrowser for help on using the repository browser.