diff --git a/src/ajax.js b/src/ajax.js index 08fbe6f01..a5fff4e81 100644 --- a/src/ajax.js +++ b/src/ajax.js @@ -191,16 +191,17 @@ jQuery.extend({ // 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: [], - + // 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: { - }, - + transports: {}, + // Checkers // 1) key is dataType // 2) they are called to control successful response diff --git a/src/transports/jsonp.js b/src/transports/jsonp.js index d9e77f2f3..6c9fb704e 100644 --- a/src/transports/jsonp.js +++ b/src/transports/jsonp.js @@ -11,12 +11,14 @@ jQuery.ajaxSettings.jsonpCallback = function() { // Normalize jsonp queries // 1) put callback parameter in url or data -// 2) ensure transportDataType is json +// 2) sneakily 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) { +jQuery.xhr.prefilter("json jsonp", function(s) { - var transportDataType = s.dataTypes[0]; + var transportDataType = s.dataTypes[ 0 ]; + + s.dataTypes[ 0 ] = "json"; if ( s.jsonp || transportDataType === "jsonp" || @@ -34,14 +36,10 @@ jQuery.xhr.prefilter( function(s) { s.url = url; s.data = data; - - s.dataTypes[0] = "json"; } -}); - // Bind transport to json dataType -jQuery.xhr.bindTransport("json", function(s) { +}).transport("json", function(s) { if ( s.jsonp ) { diff --git a/src/transports/script.js b/src/transports/script.js index 7416a2d1a..27473ee7e 100644 --- a/src/transports/script.js +++ b/src/transports/script.js @@ -17,7 +17,7 @@ jQuery.extend( true, jQuery.ajaxSettings , { } ); // Bind script tag hack transport -jQuery.xhr.bindTransport("script", function(s) { +jQuery.xhr.transport("script", function(s) { // Handle cache special case if ( s.cache === undefined ) { diff --git a/src/transports/xhr.js b/src/transports/xhr.js index 783ee4604..978f6c259 100644 --- a/src/transports/xhr.js +++ b/src/transports/xhr.js @@ -10,7 +10,7 @@ var // Next fake timer id xhrUnloadAbortMarker = []; -jQuery.xhr.bindTransport( function( s , determineDataType ) { +jQuery.xhr.transport( function( s , determineDataType ) { // Cross domain only allowed if supported through XMLHttpRequest if ( ! s.crossDomain || jQuery.support.cors ) { diff --git a/src/xhr.js b/src/xhr.js index 51bd3dfd0..d64238a60 100644 --- a/src/xhr.js +++ b/src/xhr.js @@ -86,15 +86,10 @@ jQuery.xhr = function( _native ) { if ( data && s.processData && typeof data != "string" ) { data = s.data = jQuery.param( data , s.traditional ); } - - // Apply option prefilters - for ( i = 0; i < prefilters.length; i++ ) { - prefilters[i](s); - } - + // Get internal - internal = selectTransport( s ); - + internal = jQuery.xhr.prefilter( s ).transport( s ); + // Re-actualize url & data url = s.url; data = s.data; @@ -606,101 +601,19 @@ jQuery.xhr = function( _native ) { return xhr; }; -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 ) { +// Execute or select from functions in a given structure of options +function xhr_selectOrExecute( structure , s ) { var dataTypes = s.dataTypes, transportDataType, - transportsList, - transport, + list, + selected, i, length, checked = {}, - flag; - + flag, + noSelect = structure !== "transports"; + function initSearch( dataType ) { flag = transportDataType !== dataType && ! checked[ dataType ]; @@ -709,9 +622,9 @@ function selectTransport( s ) { checked[ dataType ] = 1; transportDataType = dataType; - transportsList = s.transports[ dataType ]; + list = s[ structure ][ dataType ]; i = -1; - length = transportsList ? transportsList.length : 0 ; + length = list ? list.length : 0 ; } return flag; @@ -719,30 +632,104 @@ function selectTransport( s ) { initSearch( dataTypes[ 0 ] ); - for ( i = 0 ; ! transport && i <= length ; i++ ) { - + for ( i = 0 ; ( noSelect || ! selected ) && i <= length ; i++ ) { + if ( i === length ) { initSearch( "*" ); } else { - transport = transportsList[ i ]( s , determineDataType ); + selected = list[ 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 ) ) { + if ( typeof( selected ) === "string" && + initSearch( selected ) ) { - dataTypes.unshift( transport ); - transport = 0; + dataTypes.unshift( selected ); + selected = 0; } } } - return transport; + return noSelect ? jQuery.xhr : selected; } +// Add an element to one of the xhr structures in ajaxSettings +function xhr_addElement( structure , args ) { + + var i, + j, + start = 0, + length = args.length, + dataTypes = [ "*" ], + dLength = 1, + dataType, + functors = [], + first, + append, + list; + + if ( length ) { + + first = jQuery.type( args[ 0 ] ); + + if ( first === "object" ) { + return xhr_selectOrExecute( structure , args[ 0 ] ); + } + + structure = jQuery.ajaxSettings[ structure ]; + + if ( first !== "function" ) { + + dataTypes = args[ 0 ].toLowerCase().split(/\s+/); + dLength = dataTypes.length; + start = 1; + + } + + if ( dLength && start < length ) { + + functors = sliceFunc.call( args , start ); + + length -= 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 ] || []; + + for ( j = 0; j < length; j++ ) { + append.call( list , functors[ j ] ); + } + } + } + } + } + + return jQuery.xhr; +} + +// Install prefilter & transport methods +jQuery.each( [ "prefilter" , "transport" ] , function( _ , name ) { + _ = name + "s"; + jQuery.xhr[ name ] = function() { + return xhr_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 ) {