X-Git-Url: http://git.asbjorn.biz/?p=jquery.git;a=blobdiff_plain;f=src%2Fcore.js;h=d41b9a9b6c4966265e24a775c370e3a3956ddf17;hp=e463ade017ed2b56f5ca993afd2e59025a2e61ea;hb=5bacb53866dbc3fbb36202a25c756a4ea2fd5965;hpb=c1625f6b79b2693ea85f2c16349f708ff203773b diff --git a/src/core.js b/src/core.js index e463ade..d41b9a9 100644 --- a/src/core.js +++ b/src/core.js @@ -59,9 +59,9 @@ var jQuery = function( selector, context ) { // Has the ready events already been bound? readyBound = false, - - // The functions to execute on DOM ready - readyList = [], + + // The deferred used on DOM ready + readyList, // The ready event handler DOMContentLoaded, @@ -75,7 +75,10 @@ var jQuery = function( selector, context ) { indexOf = Array.prototype.indexOf, // [[Class]] -> type pairs - class2type = {}; + class2type = {}, + + // Marker for deferred + deferredMarker = []; jQuery.fn = jQuery.prototype = { init: function( selector, context ) { @@ -252,23 +255,13 @@ jQuery.fn = jQuery.prototype = { each: function( callback, args ) { return jQuery.each( this, callback, args ); }, - - ready: function( fn ) { + + ready: function() { // Attach the listeners jQuery.bindReady(); - - // If the DOM is already ready - if ( jQuery.isReady ) { - // Execute the function immediately - fn.call( document, jQuery ); - - // Otherwise, remember the function for later - } else if ( readyList ) { - // Add the function to the wait list - readyList.push( fn ); - } - - return this; + + // Change ready & apply + return ( jQuery.fn.ready = readyList.then ).apply( this , arguments ); }, eq: function( i ) { @@ -415,23 +408,11 @@ jQuery.extend({ } // If there are functions bound, to execute - if ( readyList ) { - // Execute all of them - var fn, - i = 0, - ready = readyList; - - // Reset the list of functions - readyList = null; - - while ( (fn = ready[ i++ ]) ) { - fn.call( document, jQuery ); - } - - // Trigger any bound ready events - if ( jQuery.fn.trigger ) { - jQuery( document ).trigger( "ready" ).unbind( "ready" ); - } + readyList.fire( document , [ jQuery ] ); + + // Trigger any bound ready events + if ( jQuery.fn.trigger ) { + jQuery( document ).trigger( "ready" ).unbind( "ready" ); } } }, @@ -800,6 +781,160 @@ jQuery.extend({ now: function() { return (new Date()).getTime(); }, + + // Create a simple deferred (one callbacks list) + _deferred: function( cancellable ) { + + // cancellable by default + cancellable = cancellable !== false; + + 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 = { + + // then( f1, f2, ...) + then: function() { + + if ( ! cancelled ) { + + var args = arguments, + i, + type, + _fired; + + if ( fired ) { + _fired = fired; + fired = 0; + } + + for ( i in args ) { + i = args[ i ]; + type = jQuery.type( i ); + if ( type === "array" ) { + this.then.apply( this , i ); + } else if ( type === "function" ) { + callbacks.push( i ); + } + } + + if ( _fired ) { + deferred.fire( _fired[ 0 ] , _fired[ 1 ] ); + } + } + return this; + }, + + // resolve with given context and args + // (i is used internally) + fire: function( context , args , i ) { + if ( ! cancelled && ! fired && ! firing ) { + firing = 1; + try { + for( i = 0 ; ! cancelled && callbacks[ i ] ; i++ ) { + cancelled = ( callbacks[ i ].apply( context , args ) === false ) && cancellable; + } + } catch( e ) { + cancelled = cancellable; + jQuery.error( e ); + } finally { + fired = [ context , args ]; + callbacks = cancelled ? [] : callbacks.slice( i + 1 ); + firing = 0; + } + } + return this; + }, + + // resolve with this as context and given arguments + resolve: function() { + deferred.fire( this , arguments ); + return this; + }, + + // cancelling further callbacks + cancel: function() { + if ( cancellable ) { + callbacks = []; + cancelled = 1; + } + return this; + } + + }; + + // Add the deferred marker + deferred.then._ = deferredMarker; + + return deferred; + }, + + // Full fledged deferred (two callbacks list) + // Typical success/error system + deferred: function( func , cancellable ) { + + // Handle varargs + if ( arguments.length === 1 ) { + + if ( typeof func === "boolean" ) { + cancellable = func; + func = 0; + } + } + + var errorDeferred = jQuery._deferred( cancellable ), + deferred = jQuery._deferred( cancellable ), + // Keep reference of the cancel method since we'll redefine it + cancelThen = deferred.cancel; + + // Add errorDeferred methods and redefine cancel + jQuery.extend( deferred , { + + fail: errorDeferred.then, + fireReject: errorDeferred.fire, + reject: errorDeferred.resolve, + cancel: function() { + cancelThen(); + errorDeferred.cancel(); + return this; + } + + } ); + + // Make sure only one callback list will be used + deferred.then( errorDeferred.cancel ).fail( cancelThen ); + + // Call given func if any + if ( func ) { + func.call( deferred , deferred ); + } + + return deferred; + }, + + // Check if an object is a deferred + isDeferred: function( object , method ) { + method = method || "then"; + return !!( object && object[ method ] && object[ method ]._ === deferredMarker ); + }, + + // Deferred helper + when: function( object , method ) { + method = method || "then"; + object = jQuery.isDeferred( object , method ) ? + object : + jQuery.deferred().resolve( object ); + object.fail = object.fail || function() { return this; }; + object[ method ] = object[ method ] || object.then; + object.then = object.then || object[ method ]; + return object; + }, // Use of jQuery.browser is frowned upon. // More details: http://docs.jquery.com/Utilities/jQuery.browser @@ -818,6 +953,11 @@ jQuery.extend({ browser: {} }); +// Create readyList deferred +// also force $.fn.ready to be recognized as a defer +readyList = jQuery._deferred( false ); +jQuery.fn.ready._ = deferredMarker; + // Populate the class2type map jQuery.each("Boolean Number String Function Array Date RegExp Object".split(" "), function(i, name) { class2type[ "[object " + name + "]" ] = name.toLowerCase();