cloneCopyEvent; jQuery.clone() review
[jquery.git] / src / ajax.js
index b903358..fc1ecfd 100644 (file)
@@ -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: {
@@ -229,7 +231,61 @@ 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
@@ -253,7 +309,11 @@ jQuery.extend({
                        jQuery_lastModified = jQuery.lastModified,
                        jQuery_etag = jQuery.etag,
                        // Callbacks contexts
-                       callbackContext = options.context || s.context || s,
+                       // 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(),
@@ -271,6 +331,7 @@ jQuery.extend({
                        timeoutTimer,
                        // Cross-domain detection vars
                        loc = document.location,
+                       protocol = loc.protocol || "http:",
                        parts,
                        // The jXHR state
                        state = 0,
@@ -295,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
@@ -331,10 +387,6 @@ jQuery.extend({
                                }
                        };
 
-               // We force the original context
-               // (plain objects used as context get extended)
-               s.context = options.context;
-
                // 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)
@@ -350,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;
@@ -373,7 +425,12 @@ jQuery.extend({
                                // Stored success
                                success,
                                // Stored error
-                               error;
+                               error,
+
+                               // Keep track of statusCode callbacks
+                               oldStatusCode = statusCode;
+
+                       statusCode = undefined;
 
                        // If successful, handle type chaining
                        if ( status >= 200 && status < 300 || status === 304 ) {
@@ -415,6 +472,8 @@ jQuery.extend({
                                                        current,
                                                        // Previous dataType
                                                        prev,
+                                                       // Conversion expression
+                                                       conversion,
                                                        // Conversion function
                                                        conv,
                                                        // Conversion functions (when text is used in-between)
@@ -453,8 +512,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;
 
@@ -529,7 +588,7 @@ jQuery.extend({
                        }
 
                        // Status-dependent callbacks
-                       jXHR.statusCode( statusCode );
+                       jXHR.statusCode( oldStatusCode );
 
                        if ( s.global ) {
                                globalEventContext.trigger( "ajax" + ( isSuccess ? "Success" : "Error" ) ,
@@ -557,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;
@@ -587,9 +640,10 @@ 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 ) ) )
                        );
                }
 
@@ -674,7 +728,7 @@ jQuery.extend({
                        }
 
                        // Get transport
-                       transport = jQuery.ajaxTransport( s );
+                       transport = jQuery.ajaxTransport( s , options );
 
                        // If no transport, we auto-abort
                        if ( ! transport ) {
@@ -806,170 +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 ) {
-
-                       functors = sliceFunc.call( args , start );
+               // We control that the second argument is really a function
+               if ( type || jQuery.isFunction( arg2 ) ) {
 
-                       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);
-                               }
-
-                               if ( dataType !== "" ) {
-
-                                       append = Array.prototype[ first ? "unshift" : "push" ];
-                                       list = structure[ dataType ] = structure[ dataType ] || [];
-                                       append.apply( list , functors );
+                               // 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 );
                        }
                }
        }
-
-       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;
-                       }
-               }
-       }
-
-       // 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;
 }
 
 })( jQuery );