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