You cannot select more than 25 topics Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.

289 lines
7.5 KiB
JavaScript

/*
* jQuery JSONP Core Plugin 2.3.1 (2012-05-16)
*
* https://github.com/jaubourg/jquery-jsonp
*
* Copyright (c) 2012 Julian Aubourg
*
* This document is licensed as free software under the terms of the
* MIT License: http://www.opensource.org/licenses/mit-license.php
*/
( function( $ ) {
// ###################### UTILITIES ##
// Noop
function noop() {
}
// Generic callback
function genericCallback( data ) {
lastValue = [ data ];
}
// Call if defined
function callIfDefined( method , object , parameters , returnFlag ) {
try {
returnFlag = method && method.apply( object.context || object , parameters );
} catch( _ ) {
returnFlag = !1;
}
return returnFlag;
}
// Give joining character given url
function qMarkOrAmp( url ) {
return /\?/ .test( url ) ? "&" : "?";
}
var // String constants (for better minification)
STR_ASYNC = "async",
STR_CHARSET = "charset",
STR_EMPTY = "",
STR_ERROR = "error",
STR_INSERT_BEFORE = "insertBefore",
STR_JQUERY_JSONP = "_jqjsp",
STR_ON = "on",
STR_ON_CLICK = STR_ON + "click",
STR_ON_ERROR = STR_ON + STR_ERROR,
STR_ON_LOAD = STR_ON + "load",
STR_ON_READY_STATE_CHANGE = STR_ON + "readystatechange",
STR_READY_STATE = "readyState",
STR_REMOVE_CHILD = "removeChild",
STR_SCRIPT_TAG = "<script>",
STR_SUCCESS = "success",
STR_TIMEOUT = "timeout",
// Window
win = window,
// Deferred
Deferred = $.Deferred,
// Head element
head = $( "head" )[ 0 ] || document.documentElement,
// Page cache
pageCache = {},
// Counter
count = 0,
// Last returned value
lastValue,
// ###################### DEFAULT OPTIONS ##
xOptionsDefaults = {
//beforeSend: undefined,
//cache: false,
callback: STR_JQUERY_JSONP,
//callbackParameter: undefined,
//charset: undefined,
//complete: undefined,
//context: undefined,
//data: "",
//dataFilter: undefined,
//error: undefined,
//pageCache: false,
//success: undefined,
//timeout: 0,
//traditional: false,
url: location.href
},
// opera demands sniffing :/
opera = win.opera;
// ###################### MAIN FUNCTION ##
function jsonp( xOptions ) {
// Build data with default
xOptions = $.extend( {} , xOptionsDefaults , xOptions );
// References to xOptions members (for better minification)
var successCallback = xOptions.success,
errorCallback = xOptions.error,
completeCallback = xOptions.complete,
dataFilter = xOptions.dataFilter,
callbackParameter = xOptions.callbackParameter,
successCallbackName = xOptions.callback,
cacheFlag = xOptions.cache,
pageCacheFlag = xOptions.pageCache,
charset = xOptions.charset,
url = xOptions.url,
data = xOptions.data,
timeout = xOptions.timeout,
pageCached,
// Abort/done flag
done = 0,
// Life-cycle functions
cleanUp = noop,
// Support vars
supportOnload,
supportOnreadystatechange,
// Request execution vars
firstChild,
script,
scriptAfter,
timeoutTimer;
// If we have Deferreds:
// - substitute callbacks
// - promote xOptions to a promise
Deferred && Deferred(function( defer ) {
defer.done( successCallback ).fail( errorCallback );
successCallback = defer.resolve;
errorCallback = defer.reject;
}).promise( xOptions );
// Create the abort method
xOptions.abort = function() {
!( done++ ) && cleanUp();
};
// Call beforeSend if provided (early abort if false returned)
if ( callIfDefined( xOptions.beforeSend, xOptions , [ xOptions ] ) === !1 || done ) {
return xOptions;
}
// Control entries
url = url || STR_EMPTY;
data = data ? ( (typeof data) == "string" ? data : $.param( data , xOptions.traditional ) ) : STR_EMPTY;
// Build final url
url += data ? ( qMarkOrAmp( url ) + data ) : STR_EMPTY;
// Add callback parameter if provided as option
callbackParameter && ( url += qMarkOrAmp( url ) + encodeURIComponent( callbackParameter ) + "=?" );
// Add anticache parameter if needed
!cacheFlag && !pageCacheFlag && ( url += qMarkOrAmp( url ) + "_" + ( new Date() ).getTime() + "=" );
// Replace last ? by callback parameter
url = url.replace( /=\?(&|$)/ , "=" + successCallbackName + "$1" );
// Success notifier
function notifySuccess( json ) {
if ( !( done++ ) ) {
cleanUp();
// Pagecache if needed
pageCacheFlag && ( pageCache [ url ] = { s: [ json ] } );
// Apply the data filter if provided
dataFilter && ( json = dataFilter.apply( xOptions , [ json ] ) );
// Call success then complete
callIfDefined( successCallback , xOptions , [ json , STR_SUCCESS ] );
callIfDefined( completeCallback , xOptions , [ xOptions , STR_SUCCESS ] );
}
}
// Error notifier
function notifyError( type ) {
if ( !( done++ ) ) {
// Clean up
cleanUp();
// If pure error (not timeout), cache if needed
pageCacheFlag && type != STR_TIMEOUT && ( pageCache[ url ] = type );
// Call error then complete
callIfDefined( errorCallback , xOptions , [ xOptions , type ] );
callIfDefined( completeCallback , xOptions , [ xOptions , type ] );
}
}
// Check page cache
if ( pageCacheFlag && ( pageCached = pageCache[ url ] ) ) {
pageCached.s ? notifySuccess( pageCached.s[ 0 ] ) : notifyError( pageCached );
} else {
// Install the generic callback
// (BEWARE: global namespace pollution ahoy)
win[ successCallbackName ] = genericCallback;
// Create the script tag
script = $( STR_SCRIPT_TAG )[ 0 ];
script.id = STR_JQUERY_JSONP + count++;
// Set charset if provided
if ( charset ) {
script[ STR_CHARSET ] = charset;
}
opera && opera.version() < 11.60 ?
// onerror is not supported: do not set as async and assume in-order execution.
// Add a trailing script to emulate the event
( ( scriptAfter = $( STR_SCRIPT_TAG )[ 0 ] ).text = "document.getElementById('" + script.id + "')." + STR_ON_ERROR + "()" )
:
// onerror is supported: set the script as async to avoid requests blocking each others
( script[ STR_ASYNC ] = STR_ASYNC )
;
// Internet Explorer: event/htmlFor trick
if ( STR_ON_READY_STATE_CHANGE in script ) {
script.htmlFor = script.id;
script.event = STR_ON_CLICK;
}
// Attached event handlers
script[ STR_ON_LOAD ] = script[ STR_ON_ERROR ] = script[ STR_ON_READY_STATE_CHANGE ] = function ( result ) {
// Test readyState if it exists
if ( !script[ STR_READY_STATE ] || !/i/.test( script[ STR_READY_STATE ] ) ) {
try {
script[ STR_ON_CLICK ] && script[ STR_ON_CLICK ]();
} catch( _ ) {}
result = lastValue;
lastValue = 0;
result ? notifySuccess( result[ 0 ] ) : notifyError( STR_ERROR );
}
};
// Set source
script.src = url;
// Re-declare cleanUp function
cleanUp = function( i ) {
timeoutTimer && clearTimeout( timeoutTimer );
script[ STR_ON_READY_STATE_CHANGE ] = script[ STR_ON_LOAD ] = script[ STR_ON_ERROR ] = null;
head[ STR_REMOVE_CHILD ]( script );
scriptAfter && head[ STR_REMOVE_CHILD ]( scriptAfter );
};
// Append main script
head[ STR_INSERT_BEFORE ]( script , ( firstChild = head.firstChild ) );
// Append trailing script if needed
scriptAfter && head[ STR_INSERT_BEFORE ]( scriptAfter , firstChild );
// If a timeout is needed, install it
timeoutTimer = timeout > 0 && setTimeout( function() {
notifyError( STR_TIMEOUT );
} , timeout );
}
return xOptions;
}
// ###################### SETUP FUNCTION ##
jsonp.setup = function( xOptions ) {
$.extend( xOptionsDefaults , xOptions );
};
// ###################### INSTALL in jQuery ##
$.jsonp = jsonp;
} )( jQuery );