diff --git a/src/core.js b/src/core.js
index b81fa764..3331969a 100644
--- a/src/core.js
+++ b/src/core.js
@@ -565,24 +565,17 @@ jQuery.extend({
noop: function() {},
- // Evalulates a script in a global context
+ // Evaluates a script in a global context
+ // Workarounds based on findings by Jim Driscoll
+ // http://weblogs.java.net/blog/driscoll/archive/2009/09/08/eval-javascript-global-context
globalEval: function( data ) {
- 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.head || document.getElementsByTagName( "head" )[0] || document.documentElement,
- script = document.createElement( "script" );
-
- if ( jQuery.support.scriptEval() ) {
- script.appendChild( document.createTextNode( data ) );
- } else {
- script.text = data;
- }
-
- // Use insertBefore instead of appendChild to circumvent an IE6 bug.
- // This arises when a base node is used (#2709).
- head.insertBefore( script, head.firstChild );
- head.removeChild( script );
+ if ( data && rnotwhite.test( data ) ) {
+ // We use execScript on Internet Explorer
+ // We use an anonymous function so that context is window
+ // rather than jQuery in Firefox
+ ( window.execScript || function( data ) {
+ window[ "eval" ].call( window, data );
+ } )( data );
}
},
diff --git a/src/deferred.js b/src/deferred.js
index 90f9c808..feaccaef 100644
--- a/src/deferred.js
+++ b/src/deferred.js
@@ -1,7 +1,7 @@
(function( jQuery ) {
var // Promise methods
- promiseMethods = "then done fail isResolved isRejected promise".split( " " ),
+ promiseMethods = "done fail isResolved isRejected promise then always chain".split( " " ),
// Static reference to slice
sliceDeferred = [].slice;
@@ -100,10 +100,38 @@ jQuery.extend({
deferred.done( doneCallbacks ).fail( failCallbacks );
return this;
},
+ always: function() {
+ return deferred.done.apply( deferred, arguments ).fail.apply( this, arguments );
+ },
fail: failDeferred.done,
rejectWith: failDeferred.resolveWith,
reject: failDeferred.resolve,
isRejected: failDeferred.isResolved,
+ // Chain
+ chain: function( fnDone, fnFail ) {
+ return jQuery.Deferred(function( newDefer ) {
+ jQuery.each( {
+ done: [ fnDone, "resolve" ],
+ fail: [ fnFail, "reject" ]
+ }, function( handler, data ) {
+ var fn = data[ 0 ],
+ action = data[ 1 ],
+ returned;
+ if ( jQuery.isFunction( fn ) ) {
+ deferred[ handler ](function() {
+ returned = fn.apply( this, arguments );
+ if ( jQuery.isFunction( returned.promise ) ) {
+ returned.promise().then( newDefer.resolve, newDefer.reject );
+ } else {
+ newDefer[ action ]( returned );
+ }
+ });
+ } else {
+ deferred[ handler ]( newDefer[ action ] );
+ }
+ } );
+ }).promise();
+ },
// Get a promise for this deferred
// If obj is provided, the promise aspect is added to the object
promise: function( obj ) {
@@ -169,4 +197,4 @@ jQuery.extend({
}
});
-})( jQuery );
+})( jQuery );
\ No newline at end of file
diff --git a/src/effects.js b/src/effects.js
index d9e9a8b3..5ff85d13 100644
--- a/src/effects.js
+++ b/src/effects.js
@@ -11,7 +11,17 @@ var elemdisplay = {},
[ "width", "marginLeft", "marginRight", "paddingLeft", "paddingRight" ],
// opacity animations
[ "opacity" ]
- ];
+ ],
+ fxNow;
+
+function clearFxNow() {
+ fxNow = undefined;
+}
+
+function createFxNow() {
+ setTimeout( clearFxNow, 0 );
+ return ( fxNow = jQuery.now() );
+}
jQuery.fn.extend({
show: function( speed, easing, callback ) {
@@ -349,7 +359,7 @@ jQuery.fx.prototype = {
var self = this,
fx = jQuery.fx;
- this.startTime = jQuery.now();
+ this.startTime = fxNow || createFxNow();
this.start = from;
this.end = to;
this.unit = unit || this.unit || ( jQuery.cssNumber[ this.prop ] ? "" : "px" );
@@ -394,7 +404,8 @@ jQuery.fx.prototype = {
// Each step of an animation
step: function( gotoEnd ) {
- var t = jQuery.now(), done = true;
+ var t = fxNow || createFxNow(),
+ done = true;
if ( gotoEnd || t >= this.options.duration + this.startTime ) {
this.now = this.end;
diff --git a/src/queue.js b/src/queue.js
index 9e3e2fb5..701d06ad 100644
--- a/src/queue.js
+++ b/src/queue.js
@@ -28,7 +28,8 @@ jQuery.extend({
type = type || "fx";
var queue = jQuery.queue( elem, type ),
- fn = queue.shift();
+ fn = queue.shift(),
+ defer;
// If the fx queue is dequeued, always remove the progress sentinel
if ( fn === "inprogress" ) {
@@ -49,6 +50,17 @@ jQuery.extend({
if ( !queue.length ) {
jQuery.removeData( elem, type + "queue", true );
+ // Look if we have observers and resolve if needed
+ if (( defer = jQuery.data( elem, type + "defer", undefined, true ) )) {
+ // Give room for hard-coded callbacks to fire first
+ // and eventually add another animation on the element
+ setTimeout( function() {
+ if ( !jQuery.data( elem, type + "queue", undefined, true ) ) {
+ jQuery.removeData( elem, type + "defer", true );
+ defer.resolve();
+ }
+ }, 0 );
+ }
}
}
});
@@ -93,6 +105,37 @@ jQuery.fn.extend({
clearQueue: function( type ) {
return this.queue( type || "fx", [] );
+ },
+
+ // Get a promise resolved when queues of a certain type
+ // are emptied (fx is the type by default)
+ promise: function( type, object ) {
+ if ( typeof type !== "string" ) {
+ object = type;
+ type = undefined;
+ }
+ type = type || "fx";
+ var defer = jQuery.Deferred(),
+ elements = this,
+ i = elements.length,
+ count = 1,
+ deferDataKey = type + "defer",
+ queueDataKey = type + "queue";
+ function resolve() {
+ if ( !( --count ) ) {
+ defer.resolveWith( elements, [ elements ] );
+ }
+ }
+ while( i-- ) {
+ if (( tmp = jQuery.data( elements[ i ], deferDataKey, undefined, true ) ||
+ jQuery.data( elements[ i ], queueDataKey, undefined, true ) &&
+ jQuery.data( elements[ i ], deferDataKey, jQuery._Deferred(), true ) )) {
+ count++;
+ tmp.done( resolve );
+ }
+ }
+ resolve();
+ return defer.promise();
}
});
diff --git a/src/support.js b/src/support.js
index 8b950e25..d5625bed 100644
--- a/src/support.js
+++ b/src/support.js
@@ -1,44 +1,58 @@
(function( jQuery ) {
-(function() {
+jQuery.support = (function() {
- jQuery.support = {};
+ var div = document.createElement( "div" ),
+ all,
+ a,
+ select,
+ opt,
+ input,
+ support,
+ fragment,
+ body,
+ bodyStyle,
+ tds,
+ events,
+ eventName,
+ i,
+ isSupported;
- var div = document.createElement("div");
-
- div.style.display = "none";
+ // Preliminary tests
div.innerHTML = "
a";
- var all = div.getElementsByTagName("*"),
- a = div.getElementsByTagName("a")[0],
- select = document.createElement("select"),
- opt = select.appendChild( document.createElement("option") ),
- input = div.getElementsByTagName("input")[0];
+ all = div.getElementsByTagName( "*" );
+ a = div.getElementsByTagName( "a" )[ 0 ];
// Can't get basic test support
if ( !all || !all.length || !a ) {
- return;
+ return {};
}
- jQuery.support = {
+ // First batch of supports tests
+ select = document.createElement( "select" );
+ opt = select.appendChild( document.createElement("option") );
+ input = div.getElementsByTagName( "input" )[ 0 ];
+
+ support = {
// IE strips leading whitespace when .innerHTML is used
- leadingWhitespace: div.firstChild.nodeType === 3,
+ leadingWhitespace: ( div.firstChild.nodeType === 3 ),
// Make sure that tbody elements aren't automatically inserted
// IE will insert them into empty tables
- tbody: !div.getElementsByTagName("tbody").length,
+ tbody: !div.getElementsByTagName( "tbody" ).length,
// Make sure that link elements get serialized correctly by innerHTML
// This requires a wrapper element in IE
- htmlSerialize: !!div.getElementsByTagName("link").length,
+ htmlSerialize: !!div.getElementsByTagName( "link" ).length,
// Get the style information from getAttribute
- // (IE uses .cssText insted)
+ // (IE uses .cssText instead)
style: /red/.test( a.getAttribute("style") ),
// Make sure that URLs aren't manipulated
// (IE normalizes it by default)
- hrefNormalized: a.getAttribute("href") === "/a",
+ hrefNormalized: ( a.getAttribute( "href" ) === "/a" ),
// Make sure that element opacity exists
// (IE uses filter instead)
@@ -59,176 +73,152 @@
optSelected: opt.selected,
// Will be defined later
+ submitBubbles: true,
+ changeBubbles: true,
deleteExpando: true,
- optDisabled: false,
- checkClone: false,
noCloneEvent: true,
- noCloneChecked: true,
- boxModel: null,
inlineBlockNeedsLayout: false,
shrinkWrapBlocks: false,
- reliableHiddenOffsets: true,
reliableMarginRight: true
};
+ // Make sure checked status is properly cloned
input.checked = true;
- jQuery.support.noCloneChecked = input.cloneNode( true ).checked;
+ support.noCloneChecked = input.cloneNode( true ).checked;
// Make sure that the options inside disabled selects aren't marked as disabled
- // (WebKit marks them as diabled)
+ // (WebKit marks them as disabled)
select.disabled = true;
- jQuery.support.optDisabled = !opt.disabled;
-
- var _scriptEval = null;
- jQuery.support.scriptEval = function() {
- if ( _scriptEval === null ) {
- var root = document.documentElement,
- script = document.createElement("script"),
- id = "script" + jQuery.now();
-
- // Make sure that the execution of code works by injecting a script
- // tag with appendChild/createTextNode
- // (IE doesn't support this, fails, and uses .text instead)
- try {
- script.appendChild( document.createTextNode( "window." + id + "=1;" ) );
- } catch(e) {}
-
- root.insertBefore( script, root.firstChild );
-
- if ( window[ id ] ) {
- _scriptEval = true;
- delete window[ id ];
- } else {
- _scriptEval = false;
- }
-
- root.removeChild( script );
- }
-
- return _scriptEval;
- };
+ support.optDisabled = !opt.disabled;
// Test to see if it's possible to delete an expando from an element
// Fails in Internet Explorer
try {
delete div.test;
-
- } catch(e) {
- jQuery.support.deleteExpando = false;
+ } catch( e ) {
+ support.deleteExpando = false;
}
if ( !div.addEventListener && div.attachEvent && div.fireEvent ) {
- div.attachEvent("onclick", function click() {
+ div.attachEvent( "onclick", function click() {
// Cloning a node shouldn't copy over any
// bound event handlers (IE does this)
- jQuery.support.noCloneEvent = false;
- div.detachEvent("onclick", click);
- });
- div.cloneNode(true).fireEvent("onclick");
+ support.noCloneEvent = false;
+ div.detachEvent( "onclick", click );
+ } );
+ div.cloneNode( true ).fireEvent( "onclick" );
}
- div = document.createElement("div");
div.innerHTML = "";
- var fragment = document.createDocumentFragment();
+ fragment = document.createDocumentFragment();
fragment.appendChild( div.firstChild );
// WebKit doesn't clone checked state correctly in fragments
- jQuery.support.checkClone = fragment.cloneNode(true).cloneNode(true).lastChild.checked;
+ support.checkClone = fragment.cloneNode( true ).cloneNode( true ).lastChild.checked;
+
+ div.innerHTML = "";
// Figure out if the W3C box model works as expected
- // document.body must exist before we can do this
- jQuery(function() {
- var div = document.createElement("div"),
- body = document.getElementsByTagName("body")[0];
+ div.style.width = div.style.paddingLeft = "1px";
- // Frameset documents with no body should not run this code
- if ( !body ) {
- return;
- }
+ // We use our own, invisible, body
+ body = document.createElement( "body" );
+ bodyStyle = {
+ visibility: "hidden",
+ width: 0,
+ height: 0,
+ border: 0,
+ margin: 0
+ };
+ for ( i in bodyStyle ) {
+ body.style[ i ] = bodyStyle[ i ];
+ }
+ body.appendChild( div );
+ document.documentElement.appendChild( body );
- div.style.width = div.style.paddingLeft = "1px";
- body.appendChild( div );
- jQuery.boxModel = jQuery.support.boxModel = div.offsetWidth === 2;
+ support.boxModel = div.offsetWidth === 2;
- if ( "zoom" in div.style ) {
- // Check if natively block-level elements act like inline-block
- // elements when setting their display to 'inline' and giving
- // them layout
- // (IE < 8 does this)
- div.style.display = "inline";
- div.style.zoom = 1;
- jQuery.support.inlineBlockNeedsLayout = div.offsetWidth === 2;
+ if ( "zoom" in div.style ) {
+ // Check if natively block-level elements act like inline-block
+ // elements when setting their display to 'inline' and giving
+ // them layout
+ // (IE < 8 does this)
+ div.style.display = "inline";
+ div.style.zoom = 1;
+ support.inlineBlockNeedsLayout = ( div.offsetWidth === 2 );
- // Check if elements with layout shrink-wrap their children
- // (IE 6 does this)
- div.style.display = "";
- div.innerHTML = "";
- jQuery.support.shrinkWrapBlocks = div.offsetWidth !== 2;
- }
+ // Check if elements with layout shrink-wrap their children
+ // (IE 6 does this)
+ div.style.display = "";
+ div.innerHTML = "";
+ support.shrinkWrapBlocks = ( div.offsetWidth !== 2 );
+ }
- div.innerHTML = "";
- var tds = div.getElementsByTagName("td");
+ div.innerHTML = "";
+ tds = div.getElementsByTagName( "td" );
- // Check if table cells still have offsetWidth/Height when they are set
- // to display:none and there are still other visible table cells in a
- // table row; if so, offsetWidth/Height are not reliable for use when
- // determining if an element has been hidden directly using
- // display:none (it is still safe to use offsets if a parent element is
- // hidden; don safety goggles and see bug #4512 for more information).
- // (only IE 8 fails this test)
- jQuery.support.reliableHiddenOffsets = tds[0].offsetHeight === 0;
+ // Check if table cells still have offsetWidth/Height when they are set
+ // to display:none and there are still other visible table cells in a
+ // table row; if so, offsetWidth/Height are not reliable for use when
+ // determining if an element has been hidden directly using
+ // display:none (it is still safe to use offsets if a parent element is
+ // hidden; don safety goggles and see bug #4512 for more information).
+ // (only IE 8 fails this test)
+ isSupported = ( tds[ 0 ].offsetHeight === 0 );
- tds[0].style.display = "";
- tds[1].style.display = "none";
+ tds[ 0 ].style.display = "";
+ tds[ 1 ].style.display = "none";
- // Check if empty table cells still have offsetWidth/Height
- // (IE < 8 fail this test)
- jQuery.support.reliableHiddenOffsets = jQuery.support.reliableHiddenOffsets && tds[0].offsetHeight === 0;
- div.innerHTML = "";
+ // Check if empty table cells still have offsetWidth/Height
+ // (IE < 8 fail this test)
+ support.reliableHiddenOffsets = isSupported && ( tds[ 0 ].offsetHeight === 0 );
+ div.innerHTML = "";
- // Check if div with explicit width and no margin-right incorrectly
- // gets computed margin-right based on width of container. For more
- // info see bug #3333
- // Fails in WebKit before Feb 2011 nightlies
- // WebKit Bug 13343 - getComputedStyle returns wrong value for margin-right
- if ( document.defaultView && document.defaultView.getComputedStyle ) {
- div.style.width = "1px";
- div.style.marginRight = "0";
- jQuery.support.reliableMarginRight = ( parseInt(document.defaultView.getComputedStyle(div, null).marginRight, 10) || 0 ) === 0;
- }
+ // Check if div with explicit width and no margin-right incorrectly
+ // gets computed margin-right based on width of container. For more
+ // info see bug #3333
+ // Fails in WebKit before Feb 2011 nightlies
+ // WebKit Bug 13343 - getComputedStyle returns wrong value for margin-right
+ if ( document.defaultView && document.defaultView.getComputedStyle ) {
+ div.style.width = "1px";
+ div.style.marginRight = "0";
+ support.reliableMarginRight =
+ ( parseInt( document.defaultView.getComputedStyle(div).marginRight, 10 ) || 0 ) === 0;
+ }
- body.removeChild( div ).style.display = "none";
- div = tds = null;
- });
+ // Remove the body element we added
+ document.documentElement.removeChild( body );
// Technique from Juriy Zaytsev
// http://thinkweb2.com/projects/prototype/detecting-event-support-without-browser-sniffing/
- var eventSupported = function( eventName ) {
- var el = document.createElement("div");
- eventName = "on" + eventName;
-
- // We only care about the case where non-standard event systems
- // are used, namely in IE. Short-circuiting here helps us to
- // avoid an eval call (in setAttribute) which can cause CSP
- // to go haywire. See: https://developer.mozilla.org/en/Security/CSP
- if ( !el.attachEvent ) {
- return true;
+ // We only care about the case where non-standard event systems
+ // are used, namely in IE. Short-circuiting here helps us to
+ // avoid an eval call (in setAttribute) which can cause CSP
+ // to go haywire. See: https://developer.mozilla.org/en/Security/CSP
+ if ( div.attachEvent ) {
+ for( i in {
+ submit: 1,
+ change: 1,
+ focusin: 1
+ } ) {
+ eventName = "on" + i;
+ isSupported = ( eventName in div );
+ if ( !isSupported ) {
+ div.setAttribute( eventName, "return;" );
+ isSupported = ( typeof div[ eventName ] === "function" );
+ }
+ support[ i + "Bubbles" ] = isSupported;
}
-
- var isSupported = (eventName in el);
- if ( !isSupported ) {
- el.setAttribute(eventName, "return;");
- isSupported = typeof el[eventName] === "function";
- }
- return isSupported;
- };
-
- jQuery.support.submitBubbles = eventSupported("submit");
- jQuery.support.changeBubbles = eventSupported("change");
- jQuery.support.focusinBubbles = document.attachEvent && eventSupported("focusin");
+ }
// release memory in IE
- div = all = a = null;
+ body = div = all = a = tds = undefined;
+
+ return support;
})();
+
+// Keep track of boxModel
+jQuery.boxModel = jQuery.support.boxModel;
+
})( jQuery );
diff --git a/test/unit/core.js b/test/unit/core.js
index 03325ab7..79710025 100644
--- a/test/unit/core.js
+++ b/test/unit/core.js
@@ -172,6 +172,26 @@ test("selector state", function() {
);
});
+test( "globalEval", function() {
+
+ expect( 3 );
+
+ jQuery.globalEval( "var globalEvalTest = true;" );
+ ok( window.globalEvalTest, "Test variable declarations are global" );
+
+ window.globalEvalTest = false;
+
+ jQuery.globalEval( "globalEvalTest = true;" );
+ ok( window.globalEvalTest, "Test variable assignments are global" );
+
+ window.globalEvalTest = false;
+
+ jQuery.globalEval( "this.globalEvalTest = true;" );
+ ok( window.globalEvalTest, "Test context (this) is the window object" );
+
+ window.globalEvalTest = undefined;
+});
+
if ( !isLocal ) {
test("browser", function() {
stop();
diff --git a/test/unit/deferred.js b/test/unit/deferred.js
index 6ba4767a..c1ed7c57 100644
--- a/test/unit/deferred.js
+++ b/test/unit/deferred.js
@@ -1,153 +1,273 @@
module("deferred", { teardown: moduleTeardown });
-test("jQuery._Deferred()", function() {
+jQuery.each( [ "", " - new operator" ], function( _, withNew ) {
- expect( 11 );
-
- var deferred,
- object,
- test;
-
- deferred = jQuery._Deferred();
-
- test = false;
-
- deferred.done( function( value ) {
- equals( value , "value" , "Test pre-resolve callback" );
- test = true;
- } );
-
- deferred.resolve( "value" );
-
- ok( test , "Test pre-resolve callbacks called right away" );
-
- test = false;
-
- deferred.done( function( value ) {
- equals( value , "value" , "Test post-resolve callback" );
- test = true;
- } );
-
- ok( test , "Test post-resolve callbacks called right away" );
-
- deferred.cancel();
-
- test = true;
-
- deferred.done( function() {
- ok( false , "Cancel was ignored" );
- test = false;
- } );
-
- ok( test , "Test cancel" );
-
- deferred = jQuery._Deferred().resolve();
-
- try {
- deferred.done( function() {
- throw "Error";
- } , function() {
- ok( true , "Test deferred do not cancel on exception" );
- } );
- } catch( e ) {
- strictEqual( e , "Error" , "Test deferred propagates exceptions");
- deferred.done();
+ function createDeferred() {
+ return withNew ? new jQuery._Deferred() : jQuery._Deferred();
}
- test = "";
- deferred = jQuery._Deferred().done( function() {
+ test("jQuery._Deferred" + withNew, function() {
- test += "A";
+ expect( 11 );
- }, function() {
+ var deferred,
+ object,
+ test;
- test += "B";
+ deferred = createDeferred();
- } ).resolve();
+ test = false;
- strictEqual( test , "AB" , "Test multiple done parameters" );
+ deferred.done( function( value ) {
+ equals( value , "value" , "Test pre-resolve callback" );
+ test = true;
+ } );
- test = "";
+ deferred.resolve( "value" );
- deferred.done( function() {
+ ok( test , "Test pre-resolve callbacks called right away" );
+
+ test = false;
+
+ deferred.done( function( value ) {
+ equals( value , "value" , "Test post-resolve callback" );
+ test = true;
+ } );
+
+ ok( test , "Test post-resolve callbacks called right away" );
+
+ deferred.cancel();
+
+ test = true;
+
+ deferred.done( function() {
+ ok( false , "Cancel was ignored" );
+ test = false;
+ } );
+
+ ok( test , "Test cancel" );
+
+ deferred = createDeferred().resolve();
+
+ try {
+ deferred.done( function() {
+ throw "Error";
+ } , function() {
+ ok( true , "Test deferred do not cancel on exception" );
+ } );
+ } catch( e ) {
+ strictEqual( e , "Error" , "Test deferred propagates exceptions");
+ deferred.done();
+ }
+
+ test = "";
+ deferred = createDeferred().done( function() {
+
+ test += "A";
+
+ }, function() {
+
+ test += "B";
+
+ } ).resolve();
+
+ strictEqual( test , "AB" , "Test multiple done parameters" );
+
+ test = "";
deferred.done( function() {
- test += "C";
+ deferred.done( function() {
+ test += "C";
+
+ } );
+
+ test += "A";
+
+ }, function() {
+
+ test += "B";
} );
- test += "A";
+ strictEqual( test , "ABC" , "Test done callbacks order" );
- }, function() {
+ deferred = createDeferred();
- test += "B";
+ deferred.resolveWith( jQuery , [ document ] ).done( function( doc ) {
+ ok( this === jQuery && arguments.length === 1 && doc === document , "Test fire context & args" );
+ });
+
+ // #8421
+ deferred = createDeferred();
+ deferred.resolveWith().done(function() {
+ ok( true, "Test resolveWith can be called with no argument" );
+ });
+ });
+} );
+
+jQuery.each( [ "", " - new operator" ], function( _, withNew ) {
+
+ function createDeferred( fn ) {
+ return withNew ? new jQuery.Deferred( fn ) : jQuery.Deferred( fn );
+ }
+
+ test("jQuery.Deferred" + withNew, function() {
+
+ expect( 8 );
+
+ createDeferred().resolve().then( function() {
+ ok( true , "Success on resolve" );
+ ok( this.isResolved(), "Deferred is resolved" );
+ }, function() {
+ ok( false , "Error on resolve" );
+ }).always( function() {
+ ok( true , "Always callback on resolve" );
+ });
+
+ createDeferred().reject().then( function() {
+ ok( false , "Success on reject" );
+ }, function() {
+ ok( true , "Error on reject" );
+ ok( this.isRejected(), "Deferred is rejected" );
+ }).always( function() {
+ ok( true , "Always callback on reject" );
+ });
+
+ createDeferred( function( defer ) {
+ ok( this === defer , "Defer passed as this & first argument" );
+ this.resolve( "done" );
+ }).then( function( value ) {
+ strictEqual( value , "done" , "Passed function executed" );
+ });
+ });
+} );
+
+test( "jQuery.Deferred.chain - filtering (done)", function() {
+
+ expect(3);
+
+ var defer = jQuery.Deferred(),
+ chained = defer.chain(function( a, b ) {
+ return a * b;
+ }),
+ value1,
+ value2,
+ value3;
+
+ chained.done(function( result ) {
+ value3 = result;
+ });
+
+ defer.done(function( a, b ) {
+ value1 = a;
+ value2 = b;
+ });
+
+ defer.resolve( 2, 3 );
+
+ strictEqual( value1, 2, "first resolve value ok" );
+ strictEqual( value2, 3, "second resolve value ok" );
+ strictEqual( value3, 6, "result of filter ok" );
+
+ jQuery.Deferred().reject().chain(function() {
+ ok( false, "chain should not be called on reject" );
+ });
+});
+
+test( "jQuery.Deferred.chain - filtering (fail)", function() {
+
+ expect(3);
+
+ var defer = jQuery.Deferred(),
+ chained = defer.chain( null, function( a, b ) {
+ return a * b;
+ } ),
+ value1,
+ value2,
+ value3;
+
+ chained.fail(function( result ) {
+ value3 = result;
+ });
+
+ defer.fail(function( a, b ) {
+ value1 = a;
+ value2 = b;
+ });
+
+ defer.reject( 2, 3 );
+
+ strictEqual( value1, 2, "first reject value ok" );
+ strictEqual( value2, 3, "second reject value ok" );
+ strictEqual( value3, 6, "result of filter ok" );
+
+ jQuery.Deferred().resolve().chain( null, function() {
+ ok( false, "chain should not be called on resolve" );
} );
-
- strictEqual( test , "ABC" , "Test done callbacks order" );
-
- deferred = jQuery._Deferred();
-
- deferred.resolveWith( jQuery , [ document ] ).done( function( doc ) {
- ok( this === jQuery && arguments.length === 1 && doc === document , "Test fire context & args" );
- });
-
- // #8421
- deferred = jQuery._Deferred();
- deferred.resolveWith().done(function() {
- ok( true, "Test resolveWith can be called with no argument" );
- });
});
-test("jQuery.Deferred()", function() {
+test( "jQuery.Deferred.chain - deferred (done)", function() {
- expect( 10 );
+ expect(3);
- jQuery.Deferred( function( defer ) {
- strictEqual( this , defer , "Defer passed as this & first argument" );
- this.resolve( "done" );
- }).then( function( value ) {
- strictEqual( value , "done" , "Passed function executed" );
+ var defer = jQuery.Deferred(),
+ chained = defer.chain(function( a, b ) {
+ return jQuery.Deferred(function( defer ) {
+ defer.reject( a * b );
+ });
+ }),
+ value1,
+ value2,
+ value3;
+
+ chained.fail(function( result ) {
+ value3 = result;
});
- jQuery.Deferred().resolve().then( function() {
- ok( true , "Success on resolve" );
- }, function() {
- ok( false , "Error on resolve" );
+ defer.done(function( a, b ) {
+ value1 = a;
+ value2 = b;
});
- jQuery.Deferred().reject().then( function() {
- ok( false , "Success on reject" );
- }, function() {
- ok( true , "Error on reject" );
- });
+ defer.resolve( 2, 3 );
- ( new jQuery.Deferred( function( defer ) {
- strictEqual( this , defer , "Defer passed as this & first argument (new)" );
- this.resolve( "done" );
- }) ).then( function( value ) {
- strictEqual( value , "done" , "Passed function executed (new)" );
- });
-
- ( new jQuery.Deferred() ).resolve().then( function() {
- ok( true , "Success on resolve (new)" );
- }, function() {
- ok( false , "Error on resolve (new)" );
- });
-
- ( new jQuery.Deferred() ).reject().then( function() {
- ok( false , "Success on reject (new)" );
- }, function() {
- ok( true , "Error on reject (new)" );
- });
-
- var tmp = jQuery.Deferred();
-
- strictEqual( tmp.promise() , tmp.promise() , "Test deferred always return same promise" );
- strictEqual( tmp.promise() , tmp.promise().promise() , "Test deferred's promise always return same promise as deferred" );
+ strictEqual( value1, 2, "first resolve value ok" );
+ strictEqual( value2, 3, "second resolve value ok" );
+ strictEqual( value3, 6, "result of filter ok" );
});
-test("jQuery.when()", function() {
+test( "jQuery.Deferred.chain - deferred (fail)", function() {
+
+ expect(3);
+
+ var defer = jQuery.Deferred(),
+ chained = defer.chain( null, function( a, b ) {
+ return jQuery.Deferred(function( defer ) {
+ defer.resolve( a * b );
+ });
+ } ),
+ value1,
+ value2,
+ value3;
+
+ chained.done(function( result ) {
+ value3 = result;
+ });
+
+ defer.fail(function( a, b ) {
+ value1 = a;
+ value2 = b;
+ });
+
+ defer.reject( 2, 3 );
+
+ strictEqual( value1, 2, "first reject value ok" );
+ strictEqual( value2, 3, "second reject value ok" );
+ strictEqual( value3, 6, "result of filter ok" );
+});
+
+test( "jQuery.when" , function() {
expect( 23 );
@@ -166,57 +286,63 @@ test("jQuery.when()", function() {
} , function( message , value ) {
- ok( jQuery.isFunction( jQuery.when( value ).then( function( resolveValue ) {
+ ok( jQuery.isFunction( jQuery.when( value ).done(function( resolveValue ) {
strictEqual( resolveValue , value , "Test the promise was resolved with " + message );
- } ).promise ) , "Test " + message + " triggers the creation of a new Promise" );
+ }).promise ) , "Test " + message + " triggers the creation of a new Promise" );
} );
- ok( jQuery.isFunction( jQuery.when().then( function( resolveValue ) {
+ ok( jQuery.isFunction( jQuery.when().done(function( resolveValue ) {
strictEqual( resolveValue , undefined , "Test the promise was resolved with no parameter" );
- } ).promise ) , "Test calling when with no parameter triggers the creation of a new Promise" );
+ }).promise ) , "Test calling when with no parameter triggers the creation of a new Promise" );
var cache, i;
for( i = 1 ; i < 4 ; i++ ) {
jQuery.when( cache || jQuery.Deferred( function() {
this.resolve( i );
- }) ).then( function( value ) {
+ }) ).done(function( value ) {
strictEqual( value , 1 , "Function executed" + ( i > 1 ? " only once" : "" ) );
cache = value;
- }, function() {
- ok( false , "Fail called" );
});
}
});
-test("jQuery.when() - joined", function() {
+test("jQuery.when - joined", function() {
- expect(8);
+ expect(25);
- jQuery.when( 1, 2, 3 ).done( function( a, b, c ) {
- strictEqual( a , 1 , "Test first param is first resolved value - non-observables" );
- strictEqual( b , 2 , "Test second param is second resolved value - non-observables" );
- strictEqual( c , 3 , "Test third param is third resolved value - non-observables" );
- }).fail( function() {
- ok( false , "Test the created deferred was resolved - non-observables");
- });
+ var deferreds = {
+ value: 1,
+ success: jQuery.Deferred().resolve( 1 ),
+ error: jQuery.Deferred().reject( 0 ),
+ futureSuccess: jQuery.Deferred(),
+ futureError: jQuery.Deferred()
+ },
+ willSucceed = {
+ value: true,
+ success: true,
+ error: false,
+ futureSuccess: true,
+ futureError: false
+ };
- var successDeferred = jQuery.Deferred().resolve( 1 , 2 , 3 ),
- errorDeferred = jQuery.Deferred().reject( "error" , "errorParam" );
-
- jQuery.when( 1 , successDeferred , 3 ).done( function( a, b, c ) {
- strictEqual( a , 1 , "Test first param is first resolved value - resolved observable" );
- same( b , [ 1 , 2 , 3 ] , "Test second param is second resolved value - resolved observable" );
- strictEqual( c , 3 , "Test third param is third resolved value - resolved observable" );
- }).fail( function() {
- ok( false , "Test the created deferred was resolved - resolved observable");
- });
-
- jQuery.when( 1 , errorDeferred , 3 ).done( function() {
- ok( false , "Test the created deferred was rejected - rejected observable");
- }).fail( function( error , errorParam ) {
- strictEqual( error , "error" , "Test first param is first rejected value - rejected observable" );
- strictEqual( errorParam , "errorParam" , "Test second param is second rejected value - rejected observable" );
- });
+ jQuery.each( deferreds, function( id1, defer1 ) {
+ jQuery.each( deferreds, function( id2, defer2 ) {
+ var shouldResolve = willSucceed[ id1 ] && willSucceed[ id2 ],
+ expected = shouldResolve ? [ 1, 1 ] : [ 0, undefined ],
+ code = id1 + "/" + id2;
+ jQuery.when( defer1, defer2 ).done(function( a, b ) {
+ if ( shouldResolve ) {
+ same( [ a, b ], expected, code + " => resolve" );
+ }
+ }).fail(function( a, b ) {
+ if ( !shouldResolve ) {
+ same( [ a, b ], expected, code + " => resolve" );
+ }
+ });
+ } );
+ } );
+ deferreds.futureSuccess.resolve( 1 );
+ deferreds.futureError.reject( 0 );
});
diff --git a/test/unit/effects.js b/test/unit/effects.js
index c0a812f4..4f678511 100644
--- a/test/unit/effects.js
+++ b/test/unit/effects.js
@@ -717,59 +717,64 @@ jQuery.each( {
var anim = { width: t_w, height: t_h, opacity: t_o };
- elem.animate(anim, 50, function(){
+ elem.animate(anim, 50);
+
+ jQuery.when( elem ).done(function( elem ){
+
+ elem = elem[ 0 ];
+
if ( t_w == "show" )
- equals( this.style.display, "block", "Showing, display should block: " + this.style.display);
+ equals( elem.style.display, "block", "Showing, display should block: " + elem.style.display);
if ( t_w == "hide"||t_w == "show" )
- ok(f_w === "" ? this.style.width === f_w : this.style.width.indexOf(f_w) === 0, "Width must be reset to " + f_w + ": " + this.style.width);
+ ok(f_w === "" ? elem.style.width === f_w : elem.style.width.indexOf(f_w) === 0, "Width must be reset to " + f_w + ": " + elem.style.width);
if ( t_h == "hide"||t_h == "show" )
- ok(f_h === "" ? this.style.height === f_h : this.style.height.indexOf(f_h) === 0, "Height must be reset to " + f_h + ": " + this.style.height);
+ ok(f_h === "" ? elem.style.height === f_h : elem.style.height.indexOf(f_h) === 0, "Height must be reset to " + f_h + ": " + elem.style.height);
- var cur_o = jQuery.style(this, "opacity");
+ var cur_o = jQuery.style(elem, "opacity");
if ( t_o == "hide" || t_o == "show" )
equals(cur_o, f_o, "Opacity must be reset to " + f_o + ": " + cur_o);
if ( t_w == "hide" )
- equals(this.style.display, "none", "Hiding, display should be none: " + this.style.display);
+ equals(elem.style.display, "none", "Hiding, display should be none: " + elem.style.display);
if ( t_o.constructor == Number ) {
equals(cur_o, t_o, "Final opacity should be " + t_o + ": " + cur_o);
- ok(jQuery.css(this, "opacity") != "" || cur_o == t_o, "Opacity should be explicitly set to " + t_o + ", is instead: " + cur_o);
+ ok(jQuery.css(elem, "opacity") != "" || cur_o == t_o, "Opacity should be explicitly set to " + t_o + ", is instead: " + cur_o);
}
if ( t_w.constructor == Number ) {
- equals(this.style.width, t_w + "px", "Final width should be " + t_w + ": " + this.style.width);
+ equals(elem.style.width, t_w + "px", "Final width should be " + t_w + ": " + elem.style.width);
- var cur_w = jQuery.css(this,"width");
+ var cur_w = jQuery.css(elem,"width");
- ok(this.style.width != "" || cur_w == t_w, "Width should be explicitly set to " + t_w + ", is instead: " + cur_w);
+ ok(elem.style.width != "" || cur_w == t_w, "Width should be explicitly set to " + t_w + ", is instead: " + cur_w);
}
if ( t_h.constructor == Number ) {
- equals(this.style.height, t_h + "px", "Final height should be " + t_h + ": " + this.style.height);
+ equals(elem.style.height, t_h + "px", "Final height should be " + t_h + ": " + elem.style.height);
- var cur_h = jQuery.css(this,"height");
+ var cur_h = jQuery.css(elem,"height");
- ok(this.style.height != "" || cur_h == t_h, "Height should be explicitly set to " + t_h + ", is instead: " + cur_w);
+ ok(elem.style.height != "" || cur_h == t_h, "Height should be explicitly set to " + t_h + ", is instead: " + cur_w);
}
if ( t_h == "show" ) {
- var old_h = jQuery.css(this, "height");
- jQuery(this).append("
Some more text
and some more...");
+ var old_h = jQuery.css(elem, "height");
+ jQuery(elem).append("
Some more text
and some more...");
if ( /Auto/.test( fn ) ) {
- notEqual(jQuery.css(this, "height"), old_h, "Make sure height is auto.");
+ notEqual(jQuery.css(elem, "height"), old_h, "Make sure height is auto.");
} else {
- equals(jQuery.css(this, "height"), old_h, "Make sure height is not auto.");
+ equals(jQuery.css(elem, "height"), old_h, "Make sure height is not auto.");
}
}
// manually remove generated element
- jQuery(this).remove();
+ jQuery(elem).remove();
start();
});