软测单独项目
You can not select more than 25 topics Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.
 
 
 
 
 
 

285 lines
7.3 KiB

/*
* jQuery JSONP Core Plugin 2.4.0 (2012-08-21)
*
* 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) {
return method && method.apply(object.context || object, parameters);
}
// 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,
// IE < 10
oldIE = !!$("<div>").html("<!--[if IE]><i><![endif]-->").find("i").length;
// ###################### 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, xOptions]);
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 (oldIE) {
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);