mirror of
https://github.com/langhuihui/monibuca.git
synced 2025-10-04 13:52:41 +08:00
536 lines
14 KiB
JavaScript
536 lines
14 KiB
JavaScript
// a simple ajax
|
|
!(function () {
|
|
|
|
var jsonType = 'application/json';
|
|
var htmlType = 'text/html';
|
|
var xmlTypeRE = /^(?:text|application)\/xml/i;
|
|
var blankRE = /^\s*$/; // \s
|
|
|
|
/*
|
|
* default setting
|
|
* */
|
|
var _settings = {
|
|
|
|
type: "GET",
|
|
|
|
beforeSend: noop,
|
|
|
|
success: noop,
|
|
|
|
error: noop,
|
|
|
|
complete: noop,
|
|
|
|
context: null,
|
|
|
|
xhr: function () {
|
|
return new window.XMLHttpRequest();
|
|
},
|
|
|
|
accepts: {
|
|
json: jsonType,
|
|
xml: 'application/xml, text/xml',
|
|
html: htmlType,
|
|
text: 'text/plain'
|
|
},
|
|
|
|
crossDomain: false,
|
|
|
|
timeout: 0,
|
|
|
|
username: null,
|
|
|
|
password: null,
|
|
|
|
processData: true,
|
|
|
|
promise: noop
|
|
};
|
|
|
|
function noop() {
|
|
}
|
|
|
|
var ajax = function (options) {
|
|
|
|
//
|
|
var settings = extend({}, options || {});
|
|
|
|
//
|
|
for (var key in _settings) {
|
|
if (settings[key] === undefined) {
|
|
settings[key] = _settings[key];
|
|
}
|
|
}
|
|
|
|
//
|
|
try {
|
|
var q = {};
|
|
var promise = new Promise(function (resolve, reject) {
|
|
q.resolve = resolve;
|
|
q.reject = reject;
|
|
});
|
|
|
|
promise.resolve = q.resolve;
|
|
promise.reject = q.reject;
|
|
|
|
settings.promise = promise;
|
|
}
|
|
catch (e) {
|
|
//
|
|
settings.promise = {
|
|
resolve: noop,
|
|
reject: noop
|
|
};
|
|
}
|
|
|
|
|
|
//
|
|
if (!settings.crossDomain) {
|
|
settings.crossDomain = /^([\w-]+:)?\/\/([^\/]+)/.test(settings.url) && RegExp.$2 !== window.location.href;
|
|
}
|
|
|
|
var dataType = settings.dataType;
|
|
// jsonp
|
|
if (dataType === 'jsonp') {
|
|
//
|
|
var hasPlaceholder = /=\?/.test(settings.url);
|
|
if (!hasPlaceholder) {
|
|
var jsonpCallback = (settings.jsonp || 'callback') + '=?';
|
|
|
|
settings.url = appendQuery(settings.url, jsonpCallback)
|
|
}
|
|
return JSONP(settings);
|
|
}
|
|
|
|
// url
|
|
if (!settings.url) {
|
|
settings.url = window.location.toString();
|
|
}
|
|
|
|
//
|
|
serializeData(settings);
|
|
|
|
var mime = settings.accepts[dataType]; // mime
|
|
var baseHeader = {}; // header
|
|
var protocol = /^([\w-]+:)\/\//.test(settings.url) ? RegExp.$1 : window.location.protocol; // protocol
|
|
var xhr = _settings.xhr();
|
|
var abortTimeout;
|
|
|
|
// X-Requested-With header
|
|
// For cross-domain requests, seeing as conditions for a preflight are
|
|
// akin to a jigsaw puzzle, we simply never set it to be sure.
|
|
// (it can always be set on a per-request basis or even using ajaxSetup)
|
|
// For same-domain requests, won't change header if already provided.
|
|
if (!settings.crossDomain && !baseHeader['X-Requested-With']) {
|
|
baseHeader['X-Requested-With'] = 'XMLHttpRequest';
|
|
}
|
|
|
|
// mime
|
|
if (mime) {
|
|
//
|
|
baseHeader['Accept'] = mime;
|
|
|
|
if (mime.indexOf(',') > -1) {
|
|
mime = mime.split(',', 2)[0]
|
|
}
|
|
//
|
|
xhr.overrideMimeType && xhr.overrideMimeType(mime);
|
|
}
|
|
|
|
// contentType
|
|
if (settings.contentType || (settings.data && settings.type.toUpperCase() !== 'GET')) {
|
|
baseHeader['Content-Type'] = (settings.contentType || 'application/x-www-form-urlencoded; charset=UTF-8');
|
|
}
|
|
|
|
// headers
|
|
settings.headers = extend(baseHeader, settings.headers || {});
|
|
|
|
// on ready state change
|
|
xhr.onreadystatechange = function () {
|
|
// readystate
|
|
if (xhr.readyState === 4) {
|
|
clearTimeout(abortTimeout);
|
|
var result;
|
|
var error = false;
|
|
//
|
|
if ((xhr.status >= 200 && xhr.status < 300) || xhr.status === 304) {
|
|
dataType = dataType || mimeToDataType(xhr.getResponseHeader('content-type'));
|
|
result = xhr.responseText;
|
|
|
|
try {
|
|
// xml
|
|
if (dataType === 'xml') {
|
|
result = xhr.responseXML;
|
|
}
|
|
// json
|
|
else if (dataType === 'json') {
|
|
result = blankRE.test(result) ? null : JSON.parse(result);
|
|
}
|
|
}
|
|
catch (e) {
|
|
error = e;
|
|
}
|
|
|
|
if (error) {
|
|
ajaxError(error, 'parseerror', xhr, settings);
|
|
}
|
|
else {
|
|
ajaxSuccess(result, xhr, settings);
|
|
}
|
|
}
|
|
else {
|
|
ajaxError(null, 'error', xhr, settings);
|
|
}
|
|
|
|
}
|
|
};
|
|
|
|
// async
|
|
var async = 'async' in settings ? settings.async : true;
|
|
|
|
// open
|
|
xhr.open(settings.type, settings.url, async, settings.username, settings.password);
|
|
|
|
// xhrFields
|
|
if (settings.xhrFields) {
|
|
for (var name in settings.xhrFields) {
|
|
xhr[name] = settings.xhrFields[name];
|
|
}
|
|
}
|
|
|
|
// Override mime type if needed
|
|
if (settings.mimeType && xhr.overrideMimeType) {
|
|
xhr.overrideMimeType(settings.mimeType);
|
|
}
|
|
|
|
|
|
// set request header
|
|
for (var name in settings.headers) {
|
|
// Support: IE<9
|
|
// IE's ActiveXObject throws a 'Type Mismatch' exception when setting
|
|
// request header to a null-value.
|
|
//
|
|
// To keep consistent with other XHR implementations, cast the value
|
|
// to string and ignore `undefined`.
|
|
if (settings.headers[name] !== undefined) {
|
|
xhr.setRequestHeader(name, settings.headers[name] + "");
|
|
}
|
|
}
|
|
|
|
// before send
|
|
if (ajaxBeforeSend(xhr, settings) === false) {
|
|
xhr.abort();
|
|
return false;
|
|
}
|
|
|
|
// timeout
|
|
if (settings.timeout > 0) {
|
|
abortTimeout = window.setTimeout(function () {
|
|
xhr.onreadystatechange = noop;
|
|
xhr.abort();
|
|
ajaxError(null, 'timeout', xhr, settings);
|
|
}, settings.timeout);
|
|
}
|
|
|
|
// send
|
|
xhr.send(settings.data ? settings.data : null);
|
|
|
|
return settings.promise;
|
|
};
|
|
|
|
/*
|
|
* method get
|
|
* */
|
|
ajax.get = function (url, data, success, dataType) {
|
|
if (isFunction(data)) {
|
|
dataType = dataType || success;
|
|
success = data;
|
|
data = undefined;
|
|
}
|
|
|
|
return ajax({
|
|
url: url,
|
|
data: data,
|
|
success: success,
|
|
dataType: dataType
|
|
});
|
|
};
|
|
|
|
/*
|
|
* method post
|
|
*
|
|
* dataType:
|
|
* */
|
|
ajax.post = function (url, data, success, dataType) {
|
|
if (isFunction(data)) {
|
|
dataType = dataType || success;
|
|
success = data;
|
|
data = undefined;
|
|
}
|
|
return ajax({
|
|
type: 'POST',
|
|
url: url,
|
|
data: data,
|
|
success: success,
|
|
dataType: dataType
|
|
})
|
|
};
|
|
|
|
/*
|
|
* method getJSON
|
|
* */
|
|
ajax.getJSON = function (url, data, success) {
|
|
|
|
if (isFunction(data)) {
|
|
success = data;
|
|
data = undefined;
|
|
}
|
|
|
|
return ajax({
|
|
url: url,
|
|
data: data,
|
|
success: success,
|
|
dataType: 'json'
|
|
})
|
|
};
|
|
|
|
/*
|
|
* method ajaxSetup
|
|
* */
|
|
ajax.ajaxSetup = function (target, settings) {
|
|
return settings ? extend(extend(target, _settings), settings) : extend(_settings, target);
|
|
};
|
|
|
|
/*
|
|
* utils
|
|
*
|
|
* */
|
|
|
|
|
|
// triggers and extra global event ajaxBeforeSend that's like ajaxSend but cancelable
|
|
function ajaxBeforeSend(xhr, settings) {
|
|
var context = settings.context;
|
|
//
|
|
if (settings.beforeSend.call(context, xhr, settings) === false) {
|
|
return false;
|
|
}
|
|
}
|
|
|
|
// ajax success
|
|
function ajaxSuccess(data, xhr, settings) {
|
|
var context = settings.context;
|
|
var status = 'success';
|
|
settings.success.call(context, data, status, xhr);
|
|
settings.promise.resolve(data, status, xhr);
|
|
ajaxComplete(status, xhr, settings);
|
|
}
|
|
|
|
// status: "success", "notmodified", "error", "timeout", "abort", "parsererror"
|
|
function ajaxComplete(status, xhr, settings) {
|
|
var context = settings.context;
|
|
settings.complete.call(context, xhr, status);
|
|
}
|
|
|
|
// type: "timeout", "error", "abort", "parsererror"
|
|
function ajaxError(error, type, xhr, settings) {
|
|
var context = settings.context;
|
|
settings.error.call(context, xhr, type, error);
|
|
settings.promise.reject(xhr, type, error);
|
|
ajaxComplete(type, xhr, settings);
|
|
}
|
|
|
|
|
|
// jsonp
|
|
/*
|
|
* tks: https://www.cnblogs.com/rubylouvre/archive/2011/02/13/1953087.html
|
|
* */
|
|
function JSONP(options) {
|
|
//
|
|
var callbackName = options.jsonpCallback || 'jsonp' + (new Date().getTime());
|
|
|
|
var script = window.document.createElement('script');
|
|
|
|
var abort = function () {
|
|
// 设置 window.xxx = noop
|
|
if (callbackName in window) {
|
|
window[callbackName] = noop;
|
|
}
|
|
};
|
|
|
|
var xhr = {abort: abort};
|
|
var abortTimeout;
|
|
|
|
var head = window.document.getElementsByTagName('head')[0] || window.document.documentElement;
|
|
|
|
// ie8+
|
|
script.onerror = function (error) {
|
|
_error(error);
|
|
};
|
|
|
|
function _error(error) {
|
|
window.clearTimeout(abortTimeout);
|
|
xhr.abort();
|
|
ajaxError(error.type, xhr, error.type, options);
|
|
_removeScript();
|
|
}
|
|
|
|
window[callbackName] = function (data) {
|
|
window.clearTimeout(abortTimeout);
|
|
ajaxSuccess(data, xhr, options);
|
|
_removeScript();
|
|
};
|
|
|
|
//
|
|
serializeData(options);
|
|
|
|
script.src = options.url.replace(/=\?/, '=' + callbackName);
|
|
//
|
|
script.src = appendQuery(script.src, '_=' + (new Date()).getTime());
|
|
//
|
|
script.async = true;
|
|
|
|
// script charset
|
|
if (options.scriptCharset) {
|
|
script.charset = options.scriptCharset;
|
|
}
|
|
|
|
//
|
|
head.insertBefore(script, head.firstChild);
|
|
|
|
//
|
|
if (options.timeout > 0) {
|
|
abortTimeout = window.setTimeout(function () {
|
|
xhr.abort();
|
|
ajaxError('timeout', xhr, 'timeout', options);
|
|
_removeScript();
|
|
}, options.timeout);
|
|
}
|
|
|
|
// remove script
|
|
function _removeScript() {
|
|
if (script.clearAttributes) {
|
|
script.clearAttributes();
|
|
} else {
|
|
script.onload = script.onreadystatechange = script.onerror = null;
|
|
}
|
|
|
|
if (script.parentNode) {
|
|
script.parentNode.removeChild(script);
|
|
}
|
|
//
|
|
script = null;
|
|
|
|
delete window[callbackName];
|
|
}
|
|
|
|
return options.promise;
|
|
}
|
|
|
|
// mime to data type
|
|
function mimeToDataType(mime) {
|
|
return mime && (mime === htmlType ? 'html' : mime === jsonType ? 'json' : xmlTypeRE.test(mime) && 'xml') || 'text'
|
|
}
|
|
|
|
// append query
|
|
function appendQuery(url, query) {
|
|
return (url + '&' + query).replace(/[&?]{1,2}/, '?');
|
|
}
|
|
|
|
// serialize data
|
|
function serializeData(options) {
|
|
// formData
|
|
if (isObject(options) && !isFormData(options.data) && options.processData) {
|
|
options.data = param(options.data);
|
|
}
|
|
|
|
if (options.data && (!options.type || options.type.toUpperCase() === 'GET')) {
|
|
options.url = appendQuery(options.url, options.data);
|
|
}
|
|
}
|
|
|
|
// serialize
|
|
function serialize(params, obj, traditional, scope) {
|
|
var _isArray = isArray(obj);
|
|
|
|
for (var key in obj) {
|
|
var value = obj[key];
|
|
|
|
if (scope) {
|
|
key = traditional ? scope : scope + '[' + (_isArray ? '' : key) + ']';
|
|
}
|
|
|
|
// handle data in serializeArray format
|
|
if (!scope && _isArray) {
|
|
params.add(value.name, value.value);
|
|
|
|
}
|
|
else if (traditional ? _isArray(value) : isObject(value)) {
|
|
serialize(params, value, traditional, key);
|
|
}
|
|
else {
|
|
params.add(key, value);
|
|
}
|
|
}
|
|
|
|
}
|
|
|
|
// param
|
|
function param(obj, traditional) {
|
|
var params = [];
|
|
//
|
|
params.add = function (k, v) {
|
|
this.push(encodeURIComponent(k) + '=' + encodeURIComponent(v));
|
|
};
|
|
serialize(params, obj, traditional);
|
|
return params.join('&').replace('%20', '+');
|
|
}
|
|
|
|
// extend
|
|
function extend(target) {
|
|
var slice = Array.prototype.slice;
|
|
var args = slice.call(arguments, 1);
|
|
//
|
|
for (var i = 0, length = args.length; i < length; i++) {
|
|
var source = args[i] || {};
|
|
for (var key in source) {
|
|
if (source.hasOwnProperty(key) && source[key] !== undefined) {
|
|
target[key] = source[key];
|
|
}
|
|
}
|
|
}
|
|
|
|
return target;
|
|
}
|
|
|
|
// is object
|
|
function isObject(obj) {
|
|
var type = typeof obj;
|
|
return type === 'function' || type === 'object' && !!obj;
|
|
}
|
|
|
|
// is formData
|
|
function isFormData(obj) {
|
|
return obj instanceof FormData;
|
|
}
|
|
|
|
// is array
|
|
function isArray(value) {
|
|
return Object.prototype.toString.call(value) === "[object Array]";
|
|
}
|
|
|
|
// is function
|
|
function isFunction(value) {
|
|
return typeof value === "function";
|
|
}
|
|
|
|
// browser
|
|
window.ajax = ajax;
|
|
})();
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|