Skip to content
This repository

HTTPS clone URL

Subversion checkout URL

You can clone with HTTPS or Subversion.

Download ZIP

fixes #10996 (simplify offset) #642

Closed
wants to merge 11 commits into from

8 participants

Mike Sherov Han Julian Aubourg Richard Gibson Domenic Denicola Brian Cavalier Dave Methvin Scott González
Mike Sherov
Collaborator

In all of jQuery's supported browsers, either getBoundingClientRect() or window.webkitConvertPointFromNodeToPage() exists, thereby eliminating the need for the old lengthy getOffset function. Good riddance!

http://bugs.jquery.com/ticket/10996

In case anyone is curious, and I know you are, here is the size diff:

  247053  (-2576) jquery.js
   92588  (-1462) jquery.min.js
   32937   (-448) jquery.min.js.gz
Mike Sherov
Collaborator

Just one last thing, all 3 of my open pull requests will probably conflict with each other:

#639
#630

src/offset.js
((14 lines not shown))
9 11
 		try {
10 12
 			box = elem.getBoundingClientRect();
11 13
 		} catch(e) {}
12 14
 
13 15
 		// Make sure we're not dealing with a disconnected DOM node
14 16
 		if ( !box || !jQuery.contains( docElem, elem ) ) {
15  
-			return box ? { top: box.top, left: box.left } : { top: 0, left: 0 };
  17
+			return box ? { top: box.top, left: box.left } : noOffset;
5
Julian Aubourg Collaborator

I wouldn't do that. I know I happen to use the object returned here and modify it... better return a new object all the time.

Julian Aubourg Collaborator

Oh and merry christmas! :)

Mike Sherov Collaborator

O.o

I completely forgot that the object would be by reference! Making the change shortly. And merry Christmas to you as well.

Richard Gibson Collaborator

First: awesome job; bon voyage to manual getOffset!

Second: You can save another 8/10/2 bytes here with { top: box ? box.top : 0, left: box ? box.left : 0 }... or 19/14/2 with jQuery.extend( { top: 0, left: 0 }, box ) (but that would come with extraneous right and bottom properties).

Mike Sherov Collaborator

I'm holding off on further changes until I can get some confirmation for jQuery Mobile team that this is safe.

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Han

is it just me or is this broken?

$ make
Building ./dist/jquery.js
Minifying jQuery ./dist/jquery.min.js
Checking jQuery against JSHint...
JSHint found errors.
 [L1562:C52] 'paddingMarginBorder' is not defined.
  div.innerHTML = "<table><tr><td style='" + paddingMarginBorder + "0;display:none'></td><td>t</td></tr></table>";

 [L1580:C13] 'marginDiv' is not defined.
  marginDiv = document.createElement( "div" );

 [L1581:C13] 'marginDiv' is not defined.
  marginDiv.style.width = "0";

 [L1582:C13] 'marginDiv' is not defined.
  marginDiv.style.marginRight = "0";

 [L1584:C30] 'marginDiv' is not defined.
  div.appendChild( marginDiv );

 [L1586:C56] 'marginDiv' is not defined.
  ( parseInt( ( window.getComputedStyle( marginDiv, null ) || { marginRight: 0 } ).marginRight, 10 ) || 0 ) === 0;

 [L1630:C9] 'marginDiv' is not defined.
  marginDiv = div = container = null;

jQuery Size - compared to last make
  250149  (-2738) jquery.js
   93502  (-1344) jquery.min.js
   33258   (-391) jquery.min.js.gz
jQuery build complete.
and others added some commits April 02, 2012
Julian Aubourg Allows traditional options object for $.Callbacks flags. Fixes #11011…
…. Unit tests added.
7fa0da0
Julian Aubourg Makes Deferred implementation truly Promise/A compliant. Unit tests a…
…mended. Actually few changes required in jQuery's own source and we gained 8 bytes minified gzipped \o/.
a41f240
Julian Aubourg $.ajax now always returns an object implementing the Promise interfac…
…e. Fixes #10944. Unit tests amended.

For back-compat, in case of an early abort, callbacks passed in the options are not called (while subsequent callbacks attached to the returned Promise are).
For early abort triggered by returning false in beforeSend, statusText is "canceled".
395612b
Julian Aubourg For much improved consistency, jqXHR.abort() sets a default statusTex…
…t of 'canceled' right until after beforeSend has been called (in which case it reverts to the default of 'abort'): now all early aborts have a statusText of 'canceled'.
914df9c
Julian Aubourg Merge branch '1.8/#11010/Deferred' into 1.8pre 03c5836
Julian Aubourg Merge branch '1.8/#11011/Callbacks' into 1.8pre 41056ab
Mike Sherov remove old offset code 8190ce5
Mike Sherov remove unneeded fixed position support test fb0af94
Mike Sherov remove unnecessary support tests 4aa9619
Mike Sherov removing unnecessary unit tests 9200c64
Mike Sherov function parity with getBoundingClientRect
return new object literal in all cases
style and JSHint fixes
b784967
Mike Sherov mikesherov closed this April 03, 2012
Brian Cavalier

Cool, it's great to see this headed toward Promises/A! I think it's gonna become the norm for multiple promise implementations to be in play in any reasonably interesting app. I found a situation where I believe it still isn't fully compliant, so I created a quick test case. It should show 3 for both jQuery and when.js, but the jQuery.Deferred seems never to resolve.

Collaborator

It seems to me that when.js wrongly calls the last resolve callback. I'd expect this to be the correct code and behaviour.

Hey @jaubourg,

I'm pretty sure the correct behavior is that the promise chain should return to resolving when a registered rejection handler does not explicitly propagate the rejection by either throwing or returning a rejected promise--i.e. it should behave similar to a catch statement. To propagate the exception, a catch statement must explicitly rethrow (or throw a new exception). If it doesn't explicitly (re)throw, the original exception is considered to be handled and doesn't propagate.

I've updated the original fiddle to include Q, which matches when.js's behavior. I also created a new fiddle that includes when.js, Q, and dojo (1.6, because it's easier to use in jsfiddle than 1.7, but the behavior is the same). Those show the same behavior, so I think jQuery is the outlier in this case.

Please don't take this the wrong way. Like I said, I'm really interested in trying to ensure that the most popular promise implementations are all interoperable, and hopefully this is a test case that will help.

Collaborator

Well, Brian, it's probably the first time I see jQuery being called the "outlier" rather than the nasty-hype-machine-that-will-devour-the-world (tm), so it's quite refreshing ;)

This use-case is probably yet another nail in the coffin of jQuery's Promise/A compliance. You probably followed the multiple discussions that took place about this. Equating exceptions and rejections is something we cannot do in a our environment: it makes debugging impossible. The metaphor is broken, btw, because, with Promise/A, exceptions are always handled (which is the gist of the problem). But let's not beat a dead horse.

Here is why I have a problem with rejection handlers changing state:

// Promise/A
promise.then( function() {}  ); // => resolved
promise.then( null, function() {}  ); // => resolved
promise.then( null, null, function() {}  ); // => pending

// jQuery
promise.then( function() {}  ); // => resolved
promise.then( null, function() {}  ); // => rejected
promise.then( null, null, function() {}  ); // => pending

"Redirecting" state has to be done explicitly in jQuery's implementation: it's explicit and it's symmetrical.

If people want us to write down a spec of jQuery's take on Promises, I'll try and find time to do so (though I'd love to get some help on this one). However, pushing jQuery's implementation forward to be fully Promise/A compliant is probably never gonna happen at this point. As minimal as Promise/A appeared to be, it has one contraint too many, at least for us.

I'm def not here to be a jQuery-hater, just trying to ensure some interoperability.

I disagree with your feelings about Promises/A, and I don't see Promises/A as having too many constraints at all. In fact, I see it as quite simple:

  1. If a handler returns successfully, the next promise is resolved.
  2. If a handler throws or returns a rejection, the next promise is rejected.

That said, I respect that every project has its own goals and constraints. If it doesn't make sense for jQuery to provide a Promises/A compliant promise, then I do think it's important to document its promise behavior.

Given the current (good) trend of more modular code, and moving more responsiblity (and therefore, code) to the browser-side, it's inevitable that applications will contain multiple promise implementations. Having an equalizer like when.js's when(), that can consume all of the above will help.

I think it would make sense for jQuery documentation to point people to when.js or Q as ways to enable promise interoperability.

Owner

@briancavalier Is "what you see" written down as part of Promises/A? It would help implementers if the proposal actually had a detailed description. The divergence in implementations seems to be a direct result of that.

If the promise is rejected and the user expects their rejected promise to be sent a complex object, what should our implementation pass for that case?

@dmethvin It is indeed part of Promises/A. From previous discussions, jQuery has decided not to interoperate with the following Promises/A clauses:

This function should return a new promise...

If the callback throws an error, the returned promise will be moved to failed state.

jQuery is the only implementation (among Q, when.js, WinJS, and Dojo) that diverges from these; implementations are otherwise convergent.

FWIW I've resigned myself to this, but second @briancavalier in that pointing people to Q/when.js/WinJS/Dojo, with their assimilation methods, would be good for those desiring interoperability.

I also support jQuery's current documentation tactic of advocating .done in place of .then, since their "thenables" are not Promises/A compliant as all others are. It's a reasonable compromise given the priorities of the jQuery project. (Personally I would favor deprecating jQuery's .then entirely, but @rwldrn was pretty harsh on me when I suggested that previously, so I assume it's a no-go.)

Aside: part of the problem, IMO, is that it's hard to spot these few crucial sentences in the middle of five paragraphs of prose spec-text. If only Promises/A had come with tests, then it could have been unambiguous what the requirements for conformance were. Too late now, sadly.

Owner

Sorry, if I had time I'd look at the other implementations and perhaps they'd answer this question. In the meantime, perhaps you know?

I am assuming that when the promise is moved to the failed state due to an exception being thrown, any "fail/rejected" handlers attached (or to-be-attached) are called. What arguments are they called with?

@dmethvin afaict, it's not specified, but @domenic's eye may be more keen than mine. The bit I'm looking at is:

If the callback throws an error, the returned promise will be moved to failed state

It seems reasonable, though, to use the thrown exception as the rejection reason/value and pass it as an arg to the rejection handlers. That's what when.js, Q, and Dojo do--they pass it as the one-and-only argument to rejection handlers.

Owner

@briancavalier, that seems like a problem. If I am explicitly failing a promise with .reject({ code: 42, msg: "not good", time: new Date() }) or perhaps some other custom error object, now the client needs to be aware that their promise can fail not only with that object but also some implicit error object or string. Promise/A doesn't seem to say anything about arguments so perhaps it's outside the scope. But in practical terms how would that be handled? Are we reduced to sniffing args and duck typing?

Aren't caught exceptions real Errors in all browsers?

@dmethvin Yes, as @briancavalier says, the handling of that case is only a de-facto standard. (I find this somewhat strange; pinging @kriskowal for any insight.) It is however quite important for building implementation-agnostic promise-consuming-and-producing methods; see my linked gist below.

As to your point, I think some context is helpful. In Promises/A, there is a direct parallel between sync exceptions and async rejections, just like there is a direct parallel between sync return values and async fulfillment values. So, just as synchronous code could receive multiple types of exceptions---e.g., a custom { code, msg, time } object, or a TypeError from someone calling something incorrectly, or a SyntaxError from bad JSON parsing---asynchronous code could indeed receive multiple types of rejections. So you would handle that the same way you do exceptions: if you sniff and duck-type exceptions, do the same for rejections.

Promises/A not only gives you this parallel, but it also completely removes exceptions from your thinking in favor of rejections, since they can be thought of as an async generalization. It seems you are anticipating rejections used as more of a signaling mechanism, where people often inspect their contents and use them to perform flow control logic. But for Promises/A-using code, that is not really the case. In such code they are used identically to exceptions, in that they are only caught and handled at the boundaries of systems. (E.g.: an Ajax library has no idea how to handle network errors, but my app does; my app has no idea how to handle TypeErrors, but my top-level error handler that tells the user "something went wrong" does.)

Here is a small example that applies these principles: https://gist.github.com/2936696

Thanks for taking the time to discuss and hope this helps answer your questions.

I'll add that from my perspective, @dmethvin's question is one of application design, and not of promises or exceptions. The data used as an error payload is, imho, separate from the mechanism that transports the error. Rejecting a promise with custom data is analogous to throwing that custom data. Same data, different transport. If your application design is one that uses custom data in that way, then, as @domenic described, Promises/A simply gives you an asynchronous transport that is analogous to the synchronous transport provided by throw. Any application-level logic built around the data would remain nearly identical when using Promises/A, as Domenic's gist shows.

@scottgonzalez it depends entirely on what was thrown. You can throw anything, and a catch statement higher up will receive it verbatim:

node -e 'try { throw "hello world"; } catch(message) { console.log(message, typeof message); }'

I'm certainly not advocating that in application code ;)

Owner

Let me try to make this more concrete, so I can tell whether this is a misunderstanding on my part or yours of the impact this would have to existing jQuery code.

jQuery wears several hats in this conversation: 1) An implementer of something that aspires to be Promise/A compliant. 2) A client of the current $.Deferred implementation, for example in $.ajax. and $.fn.animate. 3) A provider of the current $.Deferred implementation to jQuery developers.

Let's say someone has included jQuery in their web page and writes this code:

$.ajax(url).then(
    function(jqXHR) { /* do successful stuff */ },
    function(jqXHR, errorCode) { /* deal with failed request */ }
);

If some code or callback has a code error today, the browser throws an uncaught error with all sorts of detail which is visible on the console. It can also be caught by a window.onerror handler and sent back to a server for analysis using tools such as DamnIT, Errorception, AirBrake, Runtime Intelligence, or Google Analytics. For unanticipated script errors that fall into the "Never check for an error condition you don't know how to handle" category, this is by far the lowest-hassle way to go.

The proposal on the table as I understand it is to catch the error and pass it to the fail handler, which is expecting the (jqXHR, errorCode) it always got in the past but now has to deal with (Error) as well. The same goes for a developer's direct use of jQuery $.Deferred. So to handle a case that is supposedly a "de-facto standard" (of the Promise/A proposal which is not a standard) we should put on Steve's hat and tell everyone to go back and rewrite their code to accommodate this? Plus, it's again asking the developer to handle a totally unanticipated condition, and giving them less information than if they had let it get to the window.onerror handler or the browser's error console.

I have been talking with @jaubourg about how we might be able to change the semantics with a flag to make it do this, but even so this seems like it would have to be opt-in or we'd be breaking code all over the place. And to prevent further hassles, we should be recommending that all fail handlers take a single Error or Error-like argument unless the function is willing to sniff around (which seems incredibly ugly to me). Still, as large as the jQuery ecosystem is, there would be a mix of old-behavior and new-behavior code out there for years to come.

Is it clear now why we can't just change the fundamental behavior of our promise implementation? Or is there some easy way out? If the issue is simply that we're not really Promise/A and can't become so without breaking user code, one option would simply be to publicize that our promises implementation isn't interoperable and explain why we placed user code compatibility over interoperability.

Ok, I think it's time step back for a moment and remember how this thread started by rereading the commit message and my initial comment.

The stated intent of the commit was for jQuery Deferred to be made Promises/A compliant. I came upon it, and was very happy to see this. In an effort to try to help, I supplied a test case where post-this-commit, it isn't compliant. I think it's also important to note that both @domenic and I have said that we respect that jQuery has it's own goals and priorities, like every project. Neither of us has in any way demanded that jQuery Deferred become Promises/A. The intent to do so was implied by the commit.

If Promises/A is not a desirable goal of jQuery Deferred, I respect that. Unfortunately, I believe there is pain for developers either way.

My original suggestion was for jQuery documentation to point developers who need or desire promise interoperability to when.js or Q, as their when() functions can provide it.

And @jaubourg suggested documenting jQuery's promise behavior.

I stand by both of those as reasonable suggestions that would benefit jQuery, implementors of other libraries, and the larger Javascript developer community.

@briancavalier basically said everything I would want to say. I just jumped in to help educate and clarify, not to recommend Promises/A interoperation---I assumed that battle was already lost. As you say, @dmethvin, there's really no easy way out.

The only thing I would argue for, that nobody else seems to be behind, is dropping then completely so that jQuery properly fails the Promises/A duck-type test. This makes a lot of sense to me: as of 1.7, it's just a less powerful pipe, and most examples use and encourage done anyway. So perhaps deprecate in 1.8, remove in 1.9. But it's not that hard to deal with anyway, so whatevs.

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Showing 11 unique commits by 2 authors.

Apr 02, 2012
Julian Aubourg Allows traditional options object for $.Callbacks flags. Fixes #11011…
…. Unit tests added.
7fa0da0
Julian Aubourg Makes Deferred implementation truly Promise/A compliant. Unit tests a…
…mended. Actually few changes required in jQuery's own source and we gained 8 bytes minified gzipped \o/.
a41f240
Julian Aubourg $.ajax now always returns an object implementing the Promise interfac…
…e. Fixes #10944. Unit tests amended.

For back-compat, in case of an early abort, callbacks passed in the options are not called (while subsequent callbacks attached to the returned Promise are).
For early abort triggered by returning false in beforeSend, statusText is "canceled".
395612b
Julian Aubourg For much improved consistency, jqXHR.abort() sets a default statusTex…
…t of 'canceled' right until after beforeSend has been called (in which case it reverts to the default of 'abort'): now all early aborts have a statusText of 'canceled'.
914df9c
Apr 03, 2012
Julian Aubourg Merge branch '1.8/#11010/Deferred' into 1.8pre 03c5836
Julian Aubourg Merge branch '1.8/#11011/Callbacks' into 1.8pre 41056ab
Mike Sherov remove old offset code 8190ce5
Mike Sherov remove unneeded fixed position support test fb0af94
Mike Sherov remove unnecessary support tests 4aa9619
Mike Sherov removing unnecessary unit tests 9200c64
Mike Sherov function parity with getBoundingClientRect
return new object literal in all cases
style and JSHint fixes
b784967
This page is out of date. Refresh to see the latest.
3  build/jshint-check.js
@@ -12,7 +12,8 @@
12 12
 			smarttabs: true,
13 13
 			predef: [
14 14
 				"define",
15  
-				"DOMParser"
  15
+				"DOMParser",
  16
+				"WebKitPoint",
16 17
 			],
17 18
 			maxerr: 100
18 19
 		};
16  src/ajax.js
@@ -426,6 +426,8 @@ jQuery.extend({
426 426
 			fireGlobals,
427 427
 			// Loop variable
428 428
 			i,
  429
+			// Default abort message
  430
+			strAbort = "canceled",
429 431
 			// Fake xhr
430 432
 			jqXHR = {
431 433
 
@@ -471,7 +473,7 @@ jQuery.extend({
471 473
 
472 474
 				// Cancel the request
473 475
 				abort: function( statusText ) {
474  
-					statusText = statusText || "abort";
  476
+					statusText = statusText || strAbort;
475 477
 					if ( transport ) {
476 478
 						transport.abort( statusText );
477 479
 					}
@@ -609,7 +611,7 @@ jQuery.extend({
609 611
 					}
610 612
 				} else {
611 613
 					tmp = map[ jqXHR.status ];
612  
-					jqXHR.then( tmp, tmp );
  614
+					jqXHR.always( tmp );
613 615
 				}
614 616
 			}
615 617
 			return this;
@@ -643,7 +645,7 @@ jQuery.extend({
643 645
 
644 646
 		// If request was aborted inside a prefilter, stop there
645 647
 		if ( state === 2 ) {
646  
-			return false;
  648
+			return jqXHR;
647 649
 		}
648 650
 
649 651
 		// We can fire global events as of now if asked to
@@ -716,12 +718,14 @@ jQuery.extend({
716 718
 
717 719
 		// Allow custom headers/mimetypes and early abort
718 720
 		if ( s.beforeSend && ( s.beforeSend.call( callbackContext, jqXHR, s ) === false || state === 2 ) ) {
719  
-				// Abort if not done already
720  
-				jqXHR.abort();
721  
-				return false;
  721
+				// Abort if not done already and return
  722
+				return jqXHR.abort();
722 723
 
723 724
 		}
724 725
 
  726
+		// aborting is no longer a cancelation
  727
+		strAbort = "abort";
  728
+
725 729
 		// Install callbacks on deferreds
726 730
 		for ( i in { success: 1, error: 1, complete: 1 } ) {
727 731
 			jqXHR[ i ]( s[ i ] );
4  src/callbacks.js
@@ -38,9 +38,9 @@ function createFlags( flags ) {
38 38
  */
39 39
 jQuery.Callbacks = function( flags ) {
40 40
 
41  
-	// Convert flags from String-formatted to Object-formatted
  41
+	// Convert flags from String-formatted to Object-formatted if needed
42 42
 	// (we check in cache first)
43  
-	flags = flags ? ( flagsCache[ flags ] || createFlags( flags ) ) : {};
  43
+	flags = typeof flags === "string" ? ( flagsCache[ flags ] || createFlags( flags ) ) : ( flags || {} );
44 44
 
45 45
 	var // Actual callback list
46 46
 		list = [],
18  src/deferred.js
@@ -28,15 +28,11 @@ jQuery.extend({
28 28
 				isResolved: doneList.fired,
29 29
 				isRejected: failList.fired,
30 30
 
31  
-				then: function( doneCallbacks, failCallbacks, progressCallbacks ) {
32  
-					deferred.done( doneCallbacks ).fail( failCallbacks ).progress( progressCallbacks );
33  
-					return this;
34  
-				},
35 31
 				always: function() {
36 32
 					deferred.done.apply( deferred, arguments ).fail.apply( deferred, arguments );
37 33
 					return this;
38 34
 				},
39  
-				pipe: function( fnDone, fnFail, fnProgress ) {
  35
+				then: function( fnDone, fnFail, fnProgress ) {
40 36
 					return jQuery.Deferred(function( newDefer ) {
41 37
 						jQuery.each( {
42 38
 							done: [ fnDone, "resolve" ],
@@ -50,7 +46,7 @@ jQuery.extend({
50 46
 								deferred[ handler ](function() {
51 47
 									returned = fn.apply( this, arguments );
52 48
 									if ( returned && jQuery.isFunction( returned.promise ) ) {
53  
-										returned.promise().then( newDefer.resolve, newDefer.reject, newDefer.notify );
  49
+										returned.promise().done( newDefer.resolve ).fail( newDefer.reject ).progress( newDefer.notify );
54 50
 									} else {
55 51
 										newDefer[ action + "With" ]( this === deferred ? newDefer : this, [ returned ] );
56 52
 									}
@@ -74,9 +70,15 @@ jQuery.extend({
74 70
 					return obj;
75 71
 				}
76 72
 			},
77  
-			deferred = promise.promise({}),
  73
+			deferred,
78 74
 			key;
79 75
 
  76
+		// Keep pipe for back-compat
  77
+		promise.pipe = promise.then;
  78
+
  79
+		// Construct deferred
  80
+		deferred = promise.promise({});
  81
+
80 82
 		for ( key in lists ) {
81 83
 			deferred[ key ] = lists[ key ].fire;
82 84
 			deferred[ key + "With" ] = lists[ key ].fireWith;
@@ -127,7 +129,7 @@ jQuery.extend({
127 129
 		if ( length > 1 ) {
128 130
 			for ( ; i < length; i++ ) {
129 131
 				if ( args[ i ] && args[ i ].promise && jQuery.isFunction( args[ i ].promise ) ) {
130  
-					args[ i ].promise().then( resolveFunc(i), deferred.reject, progressFunc(i) );
  132
+					args[ i ].promise().done( resolveFunc(i) ).fail( deferred.reject ).progress( progressFunc(i) );
131 133
 				} else {
132 134
 					--count;
133 135
 				}
57  src/offset.js
... ...
@@ -1,11 +1,12 @@
1 1
 (function( jQuery ) {
2 2
 
3 3
 var getOffset,
4  
-	rtable = /^t(?:able|d|h)$/i,
5 4
 	rroot = /^(?:body|html)$/i;
6 5
 
7 6
 if ( "getBoundingClientRect" in document.documentElement ) {
8  
-	getOffset = function( elem, doc, docElem, box ) {
  7
+	getOffset = function( elem, doc, docElem ) {
  8
+		var box;
  9
+
9 10
 		try {
10 11
 			box = elem.getBoundingClientRect();
11 12
 		} catch(e) {}
@@ -29,56 +30,12 @@ if ( "getBoundingClientRect" in document.documentElement ) {
29 30
 
30 31
 } else {
31 32
 	getOffset = function( elem, doc, docElem ) {
32  
-		var computedStyle,
33  
-			offsetParent = elem.offsetParent,
34  
-			prevOffsetParent = elem,
35  
-			body = doc.body,
36  
-			defaultView = doc.defaultView,
37  
-			prevComputedStyle = defaultView ? defaultView.getComputedStyle( elem, null ) : elem.currentStyle,
38  
-			top = elem.offsetTop,
39  
-			left = elem.offsetLeft;
40  
-
41  
-		while ( (elem = elem.parentNode) && elem !== body && elem !== docElem ) {
42  
-			if ( jQuery.support.fixedPosition && prevComputedStyle.position === "fixed" ) {
43  
-				break;
44  
-			}
45  
-
46  
-			computedStyle = defaultView ? defaultView.getComputedStyle(elem, null) : elem.currentStyle;
47  
-			top  -= elem.scrollTop;
48  
-			left -= elem.scrollLeft;
49  
-
50  
-			if ( elem === offsetParent ) {
51  
-				top  += elem.offsetTop;
52  
-				left += elem.offsetLeft;
53  
-
54  
-				if ( jQuery.support.doesNotAddBorder && !(jQuery.support.doesAddBorderForTableAndCells && rtable.test(elem.nodeName)) ) {
55  
-					top  += parseFloat( computedStyle.borderTopWidth  ) || 0;
56  
-					left += parseFloat( computedStyle.borderLeftWidth ) || 0;
57  
-				}
58  
-
59  
-				prevOffsetParent = offsetParent;
60  
-				offsetParent = elem.offsetParent;
61  
-			}
62  
-
63  
-			if ( jQuery.support.subtractsBorderForOverflowNotVisible && computedStyle.overflow !== "visible" ) {
64  
-				top  += parseFloat( computedStyle.borderTopWidth  ) || 0;
65  
-				left += parseFloat( computedStyle.borderLeftWidth ) || 0;
66  
-			}
67  
-
68  
-			prevComputedStyle = computedStyle;
69  
-		}
70  
-
71  
-		if ( prevComputedStyle.position === "relative" || prevComputedStyle.position === "static" ) {
72  
-			top  += body.offsetTop;
73  
-			left += body.offsetLeft;
74  
-		}
75  
-
76  
-		if ( jQuery.support.fixedPosition && prevComputedStyle.position === "fixed" ) {
77  
-			top  += Math.max( docElem.scrollTop, body.scrollTop );
78  
-			left += Math.max( docElem.scrollLeft, body.scrollLeft );
  33
+		if ( !jQuery.contains( docElem, elem ) ) {
  34
+			return { top: 0, left: 0 };
79 35
 		}
  36
+		var point = getWindow( doc ).webkitConvertPointFromNodeToPage( elem, new WebKitPoint( 0, 0 ) );
  37
+		return { top: point.y, left: point.x };
80 38
 
81  
-		return { top: top, left: left };
82 39
 	};
83 40
 }
84 41
 
39  src/support.js
@@ -178,9 +178,8 @@ jQuery.support = (function() {
178 178
 
179 179
 	// Run tests that need a body at doc ready
180 180
 	jQuery(function() {
181  
-		var container, outer, inner, table, td, offsetSupport,
182  
-			marginDiv, conMarginTop, style, html, positionTopLeftWidthHeight,
183  
-			paddingMarginBorderVisibility, paddingMarginBorder,
  181
+		var container, offsetSupport,
  182
+			conMarginTop = 1,
184 183
 			body = document.getElementsByTagName("body")[0];
185 184
 
186 185
 		if ( !body ) {
@@ -188,17 +187,8 @@ jQuery.support = (function() {
188 187
 			return;
189 188
 		}
190 189
 
191  
-		conMarginTop = 1;
192  
-		paddingMarginBorder = "padding:0;margin:0;border:";
193  
-		positionTopLeftWidthHeight = "position:absolute;top:0;left:0;width:1px;height:1px;";
194  
-		paddingMarginBorderVisibility = paddingMarginBorder + "0;visibility:hidden;";
195  
-		style = "style='" + positionTopLeftWidthHeight + paddingMarginBorder + "5px solid #000;";
196  
-		html = "<div " + style + "display:block;'><div style='" + paddingMarginBorder + "0;display:block;overflow:hidden;'></div></div>" +
197  
-			"<table " + style + "' cellpadding='0' cellspacing='0'>" +
198  
-			"<tr><td></td></tr></table>";
199  
-
200 190
 		container = document.createElement("div");
201  
-		container.style.cssText = paddingMarginBorderVisibility + "width:0;height:0;position:static;top:0;margin-top:" + conMarginTop + "px";
  191
+		container.style.cssText = "visibility:hidden;border:0;width:0;height:0;position:static;top:0;margin-top:" + conMarginTop + "px";
202 192
 		body.insertBefore( container, body.firstChild );
203 193
 
204 194
 		// Construct the test element
@@ -260,31 +250,10 @@ jQuery.support = (function() {
260 250
 			support.shrinkWrapBlocks = ( div.offsetWidth !== 3 );
261 251
 		}
262 252
 
263  
-		div.style.cssText = positionTopLeftWidthHeight + paddingMarginBorderVisibility;
264  
-		div.innerHTML = html;
265  
-
266  
-		outer = div.firstChild;
267  
-		inner = outer.firstChild;
268  
-		td = outer.nextSibling.firstChild.firstChild;
269  
-
270 253
 		offsetSupport = {
271  
-			doesNotAddBorder: ( inner.offsetTop !== 5 ),
272  
-			doesAddBorderForTableAndCells: ( td.offsetTop === 5 )
  254
+			doesNotIncludeMarginInBodyOffset: ( body.offsetTop !== conMarginTop )
273 255
 		};
274 256
 
275  
-		inner.style.position = "fixed";
276  
-		inner.style.top = "20px";
277  
-
278  
-		// safari subtracts parent border width here which is 5px
279  
-		offsetSupport.fixedPosition = ( inner.offsetTop === 20 || inner.offsetTop === 15 );
280  
-		inner.style.position = inner.style.top = "";
281  
-
282  
-		outer.style.overflow = "hidden";
283  
-		outer.style.position = "relative";
284  
-
285  
-		offsetSupport.subtractsBorderForOverflowNotVisible = ( inner.offsetTop === -5 );
286  
-		offsetSupport.doesNotIncludeMarginInBodyOffset = ( body.offsetTop !== conMarginTop );
287  
-
288 257
 		if ( window.getComputedStyle ) {
289 258
 			div.style.marginTop = "1%";
290 259
 			support.pixelMargin = ( window.getComputedStyle( div, null ) || { marginTop: 0 } ).marginTop !== "1%";
19  test/unit/ajax.js
@@ -857,7 +857,7 @@ test("jQuery.ajax - beforeSend", function() {
857 857
 
858 858
 test("jQuery.ajax - beforeSend, cancel request (#2688)", function() {
859 859
 	expect(2);
860  
-	var request = jQuery.ajax({
  860
+	jQuery.ajax({
861 861
 		url: url("data/name.html"),
862 862
 		beforeSend: function() {
863 863
 			ok( true, "beforeSend got called, canceling" );
@@ -872,13 +872,14 @@ test("jQuery.ajax - beforeSend, cancel request (#2688)", function() {
872 872
 		error: function() {
873 873
 			ok( false, "request didn't get canceled" );
874 874
 		}
  875
+	}).fail(function( _, reason ) {
  876
+		strictEqual( reason, "canceled", "canceled request must fail with 'canceled' status text" );
875 877
 	});
876  
-	ok( request === false, "canceled request must return false instead of XMLHttpRequest instance" );
877 878
 });
878 879
 
879 880
 test("jQuery.ajax - beforeSend, cancel request manually", function() {
880 881
 	expect(2);
881  
-	var request = jQuery.ajax({
  882
+	jQuery.ajax({
882 883
 		url: url("data/name.html"),
883 884
 		beforeSend: function(xhr) {
884 885
 			ok( true, "beforeSend got called, canceling" );
@@ -893,8 +894,9 @@ test("jQuery.ajax - beforeSend, cancel request manually", function() {
893 894
 		error: function() {
894 895
 			ok( false, "request didn't get canceled" );
895 896
 		}
  897
+	}).fail(function( _, reason ) {
  898
+		strictEqual( reason, "canceled", "manually canceled request must fail with 'canceled' status text" );
896 899
 	});
897  
-	ok( request === false, "canceled request must return false instead of XMLHttpRequest instance" );
898 900
 });
899 901
 
900 902
 window.foobar = null;
@@ -2109,13 +2111,14 @@ test( "jQuery.ajax - Context with circular references (#9887)", 2, function () {
2109 2111
 		context = {};
2110 2112
 	context.field = context;
2111 2113
 	try {
2112  
-		success = !jQuery.ajax( "non-existing", {
  2114
+		jQuery.ajax( "non-existing", {
2113 2115
 			context: context,
2114 2116
 			beforeSend: function() {
2115 2117
 				ok( this === context, "context was not deep extended" );
2116 2118
 				return false;
2117 2119
 			}
2118 2120
 		});
  2121
+		success = true;
2119 2122
 	} catch (e) { console.log( e ); }
2120 2123
 	ok( success, "context with circular reference did not generate an exception" );
2121 2124
 });
@@ -2315,12 +2318,14 @@ test("jQuery.ajax - abort in prefilter", function() {
2315 2318
 		}
2316 2319
 	});
2317 2320
 
2318  
-	strictEqual( jQuery.ajax({
  2321
+	jQuery.ajax({
2319 2322
 		abortInPrefilter: true,
2320 2323
 		error: function() {
2321 2324
 			ok( false, "error callback called" );
2322 2325
 		}
2323  
-	}), false, "Request was properly aborted early by the prefilter" );
  2326
+	}).fail(function( _, reason ) {
  2327
+		strictEqual( reason, 'canceled', "Request aborted by the prefilter must fail with 'canceled' status text" );
  2328
+	});
2324 2329
 
2325 2330
 });
2326 2331
 
292  test/unit/callbacks.js
@@ -33,149 +33,171 @@ var output,
33 33
 		}
34 34
 	};
35 35
 
36  
-jQuery.each( tests, function( flags, resultString ) {
37  
-
38  
-		jQuery.each( filters, function( filterLabel, filter ) {
39  
-
40  
-			test( "jQuery.Callbacks( \"" + flags + "\" ) - " + filterLabel, function() {
  36
+	function showFlags( flags ) {
  37
+		if ( typeof flags === "string" ) {
  38
+			return '"' + flags + '"';
  39
+		}
  40
+		var output = [], key;
  41
+		for ( key in flags ) {
  42
+			output.push( '"' + key + '": ' + flags[ key ] );
  43
+		}
  44
+		return "{ " + output.join( ", " ) + " }";
  45
+	}
41 46
 
42  
-				expect( 20 );
  47
+jQuery.each( tests, function( strFlags, resultString ) {
43 48
 
44  
-				// Give qunit a little breathing room
45  
-				stop();
46  
-				setTimeout( start, 0 );
  49
+		var objectFlags = {};
47 50
 
48  
-				var cblist;
49  
-					results = resultString.split( /\s+/ );
  51
+		jQuery.each( strFlags.split( " " ), function() {
  52
+			if ( this.length ) {
  53
+				objectFlags[ this ] = true;
  54
+			}
  55
+		});
50 56
 
51  
-				// Basic binding and firing
52  
-				output = "X";
53  
-				cblist = jQuery.Callbacks( flags );
54  
-				cblist.add(function( str ) {
55  
-					output += str;
56  
-				});
57  
-				cblist.fire( "A" );
58  
-				strictEqual( output, "XA", "Basic binding and firing" );
59  
-				strictEqual( cblist.fired(), true, ".fired() detects firing" );
60  
-				output = "X";
61  
-				cblist.disable();
62  
-				cblist.add(function( str ) {
63  
-					output += str;
64  
-				});
65  
-				strictEqual( output, "X", "Adding a callback after disabling" );
66  
-				cblist.fire( "A" );
67  
-				strictEqual( output, "X", "Firing after disabling" );
68  
-
69  
-				// Basic binding and firing (context, arguments)
70  
-				output = "X";
71  
-				cblist = jQuery.Callbacks( flags );
72  
-				cblist.add(function() {
73  
-					equal( this, window, "Basic binding and firing (context)" );
74  
-					output += Array.prototype.join.call( arguments, "" );
75  
-				});
76  
-				cblist.fireWith( window, [ "A", "B" ] );
77  
-				strictEqual( output, "XAB", "Basic binding and firing (arguments)" );
78  
-
79  
-				// fireWith with no arguments
80  
-				output = "";
81  
-				cblist = jQuery.Callbacks( flags );
82  
-				cblist.add(function() {
83  
-					equal( this, window, "fireWith with no arguments (context is window)" );
84  
-					strictEqual( arguments.length, 0, "fireWith with no arguments (no arguments)" );
85  
-				});
86  
-				cblist.fireWith();
87  
-
88  
-				// Basic binding, removing and firing
89  
-				output = "X";
90  
-				cblist = jQuery.Callbacks( flags );
91  
-				cblist.add( outputA, outputB, outputC );
92  
-				cblist.remove( outputB, outputC );
93  
-				cblist.fire();
94  
-				strictEqual( output, "XA", "Basic binding, removing and firing" );
95  
-
96  
-				// Empty
97  
-				output = "X";
98  
-				cblist = jQuery.Callbacks( flags );
99  
-				cblist.add( outputA );
100  
-				cblist.add( outputB );
101  
-				cblist.add( outputC );
102  
-				cblist.empty();
103  
-				cblist.fire();
104  
-				strictEqual( output, "X", "Empty" );
105  
-
106  
-				// Locking
107  
-				output = "X";
108  
-				cblist = jQuery.Callbacks( flags );
109  
-				cblist.add( function( str ) {
110  
-					output += str;
111  
-				});
112  
-				cblist.lock();
113  
-				cblist.add( function( str ) {
114  
-					output += str;
115  
-				});
116  
-				cblist.fire( "A" );
117  
-				cblist.add( function( str ) {
118  
-					output += str;
119  
-				});
120  
-				strictEqual( output, "X", "Lock early" );
  57
+		jQuery.each( filters, function( filterLabel, filter ) {
121 58
 
122  
-				// Ordering
123  
-				output = "X";
124  
-				cblist = jQuery.Callbacks( flags );
125  
-				cblist.add( function() {
  59
+			jQuery.each( { "string": strFlags, "object": objectFlags }, function( flagsTypes, flags ) {
  60
+
  61
+				test( "jQuery.Callbacks( " + showFlags( flags ) + " ) - " + filterLabel, function() {
  62
+
  63
+					expect( 20 );
  64
+
  65
+					// Give qunit a little breathing room
  66
+					stop();
  67
+					setTimeout( start, 0 );
  68
+
  69
+					var cblist;
  70
+						results = resultString.split( /\s+/ );
  71
+
  72
+					// Basic binding and firing
  73
+					output = "X";
  74
+					cblist = jQuery.Callbacks( flags );
  75
+					cblist.add(function( str ) {
  76
+						output += str;
  77
+					});
  78
+					cblist.fire( "A" );
  79
+					strictEqual( output, "XA", "Basic binding and firing" );
  80
+					strictEqual( cblist.fired(), true, ".fired() detects firing" );
  81
+					output = "X";
  82
+					cblist.disable();
  83
+					cblist.add(function( str ) {
  84
+						output += str;
  85
+					});
  86
+					strictEqual( output, "X", "Adding a callback after disabling" );
  87
+					cblist.fire( "A" );
  88
+					strictEqual( output, "X", "Firing after disabling" );
  89
+
  90
+					// Basic binding and firing (context, arguments)
  91
+					output = "X";
  92
+					cblist = jQuery.Callbacks( flags );
  93
+					cblist.add(function() {
  94
+						equal( this, window, "Basic binding and firing (context)" );
  95
+						output += Array.prototype.join.call( arguments, "" );
  96
+					});
  97
+					cblist.fireWith( window, [ "A", "B" ] );
  98
+					strictEqual( output, "XAB", "Basic binding and firing (arguments)" );
  99
+
  100
+					// fireWith with no arguments
  101
+					output = "";
  102
+					cblist = jQuery.Callbacks( flags );
  103
+					cblist.add(function() {
  104
+						equal( this, window, "fireWith with no arguments (context is window)" );
  105
+						strictEqual( arguments.length, 0, "fireWith with no arguments (no arguments)" );
  106
+					});
  107
+					cblist.fireWith();
  108
+
  109
+					// Basic binding, removing and firing
  110
+					output = "X";
  111
+					cblist = jQuery.Callbacks( flags );
  112
+					cblist.add( outputA, outputB, outputC );
  113
+					cblist.remove( outputB, outputC );
  114
+					cblist.fire();
  115
+					strictEqual( output, "XA", "Basic binding, removing and firing" );
  116
+
  117
+					// Empty
  118
+					output = "X";
  119
+					cblist = jQuery.Callbacks( flags );
  120
+					cblist.add( outputA );
  121
+					cblist.add( outputB );
126 122
 					cblist.add( outputC );
127  
-					outputA();
128  
-				}, outputB );
129  
-				cblist.fire();
130  
-				strictEqual( output, results.shift(), "Proper ordering" );
131  
-
132  
-				// Add and fire again
133  
-				output = "X";
134  
-				cblist.add( function() {
  123
+					cblist.empty();
  124
+					cblist.fire();
  125
+					strictEqual( output, "X", "Empty" );
  126
+
  127
+					// Locking
  128
+					output = "X";
  129
+					cblist = jQuery.Callbacks( flags );
  130
+					cblist.add( function( str ) {
  131
+						output += str;
  132
+					});
  133
+					cblist.lock();
  134
+					cblist.add( function( str ) {
  135
+						output += str;
  136
+					});
  137
+					cblist.fire( "A" );
  138
+					cblist.add( function( str ) {
  139
+						output += str;
  140
+					});
  141
+					strictEqual( output, "X", "Lock early" );
  142
+
  143
+					// Ordering
  144
+					output = "X";
  145
+					cblist = jQuery.Callbacks( flags );
  146
+					cblist.add( function() {
  147
+						cblist.add( outputC );
  148
+						outputA();
  149
+					}, outputB );
  150
+					cblist.fire();
  151
+					strictEqual( output, results.shift(), "Proper ordering" );
  152
+
  153
+					// Add and fire again
  154
+					output = "X";
  155
+					cblist.add( function() {
  156
+						cblist.add( outputC );
  157
+						outputA();
  158
+					}, outputB );
  159
+					strictEqual( output, results.shift(), "Add after fire" );
  160
+
  161
+					output = "X";
  162
+					cblist.fire();
  163
+					strictEqual( output, results.shift(), "Fire again" );
  164
+
  165
+					// Multiple fire
  166
+					output = "X";
  167
+					cblist = jQuery.Callbacks( flags );
  168
+					cblist.add( function( str ) {
  169
+						output += str;
  170
+					} );
  171
+					cblist.fire( "A" );
  172
+					strictEqual( output, "XA", "Multiple fire (first fire)" );
  173
+					output = "X";
  174
+					cblist.add( function( str ) {
  175
+						output += str;
  176
+					} );
  177
+					strictEqual( output, results.shift(), "Multiple fire (first new callback)" );
  178
+					output = "X";
  179
+					cblist.fire( "B" );
  180
+					strictEqual( output, results.shift(), "Multiple fire (second fire)" );
  181
+					output = "X";
  182
+					cblist.add( function( str ) {
  183
+						output += str;
  184
+					} );
  185
+					strictEqual( output, results.shift(), "Multiple fire (second new callback)" );
  186
+
  187
+					// Return false
  188
+					output = "X";
  189
+					cblist = jQuery.Callbacks( flags );
  190
+					cblist.add( outputA, function() { return false; }, outputB );
  191
+					cblist.add( outputA );
  192
+					cblist.fire();
  193
+					strictEqual( output, results.shift(), "Callback returning false" );
  194
+
  195
+					// Add another callback (to control lists with memory do not fire anymore)
  196
+					output = "X";
135 197
 					cblist.add( outputC );
136  
-					outputA();
137  
-				}, outputB );
138  
-				strictEqual( output, results.shift(), "Add after fire" );
139  
-
140  
-				output = "X";
141  
-				cblist.fire();
142  
-				strictEqual( output, results.shift(), "Fire again" );
143  
-
144  
-				// Multiple fire
145  
-				output = "X";
146  
-				cblist = jQuery.Callbacks( flags );
147  
-				cblist.add( function( str ) {
148  
-					output += str;
149  
-				} );
150  
-				cblist.fire( "A" );
151  
-				strictEqual( output, "XA", "Multiple fire (first fire)" );
152  
-				output = "X";
153  
-				cblist.add( function( str ) {
154  
-					output += str;
155  
-				} );
156  
-				strictEqual( output, results.shift(), "Multiple fire (first new callback)" );
157  
-				output = "X";
158  
-				cblist.fire( "B" );
159  
-				strictEqual( output, results.shift(), "Multiple fire (second fire)" );
160  
-				output = "X";
161  
-				cblist.add( function( str ) {
162  
-					output += str;
163  
-				} );
164  
-				strictEqual( output, results.shift(), "Multiple fire (second new callback)" );
165  
-
166  
-				// Return false
167  
-				output = "X";
168  
-				cblist = jQuery.Callbacks( flags );
169  
-				cblist.add( outputA, function() { return false; }, outputB );
170  
-				cblist.add( outputA );
171  
-				cblist.fire();
172  
-				strictEqual( output, results.shift(), "Callback returning false" );
173  
-
174  
-				// Add another callback (to control lists with memory do not fire anymore)
175  
-				output = "X";
176  
-				cblist.add( outputC );
177  
-				strictEqual( output, results.shift(), "Adding a callback after one returned false" );
  198
+					strictEqual( output, results.shift(), "Adding a callback after one returned false" );
178 199
 
  200
+				});
179 201
 			});
180 202
 		});
181 203
 });
70  test/unit/deferred.js
@@ -8,32 +8,36 @@ jQuery.each( [ "", " - new operator" ], function( _, withNew ) {
8 8
 
9 9
 	test("jQuery.Deferred" + withNew, function() {
10 10
 
11  
-		expect( 22 );
  11
+		expect( 23 );
12 12
 
13  
-		createDeferred().resolve().then( function() {
  13
+		var defer = createDeferred();
  14
+
  15
+		strictEqual( defer.pipe, defer.then, "pipe is an alias of then" );
  16
+
  17
+		createDeferred().resolve().done(function() {
14 18
 			ok( true , "Success on resolve" );
15 19
 			ok( this.isResolved(), "Deferred is resolved" );
16 20
 			strictEqual( this.state(), "resolved", "Deferred is resolved (state)" );
17  
-		}, function() {
  21
+		}).fail(function() {
18 22
 			ok( false , "Error on resolve" );
19  
-		}).always( function() {
  23
+		}).always(function() {
20 24
 			ok( true , "Always callback on resolve" );
21 25
 		});
22 26
 
23  
-		createDeferred().reject().then( function() {
  27
+		createDeferred().reject().done(function() {
24 28
 			ok( false , "Success on reject" );
25  
-		}, function() {
  29
+		}).fail(function() {
26 30
 			ok( true , "Error on reject" );
27 31
 			ok( this.isRejected(), "Deferred is rejected" );
28 32
 			strictEqual( this.state(), "rejected", "Deferred is rejected (state)" );
29  
-		}).always( function() {
  33
+		}).always(function() {
30 34
 			ok( true , "Always callback on reject" );
31 35
 		});
32 36
 
33  
-		createDeferred( function( defer ) {
  37
+		createDeferred(function( defer ) {
34 38
 			ok( this === defer , "Defer passed as this & first argument" );
35 39
 			this.resolve( "done" );
36  
-		}).then( function( value ) {
  40
+		}).done( function( value ) {
37 41
 			strictEqual( value , "done" , "Passed function executed" );
38 42
 		});
39 43
 
@@ -58,7 +62,7 @@ jQuery.each( [ "", " - new operator" ], function( _, withNew ) {
58 62
 
59 63
 test( "jQuery.Deferred - chainability", function() {
60 64
 
61  
-	var methods = "resolve reject notify resolveWith rejectWith notifyWith done fail progress then always".split( " " ),
  65
+	var methods = "resolve reject notify resolveWith rejectWith notifyWith done fail progress always".split( " " ),
62 66
 		defer = jQuery.Deferred();
63 67
 
64 68
 	expect( methods.length );
@@ -69,12 +73,12 @@ test( "jQuery.Deferred - chainability", function() {
69 73
 	});
70 74
 });
71 75
 
72  
-test( "jQuery.Deferred.pipe - filtering (done)", function() {
  76
+test( "jQuery.Deferred.then - filtering (done)", function() {
73 77
 
74 78
 	expect(4);
75 79
 
76 80
 	var defer = jQuery.Deferred(),
77  
-		piped = defer.pipe(function( a, b ) {
  81
+		piped = defer.then(function( a, b ) {
78 82
 			return a * b;
79 83
 		}),
80 84
 		value1,
@@ -96,21 +100,21 @@ test( "jQuery.Deferred.pipe - filtering (done)", function() {
96 100
 	strictEqual( value2, 3, "second resolve value ok" );
97 101
 	strictEqual( value3, 6, "result of filter ok" );
98 102
 
99  
-	jQuery.Deferred().reject().pipe(function() {
100  
-		ok( false, "pipe should not be called on reject" );
  103
+	jQuery.Deferred().reject().then(function() {
  104
+		ok( false, "then should not be called on reject" );
101 105
 	});
102 106
 
103  
-	jQuery.Deferred().resolve().pipe( jQuery.noop ).done(function( value ) {
104  
-		strictEqual( value, undefined, "pipe done callback can return undefined/null" );
  107
+	jQuery.Deferred().resolve().then( jQuery.noop ).done(function( value ) {
  108
+		strictEqual( value, undefined, "then done callback can return undefined/null" );
105 109
 	});
106 110
 });
107 111
 
108  
-test( "jQuery.Deferred.pipe - filtering (fail)", function() {
  112
+test( "jQuery.Deferred.then - filtering (fail)", function() {
109 113
 
110 114
 	expect(4);
111 115
 
112 116
 	var defer = jQuery.Deferred(),
113  
-		piped = defer.pipe( null, function( a, b ) {
  117
+		piped = defer.then( null, function( a, b ) {
114 118
 			return a * b;
115 119
 		} ),
116 120
 		value1,
@@ -132,21 +136,21 @@ test( "jQuery.Deferred.pipe - filtering (fail)", function() {
132 136
 	strictEqual( value2, 3, "second reject value ok" );
133 137
 	strictEqual( value3, 6, "result of filter ok" );
134 138
 
135  
-	jQuery.Deferred().resolve().pipe( null, function() {
136  
-		ok( false, "pipe should not be called on resolve" );
  139
+	jQuery.Deferred().resolve().then( null, function() {
  140
+		ok( false, "then should not be called on resolve" );
137 141
 	} );
138 142
 
139  
-	jQuery.Deferred().reject().pipe( null, jQuery.noop ).fail(function( value ) {
140  
-		strictEqual( value, undefined, "pipe fail callback can return undefined/null" );
  143
+	jQuery.Deferred().reject().then( null, jQuery.noop ).fail(function( value ) {
  144
+		strictEqual( value, undefined, "then fail callback can return undefined/null" );
141 145
 	});
142 146
 });
143 147
 
144  
-test( "jQuery.Deferred.pipe - filtering (progress)", function() {
  148
+test( "jQuery.Deferred.then - filtering (progress)", function() {
145 149
 
146 150
 	expect(3);
147 151
 
148 152
 	var defer = jQuery.Deferred(),
149  
-		piped = defer.pipe( null, null, function( a, b ) {
  153
+		piped = defer.then( null, null, function( a, b ) {
150 154
 			return a * b;
151 155
 		} ),
152 156
 		value1,
@@ -169,12 +173,12 @@ test( "jQuery.Deferred.pipe - filtering (progress)", function() {
169 173
 	strictEqual( value3, 6, "result of filter ok" );
170 174
 });
171 175
 
172  
-test( "jQuery.Deferred.pipe - deferred (done)", function() {
  176
+test( "jQuery.Deferred.then - deferred (done)", function() {
173 177
 
174 178
 	expect(3);
175 179
 
176 180
 	var defer = jQuery.Deferred(),
177  
-		piped = defer.pipe(function( a, b ) {
  181
+		piped = defer.then(function( a, b ) {
178 182
 			return jQuery.Deferred(function( defer ) {
179 183
 				defer.reject( a * b );
180 184
 			});
@@ -199,12 +203,12 @@ test( "jQuery.Deferred.pipe - deferred (done)", function() {
199 203
 	strictEqual( value3, 6, "result of filter ok" );
200 204
 });
201 205
 
202  
-test( "jQuery.Deferred.pipe - deferred (fail)", function() {
  206
+test( "jQuery.Deferred.then - deferred (fail)", function() {
203 207
 
204 208
 	expect(3);
205 209
 
206 210
 	var defer = jQuery.Deferred(),
207  
-		piped = defer.pipe( null, function( a, b ) {
  211
+		piped = defer.then( null, function( a, b ) {
208 212
 			return jQuery.Deferred(function( defer ) {
209 213
 				defer.resolve( a * b );
210 214
 			});
@@ -229,12 +233,12 @@ test( "jQuery.Deferred.pipe - deferred (fail)", function() {
229 233
 	strictEqual( value3, 6, "result of filter ok" );
230 234
 });
231 235
 
232  
-test( "jQuery.Deferred.pipe - deferred (progress)", function() {
  236
+test( "jQuery.Deferred.then - deferred (progress)", function() {
233 237
 
234 238
 	expect(3);
235 239
 
236 240
 	var defer = jQuery.Deferred(),
237  
-		piped = defer.pipe( null, null, function( a, b ) {
  241
+		piped = defer.then( null, null, function( a, b ) {
238 242
 			return jQuery.Deferred(function( defer ) {
239 243
 				defer.resolve( a * b );
240 244
 			});
@@ -259,13 +263,13 @@ test( "jQuery.Deferred.pipe - deferred (progress)", function() {
259 263
 	strictEqual( value3, 6, "result of filter ok" );
260 264
 });
261 265
 
262  
-test( "jQuery.Deferred.pipe - context", function() {
  266
+test( "jQuery.Deferred.then - context", function() {
263 267
 
264 268
 	expect(4);
265 269
 
266 270
 	var context = {};
267 271
 
268  
-	jQuery.Deferred().resolveWith( context, [ 2 ] ).pipe(function( value ) {
  272
+	jQuery.Deferred().resolveWith( context, [ 2 ] ).then(function( value ) {
269 273
 		return value * 3;
270 274
 	}).done(function( value ) {
271 275
 		strictEqual( this, context, "custom context correctly propagated" );
@@ -273,7 +277,7 @@ test( "jQuery.Deferred.pipe - context", function() {
273 277
 	});
274 278
 
275 279
 	var defer = jQuery.Deferred(),
276  
-		piped = defer.pipe(function( value ) {
  280
+		piped = defer.then(function( value ) {
277 281
 			return value * 3;
278 282
 		});
279 283
 
24  test/unit/support.js
@@ -98,10 +98,6 @@ if ( /chrome\/16\.0/i.test(userAgent) ) {
98 98
 			"reliableHiddenOffsets":true,
99 99
 			"ajax":true,
100 100
 			"cors":true,
101  
-			"doesNotAddBorder":true,
102  
-			"doesAddBorderForTableAndCells":false,
103  
-			"fixedPosition":true,
104  
-			"subtractsBorderForOverflowNotVisible":false,
105 101
 			"doesNotIncludeMarginInBodyOffset":true
106 102
 		};
107 103
 		for ( i in expected ) {
@@ -141,10 +137,6 @@ if ( /chrome\/16\.0/i.test(userAgent) ) {
141 137
 			"reliableHiddenOffsets":false,
142 138
 			"ajax":true,
143 139
 			"cors":false,
144  
-			"doesNotAddBorder":false,
145  
-			"doesAddBorderForTableAndCells":true,
146  
-			"fixedPosition":true,
147  
-			"subtractsBorderForOverflowNotVisible":false,
148 140
 			"doesNotIncludeMarginInBodyOffset":true
149 141
 		};
150 142
 		for ( i in expected ) {
@@ -164,11 +156,8 @@ if ( /chrome\/16\.0/i.test(userAgent) ) {
164 156
 			"cors": false,
165 157
 			"cssFloat": false,
166 158
 			"deleteExpando": false,
167  
-			"doesAddBorderForTableAndCells": true,
168  
-			"doesNotAddBorder": true,
169 159
 			"doesNotIncludeMarginInBodyOffset": true,
170 160
 			"enctype": true,
171  
-			"fixedPosition": true,
172 161
 			"focusinBubbles": true,
173 162
 			"getSetAttribute": false,
174 163
 			"hrefNormalized": false,
@@ -186,7 +175,6 @@ if ( /chrome\/16\.0/i.test(userAgent) ) {
186 175
 			"reliableMarginRight": true,
187 176
 			"shrinkWrapBlocks": false,
188 177
 			"submitBubbles": false,
189  
-			"subtractsBorderForOverflowNotVisible": false,
190 178
 			"tbody": false,
191 179
 			"style": false
192 180
 		};
@@ -227,10 +215,6 @@ if ( /chrome\/16\.0/i.test(userAgent) ) {
227 215
 			"reliableHiddenOffsets":false,
228 216
 			"ajax":true,
229 217
 			"cors":false,
230  
-			"doesNotAddBorder":true,
231  
-			"doesAddBorderForTableAndCells":true,
232  
-			"fixedPosition":false,
233  
-			"subtractsBorderForOverflowNotVisible":false,
234 218
 			"doesNotIncludeMarginInBodyOffset":true
235 219
 		};
236 220
 		for ( i in expected ) {
@@ -270,10 +254,6 @@ if ( /chrome\/16\.0/i.test(userAgent) ) {
270 254
 			"reliableHiddenOffsets":true,
271 255
 			"ajax":true,
272 256
 			"cors":true,
273  
-			"doesNotAddBorder":true,
274  
-			"doesAddBorderForTableAndCells":false,
275  
-			"fixedPosition":true,
276  
-			"subtractsBorderForOverflowNotVisible":false,
277 257
 			"doesNotIncludeMarginInBodyOffset":true
278 258
 		};
279 259
 		for ( i in expected ) {
@@ -313,10 +293,6 @@ if ( /chrome\/16\.0/i.test(userAgent) ) {
313 293
 			"reliableHiddenOffsets":true,
314 294
 			"ajax":true,
315 295
 			"cors":true,
316  
-			"doesNotAddBorder":true,
317  
-			"doesAddBorderForTableAndCells":true,
318  
-			"fixedPosition":true,
319  
-			"subtractsBorderForOverflowNotVisible":false,
320 296
 			"doesNotIncludeMarginInBodyOffset":true
321 297
 		};
322 298
 		for ( i in expected ) {
Commit_comment_tip

Tip: You can add notes to lines in a file. Hover to the left of a line to make a note

Something went wrong with that request. Please try again.