ajax.js 22 KB

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