X-Git-Url: http://git.asbjorn.biz/?a=blobdiff_plain;f=src%2Fajax.js;h=74c300525aae4c8ed9f6c9f80a58008d6cdcd335;hb=bea4815294f6bdf94cbe50a5a978e2c6bfa2c396;hp=5c4d469fda84a37dedac6bbfae969fe6d7e3160b;hpb=8ab23aec2c333834a6e442fa15b73125ba857afe;p=jquery.git diff --git a/src/ajax.js b/src/ajax.js index 5c4d469..74c3005 100644 --- a/src/ajax.js +++ b/src/ajax.js @@ -2,6 +2,7 @@ var r20 = /%20/g, rbracket = /\[\]$/, + rCRLF = /\r?\n/g, rhash = /#.*$/, rheaders = /^(.*?):\s*(.*?)\r?$/mg, // IE leaves an \r character at EOL rinput = /^(?:color|date|datetime|email|hidden|month|number|password|range|search|tel|text|time|url|week)$/i, @@ -9,15 +10,31 @@ var r20 = /%20/g, rquery = /\?/, rscript = /)<[^<]*)*<\/script>/gi, rselectTextarea = /^(?:select|textarea)/i, + rspacesAjax = /\s+/, rts = /([?&])_=[^&]*/, rurl = /^(\w+:)?\/\/([^\/?#:]+)(?::(\d+))?/, - rCRLF = /\r?\n/g, // Slice function sliceFunc = Array.prototype.slice, // Keep a copy of the old load method - _load = jQuery.fn.load; + _load = jQuery.fn.load, + + // 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) key is the dataType + // 4) the catchall symbol "*" can be used + // 5) execution will start with transport dataType and THEN continue down to "*" if needed + 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 = {}; jQuery.fn.extend({ load: function( url, params, callback ) { @@ -161,7 +178,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 +194,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", @@ -199,21 +216,10 @@ jQuery.extend({ 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) key is the dataType - // 4) the catchall symbol "*" can be used - // 5) execution will start with transport dataType and THEN continue down to "*" if needed - 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: {}, + responseFields: { + xml: "responseXML", + text: "responseText" + }, // List of data converters // 1) key format is "source_type destination_type" (a single space in-between) @@ -234,35 +240,36 @@ jQuery.extend({ } }, + ajaxPrefilter: function( a , b ) { + prefiltersOrTransports( prefilters , a , b ); + }, + + ajaxTransport: function( a , b ) { + return prefiltersOrTransports( transports , a , b ); + }, + // Main method - // (s is used internally) - ajax: function( url , options , s ) { + ajax: function( url , options ) { - // Handle varargs - if ( arguments.length === 1 ) { + // If options is not an object, + // we simulate pre-1.5 signature + if ( typeof( options ) !== "object" ) { options = url; - url = options ? options.url : undefined; + url = undefined; } // Force options to be an object options = options || {}; - // Get the url if provided separately - options.url = url || options.url; - - // Create the final options object - s = jQuery.extend( true , {} , jQuery.ajaxSettings , options ); - - // We force the original context - // (plain objects used as context get extended) - s.context = options.context; - - var // jQuery lists - jQuery_lastModified = jQuery.lastModified, - jQuery_etag = jQuery.etag, + var // Create the final options object + s = jQuery.extend( true , {} , jQuery.ajaxSettings , options ), // 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 +286,7 @@ jQuery.extend({ timeoutTimer, // Cross-domain detection vars loc = document.location, + protocol = loc.protocol || "http:", parts, // The jXHR state state = 0, @@ -303,30 +311,18 @@ 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 @@ -342,7 +338,7 @@ jQuery.extend({ // Callback for when everything is done // It is defined here because jslint complains if it is declared // at the end of the function (which would be more logical and readable) - function done( status , statusText , response , headers) { + function done( status , statusText , responses , headers) { // Called once if ( state === 2 ) { @@ -352,32 +348,27 @@ jQuery.extend({ // State is "done" now state = 2; - // Dereference transport for early garbage collection - // (no matter how long the jXHR transport will be used - transport = 0; - - // Set readyState - jXHR.readyState = status ? 4 : 0; - - // Cache response headers - responseHeadersString = headers || ""; - // Clear timeout if it exists if ( timeoutTimer ) { clearTimeout(timeoutTimer); } - var // Reference url - url = s.url, - // and ifModified status - ifModified = s.ifModified, + // Dereference transport for early garbage collection + // (no matter how long the jXHR object will be used) + transport = undefined; + + // Cache response headers + responseHeadersString = headers || ""; - // Is it a success? - isSuccess = 0, - // Stored success + // Set readyState + jXHR.readyState = status ? 4 : 0; + + var isSuccess, success, - // Stored error - error; + error = ( statusText = statusText || "error" ), + response = responses ? ajaxHandleResponses( s , jXHR , responses ) : undefined, + lastModified, + etag; // If successful, handle type chaining if ( status >= 200 && status < 300 || status === 304 ) { @@ -385,140 +376,33 @@ jQuery.extend({ // Set the If-Modified-Since and/or If-None-Match header, if in ifModified mode. if ( s.ifModified ) { - var lastModified = jXHR.getResponseHeader("Last-Modified"), - etag = jXHR.getResponseHeader("Etag"); - - if (lastModified) { - jQuery_lastModified[ s.url ] = lastModified; + if ( ( lastModified = jXHR.getResponseHeader("Last-Modified") ) ) { + jQuery.lastModified[ s.url ] = lastModified; } - if (etag) { - jQuery_etag[ s.url ] = etag; + if ( ( etag = jXHR.getResponseHeader("Etag") ) ) { + jQuery.etag[ s.url ] = etag; } } // If not modified if ( status === 304 ) { - // Set the statusText accordingly statusText = "notmodified"; - // Mark as a success - isSuccess = 1; + isSuccess = true; // If we have data } else { - // Set the statusText accordingly - statusText = "success"; - - // Chain data conversions and determine the final value - // (if an exception is thrown in the process, it'll be notified as an error) try { - - var i, - // Current dataType - current, - // Previous dataType - prev, - // Conversion function - conv, - // Conversion functions (when text is used in-between) - conv1, - conv2, - // Local references to dataTypes & converters - dataTypes = s.dataTypes, - converters = s.converters, - // DataType to responseXXX field mapping - responses = { - "xml": "XML", - "text": "Text" - }; - - // For each dataType in the chain - for( i = 0 ; i < dataTypes.length ; i++ ) { - - current = dataTypes[ i ]; - - // If a responseXXX field for this dataType exists - // and if it hasn't been set yet - if ( responses[ current ] ) { - // Set it - jXHR[ "response" + responses[ current ] ] = response; - // Mark it as set - responses[ current ] = 0; - } - - // If this is not the first element - if ( i ) { - - // Get the dataType to convert from - prev = dataTypes[ i - 1 ]; - - // If no catch-all and dataTypes are actually different - if ( prev !== "*" && current !== "*" && prev !== current ) { - - // Get the converter - conv = converters[ prev + " " + current ] || - converters[ "* " + current ]; - - conv1 = conv2 = 0; - - // If there is no direct converter and none of the dataTypes is text - if ( ! conv && prev !== "text" && current !== "text" ) { - // Try with text in-between - conv1 = converters[ prev + " text" ] || converters[ "* text" ]; - conv2 = converters[ "text " + current ]; - // Revert back to a single converter - // if one of the converter is an equivalence - if ( conv1 === true ) { - conv = conv2; - } else if ( conv2 === true ) { - conv = conv1; - } - } - // If we found no converter, dispatch an error - if ( ! ( conv || conv1 && conv2 ) ) { - throw conversion; - } - // If found converter is not an equivalence - if ( conv !== true ) { - // Convert with 1 or 2 converters accordingly - response = conv ? conv( response ) : conv2( conv1( response ) ); - } - } - // If it is the first element of the chain - // and we have a dataFilter - } else if ( s.dataFilter ) { - // Apply the dataFilter - response = s.dataFilter( response , current ); - // Get dataTypes again in case the filter changed them - dataTypes = s.dataTypes; - } - } - // End of loop - - // We have a real success - success = response; - isSuccess = 1; - - // If an exception was thrown + success = ajaxConvert( s , response ); + statusText = "success"; + isSuccess = true; } catch(e) { - // We have a parsererror statusText = "parsererror"; error = "" + e; - } } - - // if not success, mark it as an error - } else { - - error = statusText = statusText || "error"; - - // Set responseText if needed - if ( response ) { - jXHR.responseText = response; - } } // Set data for the fake xhr object @@ -527,13 +411,14 @@ jQuery.extend({ // Success/Error if ( isSuccess ) { - deferred.fire( callbackContext , [ success , statusText , jXHR ] ); + deferred.resolveWith( callbackContext , [ success , statusText , jXHR ] ); } else { - deferred.fireReject( callbackContext , [ jXHR , statusText , error ] ); + deferred.rejectWith( callbackContext , [ jXHR , statusText , error ] ); } // Status-dependent callbacks jXHR.statusCode( statusCode ); + statusCode = undefined; if ( s.global ) { globalEventContext.trigger( "ajax" + ( isSuccess ? "Success" : "Error" ) , @@ -541,7 +426,7 @@ jQuery.extend({ } // Complete - completeDeferred.fire( callbackContext, [ jXHR , statusText ] ); + completeDeferred.resolveWith( callbackContext, [ jXHR , statusText ] ); if ( s.global ) { globalEventContext.trigger( "ajaxComplete" , [ jXHR , s] ); @@ -561,56 +446,52 @@ 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 ( state < 2 ) { for( tmp in map ) { statusCode[ tmp ] = [ statusCode[ tmp ] , map[ tmp ] ]; } + } else { + tmp = map[ jXHR.status ]; + jXHR.then( tmp , tmp ); } } return this; }; // 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 ); + // We also use the url parameter if available + s.url = ( "" + ( url || s.url ) ).replace( rhash , "" ); // Extract dataTypes list - s.dataTypes = jQuery.trim( s.dataType || "*" ).toLowerCase().split( /\s+/ ); + s.dataTypes = jQuery.trim( s.dataType || "*" ).toLowerCase().split( rspacesAjax ); // Determine if a cross-domain request is in order if ( ! s.crossDomain ) { 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" ); @@ -643,11 +524,11 @@ jQuery.extend({ // Set the If-Modified-Since and/or If-None-Match header, if in ifModified mode. if ( s.ifModified ) { - if ( jQuery_lastModified[ s.url ] ) { - requestHeaders[ "if-modified-since" ] = jQuery_lastModified[ s.url ]; + if ( jQuery.lastModified[ s.url ] ) { + requestHeaders[ "if-modified-since" ] = jQuery.lastModified[ s.url ]; } - if ( jQuery_etag[ s.url ] ) { - requestHeaders[ "if-none-match" ] = jQuery_etag[ s.url ]; + if ( jQuery.etag[ s.url ] ) { + requestHeaders[ "if-none-match" ] = jQuery.etag[ s.url ]; } } @@ -678,13 +559,11 @@ jQuery.extend({ } // Get transport - transport = jQuery.ajaxTransport( s ); + transport = jQuery.ajaxTransport( s , options ); // If no transport, we auto-abort if ( ! transport ) { - done( 0 , "notransport" ); - } else { // Set state as sending @@ -702,16 +581,13 @@ jQuery.extend({ }, s.timeout); } - // Try to send try { transport.send(requestHeaders, done); } catch (e) { // Propagate exception as error if not done if ( status === 1 ) { - done(0, "error", "" + e); jXHR = false; - // Simply rethrow otherwise } else { jQuery.error(e); @@ -810,199 +686,237 @@ jQuery.extend({ }); -//Execute or select from functions in a given structure of options -function ajax_selectOrExecute( structure , s ) { +// Base inspection function for prefilters and transports +function inspectPrefiltersOrTransports( structure , options , originalOptions , dataType , tested ) { - var dataTypes = s.dataTypes, - transportDataType, - list, - selected, - i, - length, - checked = {}, - flag, - noSelect = structure !== "transports"; - - function initSearch( dataType ) { - - flag = transportDataType !== dataType && ! checked[ dataType ]; - - if ( flag ) { - - checked[ dataType ] = 1; - transportDataType = dataType; - list = s[ structure ][ dataType ]; - i = -1; - length = list ? list.length : 0 ; - } - - return flag; - } - - initSearch( dataTypes[ 0 ] ); + dataType = dataType || options.dataTypes[0]; + tested = tested || {}; - for ( i = 0 ; ( noSelect || ! selected ) && i <= length ; i++ ) { + if ( ! tested[ dataType ] ) { - if ( i === length ) { + tested[ dataType ] = true; - initSearch( "*" ); + var list = structure[ dataType ], + i = 0, + length = list ? list.length : 0, + executeOnly = structure === prefilters, + selected; - } 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; + for( ; ( 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 = inspectPrefiltersOrTransports( + structure , options , originalOptions , 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 ( ! tested[ "*" ] && ( executeOnly || ! selected ) ) { + selected = inspectPrefiltersOrTransports( + structure , options , originalOptions , "*" , tested ); + } + // This will be ignored by ajaxPrefilter + // so it's safe to return no matter what + return selected; } - - return noSelect ? jQuery : selected; } -// Add an element to one of the structures in ajaxSettings -function ajax_addElement( structure , args ) { +function addToPrefiltersOrTransports( structure , dataTypeExpression , functor ) { - var i, - start = 0, - length = args.length, - dataTypes = [ "*" ], - dLength = 1, + var dataTypes = dataTypeExpression.split( rspacesAjax ), + i = 0, + length = dataTypes.length, dataType, - functors = [], - first, - append, - list; - - if ( length ) { - - first = jQuery.type( args[ 0 ] ); - - if ( first === "object" ) { - return ajax_selectOrExecute( structure , args[ 0 ] ); + list, + placeBefore; + + // For each dataType in the dataTypeExpression + for( ; i < length ; i++ ) { + dataType = dataTypes[ i ]; + // We control if we're asked to add before + // any existing element + placeBefore = /^\+/.test( dataType ); + if ( placeBefore ) { + dataType = dataType.substr( 1 ); } + list = structure[ dataType ] = structure[ dataType ] || []; + // then we add to the structure accordingly + list[ placeBefore ? "unshift" : "push" ]( functor ); + } +} - structure = jQuery.ajaxSettings[ structure ]; - - if ( first !== "function" ) { +// Base function for both ajaxPrefilter and ajaxTransport +function prefiltersOrTransports( structure , arg1 , arg2 , type /* internal */ ) { - dataTypes = args[ 0 ].toLowerCase().split(/\s+/); - dLength = dataTypes.length; - start = 1; + type = jQuery.type( arg1 ); + if ( type === "object" ) { + // We have an options map so we have to inspect the structure + return inspectPrefiltersOrTransports( structure , arg1 , arg2 ); + } else { + // We're requested to add to the structure + // Signature is ( dataTypeExpression , function ) + // with dataTypeExpression being optional and + // defaulting to auto ("*") + type = ( type === "function" ); + if ( type ) { + arg2 = arg1; + arg1 = undefined; } - - if ( dLength && start < length ) { - - functors = sliceFunc.call( args , start ); - - for( i = 0 ; i < dLength ; i++ ) { - - dataType = dataTypes[ i ]; - - first = /^\+/.test( dataType ); - - if (first) { - dataType = dataType.substr(1); - } - - if ( dataType !== "" ) { - - append = Array.prototype[ first ? "unshift" : "push" ]; - list = structure[ dataType ] = structure[ dataType ] || []; - append.apply( list , functors ); - } - } + // We control that the second argument is really a function + if ( type || jQuery.isFunction( arg2 ) ) { + addToPrefiltersOrTransports( structure , arg1 || "*" , arg2 ); } } - - 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 ) { +// Handles responses to an ajax request: +// - sets all responseXXX fields accordingly +// - finds the right dataType (mediating between content-type and expecting dataType) +// - returns the corresponding response +function ajaxHandleResponses( s , jXHR , responses ) { var contents = s.contents, - type, - regexp, dataTypes = s.dataTypes, - transportDataType = dataTypes[0], - response; + responseFields = s.responseFields, + ct, + type, + finalDataType, + firstDataType; + + // Fill responseXXX fields + for( type in responseFields ) { + if ( type in responses ) { + jXHR[ responseFields[ type ] ] = responses[ type ]; + } + } - // Auto (xml, json, script or text determined given headers) - if ( transportDataType === "*" ) { + // Remove auto dataType and get content-type in the process + while( dataTypes[0] === "*" ) { + dataTypes.shift(); + if ( ct === undefined ) { + ct = jXHR.getResponseHeader( "content-type" ); + } + } + // Check if we're dealing with a known content-type + if ( ct ) { for ( type in contents ) { - if ( ( regexp = contents[ type ] ) && regexp.test( ct ) ) { - transportDataType = dataTypes[0] = type; + if ( contents[ type ] && contents[ type ].test( ct ) ) { + dataTypes.unshift( type ); break; } } } - // xml and parsed as such - if ( transportDataType === "xml" && - xml && - xml.documentElement /* #4958 */ ) { - - response = xml; - - // Text response was provided + // Check to see if we have a response for the expected dataType + if ( dataTypes[0] in responses ) { + finalDataType = dataTypes[0]; } else { - - response = text; - - // If it's not really text, defer to converters - if ( transportDataType !== "text" ) { - dataTypes.unshift( "text" ); + // Try convertible dataTypes + for ( type in responses ) { + if ( ! dataTypes[0] || s.converters[ type + " " + dataTypes[0] ] ) { + finalDataType = type; + break; + } + if ( ! firstDataType ) { + firstDataType = type; + } } - + // Or just use first one + finalDataType = finalDataType || firstDataType; } - 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 ) {} + // If we found a dataType + // We add the dataType to the list if needed + // and return the corresponding response + if ( finalDataType ) { + if ( finalDataType !== dataTypes[0] ) { + dataTypes.unshift( finalDataType ); + } + return responses[ finalDataType ]; } - - try { - return new window.ActiveXObject("Microsoft.XMLHTTP"); - } catch( activeError ) {} - }; } -var testXHR = jQuery.ajaxSettings.xhr(); +// Chain conversions given the request and the original response +function ajaxConvert( s , response ) { + + // Apply the dataFilter if provided + if ( s.dataFilter ) { + response = s.dataFilter( response , s.dataType ); + } -// Does this browser support XHR requests? -jQuery.support.ajax = !!testXHR; + var dataTypes = s.dataTypes, + converters = s.converters, + i, + length = dataTypes.length, + tmp, + // Current and previous dataTypes + current = dataTypes[0], + prev, + // Conversion expression + conversion, + // Conversion function + conv, + // Conversion functions (when text is used in-between) + conv1, + conv2; + + // For each dataType in the chain + for( i = 1 ; i < length ; i++ ) { + + // Get the dataTypes + prev = current; + current = dataTypes[ i ]; + + // If current is auto dataType, update it to prev + if( current === "*" ) { + current = prev; + // If no auto and dataTypes are actually different + } else if ( prev !== "*" && prev !== current ) { + + // Get the converter + conversion = prev + " " + current; + conv = converters[ conversion ] || converters[ "* " + current ]; + + // If there is no direct converter, search transitively + if ( ! conv ) { + conv2 = undefined; + for( conv1 in converters ) { + tmp = conv1.split( " " ); + if ( tmp[ 0 ] === prev || tmp[ 0 ] === "*" ) { + conv2 = converters[ tmp[ 1 ] + " " + current ]; + if ( conv2 ) { + conv1 = converters[ conv1 ]; + if ( conv1 === true ) { + conv = conv2; + } else if ( conv2 === true ) { + conv = conv1; + } + break; + } + } + } + } + // If we found no converter, dispatch an error + if ( ! ( conv || conv2 ) ) { + jQuery.error( "No conversion from " + conversion.replace( " " , " to " ) ); + } + // If found converter is not an equivalence + if ( conv !== true ) { + // Convert with 1 or 2 converters accordingly + response = conv ? conv( response ) : conv2( conv1( response ) ); + } + } + } -// Does this browser support crossDomain XHR requests -jQuery.support.cors = testXHR && "withCredentials" in testXHR; + return response; +} })( jQuery );