ajax.js 22 KB

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