ajax.js 21 KB

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