ajax.js 21 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554555556557558559560561562563564565566567568569570571572573574575576577578579580581582583584585586587588589590591592593594595596597598599600601602603604605606607608609610611612613614615616617618619620621622623624625626627628629630631632633634635636637638639640641642643644645646647648649650651652653654655656657658659660661662663664665666667668669670671672673674675676677678679680681682683684685686687688689690691692693694695696697698699700701702703704705706707708709710711712713714715716717718719720721722723724725726727728729730731732733734735736737738739740741742743744745746747748749750751752753754755756757758759760761762763764765766767768769770771772773774775776777778779780781782783784785786787788789790791792793794795796797798799800801802803804805806807808809810811812813814815816817818819820821822823824825826827828829830831832833834835836837838839840841842
  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/parseJSON",
  10. "./ajax/parseXML",
  11. "./deferred"
  12. ], function( jQuery, document, rnotwhite, location, nonce, rquery ) {
  13. var
  14. rhash = /#.*$/,
  15. rts = /([?&])_=[^&]*/,
  16. // IE leaves an \r character at EOL
  17. rheaders = /^(.*?):[ \t]*([^\r\n]*)\r?$/mg,
  18. // #7653, #8125, #8152: local protocol detection
  19. rlocalProtocol = /^(?:about|app|app-storage|.+-extension|file|res|widget):$/,
  20. rnoContent = /^(?:GET|HEAD)$/,
  21. rprotocol = /^\/\//,
  22. rurl = /^([\w.+-]+:)(?:\/\/(?:[^\/?#]*@|)([^\/?#:]*)(?::(\d+)|)|)/,
  23. /* Prefilters
  24. * 1) They are useful to introduce custom dataTypes (see ajax/jsonp.js for an example)
  25. * 2) These are called:
  26. * - BEFORE asking for a transport
  27. * - AFTER param serialization (s.data is a string if s.processData is true)
  28. * 3) key is the dataType
  29. * 4) the catchall symbol "*" can be used
  30. * 5) execution will start with transport dataType and THEN continue down to "*" if needed
  31. */
  32. prefilters = {},
  33. /* Transports bindings
  34. * 1) key is the dataType
  35. * 2) the catchall symbol "*" can be used
  36. * 3) selection will start with transport dataType and THEN go to "*" if needed
  37. */
  38. transports = {},
  39. // Avoid comment-prolog char sequence (#10098); must appease lint and evade compression
  40. allTypes = "*/".concat( "*" ),
  41. // Document location
  42. ajaxLocation = location.href,
  43. // Segment location into parts
  44. ajaxLocParts = rurl.exec( ajaxLocation.toLowerCase() ) || [];
  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.charAt( 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 deep, key,
  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 firstDataType, ct, finalDataType, type,
  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" ] ) { // jscs:ignore requireDotNotation
  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: ajaxLocation,
  246. type: "GET",
  247. isLocal: rlocalProtocol.test( ajaxLocParts[ 1 ] ),
  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": jQuery.parseJSON,
  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
  323. // Cross-domain detection vars
  324. parts,
  325. // Loop variable
  326. i,
  327. // URL without anti-cache param
  328. cacheURL,
  329. // Response headers as string
  330. responseHeadersString,
  331. // timeout handle
  332. timeoutTimer,
  333. // To know if global events are to be dispatched
  334. fireGlobals,
  335. transport,
  336. // Response headers
  337. responseHeaders,
  338. // Create the final options object
  339. s = jQuery.ajaxSetup( {}, options ),
  340. // Callbacks context
  341. callbackContext = s.context || s,
  342. // Context for global events is callbackContext if it is a DOM node or jQuery collection
  343. globalEventContext = s.context &&
  344. ( callbackContext.nodeType || callbackContext.jquery ) ?
  345. jQuery( callbackContext ) :
  346. jQuery.event,
  347. // Deferreds
  348. deferred = jQuery.Deferred(),
  349. completeDeferred = jQuery.Callbacks( "once memory" ),
  350. // Status-dependent callbacks
  351. statusCode = s.statusCode || {},
  352. // Headers (they are sent all at once)
  353. requestHeaders = {},
  354. requestHeadersNames = {},
  355. // The jqXHR state
  356. state = 0,
  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 ( state === 2 ) {
  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 state === 2 ? responseHeadersString : null;
  379. },
  380. // Caches the header
  381. setRequestHeader: function( name, value ) {
  382. var lname = name.toLowerCase();
  383. if ( !state ) {
  384. name = requestHeadersNames[ lname ] = requestHeadersNames[ lname ] || name;
  385. requestHeaders[ name ] = value;
  386. }
  387. return this;
  388. },
  389. // Overrides response content-type header
  390. overrideMimeType: function( type ) {
  391. if ( !state ) {
  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 ( state < 2 ) {
  401. for ( code in map ) {
  402. // Lazy-add the new callback in a way that preserves old ones
  403. statusCode[ code ] = [ statusCode[ code ], map[ code ] ];
  404. }
  405. } else {
  406. // Execute the appropriate callbacks
  407. jqXHR.always( map[ jqXHR.status ] );
  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 ).complete = completeDeferred.add;
  424. jqXHR.success = jqXHR.done;
  425. jqXHR.error = jqXHR.fail;
  426. // Remove hash character (#7531: and string promotion)
  427. // Add protocol if not provided (#5866: IE7 issue with protocol-less urls)
  428. // Handle falsy url in the settings object (#10093: consistency with old signature)
  429. // We also use the url parameter if available
  430. s.url = ( ( url || s.url || ajaxLocation ) + "" )
  431. .replace( rhash, "" )
  432. .replace( rprotocol, ajaxLocParts[ 1 ] + "//" );
  433. // Alias method option to type as per ticket #12004
  434. s.type = options.method || options.type || s.method || s.type;
  435. // Extract dataTypes list
  436. s.dataTypes = jQuery.trim( s.dataType || "*" ).toLowerCase().match( rnotwhite ) || [ "" ];
  437. // A cross-domain request is in order when we have a protocol:host:port mismatch
  438. if ( s.crossDomain == null ) {
  439. parts = rurl.exec( s.url.toLowerCase() );
  440. s.crossDomain = !!( parts &&
  441. ( parts[ 1 ] !== ajaxLocParts[ 1 ] || parts[ 2 ] !== ajaxLocParts[ 2 ] ||
  442. ( parts[ 3 ] || ( parts[ 1 ] === "http:" ? "80" : "443" ) ) !==
  443. ( ajaxLocParts[ 3 ] || ( ajaxLocParts[ 1 ] === "http:" ? "80" : "443" ) ) )
  444. );
  445. }
  446. // Convert data if not already a string
  447. if ( s.data && s.processData && typeof s.data !== "string" ) {
  448. s.data = jQuery.param( s.data, s.traditional );
  449. }
  450. // Apply prefilters
  451. inspectPrefiltersOrTransports( prefilters, s, options, jqXHR );
  452. // If request was aborted inside a prefilter, stop there
  453. if ( state === 2 ) {
  454. return jqXHR;
  455. }
  456. // We can fire global events as of now if asked to
  457. // Don't fire events if jQuery.event is undefined in an AMD-usage scenario (#15118)
  458. fireGlobals = jQuery.event && s.global;
  459. // Watch for a new set of requests
  460. if ( fireGlobals && jQuery.active++ === 0 ) {
  461. jQuery.event.trigger( "ajaxStart" );
  462. }
  463. // Uppercase the type
  464. s.type = s.type.toUpperCase();
  465. // Determine if request has content
  466. s.hasContent = !rnoContent.test( s.type );
  467. // Save the URL in case we're toying with the If-Modified-Since
  468. // and/or If-None-Match header later on
  469. cacheURL = s.url;
  470. // More options handling for requests with no content
  471. if ( !s.hasContent ) {
  472. // If data is available, append data to url
  473. if ( s.data ) {
  474. cacheURL = ( s.url += ( rquery.test( cacheURL ) ? "&" : "?" ) + s.data );
  475. // #9682: remove data so that it's not used in an eventual retry
  476. delete s.data;
  477. }
  478. // Add anti-cache in url if needed
  479. if ( s.cache === false ) {
  480. s.url = rts.test( cacheURL ) ?
  481. // If there is already a '_' parameter, set its value
  482. cacheURL.replace( rts, "$1_=" + nonce++ ) :
  483. // Otherwise add one to the end
  484. cacheURL + ( rquery.test( cacheURL ) ? "&" : "?" ) + "_=" + nonce++;
  485. }
  486. }
  487. // Set the If-Modified-Since and/or If-None-Match header, if in ifModified mode.
  488. if ( s.ifModified ) {
  489. if ( jQuery.lastModified[ cacheURL ] ) {
  490. jqXHR.setRequestHeader( "If-Modified-Since", jQuery.lastModified[ cacheURL ] );
  491. }
  492. if ( jQuery.etag[ cacheURL ] ) {
  493. jqXHR.setRequestHeader( "If-None-Match", jQuery.etag[ cacheURL ] );
  494. }
  495. }
  496. // Set the correct header, if data is being sent
  497. if ( s.data && s.hasContent && s.contentType !== false || options.contentType ) {
  498. jqXHR.setRequestHeader( "Content-Type", s.contentType );
  499. }
  500. // Set the Accepts header for the server, depending on the dataType
  501. jqXHR.setRequestHeader(
  502. "Accept",
  503. s.dataTypes[ 0 ] && s.accepts[ s.dataTypes[ 0 ] ] ?
  504. s.accepts[ s.dataTypes[ 0 ] ] +
  505. ( s.dataTypes[ 0 ] !== "*" ? ", " + allTypes + "; q=0.01" : "" ) :
  506. s.accepts[ "*" ]
  507. );
  508. // Check for headers option
  509. for ( i in s.headers ) {
  510. jqXHR.setRequestHeader( i, s.headers[ i ] );
  511. }
  512. // Allow custom headers/mimetypes and early abort
  513. if ( s.beforeSend &&
  514. ( s.beforeSend.call( callbackContext, jqXHR, s ) === false || state === 2 ) ) {
  515. // Abort if not done already and return
  516. return jqXHR.abort();
  517. }
  518. // aborting is no longer a cancellation
  519. strAbort = "abort";
  520. // Install callbacks on deferreds
  521. for ( i in { success: 1, error: 1, complete: 1 } ) {
  522. jqXHR[ i ]( s[ i ] );
  523. }
  524. // Get transport
  525. transport = inspectPrefiltersOrTransports( transports, s, options, jqXHR );
  526. // If no transport, we auto-abort
  527. if ( !transport ) {
  528. done( -1, "No Transport" );
  529. } else {
  530. jqXHR.readyState = 1;
  531. // Send global event
  532. if ( fireGlobals ) {
  533. globalEventContext.trigger( "ajaxSend", [ jqXHR, s ] );
  534. }
  535. // If request was aborted inside ajaxSend, stop there
  536. if ( state === 2 ) {
  537. return jqXHR;
  538. }
  539. // Timeout
  540. if ( s.async && s.timeout > 0 ) {
  541. timeoutTimer = window.setTimeout( function() {
  542. jqXHR.abort( "timeout" );
  543. }, s.timeout );
  544. }
  545. try {
  546. state = 1;
  547. transport.send( requestHeaders, done );
  548. } catch ( e ) {
  549. // Propagate exception as error if not done
  550. if ( state < 2 ) {
  551. done( -1, e );
  552. // Simply rethrow otherwise
  553. } else {
  554. throw e;
  555. }
  556. }
  557. }
  558. // Callback for when everything is done
  559. function done( status, nativeStatusText, responses, headers ) {
  560. var isSuccess, success, error, response, modified,
  561. statusText = nativeStatusText;
  562. // Called once
  563. if ( state === 2 ) {
  564. return;
  565. }
  566. // State is "done" now
  567. state = 2;
  568. // Clear timeout if it exists
  569. if ( timeoutTimer ) {
  570. window.clearTimeout( timeoutTimer );
  571. }
  572. // Dereference transport for early garbage collection
  573. // (no matter how long the jqXHR object will be used)
  574. transport = undefined;
  575. // Cache response headers
  576. responseHeadersString = headers || "";
  577. // Set readyState
  578. jqXHR.readyState = status > 0 ? 4 : 0;
  579. // Determine if successful
  580. isSuccess = status >= 200 && status < 300 || status === 304;
  581. // Get response data
  582. if ( responses ) {
  583. response = ajaxHandleResponses( s, jqXHR, responses );
  584. }
  585. // Convert no matter what (that way responseXXX fields are always set)
  586. response = ajaxConvert( s, response, jqXHR, isSuccess );
  587. // If successful, handle type chaining
  588. if ( isSuccess ) {
  589. // Set the If-Modified-Since and/or If-None-Match header, if in ifModified mode.
  590. if ( s.ifModified ) {
  591. modified = jqXHR.getResponseHeader( "Last-Modified" );
  592. if ( modified ) {
  593. jQuery.lastModified[ cacheURL ] = modified;
  594. }
  595. modified = jqXHR.getResponseHeader( "etag" );
  596. if ( modified ) {
  597. jQuery.etag[ cacheURL ] = modified;
  598. }
  599. }
  600. // if no content
  601. if ( status === 204 || s.type === "HEAD" ) {
  602. statusText = "nocontent";
  603. // if not modified
  604. } else if ( status === 304 ) {
  605. statusText = "notmodified";
  606. // If we have data, let's convert it
  607. } else {
  608. statusText = response.state;
  609. success = response.data;
  610. error = response.error;
  611. isSuccess = !error;
  612. }
  613. } else {
  614. // We extract error from statusText
  615. // then normalize statusText and status for non-aborts
  616. error = statusText;
  617. if ( status || !statusText ) {
  618. statusText = "error";
  619. if ( status < 0 ) {
  620. status = 0;
  621. }
  622. }
  623. }
  624. // Set data for the fake xhr object
  625. jqXHR.status = status;
  626. jqXHR.statusText = ( nativeStatusText || statusText ) + "";
  627. // Success/Error
  628. if ( isSuccess ) {
  629. deferred.resolveWith( callbackContext, [ success, statusText, jqXHR ] );
  630. } else {
  631. deferred.rejectWith( callbackContext, [ jqXHR, statusText, error ] );
  632. }
  633. // Status-dependent callbacks
  634. jqXHR.statusCode( statusCode );
  635. statusCode = undefined;
  636. if ( fireGlobals ) {
  637. globalEventContext.trigger( isSuccess ? "ajaxSuccess" : "ajaxError",
  638. [ jqXHR, s, isSuccess ? success : error ] );
  639. }
  640. // Complete
  641. completeDeferred.fireWith( callbackContext, [ jqXHR, statusText ] );
  642. if ( fireGlobals ) {
  643. globalEventContext.trigger( "ajaxComplete", [ jqXHR, s ] );
  644. // Handle the global AJAX counter
  645. if ( !( --jQuery.active ) ) {
  646. jQuery.event.trigger( "ajaxStop" );
  647. }
  648. }
  649. }
  650. return jqXHR;
  651. },
  652. getJSON: function( url, data, callback ) {
  653. return jQuery.get( url, data, callback, "json" );
  654. },
  655. getScript: function( url, callback ) {
  656. return jQuery.get( url, undefined, callback, "script" );
  657. }
  658. } );
  659. jQuery.each( [ "get", "post" ], function( i, method ) {
  660. jQuery[ method ] = function( url, data, callback, type ) {
  661. // shift arguments if data argument was omitted
  662. if ( jQuery.isFunction( data ) ) {
  663. type = type || callback;
  664. callback = data;
  665. data = undefined;
  666. }
  667. // The url can be an options object (which then must have .url)
  668. return jQuery.ajax( jQuery.extend( {
  669. url: url,
  670. type: method,
  671. dataType: type,
  672. data: data,
  673. success: callback
  674. }, jQuery.isPlainObject( url ) && url ) );
  675. };
  676. } );
  677. return jQuery;
  678. } );