Replaces "text in-between" technique with a full-fledged one-level transitive search...
authorjaubourg <j@ubourg.net>
Fri, 21 Jan 2011 02:58:28 +0000 (03:58 +0100)
committerjaubourg <j@ubourg.net>
Fri, 21 Jan 2011 02:58:28 +0000 (03:58 +0100)
src/ajax.js
test/unit/ajax.js

index bf0259c..1872365 100644 (file)
@@ -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;
-                                       }
-                                       responseField = responseFields[ type ];
-                                       if ( responseField && ! ( responseField in jXHR ) ) {
-                                               jXHR[ responseField ] = responses[ 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;
+                                               }
                                        }
+                                       // Or just use first one
+                                       finalDataType = finalDataType || firstDataType;
                                }
 
-                               // 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();
+                               // 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 );
                                        }
-                                       dataTypes.unshift( finalDataType );
                                }
 
-                               // Get final response
-                               response = responses[ finalDataType ];
+                               // Fill responseXXX fields
+                               for( type in responseFields ) {
+                                       if ( type in responses ) {
+                                               jXHR[ responseFields[ type ] ] = responses[ type ];
+                                       }
+                               }
                        }
 
                        // 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 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 there is no direct converter, search transitively
+                                                                       if ( ! conv ) {
+                                                                               conv1 = 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
index 1ed15b5..b44f077 100644 (file)
@@ -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 );
 });