From e077ffb083743f4a4b990f586c9d25d787e7b417 Mon Sep 17 00:00:00 2001 From: Dave Methvin Date: Sun, 15 Nov 2015 21:51:18 -0500 Subject: [PATCH] Ajax: Preserve URL hash on requests Fixes gh-1732 Closes gh-2721 --- src/ajax.js | 28 ++++++++++++++++------------ test/unit/ajax.js | 22 ++++++++++++++++++---- 2 files changed, 34 insertions(+), 16 deletions(-) diff --git a/src/ajax.js b/src/ajax.js index 27abe375e..195a30a20 100644 --- a/src/ajax.js +++ b/src/ajax.js @@ -415,6 +415,9 @@ jQuery.extend( { // Loop variable i, + // uncached part of the url + uncached, + // Create the final options object s = jQuery.ajaxSetup( {}, options ), @@ -516,11 +519,10 @@ jQuery.extend( { // Attach deferreds deferred.promise( jqXHR ); - // Remove hash character (#7531: and string promotion) // Add protocol if not provided (prefilters might expect it) // Handle falsy url in the settings object (#10093: consistency with old signature) // We also use the url parameter if available - s.url = ( ( url || s.url || location.href ) + "" ).replace( rhash, "" ) + s.url = ( ( url || s.url || location.href ) + "" ) .replace( rprotocol, location.protocol + "//" ); // Alias method option to type as per ticket #12004 @@ -581,30 +583,32 @@ jQuery.extend( { // Save the URL in case we're toying with the If-Modified-Since // and/or If-None-Match header later on - cacheURL = s.url; + // Remove hash to simplify url manipulation + cacheURL = s.url.replace( rhash, "" ); // More options handling for requests with no content if ( !s.hasContent ) { + // Remember the hash so we can put it back + uncached = s.url.slice( cacheURL.length ); + // If data is available, append data to url if ( s.data ) { - cacheURL = ( s.url += ( rquery.test( cacheURL ) ? "&" : "?" ) + s.data ); + cacheURL += ( rquery.test( cacheURL ) ? "&" : "?" ) + s.data; // #9682: remove data so that it's not used in an eventual retry delete s.data; } - // Add anti-cache in url if needed + // Add anti-cache in uncached url if needed if ( s.cache === false ) { - s.url = rts.test( cacheURL ) ? - - // If there is already a '_' parameter, set its value - cacheURL.replace( rts, "$1_=" + nonce++ ) : - - // Otherwise add one to the end - cacheURL + ( rquery.test( cacheURL ) ? "&" : "?" ) + "_=" + nonce++; + cacheURL = cacheURL.replace( rts, "" ); + uncached = ( rquery.test( cacheURL ) ? "&" : "?" ) + "_=" + ( nonce++ ) + uncached; } + // Put hash and anti-cache on the URL that will be requested (gh-1732) + s.url = cacheURL + uncached; + // Change '%20' to '+' if this is encoded form body content (gh-2658) } else if ( s.data && s.processData && ( s.contentType || "" ).indexOf( "application/x-www-form-urlencoded" ) === 0 ) { diff --git a/test/unit/ajax.js b/test/unit/ajax.js index 12bf2ab31..f468f44a8 100644 --- a/test/unit/ajax.js +++ b/test/unit/ajax.js @@ -328,12 +328,12 @@ QUnit.module( "ajax", { }; } ); - ajaxTest( "jQuery.ajax() - hash", 3, function( assert ) { + ajaxTest( "jQuery.ajax() - hash", 4, function( assert ) { return [ { url: "data/name.html#foo", beforeSend: function( xhr, settings ) { - assert.equal( settings.url, "data/name.html", "Make sure that the URL is trimmed." ); + assert.equal( settings.url, "data/name.html#foo", "Make sure that the URL has its hash." ); return false; }, error: true @@ -341,7 +341,7 @@ QUnit.module( "ajax", { { url: "data/name.html?abc#foo", beforeSend: function( xhr, settings ) { - assert.equal( settings.url, "data/name.html?abc", "Make sure that the URL is trimmed." ); + assert.equal( settings.url, "data/name.html?abc#foo", "Make sure that the URL has its hash." ); return false; }, error: true @@ -352,7 +352,21 @@ QUnit.module( "ajax", { "test": 123 }, beforeSend: function( xhr, settings ) { - assert.equal( settings.url, "data/name.html?abc&test=123", "Make sure that the URL is trimmed." ); + assert.equal( settings.url, "data/name.html?abc&test=123#foo", "Make sure that the URL has its hash." ); + return false; + }, + error: true + }, + { + url: "data/name.html?abc#brownies", + data: { + "devo": "hat" + }, + cache: false, + beforeSend: function( xhr, settings ) { + // Remove the random number, but ensure the cashe-buster param is there + var url = settings.url.replace( /\d+/, "" ); + assert.equal( url, "data/name.html?abc&devo=hat&_=#brownies", "Make sure that the URL has its hash." ); return false; }, error: true