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