X-Git-Url: http://git.asbjorn.it/?a=blobdiff_plain;f=src%2Fcore.js;h=f35e33c3e899ded1dfeed5fae2d9cd752bca3cb2;hb=0f6c7830ce5bdd31588dccdc40b6254fb4a9100f;hp=3bbdce3c63e12b3015acfa5d9d690b6e6a23404b;hpb=6dbffb8596a9c96c68386ecc2d95da25b9dee369;p=jquery.git diff --git a/src/core.js b/src/core.js index 3bbdce3..f35e33c 100644 --- a/src/core.js +++ b/src/core.js @@ -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 @@ -15,16 +15,11 @@ var jQuery = function( selector, context ) { // A central reference to the root jQuery(document) rootjQuery, - // A simple way to check for HTML strings or ID strings - // (both of which we optimize for) - quickExpr = /^(?:[^<]*(<[\w\W]+>)[^>]*$|#([\w\-]+)$)/, - - // Is it a simple selector - isSimple = /^.[^:#\[\.,]*$/, + // A simple way to check for HTML strings + quickExpr = /^[^<]*(<[\w\W]+>)[^>]*$/, // Check if a string has a non-whitespace character in it rnotwhite = /\S/, - rwhite = /\s/, // Used for trimming whitespace trimLeft = /^\s+/, @@ -59,10 +54,13 @@ var jQuery = function( selector, context ) { // 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, @@ -75,13 +73,11 @@ var jQuery = function( selector, context ) { indexOf = Array.prototype.indexOf, // [[Class]] -> type pairs - class2type = {}, - - // Marker for deferred - promiseMarker = []; + 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) @@ -96,75 +92,31 @@ 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 or an ID? - match = quickExpr.exec( selector ); - - // Verify a match, and that no context was specified for #id - if ( match && (match[1] || !context) ) { + // Are we dealing with HTML string + if ( (match = quickExpr.exec( selector )) ) { + context = context instanceof jQuery ? context[0] : context; + doc = (context ? context.ownerDocument || context : document); - // HANDLE: $(html) -> $(array) - if ( match[1] ) { - doc = (context ? context.ownerDocument || context : document); + // 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 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] ) ]; - } + if ( ret ) { + if ( jQuery.isPlainObject( context ) ) { + selector = [ document.createElement( ret[1] ) ]; + jQuery.fn.attr.call( selector, context, true ); } else { - ret = jQuery.buildFragment( [ match[1] ], [ doc ] ); - selector = (ret.cacheable ? ret.fragment.cloneNode(true) : ret.fragment).childNodes; + selector = [ doc.createElement( ret[1] ) ]; } - return jQuery.merge( this, selector ); - - // HANDLE: $("#id") } else { - 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; - } - - this.context = document; - this.selector = selector; - return this; + ret = jQuery.buildFragment( [ match[1] ], [ doc ] ); + selector = (ret.cacheable ? jQuery(ret.fragment).clone()[0] : ret.fragment).childNodes; } - // 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, $(...)) @@ -174,7 +126,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) @@ -225,7 +177,7 @@ 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 ); @@ -255,13 +207,13 @@ jQuery.fn = jQuery.prototype = { each: function( callback, args ) { return jQuery.each( this, callback, args ); }, - + ready: function() { // Attach the listeners jQuery.bindReady(); - + // Change ready & apply - return ( jQuery.fn.ready = readyList.then ).apply( this , arguments ); + return ( jQuery.fn.ready = readyList.done ).apply( this , arguments ); }, eq: function( i ) { @@ -290,7 +242,7 @@ jQuery.fn = jQuery.prototype = { }, end: function() { - return this.prevObject || jQuery(null); + return this.prevObject || this.constructor(null); }, // For internal use only. @@ -409,7 +361,7 @@ jQuery.extend({ // If there are functions bound, to execute readyList.fire( document , [ jQuery ] ); - + // Trigger any bound ready events if ( jQuery.fn.trigger ) { jQuery( document ).trigger( "ready" ).unbind( "ready" ); @@ -546,7 +498,7 @@ jQuery.extend({ jQuery.error( "Invalid JSON: " + data ); } }, - + // Cross-browser xml parsing // (xml & tmp used internally) parseXML: function( data , xml , tmp ) { @@ -559,13 +511,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; }, @@ -581,7 +533,7 @@ jQuery.extend({ script.type = "text/javascript"; - if ( jQuery.support.scriptEval ) { + if ( jQuery.support.scriptEval() ) { script.appendChild( document.createTextNode( data ) ); } else { script.text = data; @@ -803,10 +755,10 @@ jQuery.extend({ now: function() { return (new Date()).getTime(); }, - + // Create a simple deferred (one callbacks list) _Deferred: function() { - + var // callbacks list callbacks = [], // stored [ context , args ] @@ -817,48 +769,48 @@ jQuery.extend({ cancelled, // the deferred itself deferred = { - - // then( f1, f2, ...) - then: function () { - + + // 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.then.apply( deferred , elem ); + 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 ); @@ -871,85 +823,109 @@ jQuery.extend({ } return this; }, - + // resolve with this as context and given arguments resolve: function() { - deferred.fire( this , arguments ); + 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; - }, - - // Has this deferred been cancelled? - isCancelled: function() { - return !!cancelled; } }; - + return deferred; }, - + // Full fledged deferred (two callbacks list) // Typical success/error system Deferred: function( func ) { - - var errorDeferred = jQuery._Deferred(), - deferred = jQuery._Deferred(), - successCancel = deferred.cancel; - - // Add errorDeferred methods and redefine cancel + + var deferred = jQuery._Deferred(), + failDeferred = jQuery._Deferred(), + promise; + + // Add errorDeferred methods, then and promise jQuery.extend( deferred , { - fail: errorDeferred.then, - fireReject: errorDeferred.fire, - reject: errorDeferred.resolve, - isRejected: errorDeferred.isResolved, - // Get a promise for this deferred - // If obj is provided, the promise aspect is added to the object - promise: function( obj ) { - obj = obj || {}; - for ( var i in { then:1 , fail:1 , isResolved:1 , isRejected:1 , promise:1 } ) { - obj[ i ] = deferred[ i ]; + 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; } - return obj; + promise = obj = {}; + } + i = promiseMethods.length; + while( i-- ) { + obj[ promiseMethods[ i ] ] = deferred[ promiseMethods[ i ] ]; } + return obj; + } } ); - - // Remove cancel related - delete deferred.cancel; - delete deferred.isCancelled; - - // Add promise marker - deferred.promise._ = promiseMarker; - + // Make sure only one callback list will be used - deferred.then( errorDeferred.cancel ).fail( successCancel ); - + 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 ) { - object = object && object.promise && object.promise._ === promiseMarker ? - 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 ).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. @@ -966,6 +942,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: {} }); @@ -994,9 +989,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]+$/; } @@ -1040,11 +1034,6 @@ function doScrollCheck() { jQuery.ready(); } -// Expose jQuery as an Asynchronous Module -if ( typeof define === "function" ) { - define( "jquery", [], function () { return jQuery; } ); -} - // Expose jQuery to the global object return (window.jQuery = window.$ = jQuery);