Rewrite of the Ajax module by Julian Aubourg. Some (dated) details can be found here: http://oksoclap.com/6Y26bm1ZsB more details are forthcoming. Fixes #7195.
This commit is contained in:
parent
29616e60c8
commit
ab3ba4a812
12 changed files with 1997 additions and 469 deletions
4
Makefile
4
Makefile
|
@ -24,6 +24,10 @@ 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/script.js\
|
||||||
|
${SRC_DIR}/transports/xhr.js\
|
||||||
${SRC_DIR}/effects.js\
|
${SRC_DIR}/effects.js\
|
||||||
${SRC_DIR}/offset.js\
|
${SRC_DIR}/offset.js\
|
||||||
${SRC_DIR}/dimensions.js
|
${SRC_DIR}/dimensions.js
|
||||||
|
|
547
src/ajax.js
547
src/ajax.js
|
@ -1,17 +1,11 @@
|
||||||
(function( jQuery ) {
|
(function( jQuery ) {
|
||||||
|
|
||||||
var jsc = jQuery.now(),
|
var rscript = /<script\b[^<]*(?:(?!<\/script>)<[^<]*)*<\/script>/gi,
|
||||||
rscript = /<script\b[^<]*(?:(?!<\/script>)<[^<]*)*<\/script>/gi,
|
|
||||||
rselectTextarea = /^(?:select|textarea)/i,
|
rselectTextarea = /^(?:select|textarea)/i,
|
||||||
rinput = /^(?:color|date|datetime|email|hidden|month|number|password|range|search|tel|text|time|url|week)$/i,
|
rinput = /^(?:color|date|datetime|email|hidden|month|number|password|range|search|tel|text|time|url|week)$/i,
|
||||||
rnoContent = /^(?:GET|HEAD)$/,
|
|
||||||
rbracket = /\[\]$/,
|
rbracket = /\[\]$/,
|
||||||
jsre = /\=\?(&|$)/,
|
|
||||||
rquery = /\?/,
|
rquery = /\?/,
|
||||||
rts = /([?&])_=[^&]*/,
|
|
||||||
rurl = /^(\w+:)?\/\/([^\/?#]+)/,
|
|
||||||
r20 = /%20/g,
|
r20 = /%20/g,
|
||||||
rhash = /#.*$/,
|
|
||||||
|
|
||||||
// Keep a copy of the old load method
|
// Keep a copy of the old load method
|
||||||
_load = jQuery.fn.load;
|
_load = jQuery.fn.load;
|
||||||
|
@ -90,36 +84,37 @@ jQuery.fn.extend({
|
||||||
},
|
},
|
||||||
|
|
||||||
serializeArray: function() {
|
serializeArray: function() {
|
||||||
return this.map(function() {
|
return this.map(function(){
|
||||||
return this.elements ? jQuery.makeArray(this.elements) : this;
|
return this.elements ? jQuery.makeArray(this.elements) : this;
|
||||||
})
|
})
|
||||||
.filter(function() {
|
.filter(function(){
|
||||||
return this.name && !this.disabled &&
|
return this.name && !this.disabled &&
|
||||||
(this.checked || rselectTextarea.test(this.nodeName) ||
|
(this.checked || rselectTextarea.test(this.nodeName) ||
|
||||||
rinput.test(this.type));
|
rinput.test(this.type));
|
||||||
})
|
})
|
||||||
.map(function( i, elem ) {
|
.map(function(i, elem){
|
||||||
var val = jQuery(this).val();
|
var val = jQuery(this).val();
|
||||||
|
|
||||||
return val == null ?
|
return val == null ?
|
||||||
null :
|
null :
|
||||||
jQuery.isArray(val) ?
|
jQuery.isArray(val) ?
|
||||||
jQuery.map( val, function( val, i ) {
|
jQuery.map( val, function(val, i){
|
||||||
return { name: elem.name, value: val };
|
return {name: elem.name, value: val};
|
||||||
}) :
|
}) :
|
||||||
{ name: elem.name, value: val };
|
{name: elem.name, value: val};
|
||||||
}).get();
|
}).get();
|
||||||
}
|
}
|
||||||
});
|
});
|
||||||
|
|
||||||
// Attach a bunch of functions for handling common AJAX events
|
// Attach a bunch of functions for handling common AJAX events
|
||||||
jQuery.each( "ajaxStart ajaxStop ajaxComplete ajaxError ajaxSuccess ajaxSend".split(" "), function( i, o ) {
|
jQuery.each( "ajaxStart ajaxStop ajaxComplete ajaxError ajaxSuccess ajaxSend".split(" "), function(i,o){
|
||||||
jQuery.fn[o] = function( f ) {
|
jQuery.fn[o] = function(f){
|
||||||
return this.bind(o, f);
|
return this.bind(o, f);
|
||||||
};
|
};
|
||||||
});
|
});
|
||||||
|
|
||||||
jQuery.extend({
|
jQuery.extend({
|
||||||
|
|
||||||
get: function( url, data, callback, type ) {
|
get: function( url, data, callback, type ) {
|
||||||
// shift arguments if data argument was omited
|
// shift arguments if data argument was omited
|
||||||
if ( jQuery.isFunction( data ) ) {
|
if ( jQuery.isFunction( data ) ) {
|
||||||
|
@ -176,342 +171,120 @@ jQuery.extend({
|
||||||
/*
|
/*
|
||||||
timeout: 0,
|
timeout: 0,
|
||||||
data: null,
|
data: null,
|
||||||
|
dataType: null,
|
||||||
|
dataTypes: null,
|
||||||
username: null,
|
username: null,
|
||||||
password: null,
|
password: null,
|
||||||
|
cache: null,
|
||||||
traditional: false,
|
traditional: false,
|
||||||
*/
|
*/
|
||||||
// This function can be overriden by calling jQuery.ajaxSetup
|
|
||||||
xhr: function() {
|
xhr: function() {
|
||||||
return new window.XMLHttpRequest();
|
return new window.XMLHttpRequest();
|
||||||
},
|
},
|
||||||
|
xhrResponseFields: {
|
||||||
|
xml: "XML",
|
||||||
|
text: "Text",
|
||||||
|
json: "JSON"
|
||||||
|
},
|
||||||
|
|
||||||
accepts: {
|
accepts: {
|
||||||
xml: "application/xml, text/xml",
|
xml: "application/xml, text/xml",
|
||||||
html: "text/html",
|
html: "text/html",
|
||||||
script: "text/javascript, application/javascript",
|
|
||||||
json: "application/json, text/javascript",
|
|
||||||
text: "text/plain",
|
text: "text/plain",
|
||||||
_default: "*/*"
|
json: "application/json, text/javascript",
|
||||||
|
"*": "*/*"
|
||||||
|
},
|
||||||
|
|
||||||
|
autoDataType: {
|
||||||
|
xml: /xml/,
|
||||||
|
html: /html/,
|
||||||
|
json: /json/
|
||||||
|
},
|
||||||
|
|
||||||
|
// Prefilters
|
||||||
|
// 1) They are useful to introduce custom dataTypes (see transport/jsonp for an example)
|
||||||
|
// 2) These are called:
|
||||||
|
// * BEFORE asking for a transport
|
||||||
|
// * AFTER param serialization (s.data is a string if s.processData is true)
|
||||||
|
// 3) They MUST be order agnostic
|
||||||
|
prefilters: [],
|
||||||
|
|
||||||
|
// Transports bindings
|
||||||
|
// 1) key is the dataType
|
||||||
|
// 2) the catchall symbol "*" can be used
|
||||||
|
// 3) selection will start with transport dataType and THEN go to "*" if needed
|
||||||
|
transports: {
|
||||||
|
},
|
||||||
|
|
||||||
|
// Checkers
|
||||||
|
// 1) key is dataType
|
||||||
|
// 2) they are called to control successful response
|
||||||
|
// 3) error throws is used as error data
|
||||||
|
dataCheckers: {
|
||||||
|
|
||||||
|
// Check if data is a string
|
||||||
|
"text": function(data) {
|
||||||
|
if ( typeof data != "string" ) {
|
||||||
|
jQuery.error("typeerror");
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
|
|
||||||
ajax: function( origSettings ) {
|
// Check if xml has been properly parsed
|
||||||
// IE8 leaks a lot when we've set abort, and IE6-8 a little
|
"xml": function(data) {
|
||||||
// when we have set onreadystatechange. Bug #6242
|
var documentElement = data ? data.documentElement : data;
|
||||||
// XXX IE7 still leaks when abort is called, no matter what
|
if ( ! documentElement || ! documentElement.nodeName ) {
|
||||||
// we do
|
jQuery.error("typeerror");
|
||||||
function cleanup() {
|
|
||||||
// IE6 will throw an error setting xhr.abort
|
|
||||||
try {
|
|
||||||
xhr.abort = xhr.onreadystatechange = jQuery.noop;
|
|
||||||
} catch(e) {}
|
|
||||||
}
|
}
|
||||||
|
if ( documentElement.nodeName == "parsererror" ) {
|
||||||
var s = jQuery.extend(true, {}, jQuery.ajaxSettings, origSettings),
|
jQuery.error("parsererror");
|
||||||
jsonp, status, data, type = s.type.toUpperCase(), noContent = rnoContent.test(type);
|
|
||||||
|
|
||||||
// toString fixes people passing a window.location or
|
|
||||||
// document.location to $.ajax, which worked in 1.4.2 and
|
|
||||||
// earlier (bug #7531). It should be removed in 1.5.
|
|
||||||
s.url = ("" + s.url).replace( rhash, "" );
|
|
||||||
|
|
||||||
// Use original (not extended) context object if it was provided
|
|
||||||
s.context = origSettings && origSettings.context != null ? origSettings.context : s;
|
|
||||||
|
|
||||||
// convert data if not already a string
|
|
||||||
if ( s.data && s.processData && typeof s.data !== "string" ) {
|
|
||||||
s.data = jQuery.param( s.data, s.traditional );
|
|
||||||
}
|
|
||||||
|
|
||||||
// Handle JSONP Parameter Callbacks
|
|
||||||
if ( s.dataType === "jsonp" ) {
|
|
||||||
if ( type === "GET" ) {
|
|
||||||
if ( !jsre.test( s.url ) ) {
|
|
||||||
s.url += (rquery.test( s.url ) ? "&" : "?") + (s.jsonp || "callback") + "=?";
|
|
||||||
}
|
|
||||||
} else if ( !s.data || !jsre.test(s.data) ) {
|
|
||||||
s.data = (s.data ? s.data + "&" : "") + (s.jsonp || "callback") + "=?";
|
|
||||||
}
|
|
||||||
s.dataType = "json";
|
|
||||||
}
|
|
||||||
|
|
||||||
// Build temporary JSONP function
|
|
||||||
if ( s.dataType === "json" && (s.data && jsre.test(s.data) || jsre.test(s.url)) ) {
|
|
||||||
jsonp = s.jsonpCallback || ("jsonp" + jsc++);
|
|
||||||
|
|
||||||
// Replace the =? sequence both in the query string and the data
|
|
||||||
if ( s.data ) {
|
|
||||||
s.data = (s.data + "").replace(jsre, "=" + jsonp + "$1");
|
|
||||||
}
|
|
||||||
|
|
||||||
s.url = s.url.replace(jsre, "=" + jsonp + "$1");
|
|
||||||
|
|
||||||
// We need to make sure
|
|
||||||
// that a JSONP style response is executed properly
|
|
||||||
s.dataType = "script";
|
|
||||||
|
|
||||||
// Handle JSONP-style loading
|
|
||||||
var customJsonp = window[ jsonp ];
|
|
||||||
|
|
||||||
window[ jsonp ] = function( tmp ) {
|
|
||||||
if ( jQuery.isFunction( customJsonp ) ) {
|
|
||||||
customJsonp( tmp );
|
|
||||||
|
|
||||||
} else {
|
|
||||||
// Garbage collect
|
|
||||||
window[ jsonp ] = undefined;
|
|
||||||
|
|
||||||
try {
|
|
||||||
delete window[ jsonp ];
|
|
||||||
} catch( jsonpError ) {}
|
|
||||||
}
|
|
||||||
|
|
||||||
data = tmp;
|
|
||||||
jQuery.handleSuccess( s, xhr, status, data );
|
|
||||||
jQuery.handleComplete( s, xhr, status, data );
|
|
||||||
|
|
||||||
if ( head ) {
|
|
||||||
head.removeChild( script );
|
|
||||||
}
|
|
||||||
};
|
|
||||||
}
|
|
||||||
|
|
||||||
if ( s.dataType === "script" && s.cache === undefined ) {
|
|
||||||
s.cache = false;
|
|
||||||
}
|
|
||||||
|
|
||||||
if ( s.cache === false && noContent ) {
|
|
||||||
var ts = jQuery.now();
|
|
||||||
|
|
||||||
// try replacing _= if it is there
|
|
||||||
var 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 : "");
|
|
||||||
}
|
|
||||||
|
|
||||||
// If data is available, append data to url for GET/HEAD requests
|
|
||||||
if ( s.data && noContent ) {
|
|
||||||
s.url += (rquery.test(s.url) ? "&" : "?") + s.data;
|
|
||||||
}
|
|
||||||
|
|
||||||
// Watch for a new set of requests
|
|
||||||
if ( s.global && jQuery.active++ === 0 ) {
|
|
||||||
jQuery.event.trigger( "ajaxStart" );
|
|
||||||
}
|
|
||||||
|
|
||||||
// Matches an absolute URL, and saves the domain
|
|
||||||
var parts = rurl.exec( s.url ),
|
|
||||||
remote = parts && (parts[1] && parts[1].toLowerCase() !== location.protocol || parts[2].toLowerCase() !== location.host);
|
|
||||||
|
|
||||||
// If we're requesting a remote document
|
|
||||||
// and trying to load JSON or Script with a GET
|
|
||||||
if ( s.dataType === "script" && type === "GET" && remote ) {
|
|
||||||
var head = document.getElementsByTagName("head")[0] || document.documentElement;
|
|
||||||
var script = document.createElement("script");
|
|
||||||
if ( s.scriptCharset ) {
|
|
||||||
script.charset = s.scriptCharset;
|
|
||||||
}
|
|
||||||
script.src = s.url;
|
|
||||||
|
|
||||||
// Handle Script loading
|
|
||||||
if ( !jsonp ) {
|
|
||||||
var done = false;
|
|
||||||
|
|
||||||
// Attach handlers for all browsers
|
|
||||||
script.onload = script.onreadystatechange = function() {
|
|
||||||
if ( !done && (!this.readyState ||
|
|
||||||
this.readyState === "loaded" || this.readyState === "complete") ) {
|
|
||||||
done = true;
|
|
||||||
jQuery.handleSuccess( s, xhr, status, data );
|
|
||||||
jQuery.handleComplete( s, xhr, status, data );
|
|
||||||
|
|
||||||
// Handle memory leak in IE
|
|
||||||
script.onload = script.onreadystatechange = null;
|
|
||||||
if ( head && script.parentNode ) {
|
|
||||||
head.removeChild( script );
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
};
|
},
|
||||||
|
|
||||||
|
// List of data converters
|
||||||
|
// 1) key format is "source_type => destination_type" (spaces required)
|
||||||
|
// 2) the catchall symbol "*" can be used for source_type
|
||||||
|
dataConverters: {
|
||||||
|
|
||||||
|
// Convert anything to text
|
||||||
|
"* => text": function(data) {
|
||||||
|
return "" + data;
|
||||||
|
},
|
||||||
|
|
||||||
|
// Text to html (no transformation)
|
||||||
|
"text => html": function(data) {
|
||||||
|
return data;
|
||||||
|
},
|
||||||
|
|
||||||
|
// Evaluate text as a json expression
|
||||||
|
"text => json": jQuery.parseJSON,
|
||||||
|
|
||||||
|
// Parse text as xml
|
||||||
|
"text => xml": function(data) {
|
||||||
|
var xml, parser;
|
||||||
|
if ( window.DOMParser ) { // Standard
|
||||||
|
parser = new DOMParser();
|
||||||
|
xml = parser.parseFromString(data,"text/xml");
|
||||||
|
} else { // IE
|
||||||
|
xml = new ActiveXObject("Microsoft.XMLDOM");
|
||||||
|
xml.async="false";
|
||||||
|
xml.loadXML(data);
|
||||||
}
|
}
|
||||||
|
return xml;
|
||||||
// Use insertBefore instead of appendChild to circumvent an IE6 bug.
|
|
||||||
// This arises when a base node is used (#2709 and #4378).
|
|
||||||
head.insertBefore( script, head.firstChild );
|
|
||||||
|
|
||||||
// We handle everything using the script element injection
|
|
||||||
return undefined;
|
|
||||||
}
|
|
||||||
|
|
||||||
var requestDone = false;
|
|
||||||
|
|
||||||
// Create the request object
|
|
||||||
var xhr = s.xhr();
|
|
||||||
|
|
||||||
if ( !xhr ) {
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
|
|
||||||
// Open the socket
|
|
||||||
// Passing null username, generates a login popup on Opera (#2865)
|
|
||||||
if ( s.username ) {
|
|
||||||
xhr.open(type, s.url, s.async, s.username, s.password);
|
|
||||||
} else {
|
|
||||||
xhr.open(type, s.url, s.async);
|
|
||||||
}
|
|
||||||
|
|
||||||
// Need an extra try/catch for cross domain requests in Firefox 3
|
|
||||||
try {
|
|
||||||
// Set content-type if data specified and content-body is valid for this type
|
|
||||||
if ( (s.data != null && !noContent) || (origSettings && origSettings.contentType) ) {
|
|
||||||
xhr.setRequestHeader("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] ) {
|
|
||||||
xhr.setRequestHeader("If-Modified-Since", jQuery.lastModified[s.url]);
|
|
||||||
}
|
|
||||||
|
|
||||||
if ( jQuery.etag[s.url] ) {
|
|
||||||
xhr.setRequestHeader("If-None-Match", jQuery.etag[s.url]);
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
},
|
||||||
|
|
||||||
// Set header so the called script knows that it's an XMLHttpRequest
|
// Main method
|
||||||
// Only send the header if it's not a remote XHR
|
ajax: function( url , s ) {
|
||||||
if ( !remote ) {
|
|
||||||
xhr.setRequestHeader("X-Requested-With", "XMLHttpRequest");
|
if ( arguments.length === 1 ) {
|
||||||
|
s = url;
|
||||||
|
url = s ? s.url : undefined;
|
||||||
}
|
}
|
||||||
|
|
||||||
// Set the Accepts header for the server, depending on the dataType
|
return jQuery.xhr().open( s ? s.type : undefined , url ).send( undefined , s );
|
||||||
xhr.setRequestHeader("Accept", s.dataType && s.accepts[ s.dataType ] ?
|
|
||||||
s.accepts[ s.dataType ] + ", */*; q=0.01" :
|
|
||||||
s.accepts._default );
|
|
||||||
} catch( headerError ) {}
|
|
||||||
|
|
||||||
// Allow custom headers/mimetypes and early abort
|
|
||||||
if ( s.beforeSend && s.beforeSend.call(s.context, xhr, s) === false ) {
|
|
||||||
// Handle the global AJAX counter
|
|
||||||
if ( s.global && jQuery.active-- === 1 ) {
|
|
||||||
jQuery.event.trigger( "ajaxStop" );
|
|
||||||
}
|
|
||||||
|
|
||||||
// close opended socket
|
|
||||||
xhr.abort();
|
|
||||||
return false;
|
|
||||||
}
|
|
||||||
|
|
||||||
if ( s.global ) {
|
|
||||||
jQuery.triggerGlobal( s, "ajaxSend", [xhr, s] );
|
|
||||||
}
|
|
||||||
|
|
||||||
// Wait for a response to come back
|
|
||||||
var onreadystatechange = xhr.onreadystatechange = function( isTimeout ) {
|
|
||||||
// The request was aborted
|
|
||||||
if ( !xhr || xhr.readyState === 0 || isTimeout === "abort" ) {
|
|
||||||
// Opera doesn't call onreadystatechange before this point
|
|
||||||
// so we simulate the call
|
|
||||||
if ( !requestDone ) {
|
|
||||||
jQuery.handleComplete( s, xhr, status, data );
|
|
||||||
}
|
|
||||||
|
|
||||||
requestDone = true;
|
|
||||||
if ( xhr ) {
|
|
||||||
cleanup();
|
|
||||||
}
|
|
||||||
|
|
||||||
// The transfer is complete and the data is available, or the request timed out
|
|
||||||
} else if ( !requestDone && xhr && (xhr.readyState === 4 || isTimeout === "timeout") ) {
|
|
||||||
requestDone = true;
|
|
||||||
|
|
||||||
status = isTimeout === "timeout" ?
|
|
||||||
"timeout" :
|
|
||||||
!jQuery.httpSuccess( xhr ) ?
|
|
||||||
"error" :
|
|
||||||
s.ifModified && jQuery.httpNotModified( xhr, s.url ) ?
|
|
||||||
"notmodified" :
|
|
||||||
"success";
|
|
||||||
|
|
||||||
var errMsg;
|
|
||||||
|
|
||||||
if ( status === "success" ) {
|
|
||||||
// Watch for, and catch, XML document parse errors
|
|
||||||
try {
|
|
||||||
// process the data (runs the xml through httpData regardless of callback)
|
|
||||||
data = jQuery.httpData( xhr, s.dataType, s );
|
|
||||||
} catch( parserError ) {
|
|
||||||
status = "parsererror";
|
|
||||||
errMsg = parserError;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
// Make sure that the request was successful or notmodified
|
|
||||||
if ( status === "success" || status === "notmodified" ) {
|
|
||||||
// JSONP handles its own success callback
|
|
||||||
if ( !jsonp ) {
|
|
||||||
jQuery.handleSuccess( s, xhr, status, data );
|
|
||||||
}
|
|
||||||
} else {
|
|
||||||
jQuery.handleError( s, xhr, status, errMsg );
|
|
||||||
}
|
|
||||||
|
|
||||||
// Fire the complete handlers
|
|
||||||
if ( !jsonp ) {
|
|
||||||
jQuery.handleComplete( s, xhr, status, data );
|
|
||||||
}
|
|
||||||
|
|
||||||
if ( isTimeout === "timeout" ) {
|
|
||||||
xhr.abort();
|
|
||||||
}
|
|
||||||
|
|
||||||
cleanup();
|
|
||||||
}
|
|
||||||
};
|
|
||||||
|
|
||||||
// Override the abort handler, if we can (IE 6 doesn't allow it, but that's OK)
|
|
||||||
// Opera doesn't fire onreadystatechange at all on abort
|
|
||||||
try {
|
|
||||||
var oldAbort = xhr.abort;
|
|
||||||
xhr.abort = function() {
|
|
||||||
if ( xhr ) {
|
|
||||||
// oldAbort has no call property in IE7 so
|
|
||||||
// just do it this way, which works in all
|
|
||||||
// browsers
|
|
||||||
Function.prototype.call.call( oldAbort, xhr );
|
|
||||||
}
|
|
||||||
|
|
||||||
onreadystatechange( "abort" );
|
|
||||||
};
|
|
||||||
} catch( abortError ) {}
|
|
||||||
|
|
||||||
// Timeout checker
|
|
||||||
if ( s.async && s.timeout > 0 ) {
|
|
||||||
setTimeout(function() {
|
|
||||||
// Check to see if the request is still happening
|
|
||||||
if ( xhr && !requestDone ) {
|
|
||||||
onreadystatechange( "timeout" );
|
|
||||||
}
|
|
||||||
}, s.timeout);
|
|
||||||
}
|
|
||||||
|
|
||||||
// Send the data
|
|
||||||
try {
|
|
||||||
xhr.send( noContent || s.data == null ? null : s.data );
|
|
||||||
|
|
||||||
} catch( sendError ) {
|
|
||||||
jQuery.handleError( s, xhr, null, sendError );
|
|
||||||
|
|
||||||
// Fire the complete handlers
|
|
||||||
jQuery.handleComplete( s, xhr, status, data );
|
|
||||||
}
|
|
||||||
|
|
||||||
// firefox 1.5 doesn't fire statechange for sync requests
|
|
||||||
if ( !s.async ) {
|
|
||||||
onreadystatechange();
|
|
||||||
}
|
|
||||||
|
|
||||||
// return XMLHttpRequest to allow aborting the request etc.
|
|
||||||
return xhr;
|
|
||||||
},
|
},
|
||||||
|
|
||||||
// Serialize an array of form elements or a set of
|
// Serialize an array of form elements or a set of
|
||||||
|
@ -595,110 +368,7 @@ jQuery.extend({
|
||||||
|
|
||||||
// Last-Modified header cache for next request
|
// Last-Modified header cache for next request
|
||||||
lastModified: {},
|
lastModified: {},
|
||||||
etag: {},
|
etag: {}
|
||||||
|
|
||||||
handleError: function( s, xhr, status, e ) {
|
|
||||||
// If a local callback was specified, fire it
|
|
||||||
if ( s.error ) {
|
|
||||||
s.error.call( s.context, xhr, status, e );
|
|
||||||
}
|
|
||||||
|
|
||||||
// Fire the global callback
|
|
||||||
if ( s.global ) {
|
|
||||||
jQuery.triggerGlobal( s, "ajaxError", [xhr, s, e] );
|
|
||||||
}
|
|
||||||
},
|
|
||||||
|
|
||||||
handleSuccess: function( s, xhr, status, data ) {
|
|
||||||
// If a local callback was specified, fire it and pass it the data
|
|
||||||
if ( s.success ) {
|
|
||||||
s.success.call( s.context, data, status, xhr );
|
|
||||||
}
|
|
||||||
|
|
||||||
// Fire the global callback
|
|
||||||
if ( s.global ) {
|
|
||||||
jQuery.triggerGlobal( s, "ajaxSuccess", [xhr, s] );
|
|
||||||
}
|
|
||||||
},
|
|
||||||
|
|
||||||
handleComplete: function( s, xhr, status ) {
|
|
||||||
// Process result
|
|
||||||
if ( s.complete ) {
|
|
||||||
s.complete.call( s.context, xhr, status );
|
|
||||||
}
|
|
||||||
|
|
||||||
// The request was completed
|
|
||||||
if ( s.global ) {
|
|
||||||
jQuery.triggerGlobal( s, "ajaxComplete", [xhr, s] );
|
|
||||||
}
|
|
||||||
|
|
||||||
// Handle the global AJAX counter
|
|
||||||
if ( s.global && jQuery.active-- === 1 ) {
|
|
||||||
jQuery.event.trigger( "ajaxStop" );
|
|
||||||
}
|
|
||||||
},
|
|
||||||
|
|
||||||
triggerGlobal: function( s, type, args ) {
|
|
||||||
(s.context && s.context.url == null ? jQuery(s.context) : jQuery.event).trigger(type, args);
|
|
||||||
},
|
|
||||||
|
|
||||||
// Determines if an XMLHttpRequest was successful or not
|
|
||||||
httpSuccess: function( xhr ) {
|
|
||||||
try {
|
|
||||||
// IE error sometimes returns 1223 when it should be 204 so treat it as success, see #1450
|
|
||||||
return !xhr.status && location.protocol === "file:" ||
|
|
||||||
xhr.status >= 200 && xhr.status < 300 ||
|
|
||||||
xhr.status === 304 || xhr.status === 1223;
|
|
||||||
} catch(e) {}
|
|
||||||
|
|
||||||
return false;
|
|
||||||
},
|
|
||||||
|
|
||||||
// Determines if an XMLHttpRequest returns NotModified
|
|
||||||
httpNotModified: function( xhr, url ) {
|
|
||||||
var lastModified = xhr.getResponseHeader("Last-Modified"),
|
|
||||||
etag = xhr.getResponseHeader("Etag");
|
|
||||||
|
|
||||||
if ( lastModified ) {
|
|
||||||
jQuery.lastModified[url] = lastModified;
|
|
||||||
}
|
|
||||||
|
|
||||||
if ( etag ) {
|
|
||||||
jQuery.etag[url] = etag;
|
|
||||||
}
|
|
||||||
|
|
||||||
return xhr.status === 304;
|
|
||||||
},
|
|
||||||
|
|
||||||
httpData: function( xhr, type, s ) {
|
|
||||||
var ct = xhr.getResponseHeader("content-type") || "",
|
|
||||||
xml = type === "xml" || !type && ct.indexOf("xml") >= 0,
|
|
||||||
data = xml ? xhr.responseXML : xhr.responseText;
|
|
||||||
|
|
||||||
if ( xml && data.documentElement.nodeName === "parsererror" ) {
|
|
||||||
jQuery.error( "parsererror" );
|
|
||||||
}
|
|
||||||
|
|
||||||
// Allow a pre-filtering function to sanitize the response
|
|
||||||
// s is checked to keep backwards compatibility
|
|
||||||
if ( s && s.dataFilter ) {
|
|
||||||
data = s.dataFilter( data, type );
|
|
||||||
}
|
|
||||||
|
|
||||||
// The filter can actually parse the response
|
|
||||||
if ( typeof data === "string" ) {
|
|
||||||
// Get the JavaScript object, if JSON is used.
|
|
||||||
if ( type === "json" || !type && ct.indexOf("json") >= 0 ) {
|
|
||||||
data = jQuery.parseJSON( data );
|
|
||||||
|
|
||||||
// If the type is "script", eval it in global context
|
|
||||||
} else if ( type === "script" || !type && ct.indexOf("javascript") >= 0 ) {
|
|
||||||
jQuery.globalEval( data );
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
return data;
|
|
||||||
}
|
|
||||||
|
|
||||||
});
|
});
|
||||||
|
|
||||||
|
@ -714,16 +384,21 @@ if ( window.ActiveXObject ) {
|
||||||
if ( window.location.protocol !== "file:" ) {
|
if ( window.location.protocol !== "file:" ) {
|
||||||
try {
|
try {
|
||||||
return new window.XMLHttpRequest();
|
return new window.XMLHttpRequest();
|
||||||
} catch(xhrError) {}
|
} catch( xhrError ) {}
|
||||||
}
|
}
|
||||||
|
|
||||||
try {
|
try {
|
||||||
return new window.ActiveXObject("Microsoft.XMLHTTP");
|
return new window.ActiveXObject("Microsoft.XMLHTTP");
|
||||||
} catch(activeError) {}
|
} catch( activeError ) {}
|
||||||
};
|
};
|
||||||
}
|
}
|
||||||
|
|
||||||
// Does this browser support XHR requests?
|
var testXHR = jQuery.ajaxSettings.xhr();
|
||||||
jQuery.support.ajax = !!jQuery.ajaxSettings.xhr();
|
|
||||||
|
|
||||||
})( jQuery );
|
// Does this browser support XHR requests?
|
||||||
|
jQuery.support.ajax = !!testXHR;
|
||||||
|
|
||||||
|
// Does this browser support crossDomain XHR requests
|
||||||
|
jQuery.support.cors = testXHR && "withCredentials" in testXHR;
|
||||||
|
|
||||||
|
})(jQuery);
|
89
src/transports/jsonp.js
Normal file
89
src/transports/jsonp.js
Normal file
|
@ -0,0 +1,89 @@
|
||||||
|
(function( jQuery ) {
|
||||||
|
|
||||||
|
var jsc = jQuery.now(),
|
||||||
|
jsre = /\=\?(&|$)/,
|
||||||
|
rquery = /\?/;
|
||||||
|
|
||||||
|
// Default jsonp callback name
|
||||||
|
jQuery.ajaxSettings.jsonpCallback = function() {
|
||||||
|
return "jsonp" + jsc++;
|
||||||
|
};
|
||||||
|
|
||||||
|
// Normalize jsonp queries
|
||||||
|
// 1) put callback parameter in url or data
|
||||||
|
// 2) ensure transportDataType is json
|
||||||
|
// 3) ensure options jsonp is always provided so that jsonp requests are always
|
||||||
|
// json request with the jsonp option set
|
||||||
|
jQuery.xhr.prefilter( function(s) {
|
||||||
|
|
||||||
|
var transportDataType = s.dataTypes[0];
|
||||||
|
|
||||||
|
if ( s.jsonp ||
|
||||||
|
transportDataType === "jsonp" ||
|
||||||
|
transportDataType === "json" && ( jsre.test(s.url) || typeof(s.data) === "string" && jsre.test(s.data) ) ) {
|
||||||
|
|
||||||
|
var jsonp = s.jsonp = s.jsonp || "callback",
|
||||||
|
jsonpCallback = s.jsonpCallback =
|
||||||
|
jQuery.isFunction( s.jsonpCallback ) ? s.jsonpCallback() : s.jsonpCallback,
|
||||||
|
url = s.url.replace(jsre, "=" + jsonpCallback + "$1"),
|
||||||
|
data = s.url == url && typeof(s.data) === "string" ? s.data.replace(jsre, "=" + jsonpCallback + "$1") : s.data;
|
||||||
|
|
||||||
|
if ( url == s.url && data == s.data ) {
|
||||||
|
url = url += (rquery.test( url ) ? "&" : "?") + jsonp + "=" + jsonpCallback;
|
||||||
|
}
|
||||||
|
|
||||||
|
s.url = url;
|
||||||
|
s.data = data;
|
||||||
|
|
||||||
|
s.dataTypes[0] = "json";
|
||||||
|
}
|
||||||
|
|
||||||
|
});
|
||||||
|
|
||||||
|
// Bind transport to json dataType
|
||||||
|
jQuery.xhr.bindTransport("json", function(s) {
|
||||||
|
|
||||||
|
if ( s.jsonp ) {
|
||||||
|
|
||||||
|
// Put callback in place
|
||||||
|
var responseContainer,
|
||||||
|
jsonpCallback = s.jsonpCallback,
|
||||||
|
previous = window[ jsonpCallback ];
|
||||||
|
|
||||||
|
window [ jsonpCallback ] = function( response ) {
|
||||||
|
responseContainer = [response];
|
||||||
|
};
|
||||||
|
|
||||||
|
s.complete = [function() {
|
||||||
|
|
||||||
|
// Set callback back to previous value
|
||||||
|
window[ jsonpCallback ] = previous;
|
||||||
|
|
||||||
|
// Call if it was a function and we have a response
|
||||||
|
if ( previous) {
|
||||||
|
if ( responseContainer && jQuery.isFunction ( previous ) ) {
|
||||||
|
window[ jsonpCallback ] ( responseContainer[0] );
|
||||||
|
}
|
||||||
|
} else {
|
||||||
|
// else, more memory leak avoidance
|
||||||
|
try{ delete window[ jsonpCallback ]; } catch(e){}
|
||||||
|
}
|
||||||
|
|
||||||
|
}, s.complete ];
|
||||||
|
|
||||||
|
// Use data converter to retrieve json after script execution
|
||||||
|
s.dataConverters["script => json"] = function() {
|
||||||
|
if ( ! responseContainer ) {
|
||||||
|
jQuery.error("Callback '" + jsonpCallback + "' was not called");
|
||||||
|
}
|
||||||
|
return responseContainer[ 0 ];
|
||||||
|
};
|
||||||
|
|
||||||
|
// Delegate to script transport
|
||||||
|
return "script";
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
|
});
|
||||||
|
|
||||||
|
})(jQuery);
|
83
src/transports/script.js
Normal file
83
src/transports/script.js
Normal file
|
@ -0,0 +1,83 @@
|
||||||
|
(function( jQuery ) {
|
||||||
|
|
||||||
|
// Install text to script executor
|
||||||
|
jQuery.extend( true, jQuery.ajaxSettings , {
|
||||||
|
|
||||||
|
accepts: {
|
||||||
|
script: "text/javascript, application/javascript"
|
||||||
|
},
|
||||||
|
|
||||||
|
autoDataType: {
|
||||||
|
script: /javascript/
|
||||||
|
},
|
||||||
|
|
||||||
|
dataConverters: {
|
||||||
|
"text => script": jQuery.globalEval
|
||||||
|
}
|
||||||
|
} );
|
||||||
|
|
||||||
|
// Bind script tag hack transport
|
||||||
|
jQuery.xhr.bindTransport("script", function(s) {
|
||||||
|
|
||||||
|
// Handle cache special case
|
||||||
|
if ( s.cache === undefined ) {
|
||||||
|
s.cache = false;
|
||||||
|
}
|
||||||
|
|
||||||
|
// This transport only deals with cross domain get requests
|
||||||
|
if ( s.crossDomain && s.async && ( s.type === "GET" || ! s.data ) ) {
|
||||||
|
|
||||||
|
s.global = false;
|
||||||
|
|
||||||
|
var script,
|
||||||
|
head = document.getElementsByTagName("head")[0] || document.documentElement;
|
||||||
|
|
||||||
|
return {
|
||||||
|
|
||||||
|
send: function(_, callback) {
|
||||||
|
|
||||||
|
script = document.createElement("script");
|
||||||
|
|
||||||
|
script.async = "async";
|
||||||
|
|
||||||
|
if ( s.scriptCharset ) {
|
||||||
|
script.charset = s.scriptCharset;
|
||||||
|
}
|
||||||
|
|
||||||
|
script.src = s.url;
|
||||||
|
|
||||||
|
// Attach handlers for all browsers
|
||||||
|
script.onload = script.onreadystatechange = function(statusText) {
|
||||||
|
|
||||||
|
if ( (!script.readyState ||
|
||||||
|
script.readyState === "loaded" || script.readyState === "complete") ) {
|
||||||
|
|
||||||
|
// Handle memory leak in IE
|
||||||
|
script.onload = script.onreadystatechange = null;
|
||||||
|
|
||||||
|
// Remove the script
|
||||||
|
if ( head && script.parentNode ) {
|
||||||
|
head.removeChild( script );
|
||||||
|
}
|
||||||
|
|
||||||
|
script = undefined;
|
||||||
|
|
||||||
|
// Callback & dereference
|
||||||
|
callback(statusText ? 0 : 200, statusText || "success");
|
||||||
|
}
|
||||||
|
};
|
||||||
|
// Use insertBefore instead of appendChild to circumvent an IE6 bug.
|
||||||
|
// This arises when a base node is used (#2709 and #4378).
|
||||||
|
head.insertBefore( script, head.firstChild );
|
||||||
|
},
|
||||||
|
|
||||||
|
abort: function(statusText) {
|
||||||
|
if ( script ) {
|
||||||
|
script.onload(statusText);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
};
|
||||||
|
}
|
||||||
|
});
|
||||||
|
|
||||||
|
})(jQuery);
|
191
src/transports/xhr.js
Normal file
191
src/transports/xhr.js
Normal file
|
@ -0,0 +1,191 @@
|
||||||
|
(function( jQuery ) {
|
||||||
|
|
||||||
|
var // Next fake timer id
|
||||||
|
xhrPollingId = jQuery.now(),
|
||||||
|
|
||||||
|
// Callbacks hashtable
|
||||||
|
xhrs = {},
|
||||||
|
|
||||||
|
// #5280: see end of file
|
||||||
|
xhrUnloadAbortMarker = [];
|
||||||
|
|
||||||
|
|
||||||
|
jQuery.xhr.bindTransport( function( s , determineDataType ) {
|
||||||
|
|
||||||
|
// Cross domain only allowed if supported through XMLHttpRequest
|
||||||
|
if ( ! s.crossDomain || jQuery.support.cors ) {
|
||||||
|
|
||||||
|
var callback;
|
||||||
|
|
||||||
|
return {
|
||||||
|
|
||||||
|
send: function(headers, complete) {
|
||||||
|
|
||||||
|
var xhr = s.xhr(),
|
||||||
|
handle;
|
||||||
|
|
||||||
|
// Open the socket
|
||||||
|
// Passing null username, generates a login popup on Opera (#2865)
|
||||||
|
if ( s.username ) {
|
||||||
|
xhr.open(s.type, s.url, s.async, s.username, s.password);
|
||||||
|
} else {
|
||||||
|
xhr.open(s.type, s.url, s.async);
|
||||||
|
}
|
||||||
|
|
||||||
|
// Requested-With header
|
||||||
|
// Not set for crossDomain requests with no content
|
||||||
|
// (see why at http://trac.dojotoolkit.org/ticket/9486)
|
||||||
|
// Won't change header if already provided in beforeSend
|
||||||
|
if ( ! ( s.crossDomain && ! s.hasContent ) && ! headers["x-requested-with"] ) {
|
||||||
|
headers["x-requested-with"] = "XMLHttpRequest";
|
||||||
|
}
|
||||||
|
|
||||||
|
// Need an extra try/catch for cross domain requests in Firefox 3
|
||||||
|
try {
|
||||||
|
|
||||||
|
jQuery.each(headers, function(key,value) {
|
||||||
|
xhr.setRequestHeader(key,value);
|
||||||
|
});
|
||||||
|
|
||||||
|
} catch(_) {}
|
||||||
|
|
||||||
|
// Do send the request
|
||||||
|
try {
|
||||||
|
xhr.send( ( s.hasContent && s.data ) || null );
|
||||||
|
} catch(e) {
|
||||||
|
complete(0, "error", "" + e);
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
// Listener
|
||||||
|
callback = function ( abortStatusText ) {
|
||||||
|
|
||||||
|
// Was never called and is aborted or complete
|
||||||
|
if ( callback && ( abortStatusText || xhr.readyState === 4 ) ) {
|
||||||
|
|
||||||
|
// Do not listen anymore
|
||||||
|
if (handle) {
|
||||||
|
xhr.onreadystatechange = jQuery.noop;
|
||||||
|
delete xhrs[ handle ];
|
||||||
|
handle = undefined;
|
||||||
|
}
|
||||||
|
|
||||||
|
callback = 0;
|
||||||
|
|
||||||
|
// Get info
|
||||||
|
var status, statusText, response, responseHeaders;
|
||||||
|
|
||||||
|
if ( abortStatusText ) {
|
||||||
|
|
||||||
|
if ( xhr.readyState !== 4 ) {
|
||||||
|
xhr.abort();
|
||||||
|
}
|
||||||
|
|
||||||
|
// Stop here if unloadAbort
|
||||||
|
if ( abortStatusText === xhrUnloadAbortMarker ) {
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
status = 0;
|
||||||
|
statusText = abortStatusText;
|
||||||
|
|
||||||
|
} else {
|
||||||
|
|
||||||
|
status = xhr.status;
|
||||||
|
|
||||||
|
try { // Firefox throws an exception when accessing statusText for faulty cross-domain requests
|
||||||
|
|
||||||
|
statusText = xhr.statusText;
|
||||||
|
|
||||||
|
} catch( e ) {
|
||||||
|
|
||||||
|
statusText = ""; // We normalize with Webkit giving an empty statusText
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
|
responseHeaders = xhr.getAllResponseHeaders();
|
||||||
|
|
||||||
|
// Filter status for non standard behaviours
|
||||||
|
// (so many they seem to be the actual "standard")
|
||||||
|
status =
|
||||||
|
// Opera returns 0 when it should be 304
|
||||||
|
// Webkit returns 0 for failing cross-domain no matter the real status
|
||||||
|
status === 0 ?
|
||||||
|
(
|
||||||
|
! s.crossDomain || statusText ? // Webkit, Firefox: filter out faulty cross-domain requests
|
||||||
|
(
|
||||||
|
responseHeaders ? // Opera: filter out real aborts #6060
|
||||||
|
304
|
||||||
|
:
|
||||||
|
0
|
||||||
|
)
|
||||||
|
:
|
||||||
|
302 // We assume 302 but could be anything cross-domain related
|
||||||
|
)
|
||||||
|
:
|
||||||
|
(
|
||||||
|
status == 1223 ? // IE sometimes returns 1223 when it should be 204 (see #1450)
|
||||||
|
204
|
||||||
|
:
|
||||||
|
status
|
||||||
|
);
|
||||||
|
|
||||||
|
// Guess response if needed & update datatype accordingly
|
||||||
|
if ( status >= 200 && status < 300 ) {
|
||||||
|
response =
|
||||||
|
determineDataType(
|
||||||
|
s,
|
||||||
|
xhr.getResponseHeader("content-type"),
|
||||||
|
xhr.responseText,
|
||||||
|
xhr.responseXML );
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// Call complete
|
||||||
|
complete(status,statusText,response,responseHeaders);
|
||||||
|
}
|
||||||
|
};
|
||||||
|
|
||||||
|
// if we're in sync mode
|
||||||
|
// or it's in cache and has been retrieved directly (IE6 & IE7)
|
||||||
|
// we need to manually fire the callback
|
||||||
|
if ( ! s.async || xhr.readyState === 4 ) {
|
||||||
|
|
||||||
|
callback();
|
||||||
|
|
||||||
|
} else {
|
||||||
|
|
||||||
|
// Listener is externalized to handle abort on unload
|
||||||
|
handle = xhrPollingId++;
|
||||||
|
xhrs[ handle ] = xhr;
|
||||||
|
xhr.onreadystatechange = function() {
|
||||||
|
callback();
|
||||||
|
};
|
||||||
|
}
|
||||||
|
},
|
||||||
|
|
||||||
|
abort: function(statusText) {
|
||||||
|
if ( callback ) {
|
||||||
|
callback(statusText);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
};
|
||||||
|
}
|
||||||
|
});
|
||||||
|
|
||||||
|
// #5280: we need to abort on unload or IE will keep connections alive
|
||||||
|
jQuery(window).bind( "unload" , function() {
|
||||||
|
|
||||||
|
// Abort all pending requests
|
||||||
|
jQuery.each(xhrs, function(_, xhr) {
|
||||||
|
if ( xhr.onreadystatechange ) {
|
||||||
|
xhr.onreadystatechange( xhrUnloadAbortMarker );
|
||||||
|
}
|
||||||
|
});
|
||||||
|
|
||||||
|
// Resest polling structure to be safe
|
||||||
|
xhrs = {};
|
||||||
|
|
||||||
|
});
|
||||||
|
|
||||||
|
})(jQuery);
|
941
src/xhr.js
Normal file
941
src/xhr.js
Normal file
|
@ -0,0 +1,941 @@
|
||||||
|
(function( jQuery , undefined ) {
|
||||||
|
|
||||||
|
var rquery = /\?/,
|
||||||
|
rhash = /#.*$/,
|
||||||
|
rheaders = /^(.*?):\s*(.*?)\r?$/mg, // IE leaves an \r character at EOL
|
||||||
|
rnoContent = /^(?:GET|HEAD)$/,
|
||||||
|
rts = /([?&])_=[^&]*/,
|
||||||
|
rurl = /^(\w+:)?\/\/([^\/?#]+)/,
|
||||||
|
|
||||||
|
slice = 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) ) {
|
||||||
|
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 );
|
||||||
|
}
|
||||||
|
|
||||||
|
// Apply option prefilters
|
||||||
|
for (i in prefilters) {
|
||||||
|
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.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.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
|
||||||
|
if ( headers ) {
|
||||||
|
xhr.setRequestHeaders( headers );
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
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 || "";
|
||||||
|
|
||||||
|
// 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 {
|
||||||
|
|
||||||
|
function checkData(data) {
|
||||||
|
if ( data !== undefined ) {
|
||||||
|
var testFunction = s.dataCheckers[srcDataType];
|
||||||
|
if ( isFunction( testFunction ) ) {
|
||||||
|
testFunction(data);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
function convertData (data) {
|
||||||
|
var conversionFunction = dataConverters[srcDataType+" => "+destDataType] ||
|
||||||
|
dataConverters["* => "+destDataType],
|
||||||
|
noFunction = ! isFunction( conversionFunction );
|
||||||
|
if ( noFunction ) {
|
||||||
|
if ( srcDataType != "text" && destDataType != "text" ) {
|
||||||
|
// We try to put text inbetween
|
||||||
|
var first = dataConverters[srcDataType+" => text"] ||
|
||||||
|
dataConverters["* => text"],
|
||||||
|
second = dataConverters["text => "+destDataType] ||
|
||||||
|
dataConverters["* => "+destDataType],
|
||||||
|
areFunctions = isFunction( first ) && isFunction( second );
|
||||||
|
if ( areFunctions ) {
|
||||||
|
conversionFunction = function (data) {
|
||||||
|
return second( first ( data ) );
|
||||||
|
};
|
||||||
|
}
|
||||||
|
noFunction = ! areFunctions;
|
||||||
|
}
|
||||||
|
if ( noFunction ) {
|
||||||
|
jQuery.error( "no data converter between " + srcDataType + " and " + destDataType );
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
||||||
|
return conversionFunction(data);
|
||||||
|
}
|
||||||
|
|
||||||
|
var dataTypes = s.dataTypes,
|
||||||
|
i,
|
||||||
|
length,
|
||||||
|
data = response,
|
||||||
|
dataConverters = s.dataConverters,
|
||||||
|
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
|
||||||
|
checkData(data);
|
||||||
|
// Apply dataFilter
|
||||||
|
if ( isFunction( s.dataFilter ) ) {
|
||||||
|
data = s.dataFilter(data, s.dataType);
|
||||||
|
// 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 ) {
|
||||||
|
_globalEventContext.trigger( "ajaxSuccess", [xhr, _s, success] );
|
||||||
|
}
|
||||||
|
// Error
|
||||||
|
_callbacksLists.error.fire( ! isSuccess , _callbackContext , xhr, statusText, error);
|
||||||
|
if ( !isSuccess && _s.global ) {
|
||||||
|
_globalEventContext.trigger( "ajaxError", [xhr, _s, error] );
|
||||||
|
}
|
||||||
|
// Complete
|
||||||
|
_callbacksLists.complete.fire( 1 , _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 ( isFunction( xhr.onreadystatechange ) ) {
|
||||||
|
xhr.onreadystatechange();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
var // jQuery lists
|
||||||
|
jQuery_lastModified = jQuery.lastModified,
|
||||||
|
jQuery_etag = jQuery.etag,
|
||||||
|
// Options object
|
||||||
|
s,
|
||||||
|
// Callback stuff
|
||||||
|
callbackContext,
|
||||||
|
globalEventContext,
|
||||||
|
callbacksLists,
|
||||||
|
// 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;
|
||||||
|
},
|
||||||
|
|
||||||
|
// Ditto with an s
|
||||||
|
setRequestHeaders: function(map) {
|
||||||
|
checkState(1, !sendFlag);
|
||||||
|
for ( var name in map ) {
|
||||||
|
requestHeaders[ name.toLowerCase() ] = map[name];
|
||||||
|
}
|
||||||
|
return xhr;
|
||||||
|
},
|
||||||
|
|
||||||
|
// Utility method to get headers set
|
||||||
|
getRequestHeader: function(name) {
|
||||||
|
checkState(1, !sendFlag);
|
||||||
|
return requestHeaders[ name.toLowerCase() ];
|
||||||
|
},
|
||||||
|
|
||||||
|
// 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);
|
||||||
|
|
||||||
|
// Install callbacks related methods
|
||||||
|
jQuery.each(["bind","unbind"], function(_, name) {
|
||||||
|
xhr[name] = function(type) {
|
||||||
|
|
||||||
|
var functors = slice.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() {
|
||||||
|
list = callbacksLists[name];
|
||||||
|
if ( list ) {
|
||||||
|
list.bind.apply(list, arguments );
|
||||||
|
}
|
||||||
|
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 = slice.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;
|
||||||
|
},
|
||||||
|
|
||||||
|
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,
|
||||||
|
position;
|
||||||
|
|
||||||
|
if ( length ) {
|
||||||
|
|
||||||
|
for( ; i < length ; i++ ) {
|
||||||
|
func = args[i];
|
||||||
|
if ( jQuery.isArray(func) ) {
|
||||||
|
list.unbind.apply(list,func);
|
||||||
|
} else if ( isFunction(func) ) {
|
||||||
|
position = pos(func);
|
||||||
|
if ( position ) {
|
||||||
|
functors.splice(position-1,1);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
} else {
|
||||||
|
|
||||||
|
functors = [];
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
|
};
|
||||||
|
|
||||||
|
// Get the index of the functor in the list (1-based)
|
||||||
|
function pos( func ) {
|
||||||
|
for (var i = 0, length = functors.length; i < length && functors[i] !== func; i++) {
|
||||||
|
}
|
||||||
|
return i < length ? ( i + 1 ) : 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
// Clean the object
|
||||||
|
function clean() {
|
||||||
|
// Empty callbacks list
|
||||||
|
functors = [];
|
||||||
|
// Inhibit methods
|
||||||
|
for (var i in list) {
|
||||||
|
list[i] = jQuery.noop;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
return list;
|
||||||
|
}
|
||||||
|
|
||||||
|
jQuery.extend(jQuery.xhr, {
|
||||||
|
|
||||||
|
// Add new prefilter
|
||||||
|
prefilter: function (functor) {
|
||||||
|
if ( isFunction(functor) ) {
|
||||||
|
jQuery.ajaxSettings.prefilters.push( functor );
|
||||||
|
}
|
||||||
|
return this;
|
||||||
|
},
|
||||||
|
|
||||||
|
// Bind a transport to one or more dataTypes
|
||||||
|
bindTransport: function () {
|
||||||
|
|
||||||
|
var args = arguments,
|
||||||
|
i,
|
||||||
|
start = 0,
|
||||||
|
length = args.length,
|
||||||
|
dataTypes = [ "*" ],
|
||||||
|
functors = [],
|
||||||
|
functor,
|
||||||
|
first,
|
||||||
|
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
|
||||||
|
function selectTransport( s ) {
|
||||||
|
|
||||||
|
var dataTypes = s.dataTypes,
|
||||||
|
transportDataType,
|
||||||
|
transportsList,
|
||||||
|
transport,
|
||||||
|
i,
|
||||||
|
length,
|
||||||
|
checked = {},
|
||||||
|
flag;
|
||||||
|
|
||||||
|
function initSearch( dataType ) {
|
||||||
|
|
||||||
|
flag = transportDataType !== dataType && ! checked[ dataType ];
|
||||||
|
|
||||||
|
if ( flag ) {
|
||||||
|
|
||||||
|
checked[ dataType ] = 1;
|
||||||
|
transportDataType = dataType;
|
||||||
|
transportsList = s.transports[ dataType ];
|
||||||
|
i = -1;
|
||||||
|
length = transportsList ? transportsList.length : 0 ;
|
||||||
|
}
|
||||||
|
|
||||||
|
return flag;
|
||||||
|
}
|
||||||
|
|
||||||
|
initSearch( dataTypes[ 0 ] );
|
||||||
|
|
||||||
|
for ( i = 0 ; ! transport && i <= length ; i++ ) {
|
||||||
|
|
||||||
|
if ( i === length ) {
|
||||||
|
|
||||||
|
initSearch( "*" );
|
||||||
|
|
||||||
|
} else {
|
||||||
|
|
||||||
|
transport = transportsList[ i ]( s , determineDataType );
|
||||||
|
|
||||||
|
// If we got redirected to another dataType
|
||||||
|
// Search there (if not in progress or already tried)
|
||||||
|
if ( typeof( transport ) === "string" &&
|
||||||
|
initSearch( transport ) ) {
|
||||||
|
|
||||||
|
dataTypes.unshift( transport );
|
||||||
|
transport = 0;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
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 === "*" ) {
|
||||||
|
|
||||||
|
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);
|
4
test/data/atom+xml.php
Normal file
4
test/data/atom+xml.php
Normal file
|
@ -0,0 +1,4 @@
|
||||||
|
<?php header("Content-type: atom+xml") ?>
|
||||||
|
<root>
|
||||||
|
<element />
|
||||||
|
</root>
|
15
test/data/css.php
Normal file
15
test/data/css.php
Normal file
|
@ -0,0 +1,15 @@
|
||||||
|
<?php
|
||||||
|
error_reporting(0);
|
||||||
|
$id = isset ( $_REQUEST['id'] ) ? $_REQUEST['id'] : null;
|
||||||
|
$wait = isset( $_REQUEST['wait'] ) ? $_REQUEST['wait'] : null;
|
||||||
|
|
||||||
|
if ( $wait ) sleep( $wait );
|
||||||
|
|
||||||
|
header("Content-type: text/css");
|
||||||
|
|
||||||
|
if ( $id ) {
|
||||||
|
?>
|
||||||
|
div#<?= $id ?> { margin-left: 27px }
|
||||||
|
<?php
|
||||||
|
}
|
||||||
|
?>
|
5
test/data/headers.php
Normal file
5
test/data/headers.php
Normal file
|
@ -0,0 +1,5 @@
|
||||||
|
<?php
|
||||||
|
|
||||||
|
header( "Multiple-Line: Hello\n World" );
|
||||||
|
header( "Multiple-Multiple-Line: Hello\n Beautiful\n\t World" );
|
||||||
|
header( "Single-Line: Hello World" );
|
7
test/data/with_fries_over_jsonp.php
Normal file
7
test/data/with_fries_over_jsonp.php
Normal file
|
@ -0,0 +1,7 @@
|
||||||
|
<?php
|
||||||
|
error_reporting(0);
|
||||||
|
$callback = $_REQUEST['callback'];
|
||||||
|
$json = $_REQUEST['json'];
|
||||||
|
$text = json_encode(file_get_contents(dirname(__FILE__)."/with_fries.xml"));
|
||||||
|
echo "$callback($text)";
|
||||||
|
?>
|
|
@ -20,6 +20,10 @@
|
||||||
<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/script.js"></script>
|
||||||
|
<script src="../src/transports/xhr.js"></script>
|
||||||
<script src="../src/effects.js"></script>
|
<script src="../src/effects.js"></script>
|
||||||
<script src="../src/offset.js"></script>
|
<script src="../src/offset.js"></script>
|
||||||
<script src="../src/dimensions.js"></script>
|
<script src="../src/dimensions.js"></script>
|
||||||
|
|
|
@ -38,6 +38,216 @@ test("jQuery.ajax() - success callbacks", function() {
|
||||||
});
|
});
|
||||||
});
|
});
|
||||||
|
|
||||||
|
test("jQuery.ajax() - success callbacks - (url, options) syntax", function() {
|
||||||
|
expect( 8 );
|
||||||
|
|
||||||
|
jQuery.ajaxSetup({ timeout: 0 });
|
||||||
|
|
||||||
|
stop();
|
||||||
|
|
||||||
|
setTimeout(function(){
|
||||||
|
jQuery('#foo').ajaxStart(function(){
|
||||||
|
ok( true, "ajaxStart" );
|
||||||
|
}).ajaxStop(function(){
|
||||||
|
ok( true, "ajaxStop" );
|
||||||
|
start();
|
||||||
|
}).ajaxSend(function(){
|
||||||
|
ok( true, "ajaxSend" );
|
||||||
|
}).ajaxComplete(function(){
|
||||||
|
ok( true, "ajaxComplete" );
|
||||||
|
}).ajaxError(function(){
|
||||||
|
ok( false, "ajaxError" );
|
||||||
|
}).ajaxSuccess(function(){
|
||||||
|
ok( true, "ajaxSuccess" );
|
||||||
|
});
|
||||||
|
|
||||||
|
jQuery.ajax( url("data/name.html") , {
|
||||||
|
beforeSend: function(){ ok(true, "beforeSend"); },
|
||||||
|
success: function(){ ok(true, "success"); },
|
||||||
|
error: function(){ ok(false, "error"); },
|
||||||
|
complete: function(){ ok(true, "complete"); }
|
||||||
|
});
|
||||||
|
}, 13);
|
||||||
|
});
|
||||||
|
|
||||||
|
test("jQuery.ajax() - success/error callbacks (remote)", function() {
|
||||||
|
|
||||||
|
var supports = jQuery.support.cors;
|
||||||
|
|
||||||
|
expect( supports ? 9 : 6 );
|
||||||
|
|
||||||
|
jQuery.ajaxSetup({ timeout: 0 });
|
||||||
|
|
||||||
|
stop();
|
||||||
|
|
||||||
|
setTimeout(function(){
|
||||||
|
jQuery('#foo').ajaxStart(function(){
|
||||||
|
ok( true, "ajaxStart" );
|
||||||
|
}).ajaxStop(function(){
|
||||||
|
ok( true, "ajaxStop" );
|
||||||
|
start();
|
||||||
|
}).ajaxSend(function(){
|
||||||
|
ok( supports , "ajaxSend" );
|
||||||
|
}).ajaxComplete(function(){
|
||||||
|
ok( true, "ajaxComplete" );
|
||||||
|
}).ajaxError(function(){
|
||||||
|
ok( ! supports, "ajaxError" );
|
||||||
|
}).ajaxSuccess(function(){
|
||||||
|
ok( supports, "ajaxSuccess" );
|
||||||
|
});
|
||||||
|
|
||||||
|
jQuery.ajax({
|
||||||
|
// JULIAN TODO: Get an url especially for jQuery
|
||||||
|
url: "http://rockstarapps.com/test.php",
|
||||||
|
dataType: "text",
|
||||||
|
beforeSend: function(){ ok(supports, "beforeSend"); },
|
||||||
|
success: function( val ){ ok(supports, "success"); ok(supports && val.length, "data received"); },
|
||||||
|
error: function(_ , a , b ){ ok(!supports, "error"); },
|
||||||
|
complete: function(){ ok(true, "complete"); }
|
||||||
|
});
|
||||||
|
}, 13);
|
||||||
|
});
|
||||||
|
|
||||||
|
test("jQuery.ajax() - success callbacks (late binding)", function() {
|
||||||
|
expect( 8 );
|
||||||
|
|
||||||
|
jQuery.ajaxSetup({ timeout: 0 });
|
||||||
|
|
||||||
|
stop();
|
||||||
|
|
||||||
|
setTimeout(function(){
|
||||||
|
jQuery('#foo').ajaxStart(function(){
|
||||||
|
ok( true, "ajaxStart" );
|
||||||
|
}).ajaxStop(function(){
|
||||||
|
ok( true, "ajaxStop" );
|
||||||
|
start();
|
||||||
|
}).ajaxSend(function(){
|
||||||
|
ok( true, "ajaxSend" );
|
||||||
|
}).ajaxComplete(function(){
|
||||||
|
ok( true, "ajaxComplete" );
|
||||||
|
}).ajaxError(function(){
|
||||||
|
ok( false, "ajaxError" );
|
||||||
|
}).ajaxSuccess(function(){
|
||||||
|
ok( true, "ajaxSuccess" );
|
||||||
|
});
|
||||||
|
|
||||||
|
jQuery.ajax({
|
||||||
|
url: url("data/name.html"),
|
||||||
|
beforeSend: function(){ ok(true, "beforeSend"); }
|
||||||
|
})
|
||||||
|
.complete(function(){ ok(true, "complete"); })
|
||||||
|
.success(function(){ ok(true, "success"); })
|
||||||
|
.error(function(){ ok(false, "error"); });
|
||||||
|
}, 13);
|
||||||
|
});
|
||||||
|
|
||||||
|
test("jQuery.ajax() - success callbacks (oncomplete binding)", function() {
|
||||||
|
expect( 8 );
|
||||||
|
|
||||||
|
jQuery.ajaxSetup({ timeout: 0 });
|
||||||
|
|
||||||
|
stop();
|
||||||
|
|
||||||
|
setTimeout(function(){
|
||||||
|
jQuery('#foo').ajaxStart(function(){
|
||||||
|
ok( true, "ajaxStart" );
|
||||||
|
}).ajaxStop(function(){
|
||||||
|
ok( true, "ajaxStop" );
|
||||||
|
}).ajaxSend(function(){
|
||||||
|
ok( true, "ajaxSend" );
|
||||||
|
}).ajaxComplete(function(){
|
||||||
|
ok( true, "ajaxComplete" );
|
||||||
|
}).ajaxError(function(){
|
||||||
|
ok( false, "ajaxError" );
|
||||||
|
}).ajaxSuccess(function(){
|
||||||
|
ok( true, "ajaxSuccess" );
|
||||||
|
});
|
||||||
|
|
||||||
|
jQuery.ajax({
|
||||||
|
url: url("data/name.html"),
|
||||||
|
beforeSend: function(){ ok(true, "beforeSend"); },
|
||||||
|
complete: function(xhr) {
|
||||||
|
xhr
|
||||||
|
.complete(function(){ ok(true, "complete"); })
|
||||||
|
.success(function(){ ok(true, "success"); })
|
||||||
|
.error(function(){ ok(false, "error"); })
|
||||||
|
.complete(function(){ start(); });
|
||||||
|
}
|
||||||
|
})
|
||||||
|
}, 13);
|
||||||
|
});
|
||||||
|
|
||||||
|
test("jQuery.ajax() - success callbacks (very late binding)", function() {
|
||||||
|
expect( 8 );
|
||||||
|
|
||||||
|
jQuery.ajaxSetup({ timeout: 0 });
|
||||||
|
|
||||||
|
stop();
|
||||||
|
|
||||||
|
setTimeout(function(){
|
||||||
|
jQuery('#foo').ajaxStart(function(){
|
||||||
|
ok( true, "ajaxStart" );
|
||||||
|
}).ajaxStop(function(){
|
||||||
|
ok( true, "ajaxStop" );
|
||||||
|
}).ajaxSend(function(){
|
||||||
|
ok( true, "ajaxSend" );
|
||||||
|
}).ajaxComplete(function(){
|
||||||
|
ok( true, "ajaxComplete" );
|
||||||
|
}).ajaxError(function(){
|
||||||
|
ok( false, "ajaxError" );
|
||||||
|
}).ajaxSuccess(function(){
|
||||||
|
ok( true, "ajaxSuccess" );
|
||||||
|
});
|
||||||
|
|
||||||
|
jQuery.ajax({
|
||||||
|
url: url("data/name.html"),
|
||||||
|
beforeSend: function(){ ok(true, "beforeSend"); },
|
||||||
|
complete: function(xhr) {
|
||||||
|
setTimeout (function() {
|
||||||
|
xhr
|
||||||
|
.complete(function(){ ok(true, "complete"); })
|
||||||
|
.success(function(){ ok(true, "success"); })
|
||||||
|
.error(function(){ ok(false, "error"); })
|
||||||
|
.complete(function(){ start(); });
|
||||||
|
},100);
|
||||||
|
}
|
||||||
|
})
|
||||||
|
}, 13);
|
||||||
|
});
|
||||||
|
|
||||||
|
test("jQuery.ajax() - success callbacks (order)", function() {
|
||||||
|
expect( 1 );
|
||||||
|
|
||||||
|
jQuery.ajaxSetup({ timeout: 0 });
|
||||||
|
|
||||||
|
stop();
|
||||||
|
|
||||||
|
var testString = "";
|
||||||
|
|
||||||
|
setTimeout(function(){
|
||||||
|
jQuery.ajax({
|
||||||
|
url: url("data/name.html"),
|
||||||
|
success: function( _1 , _2 , xhr ) {
|
||||||
|
xhr.success(function() {
|
||||||
|
xhr.success(function() {
|
||||||
|
testString += "E";
|
||||||
|
});
|
||||||
|
testString += "D";
|
||||||
|
});
|
||||||
|
testString += "A";
|
||||||
|
},
|
||||||
|
complete: function() {
|
||||||
|
strictEqual(testString, "ABCDE", "Proper order");
|
||||||
|
start();
|
||||||
|
}
|
||||||
|
}).success(function() {
|
||||||
|
testString += "B";
|
||||||
|
}).success(function() {
|
||||||
|
testString += "C";
|
||||||
|
});
|
||||||
|
}, 13);
|
||||||
|
});
|
||||||
|
|
||||||
test("jQuery.ajax() - error callbacks", function() {
|
test("jQuery.ajax() - error callbacks", function() {
|
||||||
expect( 8 );
|
expect( 8 );
|
||||||
stop();
|
stop();
|
||||||
|
@ -68,6 +278,32 @@ test("jQuery.ajax() - error callbacks", function() {
|
||||||
});
|
});
|
||||||
});
|
});
|
||||||
|
|
||||||
|
test(".ajax() - headers" , function() {
|
||||||
|
|
||||||
|
// No multiple line headers in IE
|
||||||
|
expect( jQuery.browser.msie ? 2 : 4 );
|
||||||
|
|
||||||
|
stop();
|
||||||
|
|
||||||
|
jQuery.ajax({
|
||||||
|
url: url("data/headers.php"),
|
||||||
|
success: function( _1 , _2 , xhr ){
|
||||||
|
ok(true, "success");
|
||||||
|
equals( xhr.getResponseHeader( "Single-Line" ) , "Hello World" , "Single line header" );
|
||||||
|
// No multiple line headers in IE
|
||||||
|
if ( ! jQuery.browser.msie ) {
|
||||||
|
// Each browser has its own unique way to deal with spaces after line breaks
|
||||||
|
// in multiple line headers, so we use regular expressions
|
||||||
|
ok( /^Hello\s+World$/.test( xhr.getResponseHeader( "Multiple-Line" ) ) , "Multiple line" );
|
||||||
|
ok( /^Hello\s+Beautiful\s+World$/.test( xhr.getResponseHeader( "Multiple-Multiple-Line" ) ) , "Multiple multiple line" );
|
||||||
|
}
|
||||||
|
start();
|
||||||
|
},
|
||||||
|
error: function(){ ok(false, "error"); }
|
||||||
|
});
|
||||||
|
|
||||||
|
});
|
||||||
|
|
||||||
test(".ajax() - hash", function() {
|
test(".ajax() - hash", function() {
|
||||||
expect(3);
|
expect(3);
|
||||||
|
|
||||||
|
@ -163,6 +399,136 @@ 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);
|
||||||
|
|
||||||
|
@ -277,6 +643,34 @@ 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();
|
||||||
|
@ -292,6 +686,21 @@ test("jQuery.ajax - xml: non-namespace elements inside namespaced elements", fun
|
||||||
});
|
});
|
||||||
});
|
});
|
||||||
|
|
||||||
|
test("jQuery.ajax - xml: non-namespace elements inside namespaced elements (over JSONP)", function() {
|
||||||
|
expect(3);
|
||||||
|
stop();
|
||||||
|
jQuery.ajax({
|
||||||
|
url: url("data/with_fries_over_jsonp.php"),
|
||||||
|
dataType: "jsonp xml",
|
||||||
|
success: function(resp) {
|
||||||
|
equals( jQuery("properties", resp).length, 1, 'properties in responseXML' );
|
||||||
|
equals( jQuery("jsconf", resp).length, 1, 'jsconf in responseXML' );
|
||||||
|
equals( jQuery("thing", resp).length, 2, 'things in responseXML' );
|
||||||
|
start();
|
||||||
|
}
|
||||||
|
});
|
||||||
|
});
|
||||||
|
|
||||||
test("jQuery.ajax - HEAD requests", function() {
|
test("jQuery.ajax - HEAD requests", function() {
|
||||||
expect(2);
|
expect(2);
|
||||||
|
|
||||||
|
@ -359,6 +768,27 @@ test("jQuery.ajax - beforeSend, cancel request (#2688)", function() {
|
||||||
ok( request === false, "canceled request must return false instead of XMLHttpRequest instance" );
|
ok( request === false, "canceled request must return false instead of XMLHttpRequest instance" );
|
||||||
});
|
});
|
||||||
|
|
||||||
|
test("jQuery.ajax - beforeSend, cancel request manually", function() {
|
||||||
|
expect(2);
|
||||||
|
var request = jQuery.ajax({
|
||||||
|
url: url("data/name.html"),
|
||||||
|
beforeSend: function(xhr) {
|
||||||
|
ok( true, "beforeSend got called, canceling" );
|
||||||
|
xhr.abort();
|
||||||
|
},
|
||||||
|
success: function() {
|
||||||
|
ok( false, "request didn't get canceled" );
|
||||||
|
},
|
||||||
|
complete: function() {
|
||||||
|
ok( false, "request didn't get canceled" );
|
||||||
|
},
|
||||||
|
error: function() {
|
||||||
|
ok( false, "request didn't get canceled" );
|
||||||
|
}
|
||||||
|
});
|
||||||
|
ok( request === false, "canceled request must return false instead of XMLHttpRequest instance" );
|
||||||
|
});
|
||||||
|
|
||||||
window.foobar = null;
|
window.foobar = null;
|
||||||
window.testFoo = undefined;
|
window.testFoo = undefined;
|
||||||
|
|
||||||
|
@ -841,12 +1271,13 @@ test("jQuery.ajax() - JSONP, Local", function() {
|
||||||
});
|
});
|
||||||
});
|
});
|
||||||
|
|
||||||
test("JSONP - Custom JSONP Callback", function() {
|
test("jQuery.ajax() - JSONP - Custom JSONP Callback", function() {
|
||||||
expect(1);
|
expect(1);
|
||||||
stop();
|
stop();
|
||||||
|
|
||||||
window.jsonpResults = function(data) {
|
window.jsonpResults = function(data) {
|
||||||
ok( data.data, "JSON results returned (GET, custom callback function)" );
|
ok( data.data, "JSON results returned (GET, custom callback function)" );
|
||||||
|
window.jsonpResults = undefined;
|
||||||
start();
|
start();
|
||||||
};
|
};
|
||||||
|
|
||||||
|
@ -1033,6 +1464,30 @@ test("jQuery.ajax() - json by content-type", function() {
|
||||||
});
|
});
|
||||||
});
|
});
|
||||||
|
|
||||||
|
test("jQuery.ajax() - json by content-type disabled with options", function() {
|
||||||
|
expect(6);
|
||||||
|
|
||||||
|
stop();
|
||||||
|
|
||||||
|
jQuery.ajax({
|
||||||
|
url: url("data/json.php"),
|
||||||
|
data: { header: "json", json: "array" },
|
||||||
|
autoDataType: {
|
||||||
|
json: false
|
||||||
|
},
|
||||||
|
success: function( text ) {
|
||||||
|
equals( typeof text , "string" , "json wasn't auto-determined" );
|
||||||
|
var json = this.dataConverters["text => json"]( text );
|
||||||
|
ok( json.length >= 2, "Check length");
|
||||||
|
equals( json[0].name, 'John', 'Check JSON: first, name' );
|
||||||
|
equals( json[0].age, 21, 'Check JSON: first, age' );
|
||||||
|
equals( json[1].name, 'Peter', 'Check JSON: second, name' );
|
||||||
|
equals( json[1].age, 25, 'Check JSON: second, age' );
|
||||||
|
start();
|
||||||
|
}
|
||||||
|
});
|
||||||
|
});
|
||||||
|
|
||||||
test("jQuery.getJSON(String, Hash, Function) - JSON array", function() {
|
test("jQuery.getJSON(String, Hash, Function) - JSON array", function() {
|
||||||
expect(5);
|
expect(5);
|
||||||
stop();
|
stop();
|
||||||
|
@ -1302,6 +1757,7 @@ test("jQuery.ajax - If-Modified-Since support", function() {
|
||||||
});
|
});
|
||||||
},
|
},
|
||||||
error: function() {
|
error: function() {
|
||||||
|
equals(false, "error");
|
||||||
// Do this because opera simply refuses to implement 304 handling :(
|
// Do this because opera simply refuses to implement 304 handling :(
|
||||||
// A feature-driven way of detecting this would be appreciated
|
// A feature-driven way of detecting this would be appreciated
|
||||||
// See: http://gist.github.com/599419
|
// See: http://gist.github.com/599419
|
||||||
|
@ -1357,6 +1813,60 @@ test("jQuery.ajax - Etag support", function() {
|
||||||
});
|
});
|
||||||
});
|
});
|
||||||
|
|
||||||
|
test("jQuery ajax - headers", function() {
|
||||||
|
|
||||||
|
stop();
|
||||||
|
|
||||||
|
jQuery.ajax(url("data/css.php?wait=1&id=headers"), {
|
||||||
|
headers: {
|
||||||
|
testKey: "testValue"
|
||||||
|
},
|
||||||
|
beforeSend: function( xhr ) {
|
||||||
|
equals( xhr.getRequestHeader("testKey") , "testValue" , "Headers properly set" );
|
||||||
|
setTimeout( start , 13 );
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
});
|
||||||
|
|
||||||
|
});
|
||||||
|
|
||||||
|
test("jQuery ajax - failing cross-domain", function() {
|
||||||
|
|
||||||
|
expect( 2 );
|
||||||
|
|
||||||
|
stop();
|
||||||
|
|
||||||
|
var i = 2;
|
||||||
|
|
||||||
|
jQuery.ajax({
|
||||||
|
url: 'http://somewebsitethatdoesnotexist.com',
|
||||||
|
success: function(){ ok( false , "success" ); },
|
||||||
|
error: function(xhr,_,e){ ok( true , "file not found: " + xhr.status + " => " + e ); },
|
||||||
|
complete: function() { if ( ! --i ) start(); }
|
||||||
|
});
|
||||||
|
|
||||||
|
jQuery.ajax({
|
||||||
|
url: 'http://www.google.com',
|
||||||
|
success: function(){ ok( false , "success" ); },
|
||||||
|
error: function(xhr,_,e){ ok( true , "access denied: " + xhr.status + " => " + e ); },
|
||||||
|
complete: function() { if ( ! --i ) start(); }
|
||||||
|
});
|
||||||
|
|
||||||
|
});
|
||||||
|
|
||||||
|
test("jQuery ajax - atom+xml", function() {
|
||||||
|
|
||||||
|
stop();
|
||||||
|
|
||||||
|
jQuery.ajax({
|
||||||
|
url: url( 'data/atom+xml.php' ),
|
||||||
|
success: function(){ ok( true , "success" ); },
|
||||||
|
error: function(){ ok( false , "error" ); },
|
||||||
|
complete: function() { start(); }
|
||||||
|
});
|
||||||
|
|
||||||
|
});
|
||||||
|
|
||||||
test("jQuery.ajax - active counter", function() {
|
test("jQuery.ajax - active counter", function() {
|
||||||
ok( jQuery.active == 0, "ajax active counter should be zero: " + jQuery.active );
|
ok( jQuery.active == 0, "ajax active counter should be zero: " + jQuery.active );
|
||||||
});
|
});
|
||||||
|
|
Loading…
Add table
Reference in a new issue