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