diff options
author | Timmy Willison <timmywillisn@gmail.com> | 2015-11-02 12:00:28 -0500 |
---|---|---|
committer | Timmy Willison <timmywillisn@gmail.com> | 2015-11-03 12:34:04 -0500 |
commit | 76e9a95dbeaf28fbc5a64571ebb5959f91a9c14a (patch) | |
tree | da3d2a0b211ca3c30677a3116bc7dcad896cc2d9 | |
parent | 70605c8e5655da996ebd395e3c43423daaa08d9c (diff) | |
download | jquery-76e9a95dbeaf28fbc5a64571ebb5959f91a9c14a.tar.gz jquery-76e9a95dbeaf28fbc5a64571ebb5959f91a9c14a.zip |
Ajax: trigger error callback on native abort
- IE9 does not have onabort. Use onreadystatechange instead.
Fixes gh-2079
Close gh-2684
-rw-r--r-- | src/ajax/xhr.js | 49 | ||||
-rw-r--r-- | test/unit/ajax.js | 21 |
2 files changed, 61 insertions, 9 deletions
diff --git a/src/ajax/xhr.js b/src/ajax/xhr.js index 7ac141e64..fd4a733e5 100644 --- a/src/ajax/xhr.js +++ b/src/ajax/xhr.js @@ -25,7 +25,7 @@ support.cors = !!xhrSupported && ( "withCredentials" in xhrSupported ); support.ajax = xhrSupported = !!xhrSupported; jQuery.ajaxTransport( function( options ) { - var callback; + var callback, errorCallback; // Cross domain only allowed if supported through XMLHttpRequest if ( support.cors || xhrSupported && !options.crossDomain ) { @@ -72,17 +72,26 @@ jQuery.ajaxTransport( function( options ) { callback = function( type ) { return function() { if ( callback ) { - callback = xhr.onload = xhr.onerror = null; + callback = errorCallback = xhr.onload = + xhr.onerror = xhr.onabort = xhr.onreadystatechange = null; if ( type === "abort" ) { xhr.abort(); } else if ( type === "error" ) { - complete( - // File: protocol always yields status 0; see #8605, #14207 - xhr.status, - xhr.statusText - ); + // Support: IE9 + // On a manual native abort, IE9 throws + // errors on any property access that is not readyState + if ( typeof xhr.status !== "number" ) { + complete( 0, "error" ); + } else { + complete( + + // File: protocol always yields status 0; see #8605, #14207 + xhr.status, + xhr.statusText + ); + } } else { complete( xhrSuccessStatus[ xhr.status ] || xhr.status, @@ -103,7 +112,31 @@ jQuery.ajaxTransport( function( options ) { // Listen to events xhr.onload = callback(); - xhr.onerror = callback( "error" ); + errorCallback = xhr.onerror = callback( "error" ); + + // Support: IE9 + // Use onreadystatechange to replace onabort + // to handle uncaught aborts + if ( xhr.onabort !== undefined ) { + xhr.onabort = errorCallback; + } else { + xhr.onreadystatechange = function() { + + // Check readyState before timeout as it changes + if ( xhr.readyState === 4 ) { + + // Allow onerror to be called first, + // but that will not handle a native abort + // Also, save errorCallback to a variable + // as xhr.onerror cannot be accessed + window.setTimeout( function() { + if ( callback ) { + errorCallback(); + } + } ); + } + }; + } // Create the abort callback callback = callback( "abort" ); diff --git a/test/unit/ajax.js b/test/unit/ajax.js index 7710f9e35..4f0530656 100644 --- a/test/unit/ajax.js +++ b/test/unit/ajax.js @@ -38,7 +38,7 @@ QUnit.module( "ajax", { ); ajaxTest( "jQuery.ajax() - success callbacks", 8, function( assert ) { - return { + return { setup: addGlobalEvents( "ajaxStart ajaxStop ajaxSend ajaxComplete ajaxSuccess", assert ), url: url( "data/name.html" ), beforeSend: function() { @@ -437,6 +437,25 @@ QUnit.module( "ajax", { }; } ); + ajaxTest( "jQuery.ajax() - native abort", 2, function( assert ) { + return { + url: url( "data/name.php?wait=1" ), + xhr: function() { + var xhr = new window.XMLHttpRequest(); + setTimeout( function() { + xhr.abort(); + }, 100 ); + return xhr; + }, + error: function( xhr, msg ) { + assert.strictEqual( msg, "error", "Native abort triggers error callback" ); + }, + complete: function() { + assert.ok( true, "complete" ); + } + }; + } ); + ajaxTest( "jQuery.ajax() - events with context", 12, function( assert ) { var context = document.createElement( "div" ); |