mdui
Version:
a CSS Framework based on material design
1,693 lines (1,598 loc) • 209 kB
JavaScript
/*!
* mdui 1.0.2 (https://mdui.org)
* Copyright 2016-2021 zdhxiong
* Licensed under MIT
*/
(function (global, factory) {
typeof exports === 'object' && typeof module !== 'undefined' ? module.exports = factory() :
typeof define === 'function' && define.amd ? define(factory) :
(global = typeof globalThis !== 'undefined' ? globalThis : global || self, global.mdui = factory());
}(this, (function () { 'use strict';
!function(){try{return new MouseEvent("test")}catch(e$1){}var e=function(e,t){t=t||{bubbles:!1,cancelable:!1};var n=document.createEvent("MouseEvent");return n.initMouseEvent(e,t.bubbles,t.cancelable,window,0,t.screenX||0,t.screenY||0,t.clientX||0,t.clientY||0,t.ctrlKey||!1,t.altKey||!1,t.shiftKey||!1,t.metaKey||!1,t.button||0,t.relatedTarget||null),n};e.prototype=Event.prototype,window.MouseEvent=e;}();
!function(){function t(t,e){e=e||{bubbles:!1,cancelable:!1,detail:void 0};var n=document.createEvent("CustomEvent");return n.initCustomEvent(t,e.bubbles,e.cancelable,e.detail),n}"function"!=typeof window.CustomEvent&&(t.prototype=window.Event.prototype,window.CustomEvent=t);}();
/**
* @this {Promise}
*/
function finallyConstructor(callback) {
var constructor = this.constructor;
return this.then(
function(value) {
// @ts-ignore
return constructor.resolve(callback()).then(function() {
return value;
});
},
function(reason) {
// @ts-ignore
return constructor.resolve(callback()).then(function() {
// @ts-ignore
return constructor.reject(reason);
});
}
);
}
function allSettled(arr) {
var P = this;
return new P(function(resolve, reject) {
if (!(arr && typeof arr.length !== 'undefined')) {
return reject(
new TypeError(
typeof arr +
' ' +
arr +
' is not iterable(cannot read property Symbol(Symbol.iterator))'
)
);
}
var args = Array.prototype.slice.call(arr);
if (args.length === 0) { return resolve([]); }
var remaining = args.length;
function res(i, val) {
if (val && (typeof val === 'object' || typeof val === 'function')) {
var then = val.then;
if (typeof then === 'function') {
then.call(
val,
function(val) {
res(i, val);
},
function(e) {
args[i] = { status: 'rejected', reason: e };
if (--remaining === 0) {
resolve(args);
}
}
);
return;
}
}
args[i] = { status: 'fulfilled', value: val };
if (--remaining === 0) {
resolve(args);
}
}
for (var i = 0; i < args.length; i++) {
res(i, args[i]);
}
});
}
// Store setTimeout reference so promise-polyfill will be unaffected by
// other code modifying setTimeout (like sinon.useFakeTimers())
var setTimeoutFunc = setTimeout;
function isArray(x) {
return Boolean(x && typeof x.length !== 'undefined');
}
function noop() {}
// Polyfill for Function.prototype.bind
function bind(fn, thisArg) {
return function() {
fn.apply(thisArg, arguments);
};
}
/**
* @constructor
* @param {Function} fn
*/
function Promise$1(fn) {
if (!(this instanceof Promise$1))
{ throw new TypeError('Promises must be constructed via new'); }
if (typeof fn !== 'function') { throw new TypeError('not a function'); }
/** @type {!number} */
this._state = 0;
/** @type {!boolean} */
this._handled = false;
/** @type {Promise|undefined} */
this._value = undefined;
/** @type {!Array<!Function>} */
this._deferreds = [];
doResolve(fn, this);
}
function handle(self, deferred) {
while (self._state === 3) {
self = self._value;
}
if (self._state === 0) {
self._deferreds.push(deferred);
return;
}
self._handled = true;
Promise$1._immediateFn(function() {
var cb = self._state === 1 ? deferred.onFulfilled : deferred.onRejected;
if (cb === null) {
(self._state === 1 ? resolve : reject)(deferred.promise, self._value);
return;
}
var ret;
try {
ret = cb(self._value);
} catch (e) {
reject(deferred.promise, e);
return;
}
resolve(deferred.promise, ret);
});
}
function resolve(self, newValue) {
try {
// Promise Resolution Procedure: https://github.com/promises-aplus/promises-spec#the-promise-resolution-procedure
if (newValue === self)
{ throw new TypeError('A promise cannot be resolved with itself.'); }
if (
newValue &&
(typeof newValue === 'object' || typeof newValue === 'function')
) {
var then = newValue.then;
if (newValue instanceof Promise$1) {
self._state = 3;
self._value = newValue;
finale(self);
return;
} else if (typeof then === 'function') {
doResolve(bind(then, newValue), self);
return;
}
}
self._state = 1;
self._value = newValue;
finale(self);
} catch (e) {
reject(self, e);
}
}
function reject(self, newValue) {
self._state = 2;
self._value = newValue;
finale(self);
}
function finale(self) {
if (self._state === 2 && self._deferreds.length === 0) {
Promise$1._immediateFn(function() {
if (!self._handled) {
Promise$1._unhandledRejectionFn(self._value);
}
});
}
for (var i = 0, len = self._deferreds.length; i < len; i++) {
handle(self, self._deferreds[i]);
}
self._deferreds = null;
}
/**
* @constructor
*/
function Handler(onFulfilled, onRejected, promise) {
this.onFulfilled = typeof onFulfilled === 'function' ? onFulfilled : null;
this.onRejected = typeof onRejected === 'function' ? onRejected : null;
this.promise = promise;
}
/**
* Take a potentially misbehaving resolver function and make sure
* onFulfilled and onRejected are only called once.
*
* Makes no guarantees about asynchrony.
*/
function doResolve(fn, self) {
var done = false;
try {
fn(
function(value) {
if (done) { return; }
done = true;
resolve(self, value);
},
function(reason) {
if (done) { return; }
done = true;
reject(self, reason);
}
);
} catch (ex) {
if (done) { return; }
done = true;
reject(self, ex);
}
}
Promise$1.prototype['catch'] = function(onRejected) {
return this.then(null, onRejected);
};
Promise$1.prototype.then = function(onFulfilled, onRejected) {
// @ts-ignore
var prom = new this.constructor(noop);
handle(this, new Handler(onFulfilled, onRejected, prom));
return prom;
};
Promise$1.prototype['finally'] = finallyConstructor;
Promise$1.all = function(arr) {
return new Promise$1(function(resolve, reject) {
if (!isArray(arr)) {
return reject(new TypeError('Promise.all accepts an array'));
}
var args = Array.prototype.slice.call(arr);
if (args.length === 0) { return resolve([]); }
var remaining = args.length;
function res(i, val) {
try {
if (val && (typeof val === 'object' || typeof val === 'function')) {
var then = val.then;
if (typeof then === 'function') {
then.call(
val,
function(val) {
res(i, val);
},
reject
);
return;
}
}
args[i] = val;
if (--remaining === 0) {
resolve(args);
}
} catch (ex) {
reject(ex);
}
}
for (var i = 0; i < args.length; i++) {
res(i, args[i]);
}
});
};
Promise$1.allSettled = allSettled;
Promise$1.resolve = function(value) {
if (value && typeof value === 'object' && value.constructor === Promise$1) {
return value;
}
return new Promise$1(function(resolve) {
resolve(value);
});
};
Promise$1.reject = function(value) {
return new Promise$1(function(resolve, reject) {
reject(value);
});
};
Promise$1.race = function(arr) {
return new Promise$1(function(resolve, reject) {
if (!isArray(arr)) {
return reject(new TypeError('Promise.race accepts an array'));
}
for (var i = 0, len = arr.length; i < len; i++) {
Promise$1.resolve(arr[i]).then(resolve, reject);
}
});
};
// Use polyfill for setImmediate for performance gains
Promise$1._immediateFn =
// @ts-ignore
(typeof setImmediate === 'function' &&
function(fn) {
// @ts-ignore
setImmediate(fn);
}) ||
function(fn) {
setTimeoutFunc(fn, 0);
};
Promise$1._unhandledRejectionFn = function _unhandledRejectionFn(err) {
if (typeof console !== 'undefined' && console) {
console.warn('Possible Unhandled Promise Rejection:', err); // eslint-disable-line no-console
}
};
/** @suppress {undefinedVars} */
var globalNS = (function() {
// the only reliable means to get the global object is
// `Function('return this')()`
// However, this causes CSP violations in Chrome apps.
if (typeof self !== 'undefined') {
return self;
}
if (typeof window !== 'undefined') {
return window;
}
if (typeof global !== 'undefined') {
return global;
}
throw new Error('unable to locate global object');
})();
// Expose the polyfill if Promise is undefined or set to a
// non-function value. The latter can be due to a named HTMLElement
// being exposed by browsers for legacy reasons.
// https://github.com/taylorhakes/promise-polyfill/issues/114
if (typeof globalNS['Promise'] !== 'function') {
globalNS['Promise'] = Promise$1;
} else if (!globalNS.Promise.prototype['finally']) {
globalNS.Promise.prototype['finally'] = finallyConstructor;
} else if (!globalNS.Promise.allSettled) {
globalNS.Promise.allSettled = allSettled;
}
function isFunction(target) {
return typeof target === 'function';
}
function isString(target) {
return typeof target === 'string';
}
function isNumber(target) {
return typeof target === 'number';
}
function isBoolean(target) {
return typeof target === 'boolean';
}
function isUndefined(target) {
return typeof target === 'undefined';
}
function isNull(target) {
return target === null;
}
function isWindow(target) {
return target instanceof Window;
}
function isDocument(target) {
return target instanceof Document;
}
function isElement(target) {
return target instanceof Element;
}
function isNode(target) {
return target instanceof Node;
}
/**
* 是否是 IE 浏览器
*/
function isIE() {
// @ts-ignore
return !!window.document.documentMode;
}
function isArrayLike(target) {
if (isFunction(target) || isWindow(target)) {
return false;
}
return isNumber(target.length);
}
function isObjectLike(target) {
return typeof target === 'object' && target !== null;
}
function toElement(target) {
return isDocument(target) ? target.documentElement : target;
}
/**
* 把用 - 分隔的字符串转为驼峰(如 box-sizing 转换为 boxSizing)
* @param string
*/
function toCamelCase(string) {
return string
.replace(/^-ms-/, 'ms-')
.replace(/-([a-z])/g, function (_, letter) { return letter.toUpperCase(); });
}
/**
* 把驼峰法转为用 - 分隔的字符串(如 boxSizing 转换为 box-sizing)
* @param string
*/
function toKebabCase(string) {
return string.replace(/[A-Z]/g, function (replacer) { return '-' + replacer.toLowerCase(); });
}
/**
* 获取元素的样式值
* @param element
* @param name
*/
function getComputedStyleValue(element, name) {
return window.getComputedStyle(element).getPropertyValue(toKebabCase(name));
}
/**
* 检查元素的 box-sizing 是否是 border-box
* @param element
*/
function isBorderBox(element) {
return getComputedStyleValue(element, 'box-sizing') === 'border-box';
}
/**
* 获取元素的 padding, border, margin 宽度(两侧宽度的和,单位为px)
* @param element
* @param direction
* @param extra
*/
function getExtraWidth(element, direction, extra) {
var position = direction === 'width' ? ['Left', 'Right'] : ['Top', 'Bottom'];
return [0, 1].reduce(function (prev, _, index) {
var prop = extra + position[index];
if (extra === 'border') {
prop += 'Width';
}
return prev + parseFloat(getComputedStyleValue(element, prop) || '0');
}, 0);
}
/**
* 获取元素的样式值,对 width 和 height 进行过处理
* @param element
* @param name
*/
function getStyle(element, name) {
// width、height 属性使用 getComputedStyle 得到的值不准确,需要使用 getBoundingClientRect 获取
if (name === 'width' || name === 'height') {
var valueNumber = element.getBoundingClientRect()[name];
if (isBorderBox(element)) {
return (valueNumber + "px");
}
return ((valueNumber -
getExtraWidth(element, name, 'border') -
getExtraWidth(element, name, 'padding')) + "px");
}
return getComputedStyleValue(element, name);
}
/**
* 获取子节点组成的数组
* @param target
* @param parent
*/
function getChildNodesArray(target, parent) {
var tempParent = document.createElement(parent);
tempParent.innerHTML = target;
return [].slice.call(tempParent.childNodes);
}
/**
* 始终返回 false 的函数
*/
function returnFalse() {
return false;
}
/**
* 数值单位的 CSS 属性
*/
var cssNumber = [
'animationIterationCount',
'columnCount',
'fillOpacity',
'flexGrow',
'flexShrink',
'fontWeight',
'gridArea',
'gridColumn',
'gridColumnEnd',
'gridColumnStart',
'gridRow',
'gridRowEnd',
'gridRowStart',
'lineHeight',
'opacity',
'order',
'orphans',
'widows',
'zIndex',
'zoom' ];
function each(target, callback) {
if (isArrayLike(target)) {
for (var i = 0; i < target.length; i += 1) {
if (callback.call(target[i], i, target[i]) === false) {
return target;
}
}
}
else {
var keys = Object.keys(target);
for (var i$1 = 0; i$1 < keys.length; i$1 += 1) {
if (callback.call(target[keys[i$1]], keys[i$1], target[keys[i$1]]) === false) {
return target;
}
}
}
return target;
}
/**
* 为了使用模块扩充,这里不能使用默认导出
*/
var JQ = function JQ(arr) {
var this$1 = this;
this.length = 0;
if (!arr) {
return this;
}
each(arr, function (i, item) {
// @ts-ignore
this$1[i] = item;
});
this.length = arr.length;
return this;
};
function get$() {
var $ = function (selector) {
if (!selector) {
return new JQ();
}
// JQ
if (selector instanceof JQ) {
return selector;
}
// function
if (isFunction(selector)) {
if (/complete|loaded|interactive/.test(document.readyState) &&
document.body) {
selector.call(document, $);
}
else {
document.addEventListener('DOMContentLoaded', function () { return selector.call(document, $); }, false);
}
return new JQ([document]);
}
// String
if (isString(selector)) {
var html = selector.trim();
// 根据 HTML 字符串创建 JQ 对象
if (html[0] === '<' && html[html.length - 1] === '>') {
var toCreate = 'div';
var tags = {
li: 'ul',
tr: 'tbody',
td: 'tr',
th: 'tr',
tbody: 'table',
option: 'select',
};
each(tags, function (childTag, parentTag) {
if (html.indexOf(("<" + childTag)) === 0) {
toCreate = parentTag;
return false;
}
return;
});
return new JQ(getChildNodesArray(html, toCreate));
}
// 根据 CSS 选择器创建 JQ 对象
var isIdSelector = selector[0] === '#' && !selector.match(/[ .<>:~]/);
if (!isIdSelector) {
return new JQ(document.querySelectorAll(selector));
}
var element = document.getElementById(selector.slice(1));
if (element) {
return new JQ([element]);
}
return new JQ();
}
if (isArrayLike(selector) && !isNode(selector)) {
return new JQ(selector);
}
return new JQ([selector]);
};
$.fn = JQ.prototype;
return $;
}
var $ = get$();
// 避免页面加载完后直接执行css动画
// https://css-tricks.com/transitions-only-after-page-load/
setTimeout(function () { return $('body').addClass('mdui-loaded'); });
var mdui = {
$: $,
};
$.fn.each = function (callback) {
return each(this, callback);
};
/**
* 检查 container 元素内是否包含 contains 元素
* @param container 父元素
* @param contains 子元素
* @example
```js
contains( document, document.body ); // true
contains( document.getElementById('test'), document ); // false
contains( $('.container').get(0), $('.contains').get(0) ); // false
```
*/
function contains(container, contains) {
return container !== contains && toElement(container).contains(contains);
}
/**
* 把第二个数组的元素追加到第一个数组中,并返回合并后的数组
* @param first 第一个数组
* @param second 该数组的元素将被追加到第一个数组中
* @example
```js
merge( [ 0, 1, 2 ], [ 2, 3, 4 ] )
// [ 0, 1, 2, 2, 3, 4 ]
```
*/
function merge(first, second) {
each(second, function (_, value) {
first.push(value);
});
return first;
}
$.fn.get = function (index) {
return index === undefined
? [].slice.call(this)
: this[index >= 0 ? index : index + this.length];
};
$.fn.find = function (selector) {
var foundElements = [];
this.each(function (_, element) {
merge(foundElements, $(element.querySelectorAll(selector)).get());
});
return new JQ(foundElements);
};
// 存储事件
var handlers = {};
// 元素ID
var mduiElementId = 1;
/**
* 为元素赋予一个唯一的ID
*/
function getElementId(element) {
var key = '_mduiEventId';
// @ts-ignore
if (!element[key]) {
// @ts-ignore
element[key] = ++mduiElementId;
}
// @ts-ignore
return element[key];
}
/**
* 解析事件名中的命名空间
*/
function parse(type) {
var parts = type.split('.');
return {
type: parts[0],
ns: parts.slice(1).sort().join(' '),
};
}
/**
* 命名空间匹配规则
*/
function matcherFor(ns) {
return new RegExp('(?:^| )' + ns.replace(' ', ' .* ?') + '(?: |$)');
}
/**
* 获取匹配的事件
* @param element
* @param type
* @param func
* @param selector
*/
function getHandlers(element, type, func, selector) {
var event = parse(type);
return (handlers[getElementId(element)] || []).filter(function (handler) { return handler &&
(!event.type || handler.type === event.type) &&
(!event.ns || matcherFor(event.ns).test(handler.ns)) &&
(!func || getElementId(handler.func) === getElementId(func)) &&
(!selector || handler.selector === selector); });
}
/**
* 添加事件监听
* @param element
* @param types
* @param func
* @param data
* @param selector
*/
function add(element, types, func, data, selector) {
var elementId = getElementId(element);
if (!handlers[elementId]) {
handlers[elementId] = [];
}
// 传入 data.useCapture 来设置 useCapture: true
var useCapture = false;
if (isObjectLike(data) && data.useCapture) {
useCapture = true;
}
types.split(' ').forEach(function (type) {
if (!type) {
return;
}
var event = parse(type);
function callFn(e, elem) {
// 因为鼠标事件模拟事件的 detail 属性是只读的,因此在 e._detail 中存储参数
var result = func.apply(elem,
// @ts-ignore
e._detail === undefined ? [e] : [e].concat(e._detail));
if (result === false) {
e.preventDefault();
e.stopPropagation();
}
}
function proxyFn(e) {
// @ts-ignore
if (e._ns && !matcherFor(e._ns).test(event.ns)) {
return;
}
// @ts-ignore
e._data = data;
if (selector) {
// 事件代理
$(element)
.find(selector)
.get()
.reverse()
.forEach(function (elem) {
if (elem === e.target ||
contains(elem, e.target)) {
callFn(e, elem);
}
});
}
else {
// 不使用事件代理
callFn(e, element);
}
}
var handler = {
type: event.type,
ns: event.ns,
func: func,
selector: selector,
id: handlers[elementId].length,
proxy: proxyFn,
};
handlers[elementId].push(handler);
element.addEventListener(handler.type, proxyFn, useCapture);
});
}
/**
* 移除事件监听
* @param element
* @param types
* @param func
* @param selector
*/
function remove(element, types, func, selector) {
var handlersInElement = handlers[getElementId(element)] || [];
var removeEvent = function (handler) {
delete handlersInElement[handler.id];
element.removeEventListener(handler.type, handler.proxy, false);
};
if (!types) {
handlersInElement.forEach(function (handler) { return removeEvent(handler); });
}
else {
types.split(' ').forEach(function (type) {
if (type) {
getHandlers(element, type, func, selector).forEach(function (handler) { return removeEvent(handler); });
}
});
}
}
$.fn.trigger = function (type, extraParameters) {
var event = parse(type);
var eventObject;
var eventParams = {
bubbles: true,
cancelable: true,
};
var isMouseEvent = ['click', 'mousedown', 'mouseup', 'mousemove'].indexOf(event.type) > -1;
if (isMouseEvent) {
// Note: MouseEvent 无法传入 detail 参数
eventObject = new MouseEvent(event.type, eventParams);
}
else {
eventParams.detail = extraParameters;
eventObject = new CustomEvent(event.type, eventParams);
}
// @ts-ignore
eventObject._detail = extraParameters;
// @ts-ignore
eventObject._ns = event.ns;
return this.each(function () {
this.dispatchEvent(eventObject);
});
};
function extend(target, object1) {
var objectN = [], len = arguments.length - 2;
while ( len-- > 0 ) objectN[ len ] = arguments[ len + 2 ];
objectN.unshift(object1);
each(objectN, function (_, object) {
each(object, function (prop, value) {
if (!isUndefined(value)) {
target[prop] = value;
}
});
});
return target;
}
/**
* 将数组或对象序列化,序列化后的字符串可作为 URL 查询字符串使用
*
* 若传入数组,则格式必须和 serializeArray 方法的返回值一样
* @param obj 对象或数组
* @example
```js
param({ width: 1680, height: 1050 });
// width=1680&height=1050
```
* @example
```js
param({ foo: { one: 1, two: 2 }})
// foo[one]=1&foo[two]=2
```
* @example
```js
param({ids: [1, 2, 3]})
// ids[]=1&ids[]=2&ids[]=3
```
* @example
```js
param([
{"name":"name","value":"mdui"},
{"name":"password","value":"123456"}
])
// name=mdui&password=123456
```
*/
function param(obj) {
if (!isObjectLike(obj) && !Array.isArray(obj)) {
return '';
}
var args = [];
function destructure(key, value) {
var keyTmp;
if (isObjectLike(value)) {
each(value, function (i, v) {
if (Array.isArray(value) && !isObjectLike(v)) {
keyTmp = '';
}
else {
keyTmp = i;
}
destructure((key + "[" + keyTmp + "]"), v);
});
}
else {
if (value == null || value === '') {
keyTmp = '=';
}
else {
keyTmp = "=" + (encodeURIComponent(value));
}
args.push(encodeURIComponent(key) + keyTmp);
}
}
if (Array.isArray(obj)) {
each(obj, function () {
destructure(this.name, this.value);
});
}
else {
each(obj, destructure);
}
return args.join('&');
}
// 全局配置参数
var globalOptions = {};
// 全局事件名
var ajaxEvents = {
ajaxStart: 'start.mdui.ajax',
ajaxSuccess: 'success.mdui.ajax',
ajaxError: 'error.mdui.ajax',
ajaxComplete: 'complete.mdui.ajax',
};
/**
* 判断此请求方法是否通过查询字符串提交参数
* @param method 请求方法,大写
*/
function isQueryStringData(method) {
return ['GET', 'HEAD'].indexOf(method) >= 0;
}
/**
* 添加参数到 URL 上,且 URL 中不存在 ? 时,自动把第一个 & 替换为 ?
* @param url
* @param query
*/
function appendQuery(url, query) {
return (url + "&" + query).replace(/[&?]{1,2}/, '?');
}
/**
* 合并请求参数,参数优先级:options > globalOptions > defaults
* @param options
*/
function mergeOptions(options) {
// 默认参数
var defaults = {
url: '',
method: 'GET',
data: '',
processData: true,
async: true,
cache: true,
username: '',
password: '',
headers: {},
xhrFields: {},
statusCode: {},
dataType: 'text',
contentType: 'application/x-www-form-urlencoded',
timeout: 0,
global: true,
};
// globalOptions 中的回调函数不合并
each(globalOptions, function (key, value) {
var callbacks = [
'beforeSend',
'success',
'error',
'complete',
'statusCode' ];
// @ts-ignore
if (callbacks.indexOf(key) < 0 && !isUndefined(value)) {
defaults[key] = value;
}
});
return extend({}, defaults, options);
}
/**
* 发送 ajax 请求
* @param options
* @example
```js
ajax({
method: "POST",
url: "some.php",
data: { name: "John", location: "Boston" }
}).then(function( msg ) {
alert( "Data Saved: " + msg );
});
```
*/
function ajax(options) {
// 是否已取消请求
var isCanceled = false;
// 事件参数
var eventParams = {};
// 参数合并
var mergedOptions = mergeOptions(options);
var url = mergedOptions.url || window.location.toString();
var method = mergedOptions.method.toUpperCase();
var data = mergedOptions.data;
var processData = mergedOptions.processData;
var async = mergedOptions.async;
var cache = mergedOptions.cache;
var username = mergedOptions.username;
var password = mergedOptions.password;
var headers = mergedOptions.headers;
var xhrFields = mergedOptions.xhrFields;
var statusCode = mergedOptions.statusCode;
var dataType = mergedOptions.dataType;
var contentType = mergedOptions.contentType;
var timeout = mergedOptions.timeout;
var global = mergedOptions.global;
// 需要发送的数据
// GET/HEAD 请求和 processData 为 true 时,转换为查询字符串格式,特殊格式不转换
if (data &&
(isQueryStringData(method) || processData) &&
!isString(data) &&
!(data instanceof ArrayBuffer) &&
!(data instanceof Blob) &&
!(data instanceof Document) &&
!(data instanceof FormData)) {
data = param(data);
}
// 对于 GET、HEAD 类型的请求,把 data 数据添加到 URL 中
if (data && isQueryStringData(method)) {
// 查询字符串拼接到 URL 中
url = appendQuery(url, data);
data = null;
}
/**
* 触发事件和回调函数
* @param event
* @param params
* @param callback
* @param args
*/
function trigger(event, params, callback) {
var args = [], len = arguments.length - 3;
while ( len-- > 0 ) args[ len ] = arguments[ len + 3 ];
// 触发全局事件
if (global) {
$(document).trigger(event, params);
}
// 触发 ajax 回调和事件
var result1;
var result2;
if (callback) {
// 全局回调
if (callback in globalOptions) {
// @ts-ignore
result1 = globalOptions[callback].apply(globalOptions, args);
}
// 自定义回调
if (mergedOptions[callback]) {
// @ts-ignore
result2 = mergedOptions[callback].apply(mergedOptions, args);
}
// beforeSend 回调返回 false 时取消 ajax 请求
if (callback === 'beforeSend' &&
(result1 === false || result2 === false)) {
isCanceled = true;
}
}
}
// XMLHttpRequest 请求
function XHR() {
var textStatus;
return new Promise(function (resolve, reject) {
// GET/HEAD 请求的缓存处理
if (isQueryStringData(method) && !cache) {
url = appendQuery(url, ("_=" + (Date.now())));
}
// 创建 XHR
var xhr = new XMLHttpRequest();
xhr.open(method, url, async, username, password);
if (contentType ||
(data && !isQueryStringData(method) && contentType !== false)) {
xhr.setRequestHeader('Content-Type', contentType);
}
// 设置 Accept
if (dataType === 'json') {
xhr.setRequestHeader('Accept', 'application/json, text/javascript');
}
// 添加 headers
if (headers) {
each(headers, function (key, value) {
// undefined 值不发送,string 和 null 需要发送
if (!isUndefined(value)) {
xhr.setRequestHeader(key, value + ''); // 把 null 转换成字符串
}
});
}
// 检查是否是跨域请求,跨域请求时不添加 X-Requested-With
var crossDomain = /^([\w-]+:)?\/\/([^/]+)/.test(url) &&
RegExp.$2 !== window.location.host;
if (!crossDomain) {
xhr.setRequestHeader('X-Requested-With', 'XMLHttpRequest');
}
if (xhrFields) {
each(xhrFields, function (key, value) {
// @ts-ignore
xhr[key] = value;
});
}
eventParams.xhr = xhr;
eventParams.options = mergedOptions;
var xhrTimeout;
xhr.onload = function () {
if (xhrTimeout) {
clearTimeout(xhrTimeout);
}
// AJAX 返回的 HTTP 响应码是否表示成功
var isHttpStatusSuccess = (xhr.status >= 200 && xhr.status < 300) ||
xhr.status === 304 ||
xhr.status === 0;
var responseData;
if (isHttpStatusSuccess) {
if (xhr.status === 204 || method === 'HEAD') {
textStatus = 'nocontent';
}
else if (xhr.status === 304) {
textStatus = 'notmodified';
}
else {
textStatus = 'success';
}
if (dataType === 'json') {
try {
responseData =
method === 'HEAD' ? undefined : JSON.parse(xhr.responseText);
eventParams.data = responseData;
}
catch (err) {
textStatus = 'parsererror';
trigger(ajaxEvents.ajaxError, eventParams, 'error', xhr, textStatus);
reject(new Error(textStatus));
}
if (textStatus !== 'parsererror') {
trigger(ajaxEvents.ajaxSuccess, eventParams, 'success', responseData, textStatus, xhr);
resolve(responseData);
}
}
else {
responseData =
method === 'HEAD'
? undefined
: xhr.responseType === 'text' || xhr.responseType === ''
? xhr.responseText
: xhr.response;
eventParams.data = responseData;
trigger(ajaxEvents.ajaxSuccess, eventParams, 'success', responseData, textStatus, xhr);
resolve(responseData);
}
}
else {
textStatus = 'error';
trigger(ajaxEvents.ajaxError, eventParams, 'error', xhr, textStatus);
reject(new Error(textStatus));
}
// statusCode
each([globalOptions.statusCode, statusCode], function (_, func) {
if (func && func[xhr.status]) {
if (isHttpStatusSuccess) {
func[xhr.status](responseData, textStatus, xhr);
}
else {
func[xhr.status](xhr, textStatus);
}
}
});
trigger(ajaxEvents.ajaxComplete, eventParams, 'complete', xhr, textStatus);
};
xhr.onerror = function () {
if (xhrTimeout) {
clearTimeout(xhrTimeout);
}
trigger(ajaxEvents.ajaxError, eventParams, 'error', xhr, xhr.statusText);
trigger(ajaxEvents.ajaxComplete, eventParams, 'complete', xhr, 'error');
reject(new Error(xhr.statusText));
};
xhr.onabort = function () {
var statusText = 'abort';
if (xhrTimeout) {
statusText = 'timeout';
clearTimeout(xhrTimeout);
}
trigger(ajaxEvents.ajaxError, eventParams, 'error', xhr, statusText);
trigger(ajaxEvents.ajaxComplete, eventParams, 'complete', xhr, statusText);
reject(new Error(statusText));
};
// ajax start 回调
trigger(ajaxEvents.ajaxStart, eventParams, 'beforeSend', xhr);
if (isCanceled) {
reject(new Error('cancel'));
return;
}
// Timeout
if (timeout > 0) {
xhrTimeout = setTimeout(function () {
xhr.abort();
}, timeout);
}
// 发送 XHR
xhr.send(data);
});
}
return XHR();
}
$.ajax = ajax;
/**
* 为 Ajax 请求设置全局配置参数
* @param options 键值对参数
* @example
```js
ajaxSetup({
dataType: 'json',
method: 'POST',
});
```
*/
function ajaxSetup(options) {
return extend(globalOptions, options);
}
$.ajaxSetup = ajaxSetup;
$.contains = contains;
var dataNS = '_mduiElementDataStorage';
/**
* 在元素上设置键值对数据
* @param element
* @param object
*/
function setObjectToElement(element, object) {
// @ts-ignore
if (!element[dataNS]) {
// @ts-ignore
element[dataNS] = {};
}
each(object, function (key, value) {
// @ts-ignore
element[dataNS][toCamelCase(key)] = value;
});
}
function data(element, key, value) {
var obj;
// 根据键值对设置值
// data(element, { 'key' : 'value' })
if (isObjectLike(key)) {
setObjectToElement(element, key);
return key;
}
// 根据 key、value 设置值
// data(element, 'key', 'value')
if (!isUndefined(value)) {
setObjectToElement(element, ( obj = {}, obj[key] = value, obj ));
return value;
}
// 获取所有值
// data(element)
if (isUndefined(key)) {
// @ts-ignore
return element[dataNS] ? element[dataNS] : {};
}
// 从 dataNS 中获取指定值
// data(element, 'key')
key = toCamelCase(key);
// @ts-ignore
if (element[dataNS] && key in element[dataNS]) {
// @ts-ignore
return element[dataNS][key];
}
return undefined;
}
$.data = data;
$.each = each;
$.extend = function () {
var this$1 = this;
var objectN = [], len = arguments.length;
while ( len-- ) objectN[ len ] = arguments[ len ];
if (objectN.length === 1) {
each(objectN[0], function (prop, value) {
this$1[prop] = value;
});
return this;
}
return extend.apply(void 0, [ objectN.shift(), objectN.shift() ].concat( objectN ));
};
function map(elements, callback) {
var ref;
var value;
var ret = [];
each(elements, function (i, element) {
value = callback.call(window, element, i);
if (value != null) {
ret.push(value);
}
});
return (ref = []).concat.apply(ref, ret);
}
$.map = map;
$.merge = merge;
$.param = param;
/**
* 移除指定元素上存放的数据
* @param element 存放数据的元素
* @param name
* 数据键名
*
* 若未指定键名,将移除元素上所有数据
*
* 多个键名可以用空格分隔,或者用数组表示多个键名
@example
```js
// 移除元素上键名为 name 的数据
removeData(document.body, 'name');
```
* @example
```js
// 移除元素上键名为 name1 和 name2 的数据
removeData(document.body, 'name1 name2');
```
* @example
```js
// 移除元素上键名为 name1 和 name2 的数据
removeData(document.body, ['name1', 'name2']);
```
* @example
```js
// 移除元素上所有数据
removeData(document.body);
```
*/
function removeData(element, name) {
// @ts-ignore
if (!element[dataNS]) {
return;
}
var remove = function (nameItem) {
nameItem = toCamelCase(nameItem);
// @ts-ignore
if (element[dataNS][nameItem]) {
// @ts-ignore
element[dataNS][nameItem] = null;
// @ts-ignore
delete element[dataNS][nameItem];
}
};
if (isUndefined(name)) {
// @ts-ignore
element[dataNS] = null;
// @ts-ignore
delete element[dataNS];
// @ts-ignore
}
else if (isString(name)) {
name
.split(' ')
.filter(function (nameItem) { return nameItem; })
.forEach(function (nameItem) { return remove(nameItem); });
}
else {
each(name, function (_, nameItem) { return remove(nameItem); });
}
}
$.removeData = removeData;
/**
* 过滤掉数组中的重复元素
* @param arr 数组
* @example
```js
unique([1, 2, 12, 3, 2, 1, 2, 1, 1]);
// [1, 2, 12, 3]
```
*/
function unique(arr) {
var result = [];
each(arr, function (_, val) {
if (result.indexOf(val) === -1) {
result.push(val);
}
});
return result;
}
$.unique = unique;
$.fn.add = function (selector) {
return new JQ(unique(merge(this.get(), $(selector).get())));
};
each(['add', 'remove', 'toggle'], function (_, name) {
$.fn[(name + "Class")] = function (className) {
if (name === 'remove' && !arguments.length) {
return this.each(function (_, element) {
element.setAttribute('class', '');
});
}
return this.each(function (i, element) {
if (!isElement(element)) {
return;
}
var classes = (isFunction(className)
? className.call(element, i, element.getAttribute('class') || '')
: className)
.split(' ')
.filter(function (name) { return name; });
each(classes, function (_, cls) {
element.classList[name](cls);
});
});
};
});
each(['insertBefore', 'insertAfter'], function (nameIndex, name) {
$.fn[name] = function (target) {
var $element = nameIndex ? $(this.get().reverse()) : this; // 顺序和 jQuery 保持一致
var $target = $(target);
var result = [];
$target.each(function (index, target) {
if (!target.parentNode) {
return;
}
$element.each(function (_, element) {
var newItem = index
? element.cloneNode(true)
: element;
var existingItem = nameIndex ? target.nextSibling : target;
result.push(newItem);
target.parentNode.insertBefore(newItem, existingItem);
});
});
return $(nameIndex ? result.reverse() : result);
};
});
/**
* 是否不是 HTML 字符串(包裹在 <> 中)
* @param target
*/
function isPlainText(target) {
return (isString(target) && (target[0] !== '<' || target[target.length - 1] !== '>'));
}
each(['before', 'after'], function (nameIndex, name) {
$.fn[name] = function () {
var args = [], len = arguments.length;
while ( len-- ) args[ len ] = arguments[ len ];
// after 方法,多个参数需要按参数顺序添加到元素后面,所以需要将参数顺序反向处理
if (nameIndex === 1) {
args = args.reverse();
}
return this.each(function (index, element) {
var targets = isFunction(args[0])
? [args[0].call(element, index, element.innerHTML)]
: args;
each(targets, function (_, target) {
var $target;
if (isPlainText(target)) {
$target = $(getChildNodesArray(target, 'div'));
}
else if (index && isElement(target)) {
$target = $(target.cloneNode(true));
}
else {
$target = $(target);
}
$target[nameIndex ? 'insertAfter' : 'insertBefore'](element);
});
});
};
});
$.fn.off = function (types, selector, callback) {
var this$1 = this;
// types 是对象
if (isObjectLike(types)) {
each(types, function (type, fn) {
// this.off('click', undefined, function () {})
// this.off('click', '.box', function () {})
this$1.off(type, selector, fn);
});
return this;
}
// selector 不存在
if (selector === false || isFunction(selector)) {
callback = selector;
selector = undefined;
// this.off('click', undefined, function () {})
}
// callback 传入 `false`,相当于 `return false`
if (callback === false) {
callback = returnFalse;
}
return this.each(function () {
remove(this, types, callback, selector);
});
};
$.fn.on = function (types, selector, data, callback, one) {
var this$1 = this;
// types 可以是 type/func 对象
if (isObjectLike(types)) {
// (types-Object, selector, data)
if (!isString(selector)) {
// (types-Object, data)
data = data || selector;
selector = undefined;
}
each(types, function (type, fn) {
// selector 和 data 都可能是 undefined
// @ts-ignore
this$1.on(type, selector, data, fn, one);
});
return this;
}
if (data == null && callback == null) {
// (types, fn)
callback = selector;
data = selector = undefined;
}
else if (callback == null) {
if (isString(selector)) {
// (types, selector, fn)
callback = data;
data = undefined;
}
else {
// (types, data, fn)
callback = data;
data = selector;
selector = undefined;
}
}
if (callback === false) {
callback = returnFalse;
}
else if (!callback) {
return this;
}
// $().one()
if (one) {
// eslint-disable-next-line @typescript-eslint/no-this-alias
var _this = this;
var origCallback = callback;
callback = function (event) {
_this.off(event.type, selector, callback);
// eslint-disable-next-line prefer-rest-params
return origCallback.apply(this, arguments);
};
}
return this.each(function () {
add(this, types, callback, data, selector);
});
};
each(ajaxEvents, function (name, eventName) {
$.fn[name] = function (fn) {
return this.on(eventName, function (e, params) {
fn(e, params.xhr, params.options, params.data);
});
};
});
$.fn.map = function (callback) {
return new JQ(map(this, function (element, i) { return callback.call(element, i, element); }));
};
$.fn.clone = function () {
return this.map(function () {
return this.cloneNode(true);
});
};
$.fn.is = function (selector) {
var isMatched = false;
if (isFunction(selector)) {
this.each(function (index, element) {
if (selector.call(element, index, element)) {
isMatched = true;
}
});
return isMatched;
}
if (isString(selector)) {
this.each(function (_, element) {
if (isDocument(element) || isWindow(element)) {
return;
}
// @ts-ignore
var matches = element.matches || element.msMatchesSelector;
if (matches.call(element, selector)) {
isMatched = true;
}
});
return isMatched;
}
var $compareWith = $(selector);
this.each(function (_, element) {
$compareWith.each(function (_, compare) {
if (element === compare) {
isMatched = true;
}
});
});
return isMatched;
};
$.fn.remove = function (selector) {
return this.each(function (_, element) {
if (element.parentNode && (!selector || $(element).is(selector))) {
element.parentNode.removeChild(element);
}
});
};
each(['prepend', 'append'], function (nameIndex, name) {
$.fn[name] = function () {
var args = [], len = arguments.length;
while ( len-- ) args[ len ] = arguments[ len ];
return this.each(function (index, element) {
var ref;
var childNodes = element.childNodes;
var childLength = childNodes.length;
var child = childLength
? childNodes[nameIndex ? childLength - 1 : 0]
: document.createElement('div');
if (!childLength) {
element.appendChild(child);
}
var contents = isFunction(args[0])
? [args[0].call(element, index, element.innerHTML)]
: args;
// 如果不是字符串,则仅第一个元素使用原始元素,其他的都克隆自第一个元素
if (index) {
contents = contents.map(function (content) {
return isString(content) ? content : $(content).clone();
});
}
(ref = $(child))[nameIndex ? 'after' : 'before'].apply(ref, contents);
if (!childLength) {
element.removeChild(child);
}
});
};
});
each(['appendTo', 'prependTo'], function (nameIndex, name) {
$.fn[name] = function (target) {
var extraChilds = [];
var $target = $(target).map(function (_, element) {
var childNodes = element.childNodes;
var childLength = childNodes.length;
if (childLength) {