Fixed function closures so that Makefile can do its magic.
[jquery.git] / src / xhr.js
1 (function( jQuery ) {
2
3 var rquery = /\?/,
4         rhash = /#.*$/,
5         rheaders = /^(.*?):\s*(.*?)\r?$/mg, // IE leaves an \r character at EOL
6         rnoContent = /^(?:GET|HEAD)$/,
7         rts = /([?&])_=[^&]*/,
8         rurl = /^(\w+:)?\/\/([^\/?#]+)/,
9         
10         slice = Array.prototype.slice,
11         
12         isFunction = jQuery.isFunction,
13         
14         undefined;
15         
16 // Creates a jQuery xhr object
17 jQuery.xhr = function( _native ) {
18         
19         if ( _native ) {
20                 return jQuery.ajaxSettings.xhr();
21         }
22         
23         function reset(force) {
24                 
25                 // We only need to reset if we went through the init phase
26                 // (with the exception of object creation)
27                 if ( force || internal ) {
28                 
29                         // Reset callbacks lists
30                         callbacksLists = {
31                                 success: createCBList(),
32                                 error: createCBList(),
33                                 complete: createCBList()
34                         };
35                         
36                         // Reset private variables
37                         requestHeaders = {};
38                         responseHeadersString = responseHeaders = internal = done = timeoutTimer = s = undefined;
39                         
40                         // Reset state
41                         xhr.readyState = 0;
42                         sendFlag = 0;
43                         
44                         // Remove responseX fields
45                         for ( var name in xhr ) {
46                                 if ( /^response/.test(name) ) {
47                                         delete xhr[name];
48                                 }
49                         }
50                 }
51         }
52         
53         function init() {
54                 
55                 var // Options extraction
56                 
57                         // Remove hash character (#7531: first for string promotion)
58                         url = s.url = ( "" + s.url ).replace( rhash , "" ),
59                         
60                         // Uppercase the type
61                         type = s.type = s.type.toUpperCase(),
62                         
63                         // Determine if request has content
64                         hasContent = s.hasContent = ! rnoContent.test( type ),
65                         
66                         // Extract dataTypes list
67                         dataType = s.dataType,
68                         dataTypes = s.dataTypes = dataType ? jQuery.trim(dataType).toLowerCase().split(/\s+/) : ["*"],
69                         
70                         // Determine if a cross-domain request is in order
71                         parts = rurl.exec( url.toLowerCase() ),
72                         loc = location,
73                         crossDomain = s.crossDomain = !!( parts && ( parts[1] && parts[1] != loc.protocol || parts[2] != loc.host ) ),
74                         
75                         // Get other options locally
76                         data = s.data,
77                         originalContentType = s.contentType,
78                         prefilters = s.prefilters,
79                         accepts = s.accepts,
80                         headers = s.headers,
81                         
82                         // Other Variables
83                         transportDataType,
84                         i;
85
86                 // Convert data if not already a string
87                 if ( data && s.processData && typeof data != "string" ) {
88                         data = s.data = jQuery.param( data , s.traditional );
89                 }
90                 
91                 // Apply option prefilters
92                 for (i in prefilters) {
93                         prefilters[i](s);
94                 }
95                 
96                 // Get internal
97                 internal = selectTransport( s );
98                 
99                 // Re-actualize url & data
100                 url = s.url;
101                 data = s.data;
102                 
103                 // If internal was found
104                 if ( internal ) {
105                         
106                         // Get transportDataType
107                         transportDataType = dataTypes[0];
108                         
109                         // More options handling for requests with no content
110                         if ( ! hasContent ) {
111                                 
112                                 // If data is available, append data to url
113                                 if ( data ) {
114                                         url += (rquery.test(url) ? "&" : "?") + data;
115                                 }
116                                                                 
117                                 // Add anti-cache in url if needed
118                                 if ( s.cache === false ) {
119                                         
120                                         var ts = jQuery.now(),
121                                                 // try replacing _= if it is there
122                                                 ret = url.replace(rts, "$1_=" + ts );
123                                                 
124                                         // if nothing was replaced, add timestamp to the end
125                                         url = ret + ((ret == url) ? (rquery.test(url) ? "&" : "?") + "_=" + ts : "");
126                                 }
127                                 
128                                 s.url = url;
129                         }
130                         
131                         // Set the correct header, if data is being sent
132                         if ( ( data && hasContent ) || originalContentType ) {
133                                 requestHeaders["content-type"] = s.contentType;
134                         }
135                 
136                         // Set the If-Modified-Since and/or If-None-Match header, if in ifModified mode.
137                         if ( s.ifModified ) {
138                                 if ( jQuery_lastModified[url] ) { 
139                                         requestHeaders["if-modified-since"] = jQuery_lastModified[url];
140                                 }
141                                 if ( jQuery_etag[url] ) {
142                                         requestHeaders["if-none-match"] = jQuery_etag[url];
143                                 }
144                         }
145                 
146                         // Set the Accepts header for the server, depending on the dataType
147                         requestHeaders.accept = transportDataType && accepts[ transportDataType ] ?
148                                 accepts[ transportDataType ] + ( transportDataType !== "*" ? ", */*; q=0.01" : "" ) :
149                                 accepts[ "*" ];
150                                 
151                         // Check for headers option
152                         for ( i in headers ) {
153                                 requestHeaders[ i.toLowerCase() ] = headers[ i ];
154                         }                       
155                 }
156                         
157                 callbackContext = s.context || s;
158                 globalEventContext = s.context ? jQuery(s.context) : jQuery.event;
159                 
160                 for ( i in callbacksLists ) {
161                         callbacksLists[i].bind(s[i]);
162                 }
163                 
164                 // Watch for a new set of requests
165                 if ( s.global && jQuery.active++ === 0 ) {
166                         jQuery.event.trigger( "ajaxStart" );
167                 }
168                 
169                 done = whenDone;
170         }
171         
172         function whenDone(status, statusText, response, headers) {
173                 
174                 // Called once
175                 done = undefined;
176                 
177                 // Reset sendFlag
178                 sendFlag = 0;
179                 
180                 // Cache response headers
181                 responseHeadersString = headers || "";
182
183                 // Clear timeout if it exists
184                 if ( timeoutTimer ) {
185                         clearTimeout(timeoutTimer);
186                 }
187                 
188                 var // Reference url
189                         url = s.url,
190                         // and ifModified status
191                         ifModified = s.ifModified,
192                         
193                         // Is it a success?
194                         isSuccess = 0,
195                         // Stored success
196                         success,
197                         // Stored error
198                         error = statusText;
199
200                 // If not timeout, force a jQuery-compliant status text
201                 if ( statusText != "timeout" ) {
202                         statusText = ( status >= 200 && status < 300 ) ? 
203                                 "success" :
204                                 ( status === 304 ? "notmodified" : "error" );
205                 }
206                 
207                 // If successful, handle type chaining
208                 if ( statusText === "success" || statusText === "notmodified" ) {
209                         
210                         // Set the If-Modified-Since and/or If-None-Match header, if in ifModified mode.
211                         if ( ifModified ) {
212                                 var lastModified = xhr.getResponseHeader("Last-Modified"),
213                                         etag = xhr.getResponseHeader("Etag");
214                                         
215                                 if (lastModified) {
216                                         jQuery_lastModified[url] = lastModified;
217                                 }
218                                 if (etag) {
219                                         jQuery_etag[url] = etag;
220                                 }
221                         }
222                         
223                         if ( ifModified && statusText === "notmodified" ) {
224                                 
225                                 success = null;
226                                 isSuccess = 1;
227                                 
228                         } else {
229                                 // Chain data conversions and determine the final value
230                                 // (if an exception is thrown in the process, it'll be notified as an error)
231                                 try {
232                                         
233                                         function checkData(data) {
234                                                 if ( data !== undefined ) {
235                                                         var testFunction = s.dataCheckers[srcDataType];
236                                                         if ( isFunction( testFunction ) ) {
237                                                                 testFunction(data);
238                                                         }
239                                                 }
240                                         }
241                                         
242                                         function convertData (data) {
243                                                 var conversionFunction = dataConverters[srcDataType+" => "+destDataType] ||
244                                                                 dataConverters["* => "+destDataType],
245                                                         noFunction = ! isFunction( conversionFunction );
246                                                 if ( noFunction ) {
247                                                         if ( srcDataType != "text" && destDataType != "text" ) {
248                                                                 // We try to put text inbetween
249                                                                 var first = dataConverters[srcDataType+" => text"] ||
250                                                                                 dataConverters["* => text"],
251                                                                         second = dataConverters["text => "+destDataType] ||
252                                                                                 dataConverters["* => "+destDataType],
253                                                                         areFunctions = isFunction( first ) && isFunction( second );
254                                                                 if ( areFunctions ) {
255                                                                         conversionFunction = function (data) {
256                                                                                 return second( first ( data ) );
257                                                                         };
258                                                                 }
259                                                                 noFunction = ! areFunctions;
260                                                         }
261                                                         if ( noFunction ) {
262                                                                 jQuery.error( "no data converter between " + srcDataType + " and " + destDataType );
263                                                         }
264                                                         
265                                                 }
266                                                 return conversionFunction(data);
267                                         }
268                                         
269                                         var dataTypes = s.dataTypes,
270                                                 i,
271                                                 length,
272                                                 data = response,
273                                                 dataConverters = s.dataConverters,
274                                                 srcDataType,
275                                                 destDataType,
276                                                 responseTypes = s.xhrResponseFields;
277                                                 
278                                         for ( i = 0, length = dataTypes.length ; i < length ; i++ ) {
279         
280                                                 destDataType = dataTypes[i];
281                                                 
282                                                 if ( !srcDataType ) { // First time
283                                                         
284                                                         // Copy type
285                                                         srcDataType = destDataType;
286                                                         // Check
287                                                         checkData(data);
288                                                         // Apply dataFilter
289                                                         if ( isFunction( s.dataFilter ) ) {
290                                                                 data = s.dataFilter(data, s.dataType);
291                                                                 // Recheck data
292                                                                 checkData(data);
293                                                         }
294                                                         
295                                                 } else { // Subsequent times
296                                                         
297                                                         // handle auto
298                                                         // JULIAN: for reasons unknown to me === doesn't work here
299                                                         if (destDataType == "*") {
300         
301                                                                 destDataType = srcDataType;
302                                                                 
303                                                         } else if ( srcDataType != destDataType ) {
304                                                                 
305                                                                 // Convert
306                                                                 data = convertData(data);
307                                                                 // Copy type & check
308                                                                 srcDataType = destDataType;
309                                                                 checkData(data);
310                                                                 
311                                                         }
312                                                         
313                                                 }
314         
315                                                 // Copy response into the xhr if it hasn't been already
316                                                 var responseDataType,
317                                                         responseType = responseTypes[srcDataType];
318                                                 
319                                                 if ( responseType ) {
320                                                         
321                                                         responseDataType = srcDataType;
322                                                         
323                                                 } else {
324                                                         
325                                                         responseType = responseTypes[ responseDataType = "text" ];
326                                                         
327                                                 }
328                                                         
329                                                 if ( responseType !== 1 ) {
330                                                         xhr[ "response" + responseType ] = data;
331                                                         responseTypes[ responseType ] = 1;
332                                                 }
333                                                 
334                                         }
335         
336                                         // We have a real success
337                                         success = data;
338                                         isSuccess = 1;
339                                         
340                                 } catch(e) {
341                                         
342                                         statusText = "parsererror";
343                                         error = "" + e;
344                                         
345                                 }
346                         }
347                         
348                 } else { // if not success, mark it as an error
349                         
350                                 error = error || statusText;
351                                 
352                 }
353                         
354                 // Set data for the fake xhr object
355                 xhr.status = status;
356                 xhr.statusText = statusText;
357                 
358                 // Keep local copies of vars in case callbacks re-use the xhr
359                 var _s = s,
360                         _callbacksLists = callbacksLists,
361                         _callbackContext = callbackContext,
362                         _globalEventContext = globalEventContext;
363                         
364                 // Set state if the xhr hasn't been re-used
365                 function _setState( value ) {
366                         if ( xhr.readyState && s === _s ) {
367                                 setState( value );
368                         }
369                 }
370                                 
371                 // Really completed?
372                 if ( status && s.async ) {
373                         setState( 2 );
374                         _setState( 3 );
375                 }
376                 
377                 // We're done
378                 _setState( 4 );
379                 
380                 // Success
381                 _callbacksLists.success.fire( isSuccess , _callbackContext , success, statusText, xhr);
382                 if ( isSuccess && _s.global ) {
383                         _globalEventContext.trigger( "ajaxSuccess", [xhr, _s, success] );
384                 }
385                 // Error
386                 _callbacksLists.error.fire( ! isSuccess , _callbackContext , xhr, statusText, error);
387                 if ( !isSuccess && _s.global ) {
388                         _globalEventContext.trigger( "ajaxError", [xhr, _s, error] );   
389                 }
390                 // Complete
391                 _callbacksLists.complete.fire( 1 , _callbackContext, xhr, statusText);
392                 if ( _s.global ) {
393                         _globalEventContext.trigger( "ajaxComplete", [xhr, _s] );
394                         // Handle the global AJAX counter
395                         if ( ! --jQuery.active ) {
396                                 jQuery.event.trigger( "ajaxStop" );
397                         }
398                 }
399         }
400         
401         // Ready state control
402         function checkState( expected , test ) {
403                 if ( expected !== true && ( expected === false || test === false || xhr.readyState !== expected ) ) {
404                         jQuery.error("INVALID_STATE_ERR");
405                 }
406         }
407         
408         // Ready state change
409         function setState( value ) {
410                 xhr.readyState = value;
411                 if ( isFunction( xhr.onreadystatechange ) ) {
412                         xhr.onreadystatechange();
413                 }
414         }
415         
416         var // jQuery lists
417                 jQuery_lastModified = jQuery.lastModified,
418                 jQuery_etag = jQuery.etag,
419                 // Options object
420                 s,
421                 // Callback stuff
422                 callbackContext,
423                 globalEventContext,
424                 callbacksLists,
425                 // Headers (they are sent all at once)
426                 requestHeaders,
427                 // Response headers
428                 responseHeadersString,
429                 responseHeaders,
430                 // Done callback
431                 done,
432                 // transport
433                 internal,
434                 // timeout handle
435                 timeoutTimer,
436                 // The send flag
437                 sendFlag,
438                 // Fake xhr
439                 xhr = {
440                         // state
441                         readyState: 0,
442                         
443                         // Callback
444                         onreadystatechange: null,
445                         
446                         // Open
447                         open: function(type, url, async, username, password) {
448                                 
449                                 xhr.abort();
450                                 reset();
451                                 
452                                 s = {
453                                         type: type,
454                                         url: url,
455                                         async: async,
456                                         username: username,
457                                         password: password
458                                 };
459                                 
460                                 setState(1);
461                                 
462                                 return xhr;
463                         },
464                         
465                         // Send
466                         send: function(data, moreOptions) {
467                                 
468                                 checkState(1 , !sendFlag);
469                                 
470                                 s.data = data;
471                                 
472                                 s = jQuery.extend( true,
473                                         {},
474                                         jQuery.ajaxSettings,
475                                         s,
476                                         moreOptions || ( moreOptions === false ? { global: false } : {} ) );
477                                         
478                                 if ( moreOptions ) {
479                                         // We force the original context
480                                         // (plain objects used as context get extended)
481                                         s.context = moreOptions.context;
482                                 }
483                                 
484                                 init();
485                                 
486                                 // If not internal, abort
487                                 if ( ! internal ) {
488                                         done( 0 , "transport not found" );
489                                         return false;
490                                 }
491                                 
492                                 // Allow custom headers/mimetypes and early abort
493                                 if ( s.beforeSend ) {
494                                         
495                                         var _s = s;
496                                         
497                                         if ( s.beforeSend.call(callbackContext, xhr, s) === false || ! xhr.readyState || _s !== s ) {
498                                                 
499                                                 // Abort if not done
500                                                 if ( xhr.readyState && _s === s ) {
501                                                         xhr.abort();
502                                                 }
503         
504                                                 // Handle the global AJAX counter
505                                                 if ( _s.global && ! --jQuery.active ) {
506                                                         jQuery.event.trigger( "ajaxStop" );
507                                                 }
508                                                 
509                                                 return false;
510                                         }
511                                 }
512                                 
513                                 sendFlag = 1;
514                                 
515                                 // Send global event
516                                 if ( s.global ) {
517                                         globalEventContext.trigger("ajaxSend", [xhr, s]);
518                                 }
519                                 
520                                 // Timeout
521                                 if ( s.async && s.timeout > 0 ) {
522                                         timeoutTimer = setTimeout(function(){
523                                                 xhr.abort("timeout");
524                                         }, s.timeout);
525                                 }
526                                 
527                                 if ( s.async ) {
528                                         setState(1);
529                                 }
530                                 
531                                 try {
532                                         
533                                         internal.send(requestHeaders, done);
534                                         return xhr;
535                                                                                         
536                                 } catch (e) {
537                                         
538                                         if ( done ) {
539                                                 
540                                                 done(0, "error", "" + e);
541                                                 
542                                         } else {
543                                                 
544                                                 jQuery.error(e);
545                                                 
546                                         }
547                                 }
548                                 
549                                 return false;
550                         },
551                         
552                         // Caches the header
553                         setRequestHeader: function(name,value) {
554                                 checkState(1, !sendFlag);
555                                 requestHeaders[ name.toLowerCase() ] = value;
556                                 return xhr;
557                         },
558                         
559                         // Raw string
560                         getAllResponseHeaders: function() {
561                                 return xhr.readyState <= 1 ? "" : responseHeadersString;
562                         },
563                         
564                         // Builds headers hashtable if needed
565                         getResponseHeader: function( key ) {
566                                 
567                                 if ( xhr.readyState <= 1 ) {
568                                         
569                                         return null;
570                                         
571                                 }
572                                 
573                                 if ( responseHeaders === undefined ) {
574                                         
575                                         responseHeaders = {};
576                                         
577                                         if ( typeof responseHeadersString === "string" ) {
578                                                 
579                                                 var match;
580                                                 
581                                                 while( ( match = rheaders.exec( responseHeadersString ) ) ) {
582                                                         responseHeaders[ match[ 1 ].toLowerCase() ] = match[ 2 ];
583                                                 }
584                                         }
585                                 }
586                                 return responseHeaders[ key.toLowerCase() ];
587                         },
588                         
589                         // Cancel the request
590                         abort: function(statusText) {
591                                 if (internal) {
592                                         internal.abort( statusText || "abort" );
593                                 }
594                                 xhr.readyState = 0;
595                         }
596                 };
597                 
598         // Init data (so that we can bind callbacks early
599         reset(1);
600
601         // Install callbacks related methods
602         jQuery.each(["bind","unbind"], function(_, name) {
603                 xhr[name] = function(type) {
604                         
605                         var functors = slice.call(arguments,1),
606                                 list;
607                                 
608                         jQuery.each(type.split(/\s+/g), function() {
609                                 list = callbacksLists[this];
610                                 if ( list ) {
611                                         list[name].apply(list, functors );
612                                 }
613                         });
614                         
615                         return this;
616                 };
617         });
618
619         jQuery.each(callbacksLists, function(name) {
620                 var list;
621                 xhr[name] = function() {
622                         list = callbacksLists[name];
623                         if ( list ) {
624                                 list.bind.apply(list, arguments );
625                         }
626                         return this;
627                 };
628         });
629         
630         // Return the xhr emulation
631         return xhr;
632 };
633
634 // Create a callback list
635 function createCBList() {
636         
637         var functors = [],
638                 autoFire = 0,
639                 fireArgs,
640                 list = {
641                 
642                         fire: function( flag , context ) {
643                                 
644                                 // Save info for later bindings
645                                 fireArgs = arguments;
646                                 
647                                 // Remove autoFire to keep bindings in order
648                                 autoFire = 0;
649                                         
650                                 var args = slice.call( fireArgs , 2 );
651                                         
652                                 // Execute callbacks
653                                 while ( flag && functors.length ) {
654                                         flag = functors.shift().apply( context , args ) !== false;
655                                 }
656                                         
657                                 // Clean if asked to stop
658                                 if ( ! flag ) {
659                                         clean();
660                                 }
661                                                 
662                                 // Set autoFire
663                                 autoFire = 1;                                   
664                         },
665                         
666                         bind: function() {
667                                 
668                                 var args = arguments,
669                                         i = 0,
670                                         length = args.length,
671                                         func;
672                                 
673                                 for ( ; i < length ; i++ ) {
674                                         
675                                         func = args[ i ];
676                                         
677                                         if ( jQuery.isArray(func) ) {
678                                                 
679                                                 list.bind.apply( list , func );
680                                                 
681                                         } else if ( isFunction(func) ) {
682                                                 
683                                                 // Add if not already in
684                                                 if ( ! pos( func ) ) {
685                                                         functors.push( func );
686                                                 }
687                                         }
688                                 }
689                                 
690                                 if ( autoFire ) {
691                                         list.fire.apply( list , fireArgs );
692                                 }
693                         },
694                         
695                         unbind: function() {
696                                 
697                                 var i = 0,
698                                         args = arguments,
699                                         length = args.length,
700                                         func,                                   
701                                         position;
702                                         
703                                 if ( length ) {
704                                                 
705                                         for( ; i < length ; i++ ) {
706                                                 func = args[i];
707                                                 if ( jQuery.isArray(func) ) {
708                                                         list.unbind.apply(list,func);
709                                                 } else if ( isFunction(func) ) {
710                                                         position = pos(func);
711                                                         if ( position ) {
712                                                                 functors.splice(position-1,1);
713                                                         }
714                                                 }
715                                         }
716                                 
717                                 } else {
718                                         
719                                         functors = [];
720                                 
721                                 }
722
723                         }
724                         
725                 };
726
727         // Get the index of the functor in the list (1-based)
728         function pos( func ) {
729                 for (var i = 0, length = functors.length; i < length && functors[i] !== func; i++) {
730                 }
731                 return i < length ? ( i + 1 ) : 0;
732         }
733                 
734         // Clean the object
735         function clean() {
736                 // Empty callbacks list
737                 functors = [];
738                 // Inhibit methods
739                 for (var i in list) {
740                         list[i] = jQuery.noop;
741                 }
742         }
743                                 
744         return list;
745 }
746
747 jQuery.extend(jQuery.xhr, {
748         
749         // Add new prefilter
750         prefilter: function (functor) {
751                 if ( isFunction(functor) ) {
752                         jQuery.ajaxSettings.prefilters.push( functor );
753                 }
754                 return this;
755         },
756         
757         // Bind a transport to one or more dataTypes
758         bindTransport: function () {
759                 
760                 var args = arguments,
761                         i,
762                         start = 0,
763                         length = args.length,
764                         dataTypes = [ "*" ],
765                         functors = [],
766                         functor,
767                         first,
768                         append,
769                         list,
770                         transports = jQuery.ajaxSettings.transports;
771                         
772                 if ( length ) {
773                                 
774                         if ( ! isFunction( args[ 0 ] ) ) {
775                                 
776                                 dataTypes = args[ 0 ].toLowerCase().split(/\s+/);
777                                 start = 1;
778                                 
779                         }
780                         
781                         if ( dataTypes.length && start < length ) {
782                                 
783                                 for ( i = start; i < length; i++ ) {
784                                         functor = args[i];
785                                         if ( isFunction(functor) ) {
786                                                 functors.push( functor );
787                                         }
788                                 }
789                                                 
790                                 if ( functors.length ) {
791                                                         
792                                         jQuery.each ( dataTypes, function( _ , dataType ) {
793                                                 
794                                                 first = /^\+/.test( dataType );
795                                                 
796                                                 if (first) {
797                                                         dataType = dataType.substr(1);
798                                                 }
799                                                 
800                                                 if ( dataType !== "" ) {
801                                                 
802                                                         append = Array.prototype[ first ? "unshift" : "push" ];
803                                                         
804                                                         list = transports[ dataType ];
805                                         
806                                                         jQuery.each ( functors, function( _ , functor ) {
807                                                                         
808                                                                 if ( ! list ) {
809                                                                         
810                                                                         list = transports[ dataType ] = [ functor ];
811                                                                         
812                                                                 } else {
813                                                                         
814                                                                         append.call( list , functor );
815                                                                 }
816                                                         } );
817                                                 }
818                                                                         
819                                         } );
820                                 }
821                         }
822                 }
823                 
824                 return this;
825         }
826
827         
828 });
829
830 // Select a transport given options
831 function selectTransport( s ) {
832
833         var dataTypes = s.dataTypes,
834                 transportDataType,
835                 transportsList,
836                 transport,
837                 i,
838                 length,
839                 checked = {},
840                 flag;
841                 
842         function initSearch( dataType ) {
843
844                 flag = transportDataType !== dataType && ! checked[ dataType ];
845                 
846                 if ( flag ) {
847                         
848                         checked[ dataType ] = 1;
849                         transportDataType = dataType;
850                         transportsList = s.transports[ dataType ];
851                         i = -1;
852                         length = transportsList ? transportsList.length : 0 ;
853                 }
854
855                 return flag;
856         }
857         
858         initSearch( dataTypes[ 0 ] );
859
860         for ( i = 0 ; ! transport && i <= length ; i++ ) {
861                 
862                 if ( i === length ) {
863                         
864                         initSearch( "*" );
865                         
866                 } else {
867
868                         transport = transportsList[ i ]( s , determineDataType );
869
870                         // If we got redirected to another dataType
871                         // Search there (if not in progress or already tried)
872                         if ( typeof( transport ) === "string" &&
873                                 initSearch( transport ) ) {
874
875                                 dataTypes.unshift( transport );
876                                 transport = 0;
877                         }
878                 }
879         }
880
881         return transport;
882 }
883         
884 // Utility function that handles dataType when response is received
885 // (for those transports that can give text or xml responses)
886 function determineDataType( s , ct , text , xml ) {
887         
888         var autoDataType = s.autoDataType,
889                 type,
890                 regexp,
891                 dataTypes = s.dataTypes,
892                 transportDataType = dataTypes[0],
893                 response;
894         
895         // Auto (xml, json, script or text determined given headers)
896         if ( transportDataType === "*" ) {
897
898                 for ( type in autoDataType ) {
899                         if ( ( regexp = autoDataType[ type ] ) && regexp.test( ct ) ) {
900                                 transportDataType = dataTypes[0] = type;
901                                 break;
902                         }
903                 }                       
904         } 
905         
906         // xml and parsed as such
907         if ( transportDataType === "xml" &&
908                 xml &&
909                 xml.documentElement /* #4958 */ ) {
910                 
911                 response = xml;
912         
913         // Text response was provided
914         } else {
915                 
916                 response = text;
917                 
918                 // If it's not really text, defer to dataConverters
919                 if ( transportDataType !== "text" ) {
920                         dataTypes.unshift( "text" );
921                 }
922                 
923         }
924         
925         return response;
926 }       
927
928 })( jQuery );