X-Git-Url: http://git.asbjorn.biz/?a=blobdiff_plain;f=src%2Fajax.js;h=63914d23a7aa876499b87be16ea6c1ccec1f0a40;hb=9ab00a712fe3757f130dce8b42293c82a68c690e;hp=5c4d469fda84a37dedac6bbfae969fe6d7e3160b;hpb=8ab23aec2c333834a6e442fa15b73125ba857afe;p=jquery.git diff --git a/src/ajax.js b/src/ajax.js index 5c4d469..63914d2 100644 --- a/src/ajax.js +++ b/src/ajax.js @@ -161,7 +161,9 @@ jQuery.extend({ ajaxSetup: function( settings ) { jQuery.extend( true, jQuery.ajaxSettings, settings ); - return this; + if ( settings.context ) { + jQuery.ajaxSettings.context = settings.context; + } }, ajaxSettings: { @@ -175,15 +177,13 @@ jQuery.extend({ timeout: 0, data: null, dataType: null, - dataTypes: null, username: null, password: null, cache: null, traditional: false, + headers: {}, + crossDomain: null, */ - xhr: function() { - return new window.XMLHttpRequest(); - }, accepts: { xml: "application/xml, text/xml", @@ -231,12 +231,65 @@ jQuery.extend({ // Parse text as xml "text xml": jQuery.parseXML + }, + + // Utility function that handles dataType when response is received + // (for those transports that can give text or xml responses) + determineDataType: function( ct , text , xml ) { + + var s = this, + contents = s.contents, + type, + regexp, + dataTypes = s.dataTypes, + transportDataType = dataTypes[0], + response; + + // Auto (xml, json, script or text determined given headers) + if ( transportDataType === "*" ) { + + for ( type in contents ) { + if ( ( regexp = contents[ 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 converters + if ( transportDataType !== "text" ) { + dataTypes.unshift( "text" ); + } + + } + + return response; } + + }, + + ajaxPrefilter: function( a , b ) { + ajaxPrefilterOrTransport( "prefilters" , a , b ); + }, + + ajaxTransport: function( a , b ) { + return ajaxPrefilterOrTransport( "transports" , a , b ); }, // Main method - // (s is used internally) - ajax: function( url , options , s ) { + ajax: function( url , options ) { // Handle varargs if ( arguments.length === 1 ) { @@ -250,19 +303,18 @@ jQuery.extend({ // Get the url if provided separately options.url = url || options.url; - // Create the final options object - s = jQuery.extend( true , {} , jQuery.ajaxSettings , options ); - - // We force the original context - // (plain objects used as context get extended) - s.context = options.context; - - var // jQuery lists + var // Create the final options object + s = jQuery.extend( true , {} , jQuery.ajaxSettings , options ), + // jQuery lists jQuery_lastModified = jQuery.lastModified, jQuery_etag = jQuery.etag, // Callbacks contexts - callbackContext = s.context || s, - globalEventContext = s.context ? jQuery( s.context ) : jQuery.event, + // We force the original context if it exists + // or take it from jQuery.ajaxSettings otherwise + // (plain objects used as context get extended) + callbackContext = + ( s.context = ( "context" in options ? options : jQuery.ajaxSettings ).context ) || s, + globalEventContext = callbackContext === s ? jQuery.event : jQuery( callbackContext ), // Deferreds deferred = jQuery.Deferred(), completeDeferred = jQuery._Deferred(), @@ -279,6 +331,7 @@ jQuery.extend({ timeoutTimer, // Cross-domain detection vars loc = document.location, + protocol = loc.protocol || "http:", parts, // The jXHR state state = 0, @@ -303,30 +356,25 @@ jQuery.extend({ }, // Builds headers hashtable if needed - // (match is used internally) - getResponseHeader: function( key , match ) { + getResponseHeader: function( key ) { + + var match; if ( state === 2 ) { - if ( responseHeaders === undefined ) { + if ( !responseHeaders ) { responseHeaders = {}; - if ( typeof responseHeadersString === "string" ) { - - while( ( match = rheaders.exec( responseHeadersString ) ) ) { - responseHeaders[ match[ 1 ].toLowerCase() ] = match[ 2 ]; - } + while( ( match = rheaders.exec( responseHeadersString ) ) ) { + responseHeaders[ match[ 1 ].toLowerCase() ] = match[ 2 ]; } } match = responseHeaders[ key.toLowerCase() ]; - } else { - - match = null; } - return match; + return match || null; }, // Cancel the request @@ -354,7 +402,7 @@ jQuery.extend({ // Dereference transport for early garbage collection // (no matter how long the jXHR transport will be used - transport = 0; + transport = undefined; // Set readyState jXHR.readyState = status ? 4 : 0; @@ -377,7 +425,10 @@ jQuery.extend({ // Stored success success, // Stored error - error; + error, + + // To keep track of statusCode based callbacks + oldStatusCode; // If successful, handle type chaining if ( status >= 200 && status < 300 || status === 304 ) { @@ -419,6 +470,8 @@ jQuery.extend({ current, // Previous dataType prev, + // Conversion expression + conversion, // Conversion function conv, // Conversion functions (when text is used in-between) @@ -457,8 +510,8 @@ jQuery.extend({ if ( prev !== "*" && current !== "*" && prev !== current ) { // Get the converter - conv = converters[ prev + " " + current ] || - converters[ "* " + current ]; + conversion = prev + " " + current; + conv = converters[ conversion ] || converters[ "* " + current ]; conv1 = conv2 = 0; @@ -533,7 +586,9 @@ jQuery.extend({ } // Status-dependent callbacks - jXHR.statusCode( statusCode ); + oldStatusCode = statusCode; + statusCode = undefined; + jXHR.statusCode( oldStatusCode ); if ( s.global ) { globalEventContext.trigger( "ajax" + ( isSuccess ? "Success" : "Error" ) , @@ -561,20 +616,14 @@ jQuery.extend({ // Status-dependent callbacks jXHR.statusCode = function( map ) { if ( map ) { - var resolved = jXHR.isResolved(), - tmp; - if ( resolved || jXHR.isRejected() ) { - tmp = map[ jXHR.status ]; - if ( tmp ) { - if ( map === statusCode ) { - delete statusCode[ jXHR.status ]; - } - jXHR[ resolved ? "done" : "fail" ]( tmp ); - } - } else { + var tmp; + if ( statusCode ) { for( tmp in map ) { statusCode[ tmp ] = [ statusCode[ tmp ] , map[ tmp ] ]; } + } else { + tmp = map[ jXHR.status ]; + jXHR.done( tmp ).fail( tmp ); } } return this; @@ -583,12 +632,6 @@ jQuery.extend({ // Remove hash character (#7531: and string promotion) s.url = ( "" + s.url ).replace( rhash , "" ); - // Uppercase the type - s.type = s.type.toUpperCase(); - - // Determine if request has content - s.hasContent = ! rnoContent.test( s.type ); - // Extract dataTypes list s.dataTypes = jQuery.trim( s.dataType || "*" ).toLowerCase().split( /\s+/ ); @@ -597,20 +640,27 @@ jQuery.extend({ parts = rurl.exec( s.url.toLowerCase() ); s.crossDomain = !!( parts && - ( parts[ 1 ] && parts[ 1 ] != loc.protocol || + ( parts[ 1 ] && parts[ 1 ] != protocol || parts[ 2 ] != loc.hostname || - ( parts[ 3 ] || 80 ) != ( loc.port || 80 ) ) + ( parts[ 3 ] || ( ( parts[ 1 ] || protocol ) === "http:" ? 80 : 443 ) ) != + ( loc.port || ( protocol === "http:" ? 80 : 443 ) ) ) ); } // Convert data if not already a string - if ( s.data && s.processData && typeof s.data != "string" ) { + if ( s.data && s.processData && typeof s.data !== "string" ) { s.data = jQuery.param( s.data , s.traditional ); } // Apply prefilters jQuery.ajaxPrefilter( s , options ); + // Uppercase the type + s.type = s.type.toUpperCase(); + + // Determine if request has content + s.hasContent = ! rnoContent.test( s.type ); + // Watch for a new set of requests if ( s.global && jQuery.active++ === 0 ) { jQuery.event.trigger( "ajaxStart" ); @@ -678,7 +728,7 @@ jQuery.extend({ } // Get transport - transport = jQuery.ajaxTransport( s ); + transport = jQuery.ajaxTransport( s , options ); // If no transport, we auto-abort if ( ! transport ) { @@ -810,199 +860,97 @@ jQuery.extend({ }); -//Execute or select from functions in a given structure of options -function ajax_selectOrExecute( structure , s ) { +// Base function for both ajaxPrefilter and ajaxTransport +function ajaxPrefilterOrTransport( arg0 , arg1 , arg2 ) { - var dataTypes = s.dataTypes, - transportDataType, - list, - selected, + var type = jQuery.type( arg1 ), + structure = jQuery.ajaxSettings[ arg0 ], i, - length, - checked = {}, - flag, - noSelect = structure !== "transports"; - - function initSearch( dataType ) { - - flag = transportDataType !== dataType && ! checked[ dataType ]; - - if ( flag ) { - - checked[ dataType ] = 1; - transportDataType = dataType; - list = s[ structure ][ dataType ]; - i = -1; - length = list ? list.length : 0 ; - } - - return flag; - } - - initSearch( dataTypes[ 0 ] ); - - for ( i = 0 ; ( noSelect || ! selected ) && i <= length ; i++ ) { - - if ( i === length ) { - - initSearch( "*" ); - - } else { - - selected = list[ i ]( s , determineDataType ); - - // If we got redirected to another dataType - // Search there (if not in progress or already tried) - if ( typeof( selected ) === "string" && - initSearch( selected ) ) { - - dataTypes.unshift( selected ); - selected = 0; - } - } - } - - return noSelect ? jQuery : selected; -} - -// Add an element to one of the structures in ajaxSettings -function ajax_addElement( structure , args ) { - - var i, - start = 0, - length = args.length, - dataTypes = [ "*" ], - dLength = 1, - dataType, - functors = [], - first, - append, - list; - - if ( length ) { - - first = jQuery.type( args[ 0 ] ); + length; + + // We have an options map so we have to inspect the structure + if ( type === "object" ) { + + var options = arg1, + originalOptions = arg2, + // When dealing with prefilters, we execute only + // (no selection so we never stop when a function + // returns a non-falsy, non-string value) + executeOnly = ( arg0 === "prefilters" ), + inspect = function( dataType, tested ) { + + if ( ! tested[ dataType ] ) { + + tested[ dataType ] = true; + + var list = structure[ dataType ], + selected; + + for( i = 0, length = list ? list.length : 0 ; ( executeOnly || ! selected ) && i < length ; i++ ) { + selected = list[ i ]( options , originalOptions ); + // If we got redirected to a different dataType, + // we add it and switch to the corresponding list + if ( typeof( selected ) === "string" && selected !== dataType ) { + options.dataTypes.unshift( selected ); + selected = inspect( selected , tested ); + // We always break in order not to continue + // to iterate in previous list + break; + } + } + // If we're only executing or nothing was selected + // we try the catchall dataType + if ( executeOnly || ! selected ) { + selected = inspect( "*" , tested ); + } + // This will be ignored by ajaxPrefilter + // so it's safe to return no matter what + return selected; + } - if ( first === "object" ) { - return ajax_selectOrExecute( structure , args[ 0 ] ); - } + }; - structure = jQuery.ajaxSettings[ structure ]; + // Start inspection with current transport dataType + return inspect( options.dataTypes[ 0 ] , {} ); - if ( first !== "function" ) { + } else { - dataTypes = args[ 0 ].toLowerCase().split(/\s+/); - dLength = dataTypes.length; - start = 1; + // We're requested to add to the structure + // Signature is ( dataTypeExpression , function ) + // with dataTypeExpression being optional and + // defaulting to catchAll (*) + type = type === "function"; + if ( type ) { + arg2 = arg1; + arg1 = undefined; } + arg1 = arg1 || "*"; - if ( dLength && start < length ) { + // We control that the second argument is really a function + if ( type || jQuery.isFunction( arg2 ) ) { - functors = sliceFunc.call( args , start ); - - for( i = 0 ; i < dLength ; i++ ) { + var dataTypes = arg1.split( /\s+/ ), + functor = arg2, + dataType, + list, + placeBefore; + // For each dataType in the dataTypeExpression + for( i = 0 , length = dataTypes.length ; i < length ; i++ ) { dataType = dataTypes[ i ]; - - first = /^\+/.test( dataType ); - - if (first) { - dataType = dataType.substr(1); + // We control if we're asked to add before + // any existing element + placeBefore = /^\+/.test( dataType ); + if ( placeBefore ) { + dataType = dataType.substr( 1 ); } - - if ( dataType !== "" ) { - - append = Array.prototype[ first ? "unshift" : "push" ]; - list = structure[ dataType ] = structure[ dataType ] || []; - append.apply( list , functors ); - } - } - } - } - - return jQuery; -} - -// Install prefilter & transport methods -jQuery.each( [ "Prefilter" , "Transport" ] , function( _ , name ) { - _ = name.toLowerCase() + "s"; - jQuery[ "ajax" + name ] = function() { - return ajax_addElement( _ , arguments ); - }; -} ); - -// Utility function that handles dataType when response is received -// (for those transports that can give text or xml responses) -function determineDataType( s , ct , text , xml ) { - - var contents = s.contents, - type, - regexp, - dataTypes = s.dataTypes, - transportDataType = dataTypes[0], - response; - - // Auto (xml, json, script or text determined given headers) - if ( transportDataType === "*" ) { - - for ( type in contents ) { - if ( ( regexp = contents[ type ] ) && regexp.test( ct ) ) { - transportDataType = dataTypes[0] = type; - break; + list = structure[ dataType ] = structure[ dataType ] || []; + // then we add to the structure accordingly + list[ placeBefore ? "unshift" : "push" ]( functor ); } } } - - // 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 converters - if ( transportDataType !== "text" ) { - dataTypes.unshift( "text" ); - } - - } - - return response; -} - -/* - * Create the request object; Microsoft failed to properly - * implement the XMLHttpRequest in IE7 (can't request local files), - * so we use the ActiveXObject when it is available - * Additionally XMLHttpRequest can be disabled in IE7/IE8 so - * we need a fallback. - */ -if ( window.ActiveXObject ) { - jQuery.ajaxSettings.xhr = function() { - if ( window.location.protocol !== "file:" ) { - try { - return new window.XMLHttpRequest(); - } catch( xhrError ) {} - } - - try { - return new window.ActiveXObject("Microsoft.XMLHTTP"); - } catch( activeError ) {} - }; } -var testXHR = jQuery.ajaxSettings.xhr(); - -// 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 );