Merge branch 'master' of git://github.com/jquery/jquery into fixedbuild
[jquery.git] / src / core.js
index 48261fc..9312ee2 100644 (file)
@@ -15,8 +15,9 @@ var jQuery = function( selector, context ) {
        // A central reference to the root jQuery(document)
        rootjQuery,
 
-       // A simple way to check for HTML strings
-       quickExpr = /^(?:[^<]*(<[\w\W]+>)[^>]*$/,
+       // A simple way to check for HTML strings or ID strings
+       // (both of which we optimize for)
+       quickExpr = /^(?:[^<]*(<[\w\W]+>)[^>]*$|#([\w\-]+)$)/,
 
        // Check if a string has a non-whitespace character in it
        rnotwhite = /\S/,
@@ -25,9 +26,6 @@ var jQuery = function( selector, context ) {
        trimLeft = /^\s+/,
        trimRight = /\s+$/,
 
-       // Check for non-word characters
-       rnonword = /\W/,
-
        // Check for digits
        rdigit = /\d/,
 
@@ -52,15 +50,9 @@ 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,
 
@@ -92,32 +84,70 @@ jQuery.fn = jQuery.prototype = {
                        return this;
                }
 
+               // The body element only exists once, optimize finding it
+               if ( selector === "body" && !context && document.body ) {
+                       this.context = document;
+                       this[0] = document.body;
+                       this.selector = "body";
+                       this.length = 1;
+                       return this;
+               }
+
                // Handle HTML strings
                if ( typeof selector === "string" ) {
-                       // Are we dealing with HTML string
-                       if ( (match = quickExpr.exec( selector )) ) {
-                               context = context instanceof jQuery ? context[0] : context;
-                               doc = (context ? context.ownerDocument || context : document);
+                       // Are we dealing with HTML string or an ID?
+                       match = quickExpr.exec( selector );
+
+                       // Verify a match, and that no context was specified for #id
+                       if ( match && (match[1] || !context) ) {
 
-                               // If a single string is passed in and it's a single tag
-                               // just do a createElement and skip the rest
-                               ret = rsingleTag.exec( selector );
+                               // HANDLE: $(html) -> $(array)
+                               if ( match[1] ) {
+                                       context = context instanceof jQuery ? context[0] : context;
+                                       doc = (context ? context.ownerDocument || context : document);
 
-                               if ( ret ) {
-                                       if ( jQuery.isPlainObject( context ) ) {
-                                               selector = [ document.createElement( ret[1] ) ];
-                                               jQuery.fn.attr.call( selector, context, true );
+                                       // If a single string is passed in and it's a single tag
+                                       // just do a createElement and skip the rest
+                                       ret = rsingleTag.exec( selector );
+
+                                       if ( ret ) {
+                                               if ( jQuery.isPlainObject( context ) ) {
+                                                       selector = [ document.createElement( ret[1] ) ];
+                                                       jQuery.fn.attr.call( selector, context, true );
+
+                                               } else {
+                                                       selector = [ doc.createElement( ret[1] ) ];
+                                               }
 
                                        } else {
-                                               selector = [ doc.createElement( ret[1] ) ];
+                                               ret = jQuery.buildFragment( [ match[1] ], [ doc ] );
+                                               selector = (ret.cacheable ? jQuery.clone(ret.fragment) : ret.fragment).childNodes;
                                        }
 
+                                       return jQuery.merge( this, selector );
+
+                               // HANDLE: $("#id")
                                } else {
-                                       ret = jQuery.buildFragment( [ match[1] ], [ doc ] );
-                                       selector = (ret.cacheable ? jQuery(ret.fragment).clone()[0] : ret.fragment).childNodes;
-                               }
+                                       elem = document.getElementById( match[2] );
+
+                                       // Check parentNode to catch when Blackberry 4.6 returns
+                                       // nodes that are no longer in the document #6963
+                                       if ( elem && elem.parentNode ) {
+                                               // Handle the case where IE and Opera return items
+                                               // by name instead of ID
+                                               if ( elem.id !== match[2] ) {
+                                                       return rootjQuery.find( selector );
+                                               }
+
+                                               // Otherwise, we inject the element directly into the jQuery object
+                                               this.length = 1;
+                                               this[0] = elem;
+                                       }
 
-                               return jQuery.merge( this, selector );
+                                       this.context = document;
+                                       this.selector = selector;
+                                       return this;
+                               }
 
                        // HANDLE: $(expr, $(...))
                        } else if ( !context || context.jquery ) {
@@ -208,12 +238,14 @@ jQuery.fn = jQuery.prototype = {
                return jQuery.each( this, callback, args );
        },
 
-       ready: function() {
+       ready: function( fn ) {
                // Attach the listeners
                jQuery.bindReady();
 
-               // Change ready & apply
-               return ( jQuery.fn.ready = readyList.done ).apply( this , arguments );
+               // Add the callback
+               readyList.done( fn );
+
+               return this;
        },
 
        eq: function( i ) {
@@ -256,7 +288,7 @@ jQuery.fn = jQuery.prototype = {
 jQuery.fn.init.prototype = jQuery.fn;
 
 jQuery.extend = jQuery.fn.extend = function() {
-        var options, name, src, copy, copyIsArray, clone,
+       var options, name, src, copy, copyIsArray, clone,
                target = arguments[0] || {},
                i = 1,
                length = arguments.length,
@@ -360,7 +392,7 @@ 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 ) {
@@ -370,11 +402,11 @@ jQuery.extend({
        },
 
        bindReady: function() {
-               if ( readyBound ) {
+               if ( readyList ) {
                        return;
                }
 
-               readyBound = true;
+               readyList = jQuery._Deferred();
 
                // Catch cases where $(document).ready() is called after the
                // browser event has already occurred.
@@ -528,10 +560,8 @@ jQuery.extend({
                if ( data && rnotwhite.test(data) ) {
                        // Inspired by code by Andrea Giammarchi
                        // http://webreflection.blogspot.com/2007/08/global-scope-evaluation-and-dom.html
-                       var head = document.getElementsByTagName("head")[0] || document.documentElement,
-                               script = document.createElement("script");
-
-                       script.type = "text/javascript";
+                       var head = document.head || document.getElementsByTagName( "head" )[0] || document.documentElement,
+                               script = document.createElement( "script" );
 
                        if ( jQuery.support.scriptEval() ) {
                                script.appendChild( document.createTextNode( data ) );
@@ -756,178 +786,6 @@ jQuery.extend({
                return (new Date()).getTime();
        },
 
-       // Create a simple deferred (one callbacks list)
-       _Deferred: function() {
-
-               var // callbacks list
-                       callbacks = [],
-                       // stored [ context , args ]
-                       fired,
-                       // to avoid firing when already doing so
-                       firing,
-                       // flag to know if the deferred has been cancelled
-                       cancelled,
-                       // the deferred itself
-                       deferred  = {
-
-                               // 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++ ) {
-                                                       elem = args[ i ];
-                                                       type = jQuery.type( elem );
-                                                       if ( type === "array" ) {
-                                                               deferred.done.apply( deferred , elem );
-                                                       } else if ( type === "function" ) {
-                                                               callbacks.push( elem );
-                                                       }
-                                               }
-
-                                               if ( _fired ) {
-                                                       deferred.fire( _fired[ 0 ] , _fired[ 1 ] );
-                                               }
-                                       }
-
-                                       return this;
-                               },
-
-                               // resolve with given context and args
-                               fire: function( context , args ) {
-                                       if ( ! cancelled && ! fired && ! firing ) {
-
-                                               firing = 1;
-
-                                               try {
-                                                       while( callbacks[ 0 ] ) {
-                                                               callbacks.shift().apply( context , args );
-                                                       }
-                                               }
-                                               finally {
-                                                       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 );
-                                       return this;
-                               },
-
-                               // Has this deferred been resolved?
-                               isResolved: function() {
-                                       return !!( firing || fired );
-                               },
-
-                               // Cancel
-                               cancel: function() {
-                                       cancelled = 1;
-                                       callbacks = [];
-                                       return this;
-                               }
-                       };
-
-               return deferred;
-       },
-
-       // Full fledged deferred (two callbacks list)
-       // Typical success/error system
-       Deferred: function( func ) {
-
-               var deferred = jQuery._Deferred(),
-                       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,
-                       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
-                       // (i is used internally)
-                       promise: function( obj , i ) {
-                               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 , deferred.cancel );
-
-               // Unexpose cancel
-               delete deferred.cancel;
-
-               // Call given func if any
-               if ( func ) {
-                       func.call( deferred , deferred );
-               }
-
-               return deferred;
-       },
-
-       // Deferred helper
-       when: function( object ) {
-               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 ).done( function( value ) {
-                                       args = arguments;
-                                       resolveArray[ index ] = args.length > 1 ? slice.call( args , 0 ) : value;
-                                       if( ! --length ) {
-                                               deferred.fire( promise, resolveArray );
-                                       }
-                               }).fail( function() {
-                                       deferred.fireReject( promise, arguments );
-                               });
-                               return !deferred.isRejected();
-                       });
-               } else if ( deferred !== object ) {
-                       deferred.resolve( object );
-               }
-               return promise;
-       },
-
        // Use of jQuery.browser is frowned upon.
        // More details: http://docs.jquery.com/Utilities/jQuery.browser
        uaMatch: function( ua ) {
@@ -942,18 +800,20 @@ jQuery.extend({
                return { browser: match[1] || "", version: match[2] || "0" };
        },
 
-       subclass: function(){
+       sub: function() {
                function jQuerySubclass( selector, context ) {
                        return new jQuerySubclass.fn.init( selector, context );
                }
+               jQuery.extend( true, jQuerySubclass, this );
                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)){
+                       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;
@@ -964,9 +824,6 @@ jQuery.extend({
        browser: {}
 });
 
-// Create readyList deferred
-readyList = jQuery._Deferred();
-
 // Populate the class2type map
 jQuery.each("Boolean Number String Function Array Date RegExp Object".split(" "), function(i, name) {
        class2type[ "[object " + name + "]" ] = name.toLowerCase();
@@ -1035,6 +892,6 @@ function doScrollCheck() {
 }
 
 // Expose jQuery to the global object
-return (window.jQuery = window.$ = jQuery);
+return jQuery;
 
 })();