Tagging the 1.5rc1 release.
[jquery.git] / src / core.js
index 95de5b9..520db45 100644 (file)
@@ -3,7 +3,7 @@ var jQuery = (function() {
 // Define a local copy of jQuery
 var jQuery = function( selector, context ) {
                // The jQuery object is actually just the init constructor 'enhanced'
-               return new jQuery.fn.init( selector, context );
+               return new jQuery.fn.init( selector, context, rootjQuery );
        },
 
        // Map over jQuery in case of overwrite
@@ -19,12 +19,8 @@ var jQuery = function( selector, context ) {
        // (both of which we optimize for)
        quickExpr = /^(?:[^<]*(<[\w\W]+>)[^>]*$|#([\w\-]+)$)/,
 
-       // Is it a simple selector
-       isSimple = /^.[^:#\[\.,]*$/,
-
        // Check if a string has a non-whitespace character in it
        rnotwhite = /\S/,
-       rwhite = /\s/,
 
        // Used for trimming whitespace
        trimLeft = /^\s+/,
@@ -56,13 +52,16 @@ var jQuery = function( selector, context ) {
 
        // For matching the engine and version of the browser
        browserMatch,
-       
+
        // Has the ready events already been bound?
        readyBound = false,
-       
+
        // The deferred used on DOM ready
        readyList,
 
+       // Promise methods
+       promiseMethods = "then done fail isResolved isRejected promise".split( " " ),
+
        // The ready event handler
        DOMContentLoaded,
 
@@ -73,12 +72,13 @@ var jQuery = function( selector, context ) {
        slice = Array.prototype.slice,
        trim = String.prototype.trim,
        indexOf = Array.prototype.indexOf,
-       
+
        // [[Class]] -> type pairs
        class2type = {};
 
 jQuery.fn = jQuery.prototype = {
-       init: function( selector, context ) {
+       constructor: jQuery,
+       init: function( selector, context, rootjQuery ) {
                var match, elem, ret, doc;
 
                // Handle $(""), $(null), or $(undefined)
@@ -92,7 +92,7 @@ jQuery.fn = jQuery.prototype = {
                        this.length = 1;
                        return this;
                }
-               
+
                // The body element only exists once, optimize finding it
                if ( selector === "body" && !context && document.body ) {
                        this.context = document;
@@ -112,6 +112,7 @@ jQuery.fn = jQuery.prototype = {
 
                                // HANDLE: $(html) -> $(array)
                                if ( match[1] ) {
+                                       context = context instanceof jQuery ? context[0] : context;
                                        doc = (context ? context.ownerDocument || context : document);
 
                                        // If a single string is passed in and it's a single tag
@@ -129,11 +130,11 @@ jQuery.fn = jQuery.prototype = {
 
                                        } else {
                                                ret = jQuery.buildFragment( [ match[1] ], [ doc ] );
-                                               selector = (ret.cacheable ? ret.fragment.cloneNode(true) : ret.fragment).childNodes;
+                                               selector = (ret.cacheable ? jQuery.clone(ret.fragment) : ret.fragment).childNodes;
                                        }
-                                       
+
                                        return jQuery.merge( this, selector );
-                                       
+
                                // HANDLE: $("#id")
                                } else {
                                        elem = document.getElementById( match[2] );
@@ -157,13 +158,6 @@ jQuery.fn = jQuery.prototype = {
                                        return this;
                                }
 
-                       // HANDLE: $("TAG")
-                       } else if ( !context && !rnonword.test( selector ) ) {
-                               this.selector = selector;
-                               this.context = document;
-                               selector = document.getElementsByTagName( selector );
-                               return jQuery.merge( this, selector );
-
                        // HANDLE: $(expr, $(...))
                        } else if ( !context || context.jquery ) {
                                return (context || rootjQuery).find( selector );
@@ -171,7 +165,7 @@ jQuery.fn = jQuery.prototype = {
                        // HANDLE: $(expr, context)
                        // (which is just equivalent to: $(context).find(expr)
                        } else {
-                               return jQuery( context ).find( selector );
+                               return this.constructor( context ).find( selector );
                        }
 
                // HANDLE: $(function)
@@ -222,11 +216,11 @@ jQuery.fn = jQuery.prototype = {
        // (returning the new matched element set)
        pushStack: function( elems, name, selector ) {
                // Build a new jQuery matched element set
-               var ret = jQuery();
+               var ret = this.constructor();
 
                if ( jQuery.isArray( elems ) ) {
                        push.apply( ret, elems );
-               
+
                } else {
                        jQuery.merge( ret, elems );
                }
@@ -252,15 +246,17 @@ jQuery.fn = jQuery.prototype = {
        each: function( callback, args ) {
                return jQuery.each( this, callback, args );
        },
-       
-       ready: function() {
+
+       ready: function( fn ) {
                // Attach the listeners
                jQuery.bindReady();
-               
-               // Change ready & apply
-               return ( jQuery.fn.ready = readyList.then ).apply( this , arguments );
+
+               // Add the callback
+               readyList.done( fn );
+
+               return this;
        },
-       
+
        eq: function( i ) {
                return i === -1 ?
                        this.slice( i ) :
@@ -285,9 +281,9 @@ jQuery.fn = jQuery.prototype = {
                        return callback.call( elem, i, elem );
                }));
        },
-       
+
        end: function() {
-               return this.prevObject || jQuery(null);
+               return this.prevObject || this.constructor(null);
        },
 
        // For internal use only.
@@ -374,14 +370,14 @@ jQuery.extend({
 
                return jQuery;
        },
-       
+
        // Is the DOM ready to be used? Set to true once it occurs.
        isReady: false,
 
        // A counter to track how many items to wait for before
        // the ready event fires. See #6781
        readyWait: 1,
-       
+
        // Handle when the DOM is ready
        ready: function( wait ) {
                // A third-party is pushing the ready event forwards
@@ -405,15 +401,15 @@ jQuery.extend({
                        }
 
                        // If there are functions bound, to execute
-                       readyList.fire( document , [ jQuery ] );
-                       
+                       readyList.resolveWith( document, [ jQuery ] );
+
                        // Trigger any bound ready events
                        if ( jQuery.fn.trigger ) {
                                jQuery( document ).trigger( "ready" ).unbind( "ready" );
                        }
                }
        },
-       
+
        bindReady: function() {
                if ( readyBound ) {
                        return;
@@ -432,7 +428,7 @@ jQuery.extend({
                if ( document.addEventListener ) {
                        // Use the handy event callback
                        document.addEventListener( "DOMContentLoaded", DOMContentLoaded, false );
-                       
+
                        // A fallback to window.onload, that will always work
                        window.addEventListener( "load", jQuery.ready, false );
 
@@ -441,7 +437,7 @@ jQuery.extend({
                        // ensure firing before onload,
                        // maybe late but safe also for iframes
                        document.attachEvent("onreadystatechange", DOMContentLoaded);
-                       
+
                        // A fallback to window.onload, that will always work
                        window.attachEvent( "onload", jQuery.ready );
 
@@ -492,20 +488,20 @@ jQuery.extend({
                if ( !obj || jQuery.type(obj) !== "object" || obj.nodeType || jQuery.isWindow( obj ) ) {
                        return false;
                }
-               
+
                // Not own constructor property must be Object
                if ( obj.constructor &&
                        !hasOwn.call(obj, "constructor") &&
                        !hasOwn.call(obj.constructor.prototype, "isPrototypeOf") ) {
                        return false;
                }
-               
+
                // Own properties are enumerated firstly, so to speed up,
                // if last one is own, then all properties are own.
-       
+
                var key;
                for ( key in obj ) {}
-               
+
                return key === undefined || hasOwn.call( obj, key );
        },
 
@@ -515,11 +511,11 @@ jQuery.extend({
                }
                return true;
        },
-       
+
        error: function( msg ) {
                throw msg;
        },
-       
+
        parseJSON: function( data ) {
                if ( typeof data !== "string" || !data ) {
                        return null;
@@ -527,7 +523,7 @@ jQuery.extend({
 
                // Make sure leading/trailing whitespace is removed (IE can't handle it)
                data = jQuery.trim( data );
-               
+
                // Make sure the incoming data is actual JSON
                // Logic borrowed from http://json.org/json2.js
                if ( rvalidchars.test(data.replace(rvalidescape, "@")
@@ -543,7 +539,7 @@ jQuery.extend({
                        jQuery.error( "Invalid JSON: " + data );
                }
        },
-       
+
        // Cross-browser xml parsing
        // (xml & tmp used internally)
        parseXML: function( data , xml , tmp ) {
@@ -556,13 +552,13 @@ jQuery.extend({
                        xml.async = "false";
                        xml.loadXML( data );
                }
-               
+
                tmp = xml.documentElement;
-               
+
                if ( ! tmp || ! tmp.nodeName || tmp.nodeName === "parsererror" ) {
                        jQuery.error( "Invalid XML: " + data );
                }
-               
+
                return xml;
        },
 
@@ -578,7 +574,7 @@ jQuery.extend({
 
                        script.type = "text/javascript";
 
-                       if ( jQuery.support.scriptEval ) {
+                       if ( jQuery.support.scriptEval() ) {
                                script.appendChild( document.createTextNode( data ) );
                        } else {
                                script.text = data;
@@ -691,7 +687,7 @@ jQuery.extend({
                        for ( var l = second.length; j < l; j++ ) {
                                first[ i++ ] = second[ j ];
                        }
-               
+
                } else {
                        while ( second[j] !== undefined ) {
                                first[ i++ ] = second[ j++ ];
@@ -772,7 +768,7 @@ jQuery.extend({
        // The value/s can be optionally by executed if its a function
        access: function( elems, key, value, exec, fn, pass ) {
                var length = elems.length;
-       
+
                // Setting many attributes
                if ( typeof key === "object" ) {
                        for ( var k in key ) {
@@ -780,19 +776,19 @@ jQuery.extend({
                        }
                        return elems;
                }
-       
+
                // Setting one attribute
                if ( value !== undefined ) {
                        // Optionally, function values get executed if exec is true
                        exec = !pass && exec && jQuery.isFunction(value);
-               
+
                        for ( var i = 0; i < length; i++ ) {
                                fn( elems[i], key, exec ? value.call( elems[i], i, fn( elems[i], key ) ) : value, pass );
                        }
-               
+
                        return elems;
                }
-       
+
                // Getting an attribute
                return length ? fn( elems[0], key ) : undefined;
        },
@@ -800,10 +796,9 @@ jQuery.extend({
        now: function() {
                return (new Date()).getTime();
        },
-       
+
        // Create a simple deferred (one callbacks list)
        _Deferred: function() {
-               
                var // callbacks list
                        callbacks = [],
                        // stored [ context , args ]
@@ -814,72 +809,64 @@ jQuery.extend({
                        cancelled,
                        // the deferred itself
                        deferred  = {
-                               
-                               // then( f1, f2, ...)
-                               then: function () {
-                                       
-                                       if ( ! cancelled ) {
-                                               
+
+                               // done( f1, f2, ...)
+                               done: function() {
+                                       if ( !cancelled ) {
                                                var args = arguments,
                                                        i,
                                                        length,
                                                        elem,
                                                        type,
                                                        _fired;
-                                                       
                                                if ( fired ) {
                                                        _fired = fired;
                                                        fired = 0;
                                                }
-                                               
-                                               for ( i = 0, length = args.length ; i < length ; i++ ) {
+                                               for ( i = 0, length = args.length; i < length; i++ ) {
                                                        elem = args[ i ];
                                                        type = jQuery.type( elem );
                                                        if ( type === "array" ) {
-                                                               deferred.then.apply( deferred , elem );
+                                                               deferred.done.apply( deferred, elem );
                                                        } else if ( type === "function" ) {
                                                                callbacks.push( elem );
                                                        }
                                                }
-                                               
                                                if ( _fired ) {
-                                                       deferred.fire( _fired[ 0 ] , _fired[ 1 ] );
+                                                       deferred.resolveWith( _fired[ 0 ], _fired[ 1 ] );
                                                }
                                        }
-                                       
                                        return this;
                                },
-                               
+
                                // resolve with given context and args
-                               fire: function( context , args ) {
-                                       if ( ! cancelled && ! fired && ! firing ) {
-                                               
+                               resolveWith: function( context, args ) {
+                                       if ( !cancelled && !fired && !firing ) {
                                                firing = 1;
-                                               
                                                try {
                                                        while( callbacks[ 0 ] ) {
-                                                               callbacks.shift().apply( context , args );
+                                                               callbacks.shift().apply( context, args );
                                                        }
                                                }
                                                finally {
-                                                       fired = [ context , args ];
+                                                       fired = [ context, args ];
                                                        firing = 0;
                                                }
                                        }
                                        return this;
                                },
-                               
+
                                // resolve with this as context and given arguments
                                resolve: function() {
-                                       deferred.fire( jQuery.isFunction( this.promise ) ? this.promise() : this , arguments );
+                                       deferred.resolveWith( jQuery.isFunction( this.promise ) ? this.promise() : this, arguments );
                                        return this;
                                },
-                               
+
                                // Has this deferred been resolved?
                                isResolved: function() {
                                        return !!( firing || fired );
                                },
-                               
+
                                // Cancel
                                cancel: function() {
                                        cancelled = 1;
@@ -887,59 +874,77 @@ jQuery.extend({
                                        return this;
                                }
                        };
-               
+
                return deferred;
        },
-       
+
        // Full fledged deferred (two callbacks list)
-       // Typical success/error system
        Deferred: function( func ) {
-               
                var deferred = jQuery._Deferred(),
-                       failDeferred = jQuery._Deferred();
-                       
-               // Add errorDeferred methods and redefine cancel                        
-               jQuery.extend( deferred , {
-
-                               fail: failDeferred.then,
-                               fireReject: failDeferred.fire,
-                               reject: failDeferred.resolve,
-                               isRejected: failDeferred.isResolved,
-                               // Get a promise for this deferred
-                               // If obj is provided, the promise aspect is added to the object
-                               promise: function( obj ) {
-                                       obj = obj || {};
-                                       jQuery.each( "then fail isResolved isRejected".split( " " ) , function( _ , method ) {
-                                               obj[ method ] = deferred[ method ];
-                                       });
-                                       obj.promise = function() {
-                                               return obj;
-                                       };
-                                       return obj;
+                       failDeferred = jQuery._Deferred(),
+                       promise;
+               // Add errorDeferred methods, then and promise
+               jQuery.extend( deferred, {
+                       then: function( doneCallbacks, failCallbacks ) {
+                               deferred.done( doneCallbacks ).fail( failCallbacks );
+                               return this;
+                       },
+                       fail: failDeferred.done,
+                       rejectWith: failDeferred.resolveWith,
+                       reject: failDeferred.resolve,
+                       isRejected: failDeferred.isResolved,
+                       // Get a promise for this deferred
+                       // If obj is provided, the promise aspect is added to the object
+                       promise: function( obj , i /* internal */ ) {
+                               if ( obj == null ) {
+                                       if ( promise ) {
+                                               return promise;
+                                       }
+                                       promise = obj = {};
                                }
-
+                               i = promiseMethods.length;
+                               while( i-- ) {
+                                       obj[ promiseMethods[ i ] ] = deferred[ promiseMethods[ i ] ];
+                               }
+                               return obj;
+                       }
                } );
-               
                // Make sure only one callback list will be used
-               deferred.then( failDeferred.cancel ).fail( deferred.cancel );
-               
+               deferred.then( failDeferred.cancel, deferred.cancel );
                // Unexpose cancel
                delete deferred.cancel;
-               
                // Call given func if any
                if ( func ) {
-                       func.call( deferred , deferred );
+                       func.call( deferred, deferred );
                }
-               
                return deferred;
        },
 
        // Deferred helper
        when: function( object ) {
-               object = object && jQuery.isFunction( object.promise ) ?
-                       object :
-                       jQuery.Deferred().resolve( object );
-               return object.promise();
+               var args = arguments,
+                       length = args.length,
+                       deferred = length <= 1 && object && jQuery.isFunction( object.promise ) ?
+                               object :
+                               jQuery.Deferred(),
+                       promise = deferred.promise(),
+                       resolveArray;
+
+               if ( length > 1 ) {
+                       resolveArray = new Array( length );
+                       jQuery.each( args, function( index, element, args ) {
+                               jQuery.when( element ).then( function( value ) {
+                                       args = arguments;
+                                       resolveArray[ index ] = args.length > 1 ? slice.call( args, 0 ) : value;
+                                       if( ! --length ) {
+                                               deferred.resolveWith( promise, resolveArray );
+                                       }
+                               }, deferred.reject );
+                       } );
+               } else if ( deferred !== object ) {
+                       deferred.resolve( object );
+               }
+               return promise;
        },
 
        // Use of jQuery.browser is frowned upon.
@@ -956,6 +961,25 @@ jQuery.extend({
                return { browser: match[1] || "", version: match[2] || "0" };
        },
 
+       subclass: function(){
+               function jQuerySubclass( selector, context ) {
+                       return new jQuerySubclass.fn.init( selector, context );
+               }
+               jQuerySubclass.superclass = this;
+               jQuerySubclass.fn = jQuerySubclass.prototype = this();
+               jQuerySubclass.fn.constructor = jQuerySubclass;
+               jQuerySubclass.subclass = this.subclass;
+               jQuerySubclass.fn.init = function init( selector, context ) {
+                       if (context && context instanceof jQuery && !(context instanceof jQuerySubclass)){
+                               context = jQuerySubclass(context);
+                       }
+                       return jQuery.fn.init.call( this, selector, context, rootjQuerySubclass );
+               };
+               jQuerySubclass.fn.init.prototype = jQuerySubclass.fn;
+               var rootjQuerySubclass = jQuerySubclass(document);
+               return jQuerySubclass;
+       },
+
        browser: {}
 });
 
@@ -984,9 +1008,8 @@ if ( indexOf ) {
        };
 }
 
-// Verify that \s matches non-breaking spaces
-// (IE fails on this test)
-if ( !rwhite.test( "\xA0" ) ) {
+// IE doesn't match non-breaking spaces with \s
+if ( rnotwhite.test( "\xA0" ) ) {
        trimLeft = /^[\s\xA0]+/;
        trimRight = /[\s\xA0]+$/;
 }
@@ -1030,11 +1053,6 @@ function doScrollCheck() {
        jQuery.ready();
 }
 
-// Expose jQuery as an Asynchronous Module
-if ( typeof define !== "undefined" ) {
-       define( "jquery", [], function () { return jQuery; } );
-}
-
 // Expose jQuery to the global object
 return (window.jQuery = window.$ = jQuery);