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