PageRenderTime 48ms CodeModel.GetById 15ms RepoModel.GetById 0ms app.codeStats 1ms

/book/bower_components/jquery/src/ajax.js

https://gitlab.com/jeichert/essential-js-design-patterns
JavaScript | 855 lines | 526 code | 143 blank | 186 comment | 159 complexity | ab5f5fffe29b8cd89baca2fb522e54d5 MD5 | raw file
  1. var
  2. // Document location
  3. ajaxLocParts,
  4. ajaxLocation,
  5. ajax_nonce = jQuery.now(),
  6. ajax_rquery = /\?/,
  7. rhash = /#.*$/,
  8. rts = /([?&])_=[^&]*/,
  9. rheaders = /^(.*?):[ \t]*([^\r\n]*)\r?$/mg, // IE leaves an \r character at EOL
  10. // #7653, #8125, #8152: local protocol detection
  11. rlocalProtocol = /^(?:about|app|app-storage|.+-extension|file|res|widget):$/,
  12. rnoContent = /^(?:GET|HEAD)$/,
  13. rprotocol = /^\/\//,
  14. rurl = /^([\w.+-]+:)(?:\/\/([^\/?#:]*)(?::(\d+)|)|)/,
  15. // Keep a copy of the old load method
  16. _load = jQuery.fn.load,
  17. /* Prefilters
  18. * 1) They are useful to introduce custom dataTypes (see ajax/jsonp.js for an example)
  19. * 2) These are called:
  20. * - BEFORE asking for a transport
  21. * - AFTER param serialization (s.data is a string if s.processData is true)
  22. * 3) key is the dataType
  23. * 4) the catchall symbol "*" can be used
  24. * 5) execution will start with transport dataType and THEN continue down to "*" if needed
  25. */
  26. prefilters = {},
  27. /* Transports bindings
  28. * 1) key is the dataType
  29. * 2) the catchall symbol "*" can be used
  30. * 3) selection will start with transport dataType and THEN go to "*" if needed
  31. */
  32. transports = {},
  33. // Avoid comment-prolog char sequence (#10098); must appease lint and evade compression
  34. allTypes = "*/".concat("*");
  35. // #8138, IE may throw an exception when accessing
  36. // a field from window.location if document.domain has been set
  37. try {
  38. ajaxLocation = location.href;
  39. } catch( e ) {
  40. // Use the href attribute of an A element
  41. // since IE will modify it given document.location
  42. ajaxLocation = document.createElement( "a" );
  43. ajaxLocation.href = "";
  44. ajaxLocation = ajaxLocation.href;
  45. }
  46. // Segment location into parts
  47. ajaxLocParts = rurl.exec( ajaxLocation.toLowerCase() ) || [];
  48. // Base "constructor" for jQuery.ajaxPrefilter and jQuery.ajaxTransport
  49. function addToPrefiltersOrTransports( structure ) {
  50. // dataTypeExpression is optional and defaults to "*"
  51. return function( dataTypeExpression, func ) {
  52. if ( typeof dataTypeExpression !== "string" ) {
  53. func = dataTypeExpression;
  54. dataTypeExpression = "*";
  55. }
  56. var dataType,
  57. i = 0,
  58. dataTypes = dataTypeExpression.toLowerCase().match( core_rnotwhite ) || [];
  59. if ( jQuery.isFunction( func ) ) {
  60. // For each dataType in the dataTypeExpression
  61. while ( (dataType = dataTypes[i++]) ) {
  62. // Prepend if requested
  63. if ( dataType[0] === "+" ) {
  64. dataType = dataType.slice( 1 ) || "*";
  65. (structure[ dataType ] = structure[ dataType ] || []).unshift( func );
  66. // Otherwise append
  67. } else {
  68. (structure[ dataType ] = structure[ dataType ] || []).push( func );
  69. }
  70. }
  71. }
  72. };
  73. }
  74. // Base inspection function for prefilters and transports
  75. function inspectPrefiltersOrTransports( structure, options, originalOptions, jqXHR ) {
  76. var inspected = {},
  77. seekingTransport = ( structure === transports );
  78. function inspect( dataType ) {
  79. var selected;
  80. inspected[ dataType ] = true;
  81. jQuery.each( structure[ dataType ] || [], function( _, prefilterOrFactory ) {
  82. var dataTypeOrTransport = prefilterOrFactory( options, originalOptions, jqXHR );
  83. if( typeof dataTypeOrTransport === "string" && !seekingTransport && !inspected[ dataTypeOrTransport ] ) {
  84. options.dataTypes.unshift( dataTypeOrTransport );
  85. inspect( dataTypeOrTransport );
  86. return false;
  87. } else if ( seekingTransport ) {
  88. return !( selected = dataTypeOrTransport );
  89. }
  90. });
  91. return selected;
  92. }
  93. return inspect( options.dataTypes[ 0 ] ) || !inspected[ "*" ] && inspect( "*" );
  94. }
  95. // A special extend for ajax options
  96. // that takes "flat" options (not to be deep extended)
  97. // Fixes #9887
  98. function ajaxExtend( target, src ) {
  99. var deep, key,
  100. flatOptions = jQuery.ajaxSettings.flatOptions || {};
  101. for ( key in src ) {
  102. if ( src[ key ] !== undefined ) {
  103. ( flatOptions[ key ] ? target : ( deep || (deep = {}) ) )[ key ] = src[ key ];
  104. }
  105. }
  106. if ( deep ) {
  107. jQuery.extend( true, target, deep );
  108. }
  109. return target;
  110. }
  111. jQuery.fn.load = function( url, params, callback ) {
  112. if ( typeof url !== "string" && _load ) {
  113. return _load.apply( this, arguments );
  114. }
  115. var selector, response, type,
  116. self = this,
  117. off = url.indexOf(" ");
  118. if ( off >= 0 ) {
  119. selector = url.slice( off, url.length );
  120. url = url.slice( 0, off );
  121. }
  122. // If it's a function
  123. if ( jQuery.isFunction( params ) ) {
  124. // We assume that it's the callback
  125. callback = params;
  126. params = undefined;
  127. // Otherwise, build a param string
  128. } else if ( params && typeof params === "object" ) {
  129. type = "POST";
  130. }
  131. // If we have elements to modify, make the request
  132. if ( self.length > 0 ) {
  133. jQuery.ajax({
  134. url: url,
  135. // if "type" variable is undefined, then "GET" method will be used
  136. type: type,
  137. dataType: "html",
  138. data: params
  139. }).done(function( responseText ) {
  140. // Save response for use in complete callback
  141. response = arguments;
  142. self.html( selector ?
  143. // If a selector was specified, locate the right elements in a dummy div
  144. // Exclude scripts to avoid IE 'Permission Denied' errors
  145. jQuery("<div>").append( jQuery.parseHTML( responseText ) ).find( selector ) :
  146. // Otherwise use the full result
  147. responseText );
  148. }).complete( callback && function( jqXHR, status ) {
  149. self.each( callback, response || [ jqXHR.responseText, status, jqXHR ] );
  150. });
  151. }
  152. return this;
  153. };
  154. // Attach a bunch of functions for handling common AJAX events
  155. jQuery.each( [ "ajaxStart", "ajaxStop", "ajaxComplete", "ajaxError", "ajaxSuccess", "ajaxSend" ], function( i, type ){
  156. jQuery.fn[ type ] = function( fn ){
  157. return this.on( type, fn );
  158. };
  159. });
  160. jQuery.extend({
  161. // Counter for holding the number of active queries
  162. active: 0,
  163. // Last-Modified header cache for next request
  164. lastModified: {},
  165. etag: {},
  166. ajaxSettings: {
  167. url: ajaxLocation,
  168. type: "GET",
  169. isLocal: rlocalProtocol.test( ajaxLocParts[ 1 ] ),
  170. global: true,
  171. processData: true,
  172. async: true,
  173. contentType: "application/x-www-form-urlencoded; charset=UTF-8",
  174. /*
  175. timeout: 0,
  176. data: null,
  177. dataType: null,
  178. username: null,
  179. password: null,
  180. cache: null,
  181. throws: false,
  182. traditional: false,
  183. headers: {},
  184. */
  185. accepts: {
  186. "*": allTypes,
  187. text: "text/plain",
  188. html: "text/html",
  189. xml: "application/xml, text/xml",
  190. json: "application/json, text/javascript"
  191. },
  192. contents: {
  193. xml: /xml/,
  194. html: /html/,
  195. json: /json/
  196. },
  197. responseFields: {
  198. xml: "responseXML",
  199. text: "responseText",
  200. json: "responseJSON"
  201. },
  202. // Data converters
  203. // Keys separate source (or catchall "*") and destination types with a single space
  204. converters: {
  205. // Convert anything to text
  206. "* text": String,
  207. // Text to html (true = no transformation)
  208. "text html": true,
  209. // Evaluate text as a json expression
  210. "text json": jQuery.parseJSON,
  211. // Parse text as xml
  212. "text xml": jQuery.parseXML
  213. },
  214. // For options that shouldn't be deep extended:
  215. // you can add your own custom options here if
  216. // and when you create one that shouldn't be
  217. // deep extended (see ajaxExtend)
  218. flatOptions: {
  219. url: true,
  220. context: true
  221. }
  222. },
  223. // Creates a full fledged settings object into target
  224. // with both ajaxSettings and settings fields.
  225. // If target is omitted, writes into ajaxSettings.
  226. ajaxSetup: function( target, settings ) {
  227. return settings ?
  228. // Building a settings object
  229. ajaxExtend( ajaxExtend( target, jQuery.ajaxSettings ), settings ) :
  230. // Extending ajaxSettings
  231. ajaxExtend( jQuery.ajaxSettings, target );
  232. },
  233. ajaxPrefilter: addToPrefiltersOrTransports( prefilters ),
  234. ajaxTransport: addToPrefiltersOrTransports( transports ),
  235. // Main method
  236. ajax: function( url, options ) {
  237. // If url is an object, simulate pre-1.5 signature
  238. if ( typeof url === "object" ) {
  239. options = url;
  240. url = undefined;
  241. }
  242. // Force options to be an object
  243. options = options || {};
  244. var // Cross-domain detection vars
  245. parts,
  246. // Loop variable
  247. i,
  248. // URL without anti-cache param
  249. cacheURL,
  250. // Response headers as string
  251. responseHeadersString,
  252. // timeout handle
  253. timeoutTimer,
  254. // To know if global events are to be dispatched
  255. fireGlobals,
  256. transport,
  257. // Response headers
  258. responseHeaders,
  259. // Create the final options object
  260. s = jQuery.ajaxSetup( {}, options ),
  261. // Callbacks context
  262. callbackContext = s.context || s,
  263. // Context for global events is callbackContext if it is a DOM node or jQuery collection
  264. globalEventContext = s.context && ( callbackContext.nodeType || callbackContext.jquery ) ?
  265. jQuery( callbackContext ) :
  266. jQuery.event,
  267. // Deferreds
  268. deferred = jQuery.Deferred(),
  269. completeDeferred = jQuery.Callbacks("once memory"),
  270. // Status-dependent callbacks
  271. statusCode = s.statusCode || {},
  272. // Headers (they are sent all at once)
  273. requestHeaders = {},
  274. requestHeadersNames = {},
  275. // The jqXHR state
  276. state = 0,
  277. // Default abort message
  278. strAbort = "canceled",
  279. // Fake xhr
  280. jqXHR = {
  281. readyState: 0,
  282. // Builds headers hashtable if needed
  283. getResponseHeader: function( key ) {
  284. var match;
  285. if ( state === 2 ) {
  286. if ( !responseHeaders ) {
  287. responseHeaders = {};
  288. while ( (match = rheaders.exec( responseHeadersString )) ) {
  289. responseHeaders[ match[1].toLowerCase() ] = match[ 2 ];
  290. }
  291. }
  292. match = responseHeaders[ key.toLowerCase() ];
  293. }
  294. return match == null ? null : match;
  295. },
  296. // Raw string
  297. getAllResponseHeaders: function() {
  298. return state === 2 ? responseHeadersString : null;
  299. },
  300. // Caches the header
  301. setRequestHeader: function( name, value ) {
  302. var lname = name.toLowerCase();
  303. if ( !state ) {
  304. name = requestHeadersNames[ lname ] = requestHeadersNames[ lname ] || name;
  305. requestHeaders[ name ] = value;
  306. }
  307. return this;
  308. },
  309. // Overrides response content-type header
  310. overrideMimeType: function( type ) {
  311. if ( !state ) {
  312. s.mimeType = type;
  313. }
  314. return this;
  315. },
  316. // Status-dependent callbacks
  317. statusCode: function( map ) {
  318. var code;
  319. if ( map ) {
  320. if ( state < 2 ) {
  321. for ( code in map ) {
  322. // Lazy-add the new callback in a way that preserves old ones
  323. statusCode[ code ] = [ statusCode[ code ], map[ code ] ];
  324. }
  325. } else {
  326. // Execute the appropriate callbacks
  327. jqXHR.always( map[ jqXHR.status ] );
  328. }
  329. }
  330. return this;
  331. },
  332. // Cancel the request
  333. abort: function( statusText ) {
  334. var finalText = statusText || strAbort;
  335. if ( transport ) {
  336. transport.abort( finalText );
  337. }
  338. done( 0, finalText );
  339. return this;
  340. }
  341. };
  342. // Attach deferreds
  343. deferred.promise( jqXHR ).complete = completeDeferred.add;
  344. jqXHR.success = jqXHR.done;
  345. jqXHR.error = jqXHR.fail;
  346. // Remove hash character (#7531: and string promotion)
  347. // Add protocol if not provided (#5866: IE7 issue with protocol-less urls)
  348. // Handle falsy url in the settings object (#10093: consistency with old signature)
  349. // We also use the url parameter if available
  350. s.url = ( ( url || s.url || ajaxLocation ) + "" ).replace( rhash, "" ).replace( rprotocol, ajaxLocParts[ 1 ] + "//" );
  351. // Alias method option to type as per ticket #12004
  352. s.type = options.method || options.type || s.method || s.type;
  353. // Extract dataTypes list
  354. s.dataTypes = jQuery.trim( s.dataType || "*" ).toLowerCase().match( core_rnotwhite ) || [""];
  355. // A cross-domain request is in order when we have a protocol:host:port mismatch
  356. if ( s.crossDomain == null ) {
  357. parts = rurl.exec( s.url.toLowerCase() );
  358. s.crossDomain = !!( parts &&
  359. ( parts[ 1 ] !== ajaxLocParts[ 1 ] || parts[ 2 ] !== ajaxLocParts[ 2 ] ||
  360. ( parts[ 3 ] || ( parts[ 1 ] === "http:" ? "80" : "443" ) ) !==
  361. ( ajaxLocParts[ 3 ] || ( ajaxLocParts[ 1 ] === "http:" ? "80" : "443" ) ) )
  362. );
  363. }
  364. // Convert data if not already a string
  365. if ( s.data && s.processData && typeof s.data !== "string" ) {
  366. s.data = jQuery.param( s.data, s.traditional );
  367. }
  368. // Apply prefilters
  369. inspectPrefiltersOrTransports( prefilters, s, options, jqXHR );
  370. // If request was aborted inside a prefilter, stop there
  371. if ( state === 2 ) {
  372. return jqXHR;
  373. }
  374. // We can fire global events as of now if asked to
  375. fireGlobals = s.global;
  376. // Watch for a new set of requests
  377. if ( fireGlobals && jQuery.active++ === 0 ) {
  378. jQuery.event.trigger("ajaxStart");
  379. }
  380. // Uppercase the type
  381. s.type = s.type.toUpperCase();
  382. // Determine if request has content
  383. s.hasContent = !rnoContent.test( s.type );
  384. // Save the URL in case we're toying with the If-Modified-Since
  385. // and/or If-None-Match header later on
  386. cacheURL = s.url;
  387. // More options handling for requests with no content
  388. if ( !s.hasContent ) {
  389. // If data is available, append data to url
  390. if ( s.data ) {
  391. cacheURL = ( s.url += ( ajax_rquery.test( cacheURL ) ? "&" : "?" ) + s.data );
  392. // #9682: remove data so that it's not used in an eventual retry
  393. delete s.data;
  394. }
  395. // Add anti-cache in url if needed
  396. if ( s.cache === false ) {
  397. s.url = rts.test( cacheURL ) ?
  398. // If there is already a '_' parameter, set its value
  399. cacheURL.replace( rts, "$1_=" + ajax_nonce++ ) :
  400. // Otherwise add one to the end
  401. cacheURL + ( ajax_rquery.test( cacheURL ) ? "&" : "?" ) + "_=" + ajax_nonce++;
  402. }
  403. }
  404. // Set the If-Modified-Since and/or If-None-Match header, if in ifModified mode.
  405. if ( s.ifModified ) {
  406. if ( jQuery.lastModified[ cacheURL ] ) {
  407. jqXHR.setRequestHeader( "If-Modified-Since", jQuery.lastModified[ cacheURL ] );
  408. }
  409. if ( jQuery.etag[ cacheURL ] ) {
  410. jqXHR.setRequestHeader( "If-None-Match", jQuery.etag[ cacheURL ] );
  411. }
  412. }
  413. // Set the correct header, if data is being sent
  414. if ( s.data && s.hasContent && s.contentType !== false || options.contentType ) {
  415. jqXHR.setRequestHeader( "Content-Type", s.contentType );
  416. }
  417. // Set the Accepts header for the server, depending on the dataType
  418. jqXHR.setRequestHeader(
  419. "Accept",
  420. s.dataTypes[ 0 ] && s.accepts[ s.dataTypes[0] ] ?
  421. s.accepts[ s.dataTypes[0] ] + ( s.dataTypes[ 0 ] !== "*" ? ", " + allTypes + "; q=0.01" : "" ) :
  422. s.accepts[ "*" ]
  423. );
  424. // Check for headers option
  425. for ( i in s.headers ) {
  426. jqXHR.setRequestHeader( i, s.headers[ i ] );
  427. }
  428. // Allow custom headers/mimetypes and early abort
  429. if ( s.beforeSend && ( s.beforeSend.call( callbackContext, jqXHR, s ) === false || state === 2 ) ) {
  430. // Abort if not done already and return
  431. return jqXHR.abort();
  432. }
  433. // aborting is no longer a cancellation
  434. strAbort = "abort";
  435. // Install callbacks on deferreds
  436. for ( i in { success: 1, error: 1, complete: 1 } ) {
  437. jqXHR[ i ]( s[ i ] );
  438. }
  439. // Get transport
  440. transport = inspectPrefiltersOrTransports( transports, s, options, jqXHR );
  441. // If no transport, we auto-abort
  442. if ( !transport ) {
  443. done( -1, "No Transport" );
  444. } else {
  445. jqXHR.readyState = 1;
  446. // Send global event
  447. if ( fireGlobals ) {
  448. globalEventContext.trigger( "ajaxSend", [ jqXHR, s ] );
  449. }
  450. // Timeout
  451. if ( s.async && s.timeout > 0 ) {
  452. timeoutTimer = setTimeout(function() {
  453. jqXHR.abort("timeout");
  454. }, s.timeout );
  455. }
  456. try {
  457. state = 1;
  458. transport.send( requestHeaders, done );
  459. } catch ( e ) {
  460. // Propagate exception as error if not done
  461. if ( state < 2 ) {
  462. done( -1, e );
  463. // Simply rethrow otherwise
  464. } else {
  465. throw e;
  466. }
  467. }
  468. }
  469. // Callback for when everything is done
  470. function done( status, nativeStatusText, responses, headers ) {
  471. var isSuccess, success, error, response, modified,
  472. statusText = nativeStatusText;
  473. // Called once
  474. if ( state === 2 ) {
  475. return;
  476. }
  477. // State is "done" now
  478. state = 2;
  479. // Clear timeout if it exists
  480. if ( timeoutTimer ) {
  481. clearTimeout( timeoutTimer );
  482. }
  483. // Dereference transport for early garbage collection
  484. // (no matter how long the jqXHR object will be used)
  485. transport = undefined;
  486. // Cache response headers
  487. responseHeadersString = headers || "";
  488. // Set readyState
  489. jqXHR.readyState = status > 0 ? 4 : 0;
  490. // Determine if successful
  491. isSuccess = status >= 200 && status < 300 || status === 304;
  492. // Get response data
  493. if ( responses ) {
  494. response = ajaxHandleResponses( s, jqXHR, responses );
  495. }
  496. // Convert no matter what (that way responseXXX fields are always set)
  497. response = ajaxConvert( s, response, jqXHR, isSuccess );
  498. // If successful, handle type chaining
  499. if ( isSuccess ) {
  500. // Set the If-Modified-Since and/or If-None-Match header, if in ifModified mode.
  501. if ( s.ifModified ) {
  502. modified = jqXHR.getResponseHeader("Last-Modified");
  503. if ( modified ) {
  504. jQuery.lastModified[ cacheURL ] = modified;
  505. }
  506. modified = jqXHR.getResponseHeader("etag");
  507. if ( modified ) {
  508. jQuery.etag[ cacheURL ] = modified;
  509. }
  510. }
  511. // if no content
  512. if ( status === 204 || s.type === "HEAD" ) {
  513. statusText = "nocontent";
  514. // if not modified
  515. } else if ( status === 304 ) {
  516. statusText = "notmodified";
  517. // If we have data, let's convert it
  518. } else {
  519. statusText = response.state;
  520. success = response.data;
  521. error = response.error;
  522. isSuccess = !error;
  523. }
  524. } else {
  525. // We extract error from statusText
  526. // then normalize statusText and status for non-aborts
  527. error = statusText;
  528. if ( status || !statusText ) {
  529. statusText = "error";
  530. if ( status < 0 ) {
  531. status = 0;
  532. }
  533. }
  534. }
  535. // Set data for the fake xhr object
  536. jqXHR.status = status;
  537. jqXHR.statusText = ( nativeStatusText || statusText ) + "";
  538. // Success/Error
  539. if ( isSuccess ) {
  540. deferred.resolveWith( callbackContext, [ success, statusText, jqXHR ] );
  541. } else {
  542. deferred.rejectWith( callbackContext, [ jqXHR, statusText, error ] );
  543. }
  544. // Status-dependent callbacks
  545. jqXHR.statusCode( statusCode );
  546. statusCode = undefined;
  547. if ( fireGlobals ) {
  548. globalEventContext.trigger( isSuccess ? "ajaxSuccess" : "ajaxError",
  549. [ jqXHR, s, isSuccess ? success : error ] );
  550. }
  551. // Complete
  552. completeDeferred.fireWith( callbackContext, [ jqXHR, statusText ] );
  553. if ( fireGlobals ) {
  554. globalEventContext.trigger( "ajaxComplete", [ jqXHR, s ] );
  555. // Handle the global AJAX counter
  556. if ( !( --jQuery.active ) ) {
  557. jQuery.event.trigger("ajaxStop");
  558. }
  559. }
  560. }
  561. return jqXHR;
  562. },
  563. getJSON: function( url, data, callback ) {
  564. return jQuery.get( url, data, callback, "json" );
  565. },
  566. getScript: function( url, callback ) {
  567. return jQuery.get( url, undefined, callback, "script" );
  568. }
  569. });
  570. jQuery.each( [ "get", "post" ], function( i, method ) {
  571. jQuery[ method ] = function( url, data, callback, type ) {
  572. // shift arguments if data argument was omitted
  573. if ( jQuery.isFunction( data ) ) {
  574. type = type || callback;
  575. callback = data;
  576. data = undefined;
  577. }
  578. return jQuery.ajax({
  579. url: url,
  580. type: method,
  581. dataType: type,
  582. data: data,
  583. success: callback
  584. });
  585. };
  586. });
  587. /* Handles responses to an ajax request:
  588. * - finds the right dataType (mediates between content-type and expected dataType)
  589. * - returns the corresponding response
  590. */
  591. function ajaxHandleResponses( s, jqXHR, responses ) {
  592. var firstDataType, ct, finalDataType, type,
  593. contents = s.contents,
  594. dataTypes = s.dataTypes;
  595. // Remove auto dataType and get content-type in the process
  596. while( dataTypes[ 0 ] === "*" ) {
  597. dataTypes.shift();
  598. if ( ct === undefined ) {
  599. ct = s.mimeType || jqXHR.getResponseHeader("Content-Type");
  600. }
  601. }
  602. // Check if we're dealing with a known content-type
  603. if ( ct ) {
  604. for ( type in contents ) {
  605. if ( contents[ type ] && contents[ type ].test( ct ) ) {
  606. dataTypes.unshift( type );
  607. break;
  608. }
  609. }
  610. }
  611. // Check to see if we have a response for the expected dataType
  612. if ( dataTypes[ 0 ] in responses ) {
  613. finalDataType = dataTypes[ 0 ];
  614. } else {
  615. // Try convertible dataTypes
  616. for ( type in responses ) {
  617. if ( !dataTypes[ 0 ] || s.converters[ type + " " + dataTypes[0] ] ) {
  618. finalDataType = type;
  619. break;
  620. }
  621. if ( !firstDataType ) {
  622. firstDataType = type;
  623. }
  624. }
  625. // Or just use first one
  626. finalDataType = finalDataType || firstDataType;
  627. }
  628. // If we found a dataType
  629. // We add the dataType to the list if needed
  630. // and return the corresponding response
  631. if ( finalDataType ) {
  632. if ( finalDataType !== dataTypes[ 0 ] ) {
  633. dataTypes.unshift( finalDataType );
  634. }
  635. return responses[ finalDataType ];
  636. }
  637. }
  638. /* Chain conversions given the request and the original response
  639. * Also sets the responseXXX fields on the jqXHR instance
  640. */
  641. function ajaxConvert( s, response, jqXHR, isSuccess ) {
  642. var conv2, current, conv, tmp, prev,
  643. converters = {},
  644. // Work with a copy of dataTypes in case we need to modify it for conversion
  645. dataTypes = s.dataTypes.slice();
  646. // Create converters map with lowercased keys
  647. if ( dataTypes[ 1 ] ) {
  648. for ( conv in s.converters ) {
  649. converters[ conv.toLowerCase() ] = s.converters[ conv ];
  650. }
  651. }
  652. current = dataTypes.shift();
  653. // Convert to each sequential dataType
  654. while ( current ) {
  655. if ( s.responseFields[ current ] ) {
  656. jqXHR[ s.responseFields[ current ] ] = response;
  657. }
  658. // Apply the dataFilter if provided
  659. if ( !prev && isSuccess && s.dataFilter ) {
  660. response = s.dataFilter( response, s.dataType );
  661. }
  662. prev = current;
  663. current = dataTypes.shift();
  664. if ( current ) {
  665. // There's only work to do if current dataType is non-auto
  666. if ( current === "*" ) {
  667. current = prev;
  668. // Convert response if prev dataType is non-auto and differs from current
  669. } else if ( prev !== "*" && prev !== current ) {
  670. // Seek a direct converter
  671. conv = converters[ prev + " " + current ] || converters[ "* " + current ];
  672. // If none found, seek a pair
  673. if ( !conv ) {
  674. for ( conv2 in converters ) {
  675. // If conv2 outputs current
  676. tmp = conv2.split( " " );
  677. if ( tmp[ 1 ] === current ) {
  678. // If prev can be converted to accepted input
  679. conv = converters[ prev + " " + tmp[ 0 ] ] ||
  680. converters[ "* " + tmp[ 0 ] ];
  681. if ( conv ) {
  682. // Condense equivalence converters
  683. if ( conv === true ) {
  684. conv = converters[ conv2 ];
  685. // Otherwise, insert the intermediate dataType
  686. } else if ( converters[ conv2 ] !== true ) {
  687. current = tmp[ 0 ];
  688. dataTypes.unshift( tmp[ 1 ] );
  689. }
  690. break;
  691. }
  692. }
  693. }
  694. }
  695. // Apply converter (if not an equivalence)
  696. if ( conv !== true ) {
  697. // Unless errors are allowed to bubble, catch and return them
  698. if ( conv && s[ "throws" ] ) {
  699. response = conv( response );
  700. } else {
  701. try {
  702. response = conv( response );
  703. } catch ( e ) {
  704. return { state: "parsererror", error: conv ? e : "No conversion from " + prev + " to " + current };
  705. }
  706. }
  707. }
  708. }
  709. }
  710. }
  711. return { state: "success", data: response };
  712. }