rnoContent = /^(?:GET|HEAD)$/,
rts = /([?&])_=[^&]*/,
rurl = /^(\w+:)?\/\/([^\/?#]+)/,
-
+
sliceFunc = Array.prototype.slice,
-
+
isFunction = jQuery.isFunction;
-
+
// 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
callbacksLists = {
success: createCBList(),
error: createCBList(),
complete: createCBList()
};
-
+
// 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) ) {
}
}
}
-
+
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 );
}
-
+
// Apply option prefilters
- for (i in prefilters) {
+ for ( i = 0; i < prefilters.length; i++ ) {
prefilters[i](s);
}
-
+
// Get internal
internal = selectTransport( 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] ) {
+ 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 callbacksLists ) {
callbacksLists[i].bind(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 || "";
if ( timeoutTimer ) {
clearTimeout(timeoutTimer);
}
-
+
var // Reference url
url = s.url,
// and ifModified status
ifModified = s.ifModified,
-
+
// Is it a success?
isSuccess = 0,
// Stored success
// If not timeout, force a jQuery-compliant status text
if ( statusText != "timeout" ) {
- statusText = ( status >= 200 && status < 300 ) ?
+ 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;
}
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 {
-
+
function checkData(data) {
if ( data !== undefined ) {
var testFunction = s.dataCheckers[srcDataType];
}
}
}
-
+
function convertData (data) {
var conversionFunction = dataConverters[srcDataType+" => "+destDataType] ||
dataConverters["* => "+destDataType],
if ( noFunction ) {
jQuery.error( "no data converter between " + srcDataType + " and " + destDataType );
}
-
+
}
return conversionFunction(data);
}
-
+
var dataTypes = s.dataTypes,
i,
length,
srcDataType,
destDataType,
responseTypes = s.xhrResponseFields;
-
+
for ( i = 0, length = dataTypes.length ; i < length ; i++ ) {
-
+
destDataType = dataTypes[i];
-
+
if ( !srcDataType ) { // First time
-
+
// Copy type
srcDataType = destDataType;
// Check
// Recheck data
checkData(data);
}
-
+
} else { // Subsequent times
-
+
// handle auto
// JULIAN: for reasons unknown to me === doesn't work here
if (destDataType == "*") {
-
+
destDataType = srcDataType;
-
+
} else if ( srcDataType != destDataType ) {
-
+
// Convert
data = convertData(data);
// Copy type & check
srcDataType = destDataType;
checkData(data);
-
+
}
-
+
}
-
+
// Copy response into the xhr if it hasn't been already
var responseDataType,
responseType = responseTypes[srcDataType];
-
+
if ( responseType ) {
-
+
responseDataType = srcDataType;
-
+
} else {
-
+
responseType = responseTypes[ responseDataType = "text" ];
-
+
}
-
+
if ( responseType !== 1 ) {
xhr[ "response" + responseType ] = data;
responseTypes[ responseType ] = 1;
}
-
+
}
-
+
// We have a real success
success = data;
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,
_callbacksLists = callbacksLists,
_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
_callbacksLists.success.fire( isSuccess , _callbackContext , success, statusText, xhr);
if ( isSuccess && _s.global ) {
// Error
_callbacksLists.error.fire( ! isSuccess , _callbackContext , xhr, statusText, error);
if ( !isSuccess && _s.global ) {
- _globalEventContext.trigger( "ajaxError", [xhr, _s, error] );
+ _globalEventContext.trigger( "ajaxError", [xhr, _s, error] );
}
// Complete
_callbacksLists.complete.fire( 1 , _callbackContext, xhr, statusText);
}
}
}
-
+
// 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;
xhr.onreadystatechange();
}
}
-
+
var // jQuery lists
jQuery_lastModified = jQuery.lastModified,
jQuery_etag = jQuery.etag,
xhr = {
// state
readyState: 0,
-
+
// Callback
onreadystatechange: null,
-
+
// Open
open: function(type, url, async, username, password) {
-
+
xhr.abort();
reset();
-
+
s = {
type: type,
url: url,
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) {
xhr.readyState = 0;
}
};
-
+
// Init data (so that we can bind callbacks early
reset(1);
// Install callbacks related methods
- jQuery.each(["bind","unbind"], function(_, name) {
- xhr[name] = function(type) {
-
- var functors = sliceFunc.call(arguments,1),
- list;
-
- jQuery.each(type.split(/\s+/g), function() {
- list = callbacksLists[this];
- if ( list ) {
- list[name].apply(list, functors );
- }
- });
-
- return this;
- };
- });
-
jQuery.each(callbacksLists, function(name) {
var list;
xhr[name] = function() {
return this;
};
});
-
+
// Return the xhr emulation
return xhr;
};
// Create a callback list
function createCBList() {
-
+
var functors = [],
autoFire = 0,
fireArgs,
list = {
-
+
fire: function( flag , context ) {
-
+
// Save info for later bindings
fireArgs = arguments;
-
+
// Remove autoFire to keep bindings in order
autoFire = 0;
-
+
var args = sliceFunc.call( fireArgs , 2 );
-
+
// Execute callbacks
while ( flag && functors.length ) {
flag = functors.shift().apply( context , args ) !== false;
}
-
+
// Clean if asked to stop
if ( ! flag ) {
clean();
}
-
+
// Set autoFire
- autoFire = 1;
+ autoFire = 1;
},
-
+
bind: function() {
-
+
var args = arguments,
i = 0,
length = args.length,
func;
-
+
for ( ; i < length ; i++ ) {
-
+
func = args[ i ];
-
+
if ( jQuery.isArray(func) ) {
-
+
list.bind.apply( list , func );
-
+
} else if ( isFunction(func) ) {
-
+
// Add if not already in
if ( ! pos( func ) ) {
functors.push( func );
}
}
}
-
+
if ( autoFire ) {
list.fire.apply( list , fireArgs );
}
},
-
+
unbind: function() {
-
+
var i = 0,
args = arguments,
length = args.length,
- func,
+ func,
position;
-
+
if ( length ) {
-
+
for( ; i < length ; i++ ) {
func = args[i];
if ( jQuery.isArray(func) ) {
}
}
}
-
+
} else {
-
+
functors = [];
-
+
}
}
-
+
};
// Get the index of the functor in the list (1-based)
}
return i < length ? ( i + 1 ) : 0;
}
-
+
// Clean the object
function clean() {
// Empty callbacks list
list[i] = jQuery.noop;
}
}
-
+
return list;
}
jQuery.extend(jQuery.xhr, {
-
+
// Add new prefilter
prefilter: function (functor) {
if ( isFunction(functor) ) {
}
return this;
},
-
+
// Bind a transport to one or more dataTypes
bindTransport: function () {
-
+
var args = arguments,
i,
start = 0,
append,
list,
transports = jQuery.ajaxSettings.transports;
-
+
if ( length ) {
-
+
if ( ! isFunction( args[ 0 ] ) ) {
-
+
dataTypes = args[ 0 ].toLowerCase().split(/\s+/);
start = 1;
-
+
}
-
+
if ( dataTypes.length && start < length ) {
-
+
for ( i = start; i < length; i++ ) {
functor = args[i];
if ( isFunction(functor) ) {
functors.push( functor );
}
}
-
+
if ( functors.length ) {
-
+
jQuery.each ( dataTypes, function( _ , dataType ) {
-
+
first = /^\+/.test( dataType );
-
+
if (first) {
dataType = dataType.substr(1);
}
-
+
if ( dataType !== "" ) {
-
+
append = Array.prototype[ first ? "unshift" : "push" ];
-
+
list = transports[ dataType ];
-
+
jQuery.each ( functors, function( _ , functor ) {
-
+
if ( ! list ) {
-
+
list = transports[ dataType ] = [ functor ];
-
+
} else {
-
+
append.call( list , functor );
}
} );
}
-
+
} );
}
}
}
-
+
return this;
}
-
+
});
// Select a transport given options
length,
checked = {},
flag;
-
+
function initSearch( dataType ) {
flag = transportDataType !== dataType && ! checked[ dataType ];
-
+
if ( flag ) {
-
+
checked[ dataType ] = 1;
transportDataType = dataType;
transportsList = s.transports[ dataType ];
return flag;
}
-
+
initSearch( dataTypes[ 0 ] );
for ( i = 0 ; ! transport && i <= length ; i++ ) {
-
+
if ( i === length ) {
-
+
initSearch( "*" );
-
+
} else {
transport = transportsList[ i ]( s , determineDataType );
return transport;
}
-
+
// 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 === "*" ) {
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 );