jsonp.js 2.66 KB
Newer Older
1 2 3 4 5 6 7 8 9
define( [
	"../core",
	"./var/nonce",
	"./var/rquery",
	"../ajax"
], function( jQuery, nonce, rquery ) {

"use strict";

Nicolas Widart's avatar
Nicolas Widart committed
10 11 12 13
var oldCallbacks = [],
	rjsonp = /(=)\?(?=&|$)|\?\?/;

// Default jsonp settings
14
jQuery.ajaxSetup( {
Nicolas Widart's avatar
Nicolas Widart committed
15 16
	jsonp: "callback",
	jsonpCallback: function() {
17
		var callback = oldCallbacks.pop() || ( jQuery.expando + "_" + ( nonce++ ) );
Nicolas Widart's avatar
Nicolas Widart committed
18 19 20
		this[ callback ] = true;
		return callback;
	}
21
} );
Nicolas Widart's avatar
Nicolas Widart committed
22 23 24 25 26 27 28

// Detect, normalize options and install callbacks for jsonp requests
jQuery.ajaxPrefilter( "json jsonp", function( s, originalSettings, jqXHR ) {

	var callbackName, overwritten, responseContainer,
		jsonProp = s.jsonp !== false && ( rjsonp.test( s.url ) ?
			"url" :
29 30 31 32
			typeof s.data === "string" &&
				( s.contentType || "" )
					.indexOf( "application/x-www-form-urlencoded" ) === 0 &&
				rjsonp.test( s.data ) && "data"
Nicolas Widart's avatar
Nicolas Widart committed
33 34 35 36 37 38 39 40 41 42 43 44 45 46
		);

	// Handle iff the expected data type is "jsonp" or we have a parameter to set
	if ( jsonProp || s.dataTypes[ 0 ] === "jsonp" ) {

		// Get callback name, remembering preexisting value associated with it
		callbackName = s.jsonpCallback = jQuery.isFunction( s.jsonpCallback ) ?
			s.jsonpCallback() :
			s.jsonpCallback;

		// Insert callback into url or form data
		if ( jsonProp ) {
			s[ jsonProp ] = s[ jsonProp ].replace( rjsonp, "$1" + callbackName );
		} else if ( s.jsonp !== false ) {
47
			s.url += ( rquery.test( s.url ) ? "&" : "?" ) + s.jsonp + "=" + callbackName;
Nicolas Widart's avatar
Nicolas Widart committed
48 49 50
		}

		// Use data converter to retrieve json after script execution
51
		s.converters[ "script json" ] = function() {
Nicolas Widart's avatar
Nicolas Widart committed
52 53 54 55 56 57
			if ( !responseContainer ) {
				jQuery.error( callbackName + " was not called" );
			}
			return responseContainer[ 0 ];
		};

58
		// Force json dataType
Nicolas Widart's avatar
Nicolas Widart committed
59 60 61 62 63 64 65 66 67
		s.dataTypes[ 0 ] = "json";

		// Install callback
		overwritten = window[ callbackName ];
		window[ callbackName ] = function() {
			responseContainer = arguments;
		};

		// Clean-up function (fires after converters)
68 69 70 71 72 73 74 75 76 77
		jqXHR.always( function() {

			// If previous value didn't exist - remove it
			if ( overwritten === undefined ) {
				jQuery( window ).removeProp( callbackName );

			// Otherwise restore preexisting value
			} else {
				window[ callbackName ] = overwritten;
			}
Nicolas Widart's avatar
Nicolas Widart committed
78 79 80

			// Save back as free
			if ( s[ callbackName ] ) {
81 82

				// Make sure that re-using the options doesn't screw things around
Nicolas Widart's avatar
Nicolas Widart committed
83 84
				s.jsonpCallback = originalSettings.jsonpCallback;

85
				// Save the callback name for future use
Nicolas Widart's avatar
Nicolas Widart committed
86 87 88 89 90 91 92 93 94
				oldCallbacks.push( callbackName );
			}

			// Call if it was a function and we have a response
			if ( responseContainer && jQuery.isFunction( overwritten ) ) {
				overwritten( responseContainer[ 0 ] );
			}

			responseContainer = overwritten = undefined;
95
		} );
Nicolas Widart's avatar
Nicolas Widart committed
96 97 98 99

		// Delegate to script
		return "script";
	}
100 101 102
} );

} );