ajax.js 21 KB

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