Replaces "text in-between" technique with a full-fledged one-level transitive search for converters (unit tests added). Also cleans up auto dataType determination and adds converter checks in order to guess the best dataType possible.
This commit is contained in:
parent
2e2d5e9db5
commit
dc2e7317a9
2 changed files with 107 additions and 39 deletions
103
src/ajax.js
103
src/ajax.js
|
@ -372,8 +372,9 @@ jQuery.extend({
|
|||
clearTimeout(timeoutTimer);
|
||||
}
|
||||
|
||||
var // Reference dataTypes and responseFields
|
||||
var // Reference dataTypes, converters and responseFields
|
||||
dataTypes = s.dataTypes,
|
||||
converters = s.converters,
|
||||
responseFields = s.responseFields,
|
||||
responseField,
|
||||
|
||||
|
@ -400,44 +401,64 @@ jQuery.extend({
|
|||
transportDataType = dataTypes[0],
|
||||
ct,
|
||||
type,
|
||||
finalDataType;
|
||||
finalDataType,
|
||||
firstDataType;
|
||||
|
||||
// Auto (xml, json, script or text determined given headers)
|
||||
if ( transportDataType === "*" && ( ct = jXHR.getResponseHeader( "content-type" ) ) ) {
|
||||
if ( transportDataType === "*" ) {
|
||||
|
||||
// Remove all auto types
|
||||
while( dataTypes[0] === "*" ) {
|
||||
dataTypes.shift();
|
||||
}
|
||||
transportDataTypes = dataTypes[0];
|
||||
|
||||
// Get content type
|
||||
ct = jXHR.getResponseHeader( "content-type" );
|
||||
|
||||
// Check if it's a known type
|
||||
for ( type in contents ) {
|
||||
if ( contents[ type ] && contents[ type ].test( ct ) ) {
|
||||
transportDataType = dataTypes[0] = type;
|
||||
dataTypes.unshift( ( transportDataType = type ) );
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
type = undefined;
|
||||
}
|
||||
|
||||
// Get final dataType
|
||||
for( type in responses ) {
|
||||
if ( ! finalDataType && type === transportDataType ) {
|
||||
finalDataType = type;
|
||||
// Check to see if we have a response for the expected dataType
|
||||
if ( transportDataType in responses ) {
|
||||
finalDataType = transportDataType;
|
||||
} else {
|
||||
// Try convertible dataTypes
|
||||
for ( type in responses ) {
|
||||
if ( ! firstDataType ) {
|
||||
firstDataType = type;
|
||||
}
|
||||
if ( ! transportDataType || converters[ type + " " + transportDataType ] ) {
|
||||
finalDataType = type;
|
||||
break;
|
||||
}
|
||||
}
|
||||
responseField = responseFields[ type ];
|
||||
if ( responseField && ! ( responseField in jXHR ) ) {
|
||||
jXHR[ responseField ] = responses[ type ];
|
||||
// Or just use first one
|
||||
finalDataType = finalDataType || firstDataType;
|
||||
}
|
||||
|
||||
// If we found a dataType
|
||||
// We get the corresponding response
|
||||
// and add the dataType to the list if needed
|
||||
if ( finalDataType ) {
|
||||
response = responses[ finalDataType ];
|
||||
if ( finalDataType !== transportDataType ) {
|
||||
dataTypes.unshift( finalDataType );
|
||||
}
|
||||
}
|
||||
|
||||
// If no response with the expected dataType was provided
|
||||
// Take the last response as a default if it exists
|
||||
if ( ! finalDataType && type ) {
|
||||
finalDataType = type;
|
||||
if ( transportDataType === "*" ) {
|
||||
dataTypes.shift();
|
||||
// Fill responseXXX fields
|
||||
for( type in responseFields ) {
|
||||
if ( type in responses ) {
|
||||
jXHR[ responseFields[ type ] ] = responses[ type ];
|
||||
}
|
||||
dataTypes.unshift( finalDataType );
|
||||
}
|
||||
|
||||
// Get final response
|
||||
response = responses[ finalDataType ];
|
||||
}
|
||||
|
||||
// If successful, handle type chaining
|
||||
|
@ -473,6 +494,7 @@ jQuery.extend({
|
|||
try {
|
||||
|
||||
var i,
|
||||
tmp,
|
||||
// Current dataType
|
||||
current,
|
||||
// Previous dataType
|
||||
|
@ -483,9 +505,7 @@ jQuery.extend({
|
|||
conv,
|
||||
// Conversion functions (when text is used in-between)
|
||||
conv1,
|
||||
conv2,
|
||||
// Local references to converters
|
||||
converters = s.converters;
|
||||
conv2;
|
||||
|
||||
// For each dataType in the chain
|
||||
for( i = 0 ; i < dataTypes.length ; i++ ) {
|
||||
|
@ -505,26 +525,31 @@ jQuery.extend({
|
|||
// Get the dataType to convert from
|
||||
prev = dataTypes[ i - 1 ];
|
||||
|
||||
// If no catch-all and dataTypes are actually different
|
||||
// If no auto and dataTypes are actually different
|
||||
if ( prev !== "*" && current !== "*" && prev !== current ) {
|
||||
|
||||
// Get the converter
|
||||
conversion = prev + " " + current;
|
||||
conv = converters[ conversion ] || converters[ "* " + current ];
|
||||
|
||||
conv1 = conv2 = 0;
|
||||
// If there is no direct converter, search transitively
|
||||
if ( ! conv ) {
|
||||
conv1 = conv2 = undefined;
|
||||
|
||||
// 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;
|
||||
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
|
||||
|
|
|
@ -2006,6 +2006,49 @@ test( "jQuery.ajax - statusCode" , function() {
|
|||
});
|
||||
});
|
||||
|
||||
test("jQuery.ajax - transitive conversions", function() {
|
||||
|
||||
expect( 8 );
|
||||
|
||||
stop();
|
||||
|
||||
jQuery.when(
|
||||
|
||||
jQuery.ajax( url("data/json.php") , {
|
||||
converters: {
|
||||
"json myjson": function( data ) {
|
||||
ok( true , "converter called" );
|
||||
return data;
|
||||
}
|
||||
},
|
||||
dataType: "myjson",
|
||||
success: function() {
|
||||
ok( true , "Transitive conversion worked" );
|
||||
strictEqual( this.dataTypes[0] , "text" , "response was retrieved as text" );
|
||||
strictEqual( this.dataTypes[1] , "myjson" , "request expected myjson dataType" );
|
||||
}
|
||||
}),
|
||||
|
||||
jQuery.ajax( url("data/json.php") , {
|
||||
converters: {
|
||||
"json myjson": function( data ) {
|
||||
ok( true , "converter called (*)" );
|
||||
return data;
|
||||
}
|
||||
},
|
||||
contents: false, /* headers are wrong so we ignore them */
|
||||
dataType: "* myjson",
|
||||
success: function() {
|
||||
ok( true , "Transitive conversion worked (*)" );
|
||||
strictEqual( this.dataTypes[0] , "text" , "response was retrieved as text (*)" );
|
||||
strictEqual( this.dataTypes[1] , "myjson" , "request expected myjson dataType (*)" );
|
||||
}
|
||||
})
|
||||
|
||||
).then( start , start );
|
||||
|
||||
});
|
||||
|
||||
test("jQuery.ajax - active counter", function() {
|
||||
ok( jQuery.active == 0, "ajax active counter should be zero: " + jQuery.active );
|
||||
});
|
||||
|
|
Loading…
Reference in a new issue