rbracket = /\[\]$/,
rCRLF = /\r?\n/g,
rhash = /#.*$/,
- rheaders = /^(.*?):\s*(.*?)\r?$/mg, // IE leaves an \r character at EOL
+ rheaders = /^(.*?):[ \t]*([^\r\n]*)\r?$/mg, // IE leaves an \r character at EOL
rinput = /^(?:color|date|datetime|email|hidden|month|number|password|range|search|tel|text|time|url|week)$/i,
+ // #7653, #8125, #8152: local protocol detection
+ rlocalProtocol = /^(?:about|app|app\-storage|.+\-extension|file|widget):$/,
rnoContent = /^(?:GET|HEAD)$/,
rprotocol = /^\/\//,
rquery = /\?/,
rselectTextarea = /^(?:select|textarea)/i,
rspacesAjax = /\s+/,
rts = /([?&])_=[^&]*/,
- rurl = /^(\w+:)\/\/([^\/?#:]+)(?::(\d+))?/,
+ rucHeaders = /(^|\-)([a-z])/g,
+ rucHeadersFunc = function( _, $1, $2 ) {
+ return $1 + $2.toUpperCase();
+ },
+ rurl = /^([\w\+\.\-]+:)(?:\/\/([^\/?#:]*)(?::(\d+))?)?/,
// Keep a copy of the old load method
_load = jQuery.fn.load,
* 2) the catchall symbol "*" can be used
* 3) selection will start with transport dataType and THEN go to "*" if needed
*/
- transports = {};
+ transports = {},
+
+ // Document location
+ ajaxLocation,
+
+ // Document location segments
+ ajaxLocParts;
+
+// #8138, IE may throw an exception when accessing
+// a field from document.location if document.domain has been set
+try {
+ ajaxLocation = document.location.href;
+} catch( e ) {
+ // Use the href attribute of an A element
+ // since IE will modify it given document.location
+ ajaxLocation = document.createElement( "a" );
+ ajaxLocation.href = "";
+ ajaxLocation = ajaxLocation.href;
+}
+
+// Segment location into parts
+ajaxLocParts = rurl.exec( ajaxLocation.toLowerCase() ) || [];
// Base "constructor" for jQuery.ajaxPrefilter and jQuery.ajaxTransport
function addToPrefiltersOrTransports( structure ) {
}
if ( jQuery.isFunction( func ) ) {
- var dataTypes = dataTypeExpression.split( rspacesAjax ),
+ var dataTypes = dataTypeExpression.toLowerCase().split( rspacesAjax ),
i = 0,
length = dataTypes.length,
dataType,
// any existing element
placeBefore = /^\+/.test( dataType );
if ( placeBefore ) {
- dataType = dataType.substr( 1 );
+ dataType = dataType.substr( 1 ) || "*";
}
list = structure[ dataType ] = structure[ dataType ] || [];
// then we add to the structure accordingly
}
//Base inspection function for prefilters and transports
-function inspectPrefiltersOrTransports( structure, options, originalOptions,
+function inspectPrefiltersOrTransports( structure, options, originalOptions, jqXHR,
dataType /* internal */, inspected /* internal */ ) {
dataType = dataType || options.dataTypes[ 0 ];
selection;
for(; i < length && ( executeOnly || !selection ); i++ ) {
- selection = list[ i ]( options, originalOptions );
+ selection = list[ i ]( options, originalOptions, jqXHR );
// If we got redirected to another dataType
- // we try there if not done already
+ // we try there if executing only and not done already
if ( typeof selection === "string" ) {
- if ( inspected[ selection ] ) {
+ if ( !executeOnly || inspected[ selection ] ) {
selection = undefined;
} else {
options.dataTypes.unshift( selection );
selection = inspectPrefiltersOrTransports(
- structure, options, originalOptions, selection, inspected );
+ structure, options, originalOptions, jqXHR, selection, inspected );
}
}
}
// we try the catchall dataType if not done already
if ( ( executeOnly || !selection ) && !inspected[ "*" ] ) {
selection = inspectPrefiltersOrTransports(
- structure, options, originalOptions, "*", inspected );
+ structure, options, originalOptions, jqXHR, "*", inspected );
}
// unnecessary when only executing (prefilters)
// but it'll be ignored by the caller in that case
if ( jQuery.isFunction( params ) ) {
// We assume that it's the callback
callback = params;
- params = null;
+ params = undefined;
// Otherwise, build a param string
} else if ( typeof params === "object" ) {
dataType: "html",
data: params,
// Complete callback (responseText is used internally)
- complete: function( jXHR, status, responseText ) {
- // Store the response as specified by the jXHR object
- responseText = jXHR.responseText;
+ complete: function( jqXHR, status, responseText ) {
+ // Store the response as specified by the jqXHR object
+ responseText = jqXHR.responseText;
// If successful, inject the HTML into all the matched elements
- if ( jXHR.isResolved() ) {
+ if ( jqXHR.isResolved() ) {
// #4825: Get the actual response in case
// a dataFilter is present in ajaxSettings
- jXHR.done(function( r ) {
+ jqXHR.done(function( r ) {
responseText = r;
});
// See if a selector was specified
}
if ( callback ) {
- self.each( callback, [ responseText, status, jXHR ] );
+ self.each( callback, [ responseText, status, jqXHR ] );
}
}
});
if ( jQuery.isFunction( data ) ) {
type = type || callback;
callback = data;
- data = null;
+ data = undefined;
}
return jQuery.ajax({
jQuery.extend({
getScript: function( url, callback ) {
- return jQuery.get( url, null, callback, "script" );
+ return jQuery.get( url, undefined, callback, "script" );
},
getJSON: function( url, data, callback ) {
return jQuery.get( url, data, callback, "json" );
},
- ajaxSetup: function( settings ) {
- jQuery.extend( true, jQuery.ajaxSettings, settings );
- if ( settings.context ) {
- jQuery.ajaxSettings.context = settings.context;
+ // Creates a full fledged settings object into target
+ // with both ajaxSettings and settings fields.
+ // If target is omitted, writes into ajaxSettings.
+ ajaxSetup: function ( target, settings ) {
+ if ( !settings ) {
+ // Only one parameter, we extend ajaxSettings
+ settings = target;
+ target = jQuery.extend( true, jQuery.ajaxSettings, settings );
+ } else {
+ // target was provided, we extend into it
+ jQuery.extend( true, target, jQuery.ajaxSettings, settings );
}
+ // Flatten fields we don't want deep extended
+ for( var field in { context: 1, url: 1 } ) {
+ if ( field in settings ) {
+ target[ field ] = settings[ field ];
+ } else if( field in jQuery.ajaxSettings ) {
+ target[ field ] = jQuery.ajaxSettings[ field ];
+ }
+ }
+ return target;
},
ajaxSettings: {
- url: location.href,
+ url: ajaxLocation,
+ isLocal: rlocalProtocol.test( ajaxLocParts[ 1 ] ),
global: true,
type: "GET",
contentType: "application/x-www-form-urlencoded",
// Main method
ajax: function( url, options ) {
- // If options is not an object,
- // we simulate pre-1.5 signature
- if ( typeof options !== "object" ) {
+ // If url is an object, simulate pre-1.5 signature
+ if ( typeof url === "object" ) {
options = url;
url = undefined;
}
options = options || {};
var // Create the final options object
- s = jQuery.extend( true, {}, jQuery.ajaxSettings, options ),
- // Callbacks contexts
- // We force the original context if it exists
- // or take it from jQuery.ajaxSettings otherwise
- // (plain objects used as context get extended)
- callbackContext =
- ( s.context = ( "context" in options ? options : jQuery.ajaxSettings ).context ) || s,
- globalEventContext = callbackContext === s ? jQuery.event : jQuery( callbackContext ),
+ s = jQuery.ajaxSetup( {}, options ),
+ // Callbacks context
+ callbackContext = s.context || s,
+ // Context for global events
+ // It's the callbackContext if one was provided in the options
+ // and if it's a DOM node or a jQuery collection
+ globalEventContext = callbackContext !== s &&
+ ( callbackContext.nodeType || callbackContext instanceof jQuery ) ?
+ jQuery( callbackContext ) : jQuery.event,
// Deferreds
deferred = jQuery.Deferred(),
completeDeferred = jQuery._Deferred(),
// Status-dependent callbacks
statusCode = s.statusCode || {},
+ // ifModified key
+ ifModifiedKey,
// Headers (they are sent all at once)
requestHeaders = {},
// Response headers
// timeout handle
timeoutTimer,
// Cross-domain detection vars
- loc = document.location,
- protocol = loc.protocol || "http:",
parts,
- // The jXHR state
+ // The jqXHR state
state = 0,
+ // To know if global events are to be dispatched
+ fireGlobals,
// Loop variable
i,
// Fake xhr
- jXHR = {
+ jqXHR = {
readyState: 0,
// Caches the header
setRequestHeader: function( name, value ) {
- if ( state === 0 ) {
- requestHeaders[ name.toLowerCase() ] = value;
+ if ( !state ) {
+ requestHeaders[ name.toLowerCase().replace( rucHeaders, rucHeadersFunc ) ] = value;
}
return this;
},
}
match = responseHeaders[ key.toLowerCase() ];
}
- return match || null;
+ return match === undefined ? null : match;
+ },
+
+ // Overrides response content-type header
+ overrideMimeType: function( type ) {
+ if ( !state ) {
+ s.mimeType = type;
+ }
+ return this;
},
// Cancel the request
// Callback for when everything is done
// It is defined here because jslint complains if it is declared
// at the end of the function (which would be more logical and readable)
- function done( status, statusText, responses, headers) {
+ function done( status, statusText, responses, headers ) {
// Called once
if ( state === 2 ) {
}
// Dereference transport for early garbage collection
- // (no matter how long the jXHR object will be used)
+ // (no matter how long the jqXHR object will be used)
transport = undefined;
// Cache response headers
responseHeadersString = headers || "";
// Set readyState
- jXHR.readyState = status ? 4 : 0;
+ jqXHR.readyState = status ? 4 : 0;
var isSuccess,
success,
error,
- response = responses ? ajaxHandleResponses( s, jXHR, responses ) : undefined,
+ response = responses ? ajaxHandleResponses( s, jqXHR, responses ) : undefined,
lastModified,
etag;
// Set the If-Modified-Since and/or If-None-Match header, if in ifModified mode.
if ( s.ifModified ) {
- if ( ( lastModified = jXHR.getResponseHeader( "Last-Modified" ) ) ) {
- jQuery.lastModified[ s.url ] = lastModified;
+ if ( ( lastModified = jqXHR.getResponseHeader( "Last-Modified" ) ) ) {
+ jQuery.lastModified[ ifModifiedKey ] = lastModified;
}
- if ( ( etag = jXHR.getResponseHeader( "Etag" ) ) ) {
- jQuery.etag[ s.url ] = etag;
+ if ( ( etag = jqXHR.getResponseHeader( "Etag" ) ) ) {
+ jQuery.etag[ ifModifiedKey ] = etag;
}
}
} catch(e) {
// We have a parsererror
statusText = "parsererror";
- error = "" + e;
+ error = e;
}
}
} else {
// We extract error from statusText
// then normalize statusText and status for non-aborts
error = statusText;
- if( status ) {
+ if( !statusText || status ) {
statusText = "error";
if ( status < 0 ) {
status = 0;
}
// Set data for the fake xhr object
- jXHR.status = status;
- jXHR.statusText = statusText;
+ jqXHR.status = status;
+ jqXHR.statusText = statusText;
// Success/Error
if ( isSuccess ) {
- deferred.resolveWith( callbackContext, [ success, statusText, jXHR ] );
+ deferred.resolveWith( callbackContext, [ success, statusText, jqXHR ] );
} else {
- deferred.rejectWith( callbackContext, [ jXHR, statusText, error ] );
+ deferred.rejectWith( callbackContext, [ jqXHR, statusText, error ] );
}
// Status-dependent callbacks
- jXHR.statusCode( statusCode );
+ jqXHR.statusCode( statusCode );
statusCode = undefined;
- if ( s.global ) {
+ if ( fireGlobals ) {
globalEventContext.trigger( "ajax" + ( isSuccess ? "Success" : "Error" ),
- [ jXHR, s, isSuccess ? success : error ] );
+ [ jqXHR, s, isSuccess ? success : error ] );
}
// Complete
- completeDeferred.resolveWith( callbackContext, [ jXHR, statusText ] );
+ completeDeferred.resolveWith( callbackContext, [ jqXHR, statusText ] );
- if ( s.global ) {
- globalEventContext.trigger( "ajaxComplete", [ jXHR, s] );
+ if ( fireGlobals ) {
+ globalEventContext.trigger( "ajaxComplete", [ jqXHR, s] );
// Handle the global AJAX counter
if ( !( --jQuery.active ) ) {
jQuery.event.trigger( "ajaxStop" );
}
// Attach deferreds
- deferred.promise( jXHR );
- jXHR.success = jXHR.done;
- jXHR.error = jXHR.fail;
- jXHR.complete = completeDeferred.done;
+ deferred.promise( jqXHR );
+ jqXHR.success = jqXHR.done;
+ jqXHR.error = jqXHR.fail;
+ jqXHR.complete = completeDeferred.done;
// Status-dependent callbacks
- jXHR.statusCode = function( map ) {
+ jqXHR.statusCode = function( map ) {
if ( map ) {
var tmp;
if ( state < 2 ) {
statusCode[ tmp ] = [ statusCode[tmp], map[tmp] ];
}
} else {
- tmp = map[ jXHR.status ];
- jXHR.then( tmp, tmp );
+ tmp = map[ jqXHR.status ];
+ jqXHR.then( tmp, tmp );
}
}
return this;
};
// Remove hash character (#7531: and string promotion)
- // Add protocol if not provided (#5856: IE7 issue with protocol-less urls)
+ // Add protocol if not provided (#5866: IE7 issue with protocol-less urls)
// We also use the url parameter if available
- s.url = ( "" + ( url || s.url ) ).replace( rhash, "" ).replace( rprotocol, protocol + "//" );
+ s.url = ( ( url || s.url ) + "" ).replace( rhash, "" ).replace( rprotocol, ajaxLocParts[ 1 ] + "//" );
// Extract dataTypes list
s.dataTypes = jQuery.trim( s.dataType || "*" ).toLowerCase().split( rspacesAjax );
if ( !s.crossDomain ) {
parts = rurl.exec( s.url.toLowerCase() );
s.crossDomain = !!( parts &&
- ( parts[ 1 ] != protocol || parts[ 2 ] != loc.hostname ||
+ ( parts[ 1 ] != ajaxLocParts[ 1 ] || parts[ 2 ] != ajaxLocParts[ 2 ] ||
( parts[ 3 ] || ( parts[ 1 ] === "http:" ? 80 : 443 ) ) !=
- ( loc.port || ( protocol === "http:" ? 80 : 443 ) ) )
+ ( ajaxLocParts[ 3 ] || ( ajaxLocParts[ 1 ] === "http:" ? 80 : 443 ) ) )
);
}
}
// Apply prefilters
- inspectPrefiltersOrTransports( prefilters, s, options );
+ inspectPrefiltersOrTransports( prefilters, s, options, jqXHR );
+
+ // If request was aborted inside a prefiler, stop there
+ if ( state === 2 ) {
+ return false;
+ }
+
+ // We can fire global events as of now if asked to
+ fireGlobals = s.global;
// Uppercase the type
s.type = s.type.toUpperCase();
s.hasContent = !rnoContent.test( s.type );
// Watch for a new set of requests
- if ( s.global && jQuery.active++ === 0 ) {
+ if ( fireGlobals && jQuery.active++ === 0 ) {
jQuery.event.trigger( "ajaxStart" );
}
s.url += ( rquery.test( s.url ) ? "&" : "?" ) + s.data;
}
+ // Get ifModifiedKey before adding the anti-cache parameter
+ ifModifiedKey = s.url;
+
// Add anti-cache in url if needed
if ( s.cache === false ) {
// Set the correct header, if data is being sent
if ( s.data && s.hasContent && s.contentType !== false || options.contentType ) {
- requestHeaders[ "content-type" ] = s.contentType;
+ requestHeaders[ "Content-Type" ] = s.contentType;
}
// Set the If-Modified-Since and/or If-None-Match header, if in ifModified mode.
if ( s.ifModified ) {
- if ( jQuery.lastModified[ s.url ] ) {
- requestHeaders[ "if-modified-since" ] = jQuery.lastModified[ s.url ];
+ ifModifiedKey = ifModifiedKey || s.url;
+ if ( jQuery.lastModified[ ifModifiedKey ] ) {
+ requestHeaders[ "If-Modified-Since" ] = jQuery.lastModified[ ifModifiedKey ];
}
- if ( jQuery.etag[ s.url ] ) {
- requestHeaders[ "if-none-match" ] = jQuery.etag[ s.url ];
+ if ( jQuery.etag[ ifModifiedKey ] ) {
+ requestHeaders[ "If-None-Match" ] = jQuery.etag[ ifModifiedKey ];
}
}
// Set the Accepts header for the server, depending on the dataType
- requestHeaders.accept = s.dataTypes[ 0 ] && s.accepts[ s.dataTypes[0] ] ?
+ requestHeaders.Accept = s.dataTypes[ 0 ] && s.accepts[ s.dataTypes[0] ] ?
s.accepts[ s.dataTypes[0] ] + ( s.dataTypes[ 0 ] !== "*" ? ", */*; q=0.01" : "" ) :
s.accepts[ "*" ];
// Check for headers option
for ( i in s.headers ) {
- requestHeaders[ i.toLowerCase() ] = s.headers[ i ];
+ jqXHR.setRequestHeader( i, s.headers[ i ] );
}
// Allow custom headers/mimetypes and early abort
- if ( s.beforeSend && ( s.beforeSend.call( callbackContext, jXHR, s ) === false || state === 2 ) ) {
+ if ( s.beforeSend && ( s.beforeSend.call( callbackContext, jqXHR, s ) === false || state === 2 ) ) {
// Abort if not done already
- done( 0, "abort" );
- // Return false
- jXHR = false;
+ jqXHR.abort();
+ return false;
- } else {
+ }
- // Install callbacks on deferreds
- for ( i in { success: 1, error: 1, complete: 1 } ) {
- jXHR[ i ]( s[ i ] );
- }
+ // Install callbacks on deferreds
+ for ( i in { success: 1, error: 1, complete: 1 } ) {
+ jqXHR[ i ]( s[ i ] );
+ }
- // Get transport
- transport = inspectPrefiltersOrTransports( transports, s, options );
+ // Get transport
+ transport = inspectPrefiltersOrTransports( transports, s, options, jqXHR );
- // If no transport, we auto-abort
- if ( !transport ) {
- done( -1, "No Transport" );
- } else {
- // Set state as sending
- state = jXHR.readyState = 1;
- // Send global event
- if ( s.global ) {
- globalEventContext.trigger( "ajaxSend", [ jXHR, s ] );
- }
- // Timeout
- if ( s.async && s.timeout > 0 ) {
- timeoutTimer = setTimeout( function(){
- jXHR.abort( "timeout" );
- }, s.timeout );
- }
+ // If no transport, we auto-abort
+ if ( !transport ) {
+ done( -1, "No Transport" );
+ } else {
+ jqXHR.readyState = 1;
+ // Send global event
+ if ( fireGlobals ) {
+ globalEventContext.trigger( "ajaxSend", [ jqXHR, s ] );
+ }
+ // Timeout
+ if ( s.async && s.timeout > 0 ) {
+ timeoutTimer = setTimeout( function(){
+ jqXHR.abort( "timeout" );
+ }, s.timeout );
+ }
- try {
- transport.send( requestHeaders, done );
- } catch (e) {
- // Propagate exception as error if not done
- if ( status < 2 ) {
- done( -1, "" + e );
- // Simply rethrow otherwise
- } else {
- jQuery.error( e );
- }
+ try {
+ state = 1;
+ transport.send( requestHeaders, done );
+ } catch (e) {
+ // Propagate exception as error if not done
+ if ( status < 2 ) {
+ done( -1, e );
+ // Simply rethrow otherwise
+ } else {
+ jQuery.error( e );
}
}
}
- return jXHR;
+
+ return jqXHR;
},
// Serialize an array of form elements or a set of
}
// If an array was passed in, assume that it is an array of form elements.
- if ( jQuery.isArray( a ) || a.jquery ) {
+ if ( jQuery.isArray( a ) || ( a.jquery && !jQuery.isPlainObject( a ) ) ) {
// Serialize the form elements
jQuery.each( a, function() {
add( this.name, this.value );
// Serialize object item.
} else {
- jQuery.each( obj, function( k, v ) {
- buildParams( prefix + "[" + k + "]", v, traditional, add );
- });
+ for ( var name in obj ) {
+ buildParams( prefix + "[" + name + "]", obj[ name ], traditional, add );
+ }
}
} else {
* - finds the right dataType (mediates between content-type and expected dataType)
* - returns the corresponding response
*/
-function ajaxHandleResponses( s, jXHR, responses ) {
+function ajaxHandleResponses( s, jqXHR, responses ) {
var contents = s.contents,
dataTypes = s.dataTypes,
// Fill responseXXX fields
for( type in responseFields ) {
if ( type in responses ) {
- jXHR[ responseFields[type] ] = responses[ type ];
+ jqXHR[ responseFields[type] ] = responses[ type ];
}
}
while( dataTypes[ 0 ] === "*" ) {
dataTypes.shift();
if ( ct === undefined ) {
- ct = jXHR.getResponseHeader( "content-type" );
+ ct = s.mimeType || jqXHR.getResponseHeader( "content-type" );
}
}
}
var dataTypes = s.dataTypes,
- converters = s.converters,
+ converters = {},
i,
+ key,
length = dataTypes.length,
tmp,
// Current and previous dataTypes
conversion,
// Conversion function
conv,
- // Conversion functions (when text is used in-between)
+ // Conversion functions (transitive conversion)
conv1,
conv2;
// For each dataType in the chain
for( i = 1; i < length; i++ ) {
+ // Create converters map
+ // with lowercased keys
+ if ( i === 1 ) {
+ for( key in s.converters ) {
+ if( typeof key === "string" ) {
+ converters[ key.toLowerCase() ] = s.converters[ key ];
+ }
+ }
+ }
+
// Get the dataTypes
prev = current;
current = dataTypes[ i ];