Removed re-usability from jXHR object (no more open, send & onreadystatechange support). Streamlined the implementation and put it back into ajax.js (removed xhr.js in the process). Went back to a more simple & direct approach to options handling (keeping much room to further minification-related optimizations). Code is cleaner, smaller & faster. Removed & edited unit tests accordingly. All build files have had xhr.js removed.
This commit is contained in:
parent
6f53be1839
commit
981d1e08eb
1
Makefile
1
Makefile
|
@ -24,7 +24,6 @@ BASE_FILES = ${SRC_DIR}/core.js\
|
||||||
${SRC_DIR}/manipulation.js\
|
${SRC_DIR}/manipulation.js\
|
||||||
${SRC_DIR}/css.js\
|
${SRC_DIR}/css.js\
|
||||||
${SRC_DIR}/ajax.js\
|
${SRC_DIR}/ajax.js\
|
||||||
${SRC_DIR}/xhr.js\
|
|
||||||
${SRC_DIR}/transports/jsonp.js\
|
${SRC_DIR}/transports/jsonp.js\
|
||||||
${SRC_DIR}/transports/script.js\
|
${SRC_DIR}/transports/script.js\
|
||||||
${SRC_DIR}/transports/xhr.js\
|
${SRC_DIR}/transports/xhr.js\
|
||||||
|
|
1
Rakefile
1
Rakefile
|
@ -22,7 +22,6 @@ base_files = %w{
|
||||||
manipulation
|
manipulation
|
||||||
css
|
css
|
||||||
ajax
|
ajax
|
||||||
xhr
|
|
||||||
transports/jsonp
|
transports/jsonp
|
||||||
transports/script
|
transports/script
|
||||||
transports/xhr
|
transports/xhr
|
||||||
|
|
|
@ -63,7 +63,6 @@
|
||||||
<fileset file="src/manipulation.js" />
|
<fileset file="src/manipulation.js" />
|
||||||
<fileset file="src/css.js" />
|
<fileset file="src/css.js" />
|
||||||
<fileset file="src/ajax.js" />
|
<fileset file="src/ajax.js" />
|
||||||
<fileset file="src/xhr.js" />
|
|
||||||
<fileset file="src/transports/jsonp.js" />
|
<fileset file="src/transports/jsonp.js" />
|
||||||
<fileset file="src/transports/script.js" />
|
<fileset file="src/transports/script.js" />
|
||||||
<fileset file="src/transports/xhr.js" />
|
<fileset file="src/transports/xhr.js" />
|
||||||
|
|
582
src/ajax.js
582
src/ajax.js
|
@ -1,11 +1,19 @@
|
||||||
(function( jQuery ) {
|
(function( jQuery ) {
|
||||||
|
|
||||||
var rscript = /<script\b[^<]*(?:(?!<\/script>)<[^<]*)*<\/script>/gi,
|
var r20 = /%20/g,
|
||||||
rselectTextarea = /^(?:select|textarea)/i,
|
|
||||||
rinput = /^(?:color|date|datetime|email|hidden|month|number|password|range|search|tel|text|time|url|week)$/i,
|
|
||||||
rbracket = /\[\]$/,
|
rbracket = /\[\]$/,
|
||||||
|
rhash = /#.*$/,
|
||||||
|
rheaders = /^(.*?):\s*(.*?)\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,
|
||||||
|
rnoContent = /^(?:GET|HEAD)$/,
|
||||||
rquery = /\?/,
|
rquery = /\?/,
|
||||||
r20 = /%20/g,
|
rscript = /<script\b[^<]*(?:(?!<\/script>)<[^<]*)*<\/script>/gi,
|
||||||
|
rselectTextarea = /^(?:select|textarea)/i,
|
||||||
|
rts = /([?&])_=[^&]*/,
|
||||||
|
rurl = /^(\w+:)?\/\/([^\/?#]+)/,
|
||||||
|
|
||||||
|
// Slice function
|
||||||
|
sliceFunc = Array.prototype.slice,
|
||||||
|
|
||||||
// Keep a copy of the old load method
|
// Keep a copy of the old load method
|
||||||
_load = jQuery.fn.load;
|
_load = jQuery.fn.load;
|
||||||
|
@ -217,15 +225,407 @@ jQuery.extend({
|
||||||
},
|
},
|
||||||
|
|
||||||
// Main method
|
// Main method
|
||||||
ajax: function( url , s ) {
|
// (s is used internally)
|
||||||
|
ajax: function( url , options , s ) {
|
||||||
|
|
||||||
|
// Handle varargs
|
||||||
if ( arguments.length === 1 ) {
|
if ( arguments.length === 1 ) {
|
||||||
s = url;
|
options = url;
|
||||||
url = s ? s.url : undefined;
|
url = options ? options.url : undefined;
|
||||||
}
|
}
|
||||||
|
|
||||||
return jQuery.xhr().open( s ? s.type : undefined , url ).send( undefined , s );
|
// Force options to be an object
|
||||||
|
options = options || {};
|
||||||
|
|
||||||
|
// Get the url if provided separately
|
||||||
|
options.url = url || options.url;
|
||||||
|
|
||||||
|
// Create the final options object
|
||||||
|
s = jQuery.extend( true , {} , jQuery.ajaxSettings , options );
|
||||||
|
|
||||||
|
// We force the original context
|
||||||
|
// (plain objects used as context get extended)
|
||||||
|
s.context = options.context;
|
||||||
|
|
||||||
|
var // jQuery lists
|
||||||
|
jQuery_lastModified = jQuery.lastModified,
|
||||||
|
jQuery_etag = jQuery.etag,
|
||||||
|
// Callbacks contexts
|
||||||
|
callbackContext = s.context || s,
|
||||||
|
globalEventContext = s.context ? jQuery( s.context ) : jQuery.event,
|
||||||
|
// Deferreds
|
||||||
|
deferred = jQuery.Deferred(),
|
||||||
|
completeDeferred = jQuery._Deferred(),
|
||||||
|
// Headers (they are sent all at once)
|
||||||
|
requestHeaders = {},
|
||||||
|
// Response headers
|
||||||
|
responseHeadersString,
|
||||||
|
responseHeaders,
|
||||||
|
// transport
|
||||||
|
transport,
|
||||||
|
// timeout handle
|
||||||
|
timeoutTimer,
|
||||||
|
// The jXHR state
|
||||||
|
state = 0,
|
||||||
|
// Loop variable
|
||||||
|
i,
|
||||||
|
// Fake xhr
|
||||||
|
jXHR = {
|
||||||
|
|
||||||
|
readyState: 0,
|
||||||
|
|
||||||
|
// Caches the header
|
||||||
|
setRequestHeader: function(name,value) {
|
||||||
|
if ( state === 0 ) {
|
||||||
|
requestHeaders[ name.toLowerCase() ] = value;
|
||||||
|
}
|
||||||
|
return this;
|
||||||
|
},
|
||||||
|
|
||||||
|
// Raw string
|
||||||
|
getAllResponseHeaders: function() {
|
||||||
|
return state === 2 ? responseHeadersString : null;
|
||||||
|
},
|
||||||
|
|
||||||
|
// Builds headers hashtable if needed
|
||||||
|
// (match is used internally)
|
||||||
|
getResponseHeader: function( key , match ) {
|
||||||
|
|
||||||
|
if ( state !== 2 ) {
|
||||||
|
return null;
|
||||||
|
}
|
||||||
|
|
||||||
|
if ( responseHeaders === undefined ) {
|
||||||
|
|
||||||
|
responseHeaders = {};
|
||||||
|
|
||||||
|
if ( typeof responseHeadersString === "string" ) {
|
||||||
|
|
||||||
|
while( ( match = rheaders.exec( responseHeadersString ) ) ) {
|
||||||
|
responseHeaders[ match[ 1 ].toLowerCase() ] = match[ 2 ];
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return responseHeaders[ key.toLowerCase() ];
|
||||||
|
},
|
||||||
|
|
||||||
|
// Cancel the request
|
||||||
|
abort: function( statusText ) {
|
||||||
|
if ( transport && state !== 2 ) {
|
||||||
|
transport.abort( statusText || "abort" );
|
||||||
|
done( 0 , statusText );
|
||||||
|
}
|
||||||
|
return this;
|
||||||
|
}
|
||||||
|
};
|
||||||
|
|
||||||
|
// 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 , response , headers) {
|
||||||
|
|
||||||
|
// Called once
|
||||||
|
if ( state === 2 ) {
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
// State is "done" now
|
||||||
|
state = 2;
|
||||||
|
|
||||||
|
// Set readyState
|
||||||
|
jXHR.readyState = status ? 4 : 0;
|
||||||
|
|
||||||
|
// Cache response headers
|
||||||
|
responseHeadersString = headers || "";
|
||||||
|
|
||||||
|
// Clear timeout if it exists
|
||||||
|
if ( timeoutTimer ) {
|
||||||
|
clearTimeout(timeoutTimer);
|
||||||
|
}
|
||||||
|
|
||||||
|
var // Reference url
|
||||||
|
url = s.url,
|
||||||
|
// and ifModified status
|
||||||
|
ifModified = s.ifModified,
|
||||||
|
|
||||||
|
// Is it a success?
|
||||||
|
isSuccess = 0,
|
||||||
|
// Stored success
|
||||||
|
success,
|
||||||
|
// Stored error
|
||||||
|
error = statusText;
|
||||||
|
|
||||||
|
// If not timeout, force a jQuery-compliant status text
|
||||||
|
if ( statusText != "timeout" ) {
|
||||||
|
statusText = ( status >= 200 && status < 300 ) ?
|
||||||
|
"success" :
|
||||||
|
( status === 304 ? "notmodified" : "error" );
|
||||||
|
}
|
||||||
|
|
||||||
|
// If successful, handle type chaining
|
||||||
|
if ( statusText === "success" || statusText === "notmodified" ) {
|
||||||
|
|
||||||
|
// Set the If-Modified-Since and/or If-None-Match header, if in ifModified mode.
|
||||||
|
if ( s.ifModified ) {
|
||||||
|
|
||||||
|
var lastModified = jXHR.getResponseHeader("Last-Modified"),
|
||||||
|
etag = jXHR.getResponseHeader("Etag");
|
||||||
|
|
||||||
|
if (lastModified) {
|
||||||
|
jQuery_lastModified[ s.url ] = lastModified;
|
||||||
|
}
|
||||||
|
if (etag) {
|
||||||
|
jQuery_etag[ s.url ] = etag;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
if ( s.ifModified && statusText === "notmodified" ) {
|
||||||
|
|
||||||
|
success = null;
|
||||||
|
isSuccess = 1;
|
||||||
|
|
||||||
|
} else {
|
||||||
|
// Chain data conversions and determine the final value
|
||||||
|
// (if an exception is thrown in the process, it'll be notified as an error)
|
||||||
|
try {
|
||||||
|
|
||||||
|
var i,
|
||||||
|
current,
|
||||||
|
prev,
|
||||||
|
checker,
|
||||||
|
conv1,
|
||||||
|
conv2,
|
||||||
|
oneConv,
|
||||||
|
convertion,
|
||||||
|
dataTypes = s.dataTypes,
|
||||||
|
dataConverters = s.dataConverters,
|
||||||
|
responses = {
|
||||||
|
"xml": "XML",
|
||||||
|
"text": "Text"
|
||||||
|
};
|
||||||
|
|
||||||
|
for( i = 0 ; i < dataTypes.length ; i++ ) {
|
||||||
|
|
||||||
|
current = dataTypes[ i ];
|
||||||
|
|
||||||
|
if ( responses[ current ] ) {
|
||||||
|
jXHR[ "response" + responses[ current ] ] = response;
|
||||||
|
responses[ current ] = 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
if ( i ) {
|
||||||
|
|
||||||
|
if ( prev !== "*" && current !== "*" && prev !== current ) {
|
||||||
|
|
||||||
|
oneConv = conv1 =
|
||||||
|
dataConverters[ ( conversion = prev + " " + current ) ] ||
|
||||||
|
dataConverters[ "* " + current ];
|
||||||
|
|
||||||
|
if ( oneConv !== true ) {
|
||||||
|
|
||||||
|
if ( ! oneConv && prev !== "text" && current !== "text" ) {
|
||||||
|
conv1 = dataConverters[ prev + " text" ] || dataConverters[ "* text" ];
|
||||||
|
conv2 = dataConverters[ "text " + current ];
|
||||||
|
}
|
||||||
|
|
||||||
|
if ( oneConv || conv1 && conv2 ) {
|
||||||
|
response = oneConv ? conv1( response ) : conv2( conv1( response ) );
|
||||||
|
} else {
|
||||||
|
throw "no " + conversion;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
} else if ( s.dataFilter ) {
|
||||||
|
|
||||||
|
response = s.dataFilter( response );
|
||||||
|
dataTypes = s.dataTypes;
|
||||||
|
}
|
||||||
|
|
||||||
|
prev = current;
|
||||||
|
}
|
||||||
|
|
||||||
|
// We have a real success
|
||||||
|
success = response;
|
||||||
|
isSuccess = 1;
|
||||||
|
|
||||||
|
} catch(e) {
|
||||||
|
|
||||||
|
statusText = "parsererror";
|
||||||
|
error = "" + e;
|
||||||
|
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
} else { // if not success, mark it as an error
|
||||||
|
|
||||||
|
error = error || statusText;
|
||||||
|
}
|
||||||
|
|
||||||
|
// Set data for the fake xhr object
|
||||||
|
jXHR.status = status;
|
||||||
|
jXHR.statusText = statusText;
|
||||||
|
|
||||||
|
// Success/Error
|
||||||
|
if ( isSuccess ) {
|
||||||
|
deferred.fire( callbackContext , [ success , statusText , jXHR ] );
|
||||||
|
} else {
|
||||||
|
deferred.fireReject( callbackContext , [ jXHR , statusText , error ] );
|
||||||
|
}
|
||||||
|
|
||||||
|
if ( s.global ) {
|
||||||
|
globalEventContext.trigger( "ajax" + ( isSuccess ? "Success" : "Error" ) ,
|
||||||
|
[ jXHR , s , isSuccess ? success : error ] );
|
||||||
|
}
|
||||||
|
|
||||||
|
// Complete
|
||||||
|
completeDeferred.fire( callbackContext, [ jXHR , statusText ] );
|
||||||
|
|
||||||
|
if ( s.global ) {
|
||||||
|
globalEventContext.trigger( "ajaxComplete" , [ jXHR , s] );
|
||||||
|
// Handle the global AJAX counter
|
||||||
|
if ( ! --jQuery.active ) {
|
||||||
|
jQuery.event.trigger( "ajaxStop" );
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// Attach deferreds
|
||||||
|
jXHR.success = jXHR.then = deferred.then;
|
||||||
|
jXHR.error = jXHR.fail = deferred.fail;
|
||||||
|
jXHR.complete = completeDeferred.then;
|
||||||
|
|
||||||
|
// Remove hash character (#7531: and string promotion)
|
||||||
|
s.url = ( "" + s.url ).replace( rhash , "" );
|
||||||
|
|
||||||
|
// Uppercase the type
|
||||||
|
s.type = s.type.toUpperCase();
|
||||||
|
|
||||||
|
// Determine if request has content
|
||||||
|
s.hasContent = ! rnoContent.test( s.type );
|
||||||
|
|
||||||
|
// Extract dataTypes list
|
||||||
|
s.dataTypes = jQuery.trim( s.dataType || "*" ).toLowerCase().split( /\s+/ );
|
||||||
|
|
||||||
|
// Determine if a cross-domain request is in order
|
||||||
|
var parts = rurl.exec( s.url.toLowerCase() ),
|
||||||
|
loc = location;
|
||||||
|
s.crossDomain = !!( parts && ( parts[ 1 ] && parts[ 1 ] != loc.protocol || parts[ 2 ] != loc.host ) );
|
||||||
|
|
||||||
|
// Convert data if not already a string
|
||||||
|
if ( s.data && s.processData && typeof s.data != "string" ) {
|
||||||
|
s.data = jQuery.param( s.data , s.traditional );
|
||||||
|
}
|
||||||
|
|
||||||
|
// Watch for a new set of requests
|
||||||
|
if ( s.global && jQuery.active++ === 0 ) {
|
||||||
|
jQuery.event.trigger( "ajaxStart" );
|
||||||
|
}
|
||||||
|
|
||||||
|
// Get transport
|
||||||
|
transport = jQuery.ajax.prefilter( s ).transport( s );
|
||||||
|
|
||||||
|
// If no transport, we auto-abort
|
||||||
|
if ( ! transport ) {
|
||||||
|
|
||||||
|
done( 0 , "transport not found" );
|
||||||
|
jXHR = false;
|
||||||
|
|
||||||
|
} else {
|
||||||
|
|
||||||
|
// More options handling for requests with no content
|
||||||
|
if ( ! s.hasContent ) {
|
||||||
|
|
||||||
|
// If data is available, append data to url
|
||||||
|
if ( s.data ) {
|
||||||
|
s.url += ( rquery.test( s.url ) ? "&" : "?" ) + s.data;
|
||||||
|
}
|
||||||
|
|
||||||
|
// Add anti-cache in url if needed
|
||||||
|
if ( s.cache === false ) {
|
||||||
|
|
||||||
|
var ts = jQuery.now(),
|
||||||
|
// try replacing _= if it is there
|
||||||
|
ret = s.url.replace( rts , "$1_=" + ts );
|
||||||
|
|
||||||
|
// if nothing was replaced, add timestamp to the end
|
||||||
|
s.url = ret + ( (ret == s.url ) ? ( rquery.test( s.url ) ? "&" : "?" ) + "_=" + ts : "");
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// Set the correct header, if data is being sent
|
||||||
|
if ( ( s.data && s.hasContent ) || options.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 ];
|
||||||
|
}
|
||||||
|
if ( jQuery_etag[ s.url ] ) {
|
||||||
|
requestHeaders[ "if-none-match" ] = jQuery_etag[ s.url ];
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// Set the Accepts header for the server, depending on the dataType
|
||||||
|
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 ];
|
||||||
|
}
|
||||||
|
|
||||||
|
// Allow custom headers/mimetypes and early abort
|
||||||
|
if ( s.beforeSend && ( s.beforeSend.call( callbackContext , jXHR , s ) === false || state === 2 ) ) {
|
||||||
|
|
||||||
|
// Abort if not done already
|
||||||
|
done( 0 , "abort" );
|
||||||
|
jXHR = false;
|
||||||
|
|
||||||
|
} else {
|
||||||
|
|
||||||
|
// Set state as sending
|
||||||
|
state = 1;
|
||||||
|
jXHR.readyState = 1;
|
||||||
|
|
||||||
|
// Install callbacks on deferreds
|
||||||
|
for ( i in { success:1, error:1, complete:1 } ) {
|
||||||
|
jXHR[ i ]( s[ i ] );
|
||||||
|
}
|
||||||
|
|
||||||
|
// 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);
|
||||||
|
}
|
||||||
|
|
||||||
|
// Try to send
|
||||||
|
try {
|
||||||
|
transport.send(requestHeaders, done);
|
||||||
|
} catch (e) {
|
||||||
|
// Propagate exception as error if not done
|
||||||
|
if ( status === 1 ) {
|
||||||
|
|
||||||
|
done(0, "error", "" + e);
|
||||||
|
jXHR = false;
|
||||||
|
|
||||||
|
// Simply rethrow otherwise
|
||||||
|
} else {
|
||||||
|
jQuery.error(e);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
return jXHR;
|
||||||
},
|
},
|
||||||
|
|
||||||
// Serialize an array of form elements or a set of
|
// Serialize an array of form elements or a set of
|
||||||
|
@ -315,6 +715,172 @@ jQuery.extend({
|
||||||
|
|
||||||
});
|
});
|
||||||
|
|
||||||
|
//Execute or select from functions in a given structure of options
|
||||||
|
function ajax_selectOrExecute( structure , s ) {
|
||||||
|
|
||||||
|
var dataTypes = s.dataTypes,
|
||||||
|
transportDataType,
|
||||||
|
list,
|
||||||
|
selected,
|
||||||
|
i,
|
||||||
|
length,
|
||||||
|
checked = {},
|
||||||
|
flag,
|
||||||
|
noSelect = structure !== "transports";
|
||||||
|
|
||||||
|
function initSearch( dataType ) {
|
||||||
|
|
||||||
|
flag = transportDataType !== dataType && ! checked[ dataType ];
|
||||||
|
|
||||||
|
if ( flag ) {
|
||||||
|
|
||||||
|
checked[ dataType ] = 1;
|
||||||
|
transportDataType = dataType;
|
||||||
|
list = s[ structure ][ dataType ];
|
||||||
|
i = -1;
|
||||||
|
length = list ? list.length : 0 ;
|
||||||
|
}
|
||||||
|
|
||||||
|
return flag;
|
||||||
|
}
|
||||||
|
|
||||||
|
initSearch( dataTypes[ 0 ] );
|
||||||
|
|
||||||
|
for ( i = 0 ; ( noSelect || ! selected ) && i <= length ; i++ ) {
|
||||||
|
|
||||||
|
if ( i === length ) {
|
||||||
|
|
||||||
|
initSearch( "*" );
|
||||||
|
|
||||||
|
} else {
|
||||||
|
|
||||||
|
selected = list[ i ]( s , determineDataType );
|
||||||
|
|
||||||
|
// If we got redirected to another dataType
|
||||||
|
// Search there (if not in progress or already tried)
|
||||||
|
if ( typeof( selected ) === "string" &&
|
||||||
|
initSearch( selected ) ) {
|
||||||
|
|
||||||
|
dataTypes.unshift( selected );
|
||||||
|
selected = 0;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
return noSelect ? jQuery.ajax : selected;
|
||||||
|
}
|
||||||
|
|
||||||
|
// Add an element to one of the structures in ajaxSettings
|
||||||
|
function ajax_addElement( structure , args ) {
|
||||||
|
|
||||||
|
var i,
|
||||||
|
start = 0,
|
||||||
|
length = args.length,
|
||||||
|
dataTypes = [ "*" ],
|
||||||
|
dLength = 1,
|
||||||
|
dataType,
|
||||||
|
functors = [],
|
||||||
|
first,
|
||||||
|
append,
|
||||||
|
list;
|
||||||
|
|
||||||
|
if ( length ) {
|
||||||
|
|
||||||
|
first = jQuery.type( args[ 0 ] );
|
||||||
|
|
||||||
|
if ( first === "object" ) {
|
||||||
|
return ajax_selectOrExecute( structure , args[ 0 ] );
|
||||||
|
}
|
||||||
|
|
||||||
|
structure = jQuery.ajaxSettings[ structure ];
|
||||||
|
|
||||||
|
if ( first !== "function" ) {
|
||||||
|
|
||||||
|
dataTypes = args[ 0 ].toLowerCase().split(/\s+/);
|
||||||
|
dLength = dataTypes.length;
|
||||||
|
start = 1;
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
|
if ( dLength && start < length ) {
|
||||||
|
|
||||||
|
functors = sliceFunc.call( args , start );
|
||||||
|
|
||||||
|
for( i = 0 ; i < dLength ; i++ ) {
|
||||||
|
|
||||||
|
dataType = dataTypes[ i ];
|
||||||
|
|
||||||
|
first = /^\+/.test( dataType );
|
||||||
|
|
||||||
|
if (first) {
|
||||||
|
dataType = dataType.substr(1);
|
||||||
|
}
|
||||||
|
|
||||||
|
if ( dataType !== "" ) {
|
||||||
|
|
||||||
|
append = Array.prototype[ first ? "unshift" : "push" ];
|
||||||
|
list = structure[ dataType ] = structure[ dataType ] || [];
|
||||||
|
append.apply( list , functors );
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
return jQuery.ajax;
|
||||||
|
}
|
||||||
|
|
||||||
|
// Install prefilter & transport methods
|
||||||
|
jQuery.each( [ "prefilter" , "transport" ] , function( _ , name ) {
|
||||||
|
_ = name + "s";
|
||||||
|
jQuery.ajax[ name ] = function() {
|
||||||
|
return ajax_addElement( _ , arguments );
|
||||||
|
};
|
||||||
|
} );
|
||||||
|
|
||||||
|
// Utility function that handles dataType when response is received
|
||||||
|
// (for those transports that can give text or xml responses)
|
||||||
|
function determineDataType( s , ct , text , xml ) {
|
||||||
|
|
||||||
|
var autoDataType = s.autoDataType,
|
||||||
|
type,
|
||||||
|
regexp,
|
||||||
|
dataTypes = s.dataTypes,
|
||||||
|
transportDataType = dataTypes[0],
|
||||||
|
response;
|
||||||
|
|
||||||
|
// Auto (xml, json, script or text determined given headers)
|
||||||
|
if ( transportDataType === "*" ) {
|
||||||
|
|
||||||
|
for ( type in autoDataType ) {
|
||||||
|
if ( ( regexp = autoDataType[ type ] ) && regexp.test( ct ) ) {
|
||||||
|
transportDataType = dataTypes[0] = type;
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// xml and parsed as such
|
||||||
|
if ( transportDataType === "xml" &&
|
||||||
|
xml &&
|
||||||
|
xml.documentElement /* #4958 */ ) {
|
||||||
|
|
||||||
|
response = xml;
|
||||||
|
|
||||||
|
// Text response was provided
|
||||||
|
} else {
|
||||||
|
|
||||||
|
response = text;
|
||||||
|
|
||||||
|
// If it's not really text, defer to dataConverters
|
||||||
|
if ( transportDataType !== "text" ) {
|
||||||
|
dataTypes.unshift( "text" );
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
|
return response;
|
||||||
|
}
|
||||||
|
|
||||||
/*
|
/*
|
||||||
* Create the request object; Microsoft failed to properly
|
* Create the request object; Microsoft failed to properly
|
||||||
* implement the XMLHttpRequest in IE7 (can't request local files),
|
* implement the XMLHttpRequest in IE7 (can't request local files),
|
||||||
|
|
|
@ -14,7 +14,7 @@ jQuery.ajaxSettings.jsonpCallback = function() {
|
||||||
// 2) sneakily ensure transportDataType is json
|
// 2) sneakily ensure transportDataType is json
|
||||||
// 3) ensure options jsonp is always provided so that jsonp requests are always
|
// 3) ensure options jsonp is always provided so that jsonp requests are always
|
||||||
// json request with the jsonp option set
|
// json request with the jsonp option set
|
||||||
jQuery.xhr.prefilter("json jsonp", function(s) {
|
jQuery.ajax.prefilter("json jsonp", function(s) {
|
||||||
|
|
||||||
var transportDataType = s.dataTypes[ 0 ];
|
var transportDataType = s.dataTypes[ 0 ];
|
||||||
|
|
||||||
|
|
|
@ -17,7 +17,7 @@ jQuery.extend( true, jQuery.ajaxSettings , {
|
||||||
} );
|
} );
|
||||||
|
|
||||||
// Bind script tag hack transport
|
// Bind script tag hack transport
|
||||||
jQuery.xhr.transport("script", function(s) {
|
jQuery.ajax.transport("script", function(s) {
|
||||||
|
|
||||||
// Handle cache special case
|
// Handle cache special case
|
||||||
if ( s.cache === undefined ) {
|
if ( s.cache === undefined ) {
|
||||||
|
|
|
@ -10,7 +10,7 @@ var // Next fake timer id
|
||||||
xhrUnloadAbortMarker = [];
|
xhrUnloadAbortMarker = [];
|
||||||
|
|
||||||
|
|
||||||
jQuery.xhr.transport( function( s , determineDataType ) {
|
jQuery.ajax.transport( function( s , determineDataType ) {
|
||||||
|
|
||||||
// Cross domain only allowed if supported through XMLHttpRequest
|
// Cross domain only allowed if supported through XMLHttpRequest
|
||||||
if ( ! s.crossDomain || jQuery.support.cors ) {
|
if ( ! s.crossDomain || jQuery.support.cors ) {
|
||||||
|
|
728
src/xhr.js
728
src/xhr.js
|
@ -1,728 +0,0 @@
|
||||||
(function( jQuery ) {
|
|
||||||
|
|
||||||
var rquery_xhr = /\?/,
|
|
||||||
rhash = /#.*$/,
|
|
||||||
rheaders = /^(.*?):\s*(.*?)\r?$/mg, // IE leaves an \r character at EOL
|
|
||||||
rnoContent = /^(?:GET|HEAD)$/,
|
|
||||||
rts = /([?&])_=[^&]*/,
|
|
||||||
rurl = /^(\w+:)?\/\/([^\/?#]+)/,
|
|
||||||
|
|
||||||
sliceFunc = Array.prototype.slice;
|
|
||||||
|
|
||||||
// Creates a jQuery xhr object
|
|
||||||
jQuery.xhr = function( _native ) {
|
|
||||||
|
|
||||||
if ( _native ) {
|
|
||||||
return jQuery.ajaxSettings.xhr();
|
|
||||||
}
|
|
||||||
|
|
||||||
function reset( force ) {
|
|
||||||
|
|
||||||
// We only need to reset if we went through the init phase
|
|
||||||
// (with the exception of object creation)
|
|
||||||
if ( force || internal ) {
|
|
||||||
|
|
||||||
// Reset callbacks lists
|
|
||||||
deferred = jQuery.Deferred();
|
|
||||||
completeDeferred = jQuery._Deferred();
|
|
||||||
|
|
||||||
xhr.success = xhr.then = deferred.then;
|
|
||||||
xhr.error = xhr.fail = deferred.fail;
|
|
||||||
xhr.complete = completeDeferred.then;
|
|
||||||
|
|
||||||
// Reset private variables
|
|
||||||
requestHeaders = {};
|
|
||||||
responseHeadersString = responseHeaders = internal = done = timeoutTimer = s = undefined;
|
|
||||||
|
|
||||||
// Reset state
|
|
||||||
xhr.readyState = 0;
|
|
||||||
sendFlag = 0;
|
|
||||||
|
|
||||||
// Remove responseX fields
|
|
||||||
for ( var name in xhr ) {
|
|
||||||
if ( /^response/.test(name) ) {
|
|
||||||
delete xhr[name];
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
function init() {
|
|
||||||
|
|
||||||
var // Options extraction
|
|
||||||
|
|
||||||
// Remove hash character (#7531: first for string promotion)
|
|
||||||
url = s.url = ( "" + s.url ).replace( rhash , "" ),
|
|
||||||
|
|
||||||
// Uppercase the type
|
|
||||||
type = s.type = s.type.toUpperCase(),
|
|
||||||
|
|
||||||
// Determine if request has content
|
|
||||||
hasContent = s.hasContent = ! rnoContent.test( type ),
|
|
||||||
|
|
||||||
// Extract dataTypes list
|
|
||||||
dataType = s.dataType,
|
|
||||||
dataTypes = s.dataTypes = dataType ? jQuery.trim(dataType).toLowerCase().split(/\s+/) : ["*"],
|
|
||||||
|
|
||||||
// Determine if a cross-domain request is in order
|
|
||||||
parts = rurl.exec( url.toLowerCase() ),
|
|
||||||
loc = location,
|
|
||||||
crossDomain = s.crossDomain = !!( parts && ( parts[1] && parts[1] != loc.protocol || parts[2] != loc.host ) ),
|
|
||||||
|
|
||||||
// Get other options locally
|
|
||||||
data = s.data,
|
|
||||||
originalContentType = s.contentType,
|
|
||||||
prefilters = s.prefilters,
|
|
||||||
accepts = s.accepts,
|
|
||||||
headers = s.headers,
|
|
||||||
|
|
||||||
// Other Variables
|
|
||||||
transportDataType,
|
|
||||||
i;
|
|
||||||
|
|
||||||
// Convert data if not already a string
|
|
||||||
if ( data && s.processData && typeof data != "string" ) {
|
|
||||||
data = s.data = jQuery.param( data , s.traditional );
|
|
||||||
}
|
|
||||||
|
|
||||||
// Get internal
|
|
||||||
internal = jQuery.xhr.prefilter( s ).transport( s );
|
|
||||||
|
|
||||||
// Re-actualize url & data
|
|
||||||
url = s.url;
|
|
||||||
data = s.data;
|
|
||||||
|
|
||||||
// If internal was found
|
|
||||||
if ( internal ) {
|
|
||||||
|
|
||||||
// Get transportDataType
|
|
||||||
transportDataType = dataTypes[0];
|
|
||||||
|
|
||||||
// More options handling for requests with no content
|
|
||||||
if ( ! hasContent ) {
|
|
||||||
|
|
||||||
// If data is available, append data to url
|
|
||||||
if ( data ) {
|
|
||||||
url += (rquery_xhr.test(url) ? "&" : "?") + data;
|
|
||||||
}
|
|
||||||
|
|
||||||
// Add anti-cache in url if needed
|
|
||||||
if ( s.cache === false ) {
|
|
||||||
|
|
||||||
var ts = jQuery.now(),
|
|
||||||
// try replacing _= if it is there
|
|
||||||
ret = url.replace(rts, "$1_=" + ts );
|
|
||||||
|
|
||||||
// if nothing was replaced, add timestamp to the end
|
|
||||||
url = ret + ((ret == url) ? (rquery_xhr.test(url) ? "&" : "?") + "_=" + ts : "");
|
|
||||||
}
|
|
||||||
|
|
||||||
s.url = url;
|
|
||||||
}
|
|
||||||
|
|
||||||
// Set the correct header, if data is being sent
|
|
||||||
if ( ( data && hasContent ) || originalContentType ) {
|
|
||||||
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[url] ) {
|
|
||||||
requestHeaders["if-modified-since"] = jQuery_lastModified[url];
|
|
||||||
}
|
|
||||||
if ( jQuery_etag[url] ) {
|
|
||||||
requestHeaders["if-none-match"] = jQuery_etag[url];
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
// Set the Accepts header for the server, depending on the dataType
|
|
||||||
requestHeaders.accept = transportDataType && accepts[ transportDataType ] ?
|
|
||||||
accepts[ transportDataType ] + ( transportDataType !== "*" ? ", */*; q=0.01" : "" ) :
|
|
||||||
accepts[ "*" ];
|
|
||||||
|
|
||||||
// Check for headers option
|
|
||||||
for ( i in headers ) {
|
|
||||||
requestHeaders[ i.toLowerCase() ] = headers[ i ];
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
callbackContext = s.context || s;
|
|
||||||
globalEventContext = s.context ? jQuery(s.context) : jQuery.event;
|
|
||||||
|
|
||||||
for ( i in { success:1, error:1, complete:1 } ) {
|
|
||||||
xhr[ i ]( s[ i ] );
|
|
||||||
}
|
|
||||||
|
|
||||||
// Watch for a new set of requests
|
|
||||||
if ( s.global && jQuery.active++ === 0 ) {
|
|
||||||
jQuery.event.trigger( "ajaxStart" );
|
|
||||||
}
|
|
||||||
|
|
||||||
done = whenDone;
|
|
||||||
}
|
|
||||||
|
|
||||||
function whenDone(status, statusText, response, headers) {
|
|
||||||
|
|
||||||
// Called once
|
|
||||||
done = undefined;
|
|
||||||
|
|
||||||
// Reset sendFlag
|
|
||||||
sendFlag = 0;
|
|
||||||
|
|
||||||
// Cache response headers
|
|
||||||
responseHeadersString = headers || "";
|
|
||||||
|
|
||||||
// Clear timeout if it exists
|
|
||||||
if ( timeoutTimer ) {
|
|
||||||
clearTimeout(timeoutTimer);
|
|
||||||
}
|
|
||||||
|
|
||||||
var // Reference url
|
|
||||||
url = s.url,
|
|
||||||
// and ifModified status
|
|
||||||
ifModified = s.ifModified,
|
|
||||||
|
|
||||||
// Is it a success?
|
|
||||||
isSuccess = 0,
|
|
||||||
// Stored success
|
|
||||||
success,
|
|
||||||
// Stored error
|
|
||||||
error = statusText;
|
|
||||||
|
|
||||||
// If not timeout, force a jQuery-compliant status text
|
|
||||||
if ( statusText != "timeout" ) {
|
|
||||||
statusText = ( status >= 200 && status < 300 ) ?
|
|
||||||
"success" :
|
|
||||||
( status === 304 ? "notmodified" : "error" );
|
|
||||||
}
|
|
||||||
|
|
||||||
// If successful, handle type chaining
|
|
||||||
if ( statusText === "success" || statusText === "notmodified" ) {
|
|
||||||
|
|
||||||
// Set the If-Modified-Since and/or If-None-Match header, if in ifModified mode.
|
|
||||||
if ( ifModified ) {
|
|
||||||
var lastModified = xhr.getResponseHeader("Last-Modified"),
|
|
||||||
etag = xhr.getResponseHeader("Etag");
|
|
||||||
|
|
||||||
if (lastModified) {
|
|
||||||
jQuery_lastModified[url] = lastModified;
|
|
||||||
}
|
|
||||||
if (etag) {
|
|
||||||
jQuery_etag[url] = etag;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
if ( ifModified && statusText === "notmodified" ) {
|
|
||||||
|
|
||||||
success = null;
|
|
||||||
isSuccess = 1;
|
|
||||||
|
|
||||||
} else {
|
|
||||||
// Chain data conversions and determine the final value
|
|
||||||
// (if an exception is thrown in the process, it'll be notified as an error)
|
|
||||||
try {
|
|
||||||
|
|
||||||
var i,
|
|
||||||
current,
|
|
||||||
prev,
|
|
||||||
checker,
|
|
||||||
conv1,
|
|
||||||
conv2,
|
|
||||||
oneConv,
|
|
||||||
convertion,
|
|
||||||
dataTypes = s.dataTypes,
|
|
||||||
dataConverters = s.dataConverters,
|
|
||||||
dataFilter = s.dataFilter,
|
|
||||||
responses = {
|
|
||||||
"xml": "XML",
|
|
||||||
"text": "Text"
|
|
||||||
};
|
|
||||||
|
|
||||||
for( i = 0 ; i < dataTypes.length ; i++ ) {
|
|
||||||
|
|
||||||
current = dataTypes[ i ];
|
|
||||||
|
|
||||||
if ( responses[ current ] ) {
|
|
||||||
xhr[ "response" + responses[ current ] ] = response;
|
|
||||||
responses[ current ] = 0;
|
|
||||||
}
|
|
||||||
|
|
||||||
if ( i ) {
|
|
||||||
|
|
||||||
if ( prev !== "*" && current !== "*" && prev !== current ) {
|
|
||||||
|
|
||||||
oneConv = conv1 =
|
|
||||||
dataConverters[ ( conversion = prev + " " + current ) ] ||
|
|
||||||
dataConverters[ "* " + current ];
|
|
||||||
|
|
||||||
if ( oneConv !== true ) {
|
|
||||||
|
|
||||||
if ( ! oneConv && prev !== "text" && current !== "text" ) {
|
|
||||||
conv1 = dataConverters[ prev + " text" ] || dataConverters[ "* text" ];
|
|
||||||
conv2 = dataConverters[ "text " + current ];
|
|
||||||
}
|
|
||||||
|
|
||||||
if ( oneConv || conv1 && conv2 ) {
|
|
||||||
response = oneConv ? conv1( response ) : conv2( conv1( response ) );
|
|
||||||
} else {
|
|
||||||
throw "no " + conversion;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
} else if ( dataFilter ) {
|
|
||||||
|
|
||||||
response = s.dataFilter( response );
|
|
||||||
dataTypes = s.dataTypes;
|
|
||||||
}
|
|
||||||
|
|
||||||
prev = current;
|
|
||||||
}
|
|
||||||
|
|
||||||
// We have a real success
|
|
||||||
success = response;
|
|
||||||
isSuccess = 1;
|
|
||||||
|
|
||||||
} catch(e) {
|
|
||||||
|
|
||||||
statusText = "parsererror";
|
|
||||||
error = "" + e;
|
|
||||||
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
} else { // if not success, mark it as an error
|
|
||||||
|
|
||||||
error = error || statusText;
|
|
||||||
|
|
||||||
}
|
|
||||||
|
|
||||||
// Set data for the fake xhr object
|
|
||||||
xhr.status = status;
|
|
||||||
xhr.statusText = statusText;
|
|
||||||
|
|
||||||
// Keep local copies of vars in case callbacks re-use the xhr
|
|
||||||
var _s = s,
|
|
||||||
_deferred = deferred,
|
|
||||||
_completeDeferred = completeDeferred,
|
|
||||||
_callbackContext = callbackContext,
|
|
||||||
_globalEventContext = globalEventContext;
|
|
||||||
|
|
||||||
|
|
||||||
// Set state if the xhr hasn't been re-used
|
|
||||||
function _setState( value ) {
|
|
||||||
if ( xhr.readyState && s === _s ) {
|
|
||||||
setState( value );
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
// Really completed?
|
|
||||||
if ( status && s.async ) {
|
|
||||||
setState( 2 );
|
|
||||||
_setState( 3 );
|
|
||||||
}
|
|
||||||
|
|
||||||
// We're done
|
|
||||||
_setState( 4 );
|
|
||||||
|
|
||||||
// Success/Error
|
|
||||||
if ( isSuccess ) {
|
|
||||||
_deferred.fire( _callbackContext , [ success , statusText , xhr ] );
|
|
||||||
} else {
|
|
||||||
_deferred.fireReject( _callbackContext , [ xhr , statusText , error ] );
|
|
||||||
}
|
|
||||||
|
|
||||||
if ( _s.global ) {
|
|
||||||
_globalEventContext.trigger( "ajax" + ( isSuccess ? "Success" : "Error" ) , [ xhr , _s , isSuccess ? success : error ] );
|
|
||||||
}
|
|
||||||
|
|
||||||
// Complete
|
|
||||||
_completeDeferred.fire( _callbackContext, [ xhr , statusText ] );
|
|
||||||
|
|
||||||
if ( _s.global ) {
|
|
||||||
_globalEventContext.trigger( "ajaxComplete", [xhr, _s] );
|
|
||||||
// Handle the global AJAX counter
|
|
||||||
if ( ! --jQuery.active ) {
|
|
||||||
jQuery.event.trigger( "ajaxStop" );
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
// Ready state control
|
|
||||||
function checkState( expected , test ) {
|
|
||||||
if ( expected !== true && ( expected === false || test === false || xhr.readyState !== expected ) ) {
|
|
||||||
jQuery.error("INVALID_STATE_ERR");
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
// Ready state change
|
|
||||||
function setState( value ) {
|
|
||||||
xhr.readyState = value;
|
|
||||||
if ( jQuery.isFunction( xhr.onreadystatechange ) ) {
|
|
||||||
xhr.onreadystatechange();
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
var // jQuery lists
|
|
||||||
jQuery_lastModified = jQuery.lastModified,
|
|
||||||
jQuery_etag = jQuery.etag,
|
|
||||||
// Options object
|
|
||||||
s,
|
|
||||||
// Callback stuff
|
|
||||||
callbackContext,
|
|
||||||
globalEventContext,
|
|
||||||
deferred,
|
|
||||||
completeDeferred,
|
|
||||||
// Headers (they are sent all at once)
|
|
||||||
requestHeaders,
|
|
||||||
// Response headers
|
|
||||||
responseHeadersString,
|
|
||||||
responseHeaders,
|
|
||||||
// Done callback
|
|
||||||
done,
|
|
||||||
// transport
|
|
||||||
internal,
|
|
||||||
// timeout handle
|
|
||||||
timeoutTimer,
|
|
||||||
// The send flag
|
|
||||||
sendFlag,
|
|
||||||
// Fake xhr
|
|
||||||
xhr = {
|
|
||||||
// state
|
|
||||||
readyState: 0,
|
|
||||||
|
|
||||||
// Callback
|
|
||||||
onreadystatechange: null,
|
|
||||||
|
|
||||||
// Open
|
|
||||||
open: function(type, url, async, username, password) {
|
|
||||||
|
|
||||||
xhr.abort();
|
|
||||||
reset();
|
|
||||||
|
|
||||||
s = {
|
|
||||||
type: type,
|
|
||||||
url: url,
|
|
||||||
async: async,
|
|
||||||
username: username,
|
|
||||||
password: password
|
|
||||||
};
|
|
||||||
|
|
||||||
setState(1);
|
|
||||||
|
|
||||||
return xhr;
|
|
||||||
},
|
|
||||||
|
|
||||||
// Send
|
|
||||||
send: function(data, moreOptions) {
|
|
||||||
|
|
||||||
checkState(1 , !sendFlag);
|
|
||||||
|
|
||||||
s.data = data;
|
|
||||||
|
|
||||||
s = jQuery.extend( true,
|
|
||||||
{},
|
|
||||||
jQuery.ajaxSettings,
|
|
||||||
s,
|
|
||||||
moreOptions || ( moreOptions === false ? { global: false } : {} ) );
|
|
||||||
|
|
||||||
if ( moreOptions ) {
|
|
||||||
// We force the original context
|
|
||||||
// (plain objects used as context get extended)
|
|
||||||
s.context = moreOptions.context;
|
|
||||||
}
|
|
||||||
|
|
||||||
init();
|
|
||||||
|
|
||||||
// If not internal, abort
|
|
||||||
if ( ! internal ) {
|
|
||||||
done( 0 , "transport not found" );
|
|
||||||
return false;
|
|
||||||
}
|
|
||||||
|
|
||||||
// Allow custom headers/mimetypes and early abort
|
|
||||||
if ( s.beforeSend ) {
|
|
||||||
|
|
||||||
var _s = s;
|
|
||||||
|
|
||||||
if ( s.beforeSend.call(callbackContext, xhr, s) === false || ! xhr.readyState || _s !== s ) {
|
|
||||||
|
|
||||||
// Abort if not done
|
|
||||||
if ( xhr.readyState && _s === s ) {
|
|
||||||
xhr.abort();
|
|
||||||
}
|
|
||||||
|
|
||||||
// Handle the global AJAX counter
|
|
||||||
if ( _s.global && ! --jQuery.active ) {
|
|
||||||
jQuery.event.trigger( "ajaxStop" );
|
|
||||||
}
|
|
||||||
|
|
||||||
return false;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
sendFlag = 1;
|
|
||||||
|
|
||||||
// Send global event
|
|
||||||
if ( s.global ) {
|
|
||||||
globalEventContext.trigger("ajaxSend", [xhr, s]);
|
|
||||||
}
|
|
||||||
|
|
||||||
// Timeout
|
|
||||||
if ( s.async && s.timeout > 0 ) {
|
|
||||||
timeoutTimer = setTimeout(function(){
|
|
||||||
xhr.abort("timeout");
|
|
||||||
}, s.timeout);
|
|
||||||
}
|
|
||||||
|
|
||||||
if ( s.async ) {
|
|
||||||
setState(1);
|
|
||||||
}
|
|
||||||
|
|
||||||
try {
|
|
||||||
|
|
||||||
internal.send(requestHeaders, done);
|
|
||||||
return xhr;
|
|
||||||
|
|
||||||
} catch (e) {
|
|
||||||
|
|
||||||
if ( done ) {
|
|
||||||
|
|
||||||
done(0, "error", "" + e);
|
|
||||||
|
|
||||||
} else {
|
|
||||||
|
|
||||||
jQuery.error(e);
|
|
||||||
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
return false;
|
|
||||||
},
|
|
||||||
|
|
||||||
// Caches the header
|
|
||||||
setRequestHeader: function(name,value) {
|
|
||||||
checkState(1, !sendFlag);
|
|
||||||
requestHeaders[ name.toLowerCase() ] = value;
|
|
||||||
return xhr;
|
|
||||||
},
|
|
||||||
|
|
||||||
// Raw string
|
|
||||||
getAllResponseHeaders: function() {
|
|
||||||
return xhr.readyState <= 1 ? "" : responseHeadersString;
|
|
||||||
},
|
|
||||||
|
|
||||||
// Builds headers hashtable if needed
|
|
||||||
getResponseHeader: function( key ) {
|
|
||||||
|
|
||||||
if ( xhr.readyState <= 1 ) {
|
|
||||||
|
|
||||||
return null;
|
|
||||||
|
|
||||||
}
|
|
||||||
|
|
||||||
if ( responseHeaders === undefined ) {
|
|
||||||
|
|
||||||
responseHeaders = {};
|
|
||||||
|
|
||||||
if ( typeof responseHeadersString === "string" ) {
|
|
||||||
|
|
||||||
var match;
|
|
||||||
|
|
||||||
while( ( match = rheaders.exec( responseHeadersString ) ) ) {
|
|
||||||
responseHeaders[ match[ 1 ].toLowerCase() ] = match[ 2 ];
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
return responseHeaders[ key.toLowerCase() ];
|
|
||||||
},
|
|
||||||
|
|
||||||
// Cancel the request
|
|
||||||
abort: function(statusText) {
|
|
||||||
if (internal) {
|
|
||||||
internal.abort( statusText || "abort" );
|
|
||||||
}
|
|
||||||
xhr.readyState = 0;
|
|
||||||
}
|
|
||||||
};
|
|
||||||
|
|
||||||
// Init data (so that we can bind callbacks early
|
|
||||||
reset(1);
|
|
||||||
|
|
||||||
// Return the xhr emulation
|
|
||||||
return xhr;
|
|
||||||
};
|
|
||||||
|
|
||||||
// Execute or select from functions in a given structure of options
|
|
||||||
function xhr_selectOrExecute( structure , s ) {
|
|
||||||
|
|
||||||
var dataTypes = s.dataTypes,
|
|
||||||
transportDataType,
|
|
||||||
list,
|
|
||||||
selected,
|
|
||||||
i,
|
|
||||||
length,
|
|
||||||
checked = {},
|
|
||||||
flag,
|
|
||||||
noSelect = structure !== "transports";
|
|
||||||
|
|
||||||
function initSearch( dataType ) {
|
|
||||||
|
|
||||||
flag = transportDataType !== dataType && ! checked[ dataType ];
|
|
||||||
|
|
||||||
if ( flag ) {
|
|
||||||
|
|
||||||
checked[ dataType ] = 1;
|
|
||||||
transportDataType = dataType;
|
|
||||||
list = s[ structure ][ dataType ];
|
|
||||||
i = -1;
|
|
||||||
length = list ? list.length : 0 ;
|
|
||||||
}
|
|
||||||
|
|
||||||
return flag;
|
|
||||||
}
|
|
||||||
|
|
||||||
initSearch( dataTypes[ 0 ] );
|
|
||||||
|
|
||||||
for ( i = 0 ; ( noSelect || ! selected ) && i <= length ; i++ ) {
|
|
||||||
|
|
||||||
if ( i === length ) {
|
|
||||||
|
|
||||||
initSearch( "*" );
|
|
||||||
|
|
||||||
} else {
|
|
||||||
|
|
||||||
selected = list[ i ]( s , determineDataType );
|
|
||||||
|
|
||||||
// If we got redirected to another dataType
|
|
||||||
// Search there (if not in progress or already tried)
|
|
||||||
if ( typeof( selected ) === "string" &&
|
|
||||||
initSearch( selected ) ) {
|
|
||||||
|
|
||||||
dataTypes.unshift( selected );
|
|
||||||
selected = 0;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
return noSelect ? jQuery.xhr : selected;
|
|
||||||
}
|
|
||||||
|
|
||||||
// Add an element to one of the xhr structures in ajaxSettings
|
|
||||||
function xhr_addElement( structure , args ) {
|
|
||||||
|
|
||||||
var i,
|
|
||||||
j,
|
|
||||||
start = 0,
|
|
||||||
length = args.length,
|
|
||||||
dataTypes = [ "*" ],
|
|
||||||
dLength = 1,
|
|
||||||
dataType,
|
|
||||||
functors = [],
|
|
||||||
first,
|
|
||||||
append,
|
|
||||||
list;
|
|
||||||
|
|
||||||
if ( length ) {
|
|
||||||
|
|
||||||
first = jQuery.type( args[ 0 ] );
|
|
||||||
|
|
||||||
if ( first === "object" ) {
|
|
||||||
return xhr_selectOrExecute( structure , args[ 0 ] );
|
|
||||||
}
|
|
||||||
|
|
||||||
structure = jQuery.ajaxSettings[ structure ];
|
|
||||||
|
|
||||||
if ( first !== "function" ) {
|
|
||||||
|
|
||||||
dataTypes = args[ 0 ].toLowerCase().split(/\s+/);
|
|
||||||
dLength = dataTypes.length;
|
|
||||||
start = 1;
|
|
||||||
|
|
||||||
}
|
|
||||||
|
|
||||||
if ( dLength && start < length ) {
|
|
||||||
|
|
||||||
functors = sliceFunc.call( args , start );
|
|
||||||
|
|
||||||
length -= start;
|
|
||||||
|
|
||||||
for( i = 0 ; i < dLength ; i++ ) {
|
|
||||||
|
|
||||||
dataType = dataTypes[ i ];
|
|
||||||
|
|
||||||
first = /^\+/.test( dataType );
|
|
||||||
|
|
||||||
if (first) {
|
|
||||||
dataType = dataType.substr(1);
|
|
||||||
}
|
|
||||||
|
|
||||||
if ( dataType !== "" ) {
|
|
||||||
|
|
||||||
append = Array.prototype[ first ? "unshift" : "push" ];
|
|
||||||
|
|
||||||
list = structure[ dataType ] = structure[ dataType ] || [];
|
|
||||||
|
|
||||||
for ( j = 0; j < length; j++ ) {
|
|
||||||
append.call( list , functors[ j ] );
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
return jQuery.xhr;
|
|
||||||
}
|
|
||||||
|
|
||||||
// Install prefilter & transport methods
|
|
||||||
jQuery.each( [ "prefilter" , "transport" ] , function( _ , name ) {
|
|
||||||
_ = name + "s";
|
|
||||||
jQuery.xhr[ name ] = function() {
|
|
||||||
return xhr_addElement( _ , arguments );
|
|
||||||
};
|
|
||||||
} );
|
|
||||||
|
|
||||||
// Utility function that handles dataType when response is received
|
|
||||||
// (for those transports that can give text or xml responses)
|
|
||||||
function determineDataType( s , ct , text , xml ) {
|
|
||||||
|
|
||||||
var autoDataType = s.autoDataType,
|
|
||||||
type,
|
|
||||||
regexp,
|
|
||||||
dataTypes = s.dataTypes,
|
|
||||||
transportDataType = dataTypes[0],
|
|
||||||
response;
|
|
||||||
|
|
||||||
// Auto (xml, json, script or text determined given headers)
|
|
||||||
if ( transportDataType === "*" ) {
|
|
||||||
|
|
||||||
for ( type in autoDataType ) {
|
|
||||||
if ( ( regexp = autoDataType[ type ] ) && regexp.test( ct ) ) {
|
|
||||||
transportDataType = dataTypes[0] = type;
|
|
||||||
break;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
// xml and parsed as such
|
|
||||||
if ( transportDataType === "xml" &&
|
|
||||||
xml &&
|
|
||||||
xml.documentElement /* #4958 */ ) {
|
|
||||||
|
|
||||||
response = xml;
|
|
||||||
|
|
||||||
// Text response was provided
|
|
||||||
} else {
|
|
||||||
|
|
||||||
response = text;
|
|
||||||
|
|
||||||
// If it's not really text, defer to dataConverters
|
|
||||||
if ( transportDataType !== "text" ) {
|
|
||||||
dataTypes.unshift( "text" );
|
|
||||||
}
|
|
||||||
|
|
||||||
}
|
|
||||||
|
|
||||||
return response;
|
|
||||||
}
|
|
||||||
|
|
||||||
})( jQuery );
|
|
|
@ -20,7 +20,6 @@
|
||||||
<script src="../src/manipulation.js"></script>
|
<script src="../src/manipulation.js"></script>
|
||||||
<script src="../src/css.js"></script>
|
<script src="../src/css.js"></script>
|
||||||
<script src="../src/ajax.js"></script>
|
<script src="../src/ajax.js"></script>
|
||||||
<script src="../src/xhr.js"></script>
|
|
||||||
<script src="../src/transports/jsonp.js"></script>
|
<script src="../src/transports/jsonp.js"></script>
|
||||||
<script src="../src/transports/script.js"></script>
|
<script src="../src/transports/script.js"></script>
|
||||||
<script src="../src/transports/xhr.js"></script>
|
<script src="../src/transports/xhr.js"></script>
|
||||||
|
|
|
@ -74,7 +74,7 @@ test("jQuery.ajax() - success/error callbacks (remote)", function() {
|
||||||
|
|
||||||
var supports = jQuery.support.cors;
|
var supports = jQuery.support.cors;
|
||||||
|
|
||||||
expect( supports ? 9 : 6 );
|
expect( supports ? 9 : 4 );
|
||||||
|
|
||||||
jQuery.ajaxSetup({ timeout: 0 });
|
jQuery.ajaxSetup({ timeout: 0 });
|
||||||
|
|
||||||
|
@ -102,8 +102,8 @@ test("jQuery.ajax() - success/error callbacks (remote)", function() {
|
||||||
dataType: "text",
|
dataType: "text",
|
||||||
beforeSend: function(){ ok(supports, "beforeSend"); },
|
beforeSend: function(){ ok(supports, "beforeSend"); },
|
||||||
success: function( val ){ ok(supports, "success"); ok(supports && val.length, "data received"); },
|
success: function( val ){ ok(supports, "success"); ok(supports && val.length, "data received"); },
|
||||||
error: function(_ , a , b ){ ok(!supports, "error"); },
|
error: function(_ , a , b ){ ok(false, "error"); },
|
||||||
complete: function(){ ok(true, "complete"); }
|
complete: function(){ ok(supports, "complete"); }
|
||||||
});
|
});
|
||||||
}, 13);
|
}, 13);
|
||||||
});
|
});
|
||||||
|
@ -409,136 +409,6 @@ test("jQuery.ajax() - abort", function() {
|
||||||
equals( xhr.readyState, 0, "XHR readyState indicates successful abortion" );
|
equals( xhr.readyState, 0, "XHR readyState indicates successful abortion" );
|
||||||
});
|
});
|
||||||
|
|
||||||
test("jQuery.ajax() - readyState (success)", function() {
|
|
||||||
expect( 1 );
|
|
||||||
|
|
||||||
jQuery.ajaxSetup({ timeout: 0 });
|
|
||||||
|
|
||||||
stop();
|
|
||||||
|
|
||||||
var control = "";
|
|
||||||
|
|
||||||
setTimeout(function(){
|
|
||||||
jQuery.ajax({
|
|
||||||
url: url("data/name.html"),
|
|
||||||
beforeSend: function( xhr ) {
|
|
||||||
xhr.onreadystatechange = function() {
|
|
||||||
control += xhr.readyState;
|
|
||||||
}
|
|
||||||
},
|
|
||||||
complete: function(){
|
|
||||||
setTimeout( function() {
|
|
||||||
equals( control , "1234" , "onreadystatechange was properly called" );
|
|
||||||
}, 13 );
|
|
||||||
start();
|
|
||||||
}
|
|
||||||
});
|
|
||||||
}, 13);
|
|
||||||
});
|
|
||||||
|
|
||||||
test("jQuery.ajax() - readyState (abort)", function() {
|
|
||||||
expect( 2 );
|
|
||||||
|
|
||||||
jQuery.ajaxSetup({ timeout: 0 });
|
|
||||||
|
|
||||||
stop();
|
|
||||||
|
|
||||||
var control = "";
|
|
||||||
|
|
||||||
setTimeout(function(){
|
|
||||||
|
|
||||||
jQuery.ajaxSetup({ timeout: 500 });
|
|
||||||
|
|
||||||
jQuery.ajax({
|
|
||||||
url: url("data/name.php?wait=5"),
|
|
||||||
beforeSend: function( xhr ) {
|
|
||||||
xhr.onreadystatechange = function() {
|
|
||||||
control += xhr.readyState;
|
|
||||||
}
|
|
||||||
},
|
|
||||||
complete: function( xhr ){
|
|
||||||
setTimeout( function() {
|
|
||||||
equals( control , "14" , "onreadystatechange was properly called" );
|
|
||||||
equals( xhr.readyState, 0 , "readyState is 0" );
|
|
||||||
}, 13 );
|
|
||||||
start();
|
|
||||||
}
|
|
||||||
});
|
|
||||||
}, 13);
|
|
||||||
});
|
|
||||||
|
|
||||||
test("jQuery.xhr() - reuse", function() {
|
|
||||||
expect( 15 );
|
|
||||||
|
|
||||||
jQuery.ajaxSetup({ timeout: 0 });
|
|
||||||
|
|
||||||
stop();
|
|
||||||
|
|
||||||
var number = 0;
|
|
||||||
|
|
||||||
setTimeout(function(){
|
|
||||||
jQuery('#foo').ajaxStart(function(){
|
|
||||||
ok( true, "ajaxStart" );
|
|
||||||
}).ajaxStop(function(){
|
|
||||||
ok( true, "ajaxStop" );
|
|
||||||
start();
|
|
||||||
}).ajaxSend(function(){
|
|
||||||
number++;
|
|
||||||
ok( true, "ajaxSend (" + number +")" );
|
|
||||||
}).ajaxComplete(function(){
|
|
||||||
ok( true, "ajaxComplete (" + number +")" );
|
|
||||||
}).ajaxError(function(){
|
|
||||||
ok( false, "ajaxError (" + number +")" );
|
|
||||||
}).ajaxSuccess(function(){
|
|
||||||
ok( true, "ajaxSuccess (" + number +")" );
|
|
||||||
});
|
|
||||||
|
|
||||||
jQuery.ajax({
|
|
||||||
url: url("data/name.html"),
|
|
||||||
beforeSend: function(){ ok(true, "beforeSend (1)"); },
|
|
||||||
success: function( _1 , _2 , xhr ){
|
|
||||||
ok(true, "success (1)");
|
|
||||||
xhr.complete(function() {
|
|
||||||
ok(true, "complete (1bis)");
|
|
||||||
});
|
|
||||||
xhr.open( "GET", url("data/name.html") );
|
|
||||||
xhr.success( function(){ ok(true, "beforeSend (2)"); } )
|
|
||||||
xhr.send( null, {
|
|
||||||
success: function(){ ok(true, "success (2)"); },
|
|
||||||
error: function(){ ok(false, "error (2)"); },
|
|
||||||
complete: function(){ ok(true, "complete (2)"); }
|
|
||||||
} );
|
|
||||||
},
|
|
||||||
error: function(){ ok(false, "error (1)"); },
|
|
||||||
complete: function(){ ok(true, "complete (1)"); }
|
|
||||||
});
|
|
||||||
}, 13);
|
|
||||||
});
|
|
||||||
|
|
||||||
test("jQuery.xhr() - early binding", function() {
|
|
||||||
expect( 2 );
|
|
||||||
|
|
||||||
jQuery.ajaxSetup({ timeout: 0 });
|
|
||||||
|
|
||||||
stop();
|
|
||||||
|
|
||||||
jQuery.xhr()
|
|
||||||
.success( function(){ ok(true, "success"); } )
|
|
||||||
.error( function(){ ok(false, "error"); } )
|
|
||||||
.complete( function(){ ok(true, "complete"); start(); } )
|
|
||||||
.open( "GET", url("data/name.html") )
|
|
||||||
.send();
|
|
||||||
});
|
|
||||||
|
|
||||||
test("jQuery.xhr() - get native implementation", function() {
|
|
||||||
|
|
||||||
var xhr = jQuery.xhr(true);
|
|
||||||
|
|
||||||
ok( xhr.readyState !== undefined , "implements XMLHttpRequest" );
|
|
||||||
ok( ! jQuery.isFunction( xhr.success ) , "is not jQuery's abstraction" );
|
|
||||||
|
|
||||||
});
|
|
||||||
|
|
||||||
test("Ajax events with context", function() {
|
test("Ajax events with context", function() {
|
||||||
expect(14);
|
expect(14);
|
||||||
|
|
||||||
|
@ -653,34 +523,6 @@ test("jQuery.ajax() - disabled globals", function() {
|
||||||
});
|
});
|
||||||
});
|
});
|
||||||
|
|
||||||
test("jQuery.xhr() - disabled globals through xhr.send(data , false)", function() {
|
|
||||||
expect( 2 );
|
|
||||||
stop();
|
|
||||||
|
|
||||||
jQuery('#foo').ajaxStart(function(){
|
|
||||||
ok( false, "ajaxStart" );
|
|
||||||
}).ajaxStop(function(){
|
|
||||||
ok( false, "ajaxStop" );
|
|
||||||
}).ajaxSend(function(){
|
|
||||||
ok( false, "ajaxSend" );
|
|
||||||
}).ajaxComplete(function(){
|
|
||||||
ok( false, "ajaxComplete" );
|
|
||||||
}).ajaxError(function(){
|
|
||||||
ok( false, "ajaxError" );
|
|
||||||
}).ajaxSuccess(function(){
|
|
||||||
ok( false, "ajaxSuccess" );
|
|
||||||
});
|
|
||||||
|
|
||||||
jQuery.xhr()
|
|
||||||
.success(function(){ ok(true, "success"); })
|
|
||||||
.error(function(){ ok(false, "error"); })
|
|
||||||
.complete(function(){
|
|
||||||
ok(true, "complete");
|
|
||||||
setTimeout(function(){ start(); }, 13);
|
|
||||||
})
|
|
||||||
.open("GET", url("data/name.html")).send(undefined, false);
|
|
||||||
});
|
|
||||||
|
|
||||||
test("jQuery.ajax - xml: non-namespace elements inside namespaced elements", function() {
|
test("jQuery.ajax - xml: non-namespace elements inside namespaced elements", function() {
|
||||||
expect(3);
|
expect(3);
|
||||||
stop();
|
stop();
|
||||||
|
|
Loading…
Reference in a new issue