ajax.js 22 KB

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