mirror of https://github.com/helloxz/onenav.git
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.
6474 lines
204 KiB
6474 lines
204 KiB
/*! |
|
* mdui 1.0.1 (https://mdui.org) |
|
* Copyright 2016-2020 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) { |
|
return childNodes[nameIndex ? 0 : childLength - 1]; |
|
} |
|
var child = document.createElement('div'); |
|
element.appendChild(child); |
|
extraChilds.push(child); |
|
return child; |
|
}); |
|
var $result = this[nameIndex ? 'insertBefore' : 'insertAfter']($target); |
|
$(extraChilds).remove(); |
|
return $result; |
|
}; |
|
}); |
|
|
|
each(['attr', 'prop', 'css'], function (nameIndex, name) { |
|
function set(element, key, value) { |
|
// 值为 undefined 时,不修改 |
|
if (isUndefined(value)) { |
|
return; |
|
} |
|
switch (nameIndex) { |
|
// attr |
|
case 0: |
|
if (isNull(value)) { |
|
element.removeAttribute(key); |
|
} |
|
else { |
|
element.setAttribute(key, value); |
|
} |
|
break; |
|
// prop |
|
case 1: |
|
// @ts-ignore |
|
element[key] = value; |
|
break; |
|
// css |
|
default: |
|
key = toCamelCase(key); |
|
// @ts-ignore |
|
element.style[key] = isNumber(value) |
|
? ("" + value + (cssNumber.indexOf(key) > -1 ? '' : 'px')) |
|
: value; |
|
break; |
|
} |
|
} |
|
function get(element, key) { |
|
switch (nameIndex) { |
|
// attr |
|
case 0: |
|
// 属性不存在时,原生 getAttribute 方法返回 null,而 jquery 返回 undefined。这里和 jquery 保持一致 |
|
var value = element.getAttribute(key); |
|
return isNull(value) ? undefined : value; |
|
// prop |
|
case 1: |
|
// @ts-ignore |
|
return element[key]; |
|
// css |
|
default: |
|
return getStyle(element, key); |
|
} |
|
} |
|
$.fn[name] = function (key, value) { |
|
var this$1 = this; |
|
|
|
if (isObjectLike(key)) { |
|
each(key, function (k, v) { |
|
// @ts-ignore |
|
this$1[name](k, v); |
|
}); |
|
return this; |
|
} |
|
if (arguments.length === 1) { |
|
var element = this[0]; |
|
return isElement(element) ? get(element, key) : undefined; |
|
} |
|
return this.each(function (i, element) { |
|
set(element, key, isFunction(value) ? value.call(element, i, get(element, key)) : value); |
|
}); |
|
}; |
|
}); |
|
|
|
$.fn.children = function (selector) { |
|
var children = []; |
|
this.each(function (_, element) { |
|
each(element.childNodes, function (__, childNode) { |
|
if (!isElement(childNode)) { |
|
return; |
|
} |
|
if (!selector || $(childNode).is(selector)) { |
|
children.push(childNode); |
|
} |
|
}); |
|
}); |
|
return new JQ(unique(children)); |
|
}; |
|
|
|
$.fn.slice = function () { |
|
var args = [], len = arguments.length; |
|
while ( len-- ) args[ len ] = arguments[ len ]; |
|
|
|
return new JQ([].slice.apply(this, args)); |
|
}; |
|
|
|
$.fn.eq = function (index) { |
|
var ret = index === -1 ? this.slice(index) : this.slice(index, +index + 1); |
|
return new JQ(ret); |
|
}; |
|
|
|
function dir($elements, nameIndex, node, selector, filter) { |
|
var ret = []; |
|
var target; |
|
$elements.each(function (_, element) { |
|
target = element[node]; |
|
// 不能包含最顶层的 document 元素 |
|
while (target && isElement(target)) { |
|
// prevUntil, nextUntil, parentsUntil |
|
if (nameIndex === 2) { |
|
if (selector && $(target).is(selector)) { |
|
break; |
|
} |
|
if (!filter || $(target).is(filter)) { |
|
ret.push(target); |
|
} |
|
} |
|
// prev, next, parent |
|
else if (nameIndex === 0) { |
|
if (!selector || $(target).is(selector)) { |
|
ret.push(target); |
|
} |
|
break; |
|
} |
|
// prevAll, nextAll, parents |
|
else { |
|
if (!selector || $(target).is(selector)) { |
|
ret.push(target); |
|
} |
|
} |
|
// @ts-ignore |
|
target = target[node]; |
|
} |
|
}); |
|
return new JQ(unique(ret)); |
|
} |
|
|
|
each(['', 's', 'sUntil'], function (nameIndex, name) { |
|
$.fn[("parent" + name)] = function (selector, filter) { |
|
// parents、parentsUntil 需要把元素的顺序反向处理,以便和 jQuery 的结果一致 |
|
var $nodes = !nameIndex ? this : $(this.get().reverse()); |
|
return dir($nodes, nameIndex, 'parentNode', selector, filter); |
|
}; |
|
}); |
|
|
|
$.fn.closest = function (selector) { |
|
if (this.is(selector)) { |
|
return this; |
|
} |
|
var matched = []; |
|
this.parents().each(function (_, element) { |
|
if ($(element).is(selector)) { |
|
matched.push(element); |
|
return false; |
|
} |
|
}); |
|
return new JQ(matched); |
|
}; |
|
|
|
var rbrace = /^(?:{[\w\W]*\}|\[[\w\W]*\])$/; |
|
// 从 `data-*` 中获取的值,需要经过该函数转换 |
|
function getData(value) { |
|
if (value === 'true') { |
|
return true; |
|
} |
|
if (value === 'false') { |
|
return false; |
|
} |
|
if (value === 'null') { |
|
return null; |
|
} |
|
if (value === +value + '') { |
|
return +value; |
|
} |
|
if (rbrace.test(value)) { |
|
return JSON.parse(value); |
|
} |
|
return value; |
|
} |
|
// 若 value 不存在,则从 `data-*` 中获取值 |
|
function dataAttr(element, key, value) { |
|
if (isUndefined(value) && element.nodeType === 1) { |
|
var name = 'data-' + toKebabCase(key); |
|
value = element.getAttribute(name); |
|
if (isString(value)) { |
|
try { |
|
value = getData(value); |
|
} |
|
catch (e) { } |
|
} |
|
else { |
|
value = undefined; |
|
} |
|
} |
|
return value; |
|
} |
|
$.fn.data = function (key, value) { |
|
// 获取所有值 |
|
if (isUndefined(key)) { |
|
if (!this.length) { |
|
return undefined; |
|
} |
|
var element = this[0]; |
|
var resultData = data(element); |
|
// window, document 上不存在 `data-*` 属性 |
|
if (element.nodeType !== 1) { |
|
return resultData; |
|
} |
|
// 从 `data-*` 中获取值 |
|
var attrs = element.attributes; |
|
var i = attrs.length; |
|
while (i--) { |
|
if (attrs[i]) { |
|
var name = attrs[i].name; |
|
if (name.indexOf('data-') === 0) { |
|
name = toCamelCase(name.slice(5)); |
|
resultData[name] = dataAttr(element, name, resultData[name]); |
|
} |
|
} |
|
} |
|
return resultData; |
|
} |
|
// 同时设置多个值 |
|
if (isObjectLike(key)) { |
|
return this.each(function () { |
|
data(this, key); |
|
}); |
|
} |
|
// value 传入了 undefined |
|
if (arguments.length === 2 && isUndefined(value)) { |
|
return this; |
|
} |
|
// 设置值 |
|
if (!isUndefined(value)) { |
|
return this.each(function () { |
|
data(this, key, value); |
|
}); |
|
} |
|
// 获取值 |
|
if (!this.length) { |
|
return undefined; |
|
} |
|
return dataAttr(this[0], key, data(this[0], key)); |
|
}; |
|
|
|
$.fn.empty = function () { |
|
return this.each(function () { |
|
this.innerHTML = ''; |
|
}); |
|
}; |
|
|
|
$.fn.extend = function (obj) { |
|
each(obj, function (prop, value) { |
|
// 在 JQ 对象上扩展方法时,需要自己添加 typescript 的类型定义 |
|
$.fn[prop] = value; |
|
}); |
|
return this; |
|
}; |
|
|
|
$.fn.filter = function (selector) { |
|
if (isFunction(selector)) { |
|
return this.map(function (index, element) { return selector.call(element, index, element) ? element : undefined; }); |
|
} |
|
if (isString(selector)) { |
|
return this.map(function (_, element) { return $(element).is(selector) ? element : undefined; }); |
|
} |
|
var $selector = $(selector); |
|
return this.map(function (_, element) { return $selector.get().indexOf(element) > -1 ? element : undefined; }); |
|
}; |
|
|
|
$.fn.first = function () { |
|
return this.eq(0); |
|
}; |
|
|
|
$.fn.has = function (selector) { |
|
var $targets = isString(selector) ? this.find(selector) : $(selector); |
|
var length = $targets.length; |
|
return this.map(function () { |
|
for (var i = 0; i < length; i += 1) { |
|
if (contains(this, $targets[i])) { |
|
return this; |
|
} |
|
} |
|
return; |
|
}); |
|
}; |
|
|
|
$.fn.hasClass = function (className) { |
|
return this[0].classList.contains(className); |
|
}; |
|
|
|
/** |
|
* 值上面的 padding、border、margin 处理 |
|
* @param element |
|
* @param name |
|
* @param value |
|
* @param funcIndex |
|
* @param includeMargin |
|
* @param multiply |
|
*/ |
|
function handleExtraWidth(element, name, value, funcIndex, includeMargin, multiply) { |
|
// 获取元素的 padding, border, margin 宽度(两侧宽度的和) |
|
var getExtraWidthValue = function (extra) { |
|
return (getExtraWidth(element, name.toLowerCase(), extra) * |
|
multiply); |
|
}; |
|
if (funcIndex === 2 && includeMargin) { |
|
value += getExtraWidthValue('margin'); |
|
} |
|
if (isBorderBox(element)) { |
|
// IE 为 box-sizing: border-box 时,得到的值不含 border 和 padding,这里先修复 |
|
// 仅获取时需要处理,multiply === 1 为 get |
|
if (isIE() && multiply === 1) { |
|
value += getExtraWidthValue('border'); |
|
value += getExtraWidthValue('padding'); |
|
} |
|
if (funcIndex === 0) { |
|
value -= getExtraWidthValue('border'); |
|
} |
|
if (funcIndex === 1) { |
|
value -= getExtraWidthValue('border'); |
|
value -= getExtraWidthValue('padding'); |
|
} |
|
} |
|
else { |
|
if (funcIndex === 0) { |
|
value += getExtraWidthValue('padding'); |
|
} |
|
if (funcIndex === 2) { |
|
value += getExtraWidthValue('border'); |
|
value += getExtraWidthValue('padding'); |
|
} |
|
} |
|
return value; |
|
} |
|
/** |
|
* 获取元素的样式值 |
|
* @param element |
|
* @param name |
|
* @param funcIndex 0: innerWidth, innerHeight; 1: width, height; 2: outerWidth, outerHeight |
|
* @param includeMargin |
|
*/ |
|
function get(element, name, funcIndex, includeMargin) { |
|
var clientProp = "client" + name; |
|
var scrollProp = "scroll" + name; |
|
var offsetProp = "offset" + name; |
|
var innerProp = "inner" + name; |
|
// $(window).width() |
|
if (isWindow(element)) { |
|
// outerWidth, outerHeight 需要包含滚动条的宽度 |
|
return funcIndex === 2 |
|
? element[innerProp] |
|
: toElement(document)[clientProp]; |
|
} |
|
// $(document).width() |
|
if (isDocument(element)) { |
|
var doc = toElement(element); |
|
return Math.max( |
|
// @ts-ignore |
|
element.body[scrollProp], doc[scrollProp], |
|
// @ts-ignore |
|
element.body[offsetProp], doc[offsetProp], doc[clientProp]); |
|
} |
|
var value = parseFloat(getComputedStyleValue(element, name.toLowerCase()) || '0'); |
|
return handleExtraWidth(element, name, value, funcIndex, includeMargin, 1); |
|
} |
|
/** |
|
* 设置元素的样式值 |
|
* @param element |
|
* @param elementIndex |
|
* @param name |
|
* @param funcIndex 0: innerWidth, innerHeight; 1: width, height; 2: outerWidth, outerHeight |
|
* @param includeMargin |
|
* @param value |
|
*/ |
|
function set(element, elementIndex, name, funcIndex, includeMargin, value) { |
|
var computedValue = isFunction(value) |
|
? value.call(element, elementIndex, get(element, name, funcIndex, includeMargin)) |
|
: value; |
|
if (computedValue == null) { |
|
return; |
|
} |
|
var $element = $(element); |
|
var dimension = name.toLowerCase(); |
|
// 特殊的值,不需要计算 padding、border、margin |
|
if (['auto', 'inherit', ''].indexOf(computedValue) > -1) { |
|
$element.css(dimension, computedValue); |
|
return; |
|
} |
|
// 其他值保留原始单位。注意:如果不使用 px 作为单位,则算出的值一般是不准确的 |
|
var suffix = computedValue.toString().replace(/\b[0-9.]*/, ''); |
|
var numerical = parseFloat(computedValue); |
|
computedValue = |
|
handleExtraWidth(element, name, numerical, funcIndex, includeMargin, -1) + |
|
(suffix || 'px'); |
|
$element.css(dimension, computedValue); |
|
} |
|
each(['Width', 'Height'], function (_, name) { |
|
each([("inner" + name), name.toLowerCase(), ("outer" + name)], function (funcIndex, funcName) { |
|
$.fn[funcName] = function (margin, value) { |
|
// 是否是赋值操作 |
|
var isSet = arguments.length && (funcIndex < 2 || !isBoolean(margin)); |
|
var includeMargin = margin === true || value === true; |
|
// 获取第一个元素的值 |
|
if (!isSet) { |
|
return this.length |
|
? get(this[0], name, funcIndex, includeMargin) |
|
: undefined; |
|
} |
|
// 设置每个元素的值 |
|
return this.each(function (index, element) { return set(element, index, name, funcIndex, includeMargin, margin); }); |
|
}; |
|
}); |
|
}); |
|
|
|
$.fn.hide = function () { |
|
return this.each(function () { |
|
this.style.display = 'none'; |
|
}); |
|
}; |
|
|
|
each(['val', 'html', 'text'], function (nameIndex, name) { |
|
var props = { |
|
0: 'value', |
|
1: 'innerHTML', |
|
2: 'textContent', |
|
}; |
|
var propName = props[nameIndex]; |
|
function get($elements) { |
|
// text() 获取所有元素的文本 |
|
if (nameIndex === 2) { |
|
// @ts-ignore |
|
return map($elements, function (element) { return toElement(element)[propName]; }).join(''); |
|
} |
|
// 空集合时,val() 和 html() 返回 undefined |
|
if (!$elements.length) { |
|
return undefined; |
|
} |
|
// val() 和 html() 仅获取第一个元素的内容 |
|
var firstElement = $elements[0]; |
|
// select multiple 返回数组 |
|
if (nameIndex === 0 && $(firstElement).is('select[multiple]')) { |
|
return map($(firstElement).find('option:checked'), function (element) { return element.value; }); |
|
} |
|
// @ts-ignore |
|
return firstElement[propName]; |
|
} |
|
function set(element, value) { |
|
// text() 和 html() 赋值为 undefined,则保持原内容不变 |
|
// val() 赋值为 undefined 则赋值为空 |
|
if (isUndefined(value)) { |
|
if (nameIndex !== 0) { |
|
return; |
|
} |
|
value = ''; |
|
} |
|
if (nameIndex === 1 && isElement(value)) { |
|
value = value.outerHTML; |
|
} |
|
// @ts-ignore |
|
element[propName] = value; |
|
} |
|
$.fn[name] = function (value) { |
|
// 获取值 |
|
if (!arguments.length) { |
|
return get(this); |
|
} |
|
// 设置值 |
|
return this.each(function (i, element) { |
|
var computedValue = isFunction(value) |
|
? value.call(element, i, get($(element))) |
|
: value; |
|
// value 是数组,则选中数组中的元素,反选不在数组中的元素 |
|
if (nameIndex === 0 && Array.isArray(computedValue)) { |
|
// select[multiple] |
|
if ($(element).is('select[multiple]')) { |
|
map($(element).find('option'), function (option) { return (option.selected = |
|
computedValue.indexOf(option.value) > |
|
-1); }); |
|
} |
|
// 其他 checkbox, radio 等元素 |
|
else { |
|
element.checked = |
|
computedValue.indexOf(element.value) > -1; |
|
} |
|
} |
|
else { |
|
set(element, computedValue); |
|
} |
|
}); |
|
}; |
|
}); |
|
|
|
$.fn.index = function (selector) { |
|
if (!arguments.length) { |
|
return this.eq(0).parent().children().get().indexOf(this[0]); |
|
} |
|
if (isString(selector)) { |
|
return $(selector).get().indexOf(this[0]); |
|
} |
|
return this.get().indexOf($(selector)[0]); |
|
}; |
|
|
|
$.fn.last = function () { |
|
return this.eq(-1); |
|
}; |
|
|
|
each(['', 'All', 'Until'], function (nameIndex, name) { |
|
$.fn[("next" + name)] = function (selector, filter) { |
|
return dir(this, nameIndex, 'nextElementSibling', selector, filter); |
|
}; |
|
}); |
|
|
|
$.fn.not = function (selector) { |
|
var $excludes = this.filter(selector); |
|
return this.map(function (_, element) { return $excludes.index(element) > -1 ? undefined : element; }); |
|
}; |
|
|
|
/** |
|
* 返回最近的用于定位的父元素 |
|
*/ |
|
$.fn.offsetParent = function () { |
|
return this.map(function () { |
|
var offsetParent = this.offsetParent; |
|
while (offsetParent && $(offsetParent).css('position') === 'static') { |
|
offsetParent = offsetParent.offsetParent; |
|
} |
|
return offsetParent || document.documentElement; |
|
}); |
|
}; |
|
|
|
function floatStyle($element, name) { |
|
return parseFloat($element.css(name)); |
|
} |
|
$.fn.position = function () { |
|
if (!this.length) { |
|
return undefined; |
|
} |
|
var $element = this.eq(0); |
|
var currentOffset; |
|
var parentOffset = { |
|
left: 0, |
|
top: 0, |
|
}; |
|
if ($element.css('position') === 'fixed') { |
|
currentOffset = $element[0].getBoundingClientRect(); |
|
} |
|
else { |
|
currentOffset = $element.offset(); |
|
var $offsetParent = $element.offsetParent(); |
|
parentOffset = $offsetParent.offset(); |
|
parentOffset.top += floatStyle($offsetParent, 'border-top-width'); |
|
parentOffset.left += floatStyle($offsetParent, 'border-left-width'); |
|
} |
|
return { |
|
top: currentOffset.top - parentOffset.top - floatStyle($element, 'margin-top'), |
|
left: currentOffset.left - |
|
parentOffset.left - |
|
floatStyle($element, 'margin-left'), |
|
}; |
|
}; |
|
|
|
function get$1(element) { |
|
if (!element.getClientRects().length) { |
|
return { top: 0, left: 0 }; |
|
} |
|
var rect = element.getBoundingClientRect(); |
|
var win = element.ownerDocument.defaultView; |
|
return { |
|
top: rect.top + win.pageYOffset, |
|
left: rect.left + win.pageXOffset, |
|
}; |
|
} |
|
function set$1(element, value, index) { |
|
var $element = $(element); |
|
var position = $element.css('position'); |
|
if (position === 'static') { |
|
$element.css('position', 'relative'); |
|
} |
|
var currentOffset = get$1(element); |
|
var currentTopString = $element.css('top'); |
|
var currentLeftString = $element.css('left'); |
|
var currentTop; |
|
var currentLeft; |
|
var calculatePosition = (position === 'absolute' || position === 'fixed') && |
|
(currentTopString + currentLeftString).indexOf('auto') > -1; |
|
if (calculatePosition) { |
|
var currentPosition = $element.position(); |
|
currentTop = currentPosition.top; |
|
currentLeft = currentPosition.left; |
|
} |
|
else { |
|
currentTop = parseFloat(currentTopString); |
|
currentLeft = parseFloat(currentLeftString); |
|
} |
|
var computedValue = isFunction(value) |
|
? value.call(element, index, extend({}, currentOffset)) |
|
: value; |
|
$element.css({ |
|
top: computedValue.top != null |
|
? computedValue.top - currentOffset.top + currentTop |
|
: undefined, |
|
left: computedValue.left != null |
|
? computedValue.left - currentOffset.left + currentLeft |
|
: undefined, |
|
}); |
|
} |
|
$.fn.offset = function (value) { |
|
// 获取坐标 |
|
if (!arguments.length) { |
|
if (!this.length) { |
|
return undefined; |
|
} |
|
return get$1(this[0]); |
|
} |
|
// 设置坐标 |
|
return this.each(function (index) { |
|
set$1(this, value, index); |
|
}); |
|
}; |
|
|
|
$.fn.one = function (types, selector, data, callback) { |
|
// @ts-ignore |
|
return this.on(types, selector, data, callback, true); |
|
}; |
|
|
|
each(['', 'All', 'Until'], function (nameIndex, name) { |
|
$.fn[("prev" + name)] = function (selector, filter) { |
|
// prevAll、prevUntil 需要把元素的顺序倒序处理,以便和 jQuery 的结果一致 |
|
var $nodes = !nameIndex ? this : $(this.get().reverse()); |
|
return dir($nodes, nameIndex, 'previousElementSibling', selector, filter); |
|
}; |
|
}); |
|
|
|
$.fn.removeAttr = function (attributeName) { |
|
var names = attributeName.split(' ').filter(function (name) { return name; }); |
|
return this.each(function () { |
|
var this$1 = this; |
|
|
|
each(names, function (_, name) { |
|
this$1.removeAttribute(name); |
|
}); |
|
}); |
|
}; |
|
|
|
$.fn.removeData = function (name) { |
|
return this.each(function () { |
|
removeData(this, name); |
|
}); |
|
}; |
|
|
|
$.fn.removeProp = function (name) { |
|
return this.each(function () { |
|
try { |
|
// @ts-ignore |
|
delete this[name]; |
|
} |
|
catch (e) { } |
|
}); |
|
}; |
|
|
|
$.fn.replaceWith = function (newContent) { |
|
this.each(function (index, element) { |
|
var content = newContent; |
|
if (isFunction(content)) { |
|
content = content.call(element, index, element.innerHTML); |
|
} |
|
else if (index && !isString(content)) { |
|
content = $(content).clone(); |
|
} |
|
$(element).before(content); |
|
}); |
|
return this.remove(); |
|
}; |
|
|
|
$.fn.replaceAll = function (target) { |
|
var this$1 = this; |
|
|
|
return $(target).map(function (index, element) { |
|
$(element).replaceWith(index ? this$1.clone() : this$1); |
|
return this$1.get(); |
|
}); |
|
}; |
|
|
|
/** |
|
* 将表单元素的值组合成键值对数组 |
|
* @returns {Array} |
|
*/ |
|
$.fn.serializeArray = function () { |
|
var result = []; |
|
this.each(function (_, element) { |
|
var elements = element instanceof HTMLFormElement ? element.elements : [element]; |
|
$(elements).each(function (_, element) { |
|
var $element = $(element); |
|
var type = element.type; |
|
var nodeName = element.nodeName.toLowerCase(); |
|
if (nodeName !== 'fieldset' && |
|
element.name && |
|
!element.disabled && |
|
['input', 'select', 'textarea', 'keygen'].indexOf(nodeName) > -1 && |
|
['submit', 'button', 'image', 'reset', 'file'].indexOf(type) === -1 && |
|
(['radio', 'checkbox'].indexOf(type) === -1 || |
|
element.checked)) { |
|
var value = $element.val(); |
|
var valueArr = Array.isArray(value) ? value : [value]; |
|
valueArr.forEach(function (value) { |
|
result.push({ |
|
name: element.name, |
|
value: value, |
|
}); |
|
}); |
|
} |
|
}); |
|
}); |
|
return result; |
|
}; |
|
|
|
$.fn.serialize = function () { |
|
return param(this.serializeArray()); |
|
}; |
|
|
|
var elementDisplay = {}; |
|
/** |
|
* 获取元素的初始 display 值,用于 .show() 方法 |
|
* @param nodeName |
|
*/ |
|
function defaultDisplay(nodeName) { |
|
var element; |
|
var display; |
|
if (!elementDisplay[nodeName]) { |
|
element = document.createElement(nodeName); |
|
document.body.appendChild(element); |
|
display = getStyle(element, 'display'); |
|
element.parentNode.removeChild(element); |
|
if (display === 'none') { |
|
display = 'block'; |
|
} |
|
elementDisplay[nodeName] = display; |
|
} |
|
return elementDisplay[nodeName]; |
|
} |
|
/** |
|
* 显示指定元素 |
|
* @returns {JQ} |
|
*/ |
|
$.fn.show = function () { |
|
return this.each(function () { |
|
if (this.style.display === 'none') { |
|
this.style.display = ''; |
|
} |
|
if (getStyle(this, 'display') === 'none') { |
|
this.style.display = defaultDisplay(this.nodeName); |
|
} |
|
}); |
|
}; |
|
|
|
/** |
|
* 取得同辈元素的集合 |
|
* @param selector {String=} |
|
* @returns {JQ} |
|
*/ |
|
$.fn.siblings = function (selector) { |
|
return this.prevAll(selector).add(this.nextAll(selector)); |
|
}; |
|
|
|
/** |
|
* 切换元素的显示状态 |
|
*/ |
|
$.fn.toggle = function () { |
|
return this.each(function () { |
|
getStyle(this, 'display') === 'none' ? $(this).show() : $(this).hide(); |
|
}); |
|
}; |
|
|
|
$.fn.reflow = function () { |
|
return this.each(function () { |
|
return this.clientLeft; |
|
}); |
|
}; |
|
|
|
$.fn.transition = function (duration) { |
|
if (isNumber(duration)) { |
|
duration = duration + "ms"; |
|
} |
|
return this.each(function () { |
|
this.style.webkitTransitionDuration = duration; |
|
this.style.transitionDuration = duration; |
|
}); |
|
}; |
|
|
|
$.fn.transitionEnd = function (callback) { |
|
// eslint-disable-next-line @typescript-eslint/no-this-alias |
|
var that = this; |
|
var events = ['webkitTransitionEnd', 'transitionend']; |
|
function fireCallback(e) { |
|
if (e.target !== this) { |
|
return; |
|
} |
|
// @ts-ignore |
|
callback.call(this, e); |
|
each(events, function (_, event) { |
|
that.off(event, fireCallback); |
|
}); |
|
} |
|
each(events, function (_, event) { |
|
that.on(event, fireCallback); |
|
}); |
|
return this; |
|
}; |
|
|
|
$.fn.transformOrigin = function (transformOrigin) { |
|
return this.each(function () { |
|
this.style.webkitTransformOrigin = transformOrigin; |
|
this.style.transformOrigin = transformOrigin; |
|
}); |
|
}; |
|
|
|
$.fn.transform = function (transform) { |
|
return this.each(function () { |
|
this.style.webkitTransform = transform; |
|
this.style.transform = transform; |
|
}); |
|
}; |
|
|
|
/** |
|
* CSS 选择器和初始化函数组成的对象 |
|
*/ |
|
var entries = {}; |
|
/** |
|
* 注册并执行初始化函数 |
|
* @param selector CSS 选择器 |
|
* @param apiInit 初始化函数 |
|
* @param i 元素索引 |
|
* @param element 元素 |
|
*/ |
|
function mutation(selector, apiInit, i, element) { |
|
var selectors = data(element, '_mdui_mutation'); |
|
if (!selectors) { |
|
selectors = []; |
|
data(element, '_mdui_mutation', selectors); |
|
} |
|
if (selectors.indexOf(selector) === -1) { |
|
selectors.push(selector); |
|
apiInit.call(element, i, element); |
|
} |
|
} |
|
|
|
$.fn.mutation = function () { |
|
return this.each(function (i, element) { |
|
var $this = $(element); |
|
each(entries, function (selector, apiInit) { |
|
if ($this.is(selector)) { |
|
mutation(selector, apiInit, i, element); |
|
} |
|
$this.find(selector).each(function (i, element) { |
|
mutation(selector, apiInit, i, element); |
|
}); |
|
}); |
|
}); |
|
}; |
|
|
|
$.showOverlay = function (zIndex) { |
|
var $overlay = $('.mdui-overlay'); |
|
if ($overlay.length) { |
|
$overlay.data('_overlay_is_deleted', false); |
|
if (!isUndefined(zIndex)) { |
|
$overlay.css('z-index', zIndex); |
|
} |
|
} |
|
else { |
|
if (isUndefined(zIndex)) { |
|
zIndex = 2000; |
|
} |
|
$overlay = $('<div class="mdui-overlay">') |
|
.appendTo(document.body) |
|
.reflow() |
|
.css('z-index', zIndex); |
|
} |
|
var level = $overlay.data('_overlay_level') || 0; |
|
return $overlay.data('_overlay_level', ++level).addClass('mdui-overlay-show'); |
|
}; |
|
|
|
$.hideOverlay = function (force) { |
|
if ( force === void 0 ) force = false; |
|
|
|
var $overlay = $('.mdui-overlay'); |
|
if (!$overlay.length) { |
|
return; |
|
} |
|
var level = force ? 1 : $overlay.data('_overlay_level'); |
|
if (level > 1) { |
|
$overlay.data('_overlay_level', --level); |
|
return; |
|
} |
|
$overlay |
|
.data('_overlay_level', 0) |
|
.removeClass('mdui-overlay-show') |
|
.data('_overlay_is_deleted', true) |
|
.transitionEnd(function () { |
|
if ($overlay.data('_overlay_is_deleted')) { |
|
$overlay.remove(); |
|
} |
|
}); |
|
}; |
|
|
|
$.lockScreen = function () { |
|
var $body = $('body'); |
|
// 不直接把 body 设为 box-sizing: border-box,避免污染全局样式 |
|
var newBodyWidth = $body.width(); |
|
var level = $body.data('_lockscreen_level') || 0; |
|
$body |
|
.addClass('mdui-locked') |
|
.width(newBodyWidth) |
|
.data('_lockscreen_level', ++level); |
|
}; |
|
|
|
$.unlockScreen = function (force) { |
|
if ( force === void 0 ) force = false; |
|
|
|
var $body = $('body'); |
|
var level = force ? 1 : $body.data('_lockscreen_level'); |
|
if (level > 1) { |
|
$body.data('_lockscreen_level', --level); |
|
return; |
|
} |
|
$body.data('_lockscreen_level', 0).removeClass('mdui-locked').width(''); |
|
}; |
|
|
|
$.throttle = function (fn, delay) { |
|
if ( delay === void 0 ) delay = 16; |
|
|
|
var timer = null; |
|
return function () { |
|
var this$1 = this; |
|
var args = [], len = arguments.length; |
|
while ( len-- ) args[ len ] = arguments[ len ]; |
|
|
|
if (isNull(timer)) { |
|
timer = setTimeout(function () { |
|
fn.apply(this$1, args); |
|
timer = null; |
|
}, delay); |
|
} |
|
}; |
|
}; |
|
|
|
var GUID = {}; |
|
$.guid = function (name) { |
|
if (!isUndefined(name) && !isUndefined(GUID[name])) { |
|
return GUID[name]; |
|
} |
|
function s4() { |
|
return Math.floor((1 + Math.random()) * 0x10000) |
|
.toString(16) |
|
.substring(1); |
|
} |
|
var guid = '_' + |
|
s4() + |
|
s4() + |
|
'-' + |
|
s4() + |
|
'-' + |
|
s4() + |
|
'-' + |
|
s4() + |
|
'-' + |
|
s4() + |
|
s4() + |
|
s4(); |
|
if (!isUndefined(name)) { |
|
GUID[name] = guid; |
|
} |
|
return guid; |
|
}; |
|
|
|
mdui.mutation = function (selector, apiInit) { |
|
if (isUndefined(selector) || isUndefined(apiInit)) { |
|
$(document).mutation(); |
|
return; |
|
} |
|
entries[selector] = apiInit; |
|
$(selector).each(function (i, element) { return mutation(selector, apiInit, i, element); }); |
|
}; |
|
|
|
/** |
|
* 触发组件上的事件 |
|
* @param eventName 事件名 |
|
* @param componentName 组件名 |
|
* @param target 在该元素上触发事件 |
|
* @param instance 组件实例 |
|
* @param parameters 事件参数 |
|
*/ |
|
function componentEvent(eventName, componentName, target, instance, parameters) { |
|
if (!parameters) { |
|
parameters = {}; |
|
} |
|
// @ts-ignore |
|
parameters.inst = instance; |
|
var fullEventName = eventName + ".mdui." + componentName; |
|
// jQuery 事件 |
|
// @ts-ignore |
|
if (typeof jQuery !== 'undefined') { |
|
// @ts-ignore |
|
jQuery(target).trigger(fullEventName, parameters); |
|
} |
|
var $target = $(target); |
|
// mdui.jq 事件 |
|
$target.trigger(fullEventName, parameters); |
|
var eventParams = { |
|
bubbles: true, |
|
cancelable: true, |
|
detail: parameters, |
|
}; |
|
var eventObject = new CustomEvent(fullEventName, eventParams); |
|
// @ts-ignore |
|
eventObject._detail = parameters; |
|
$target[0].dispatchEvent(eventObject); |
|
} |
|
|
|
var $document = $(document); |
|
var $window = $(window); |
|
var $body = $('body'); |
|
|
|
var DEFAULT_OPTIONS = { |
|
tolerance: 5, |
|
offset: 0, |
|
initialClass: 'mdui-headroom', |
|
pinnedClass: 'mdui-headroom-pinned-top', |
|
unpinnedClass: 'mdui-headroom-unpinned-top', |
|
}; |
|
var Headroom = function Headroom(selector, options) { |
|
if ( options === void 0 ) options = {}; |
|
|
|
/** |
|
* 配置参数 |
|
*/ |
|
this.options = extend({}, DEFAULT_OPTIONS); |
|
/** |
|
* 当前 headroom 的状态 |
|
*/ |
|
this.state = 'pinned'; |
|
/** |
|
* 当前是否启用 |
|
*/ |
|
this.isEnable = false; |
|
/** |
|
* 上次滚动后,垂直方向的距离 |
|
*/ |
|
this.lastScrollY = 0; |
|
/** |
|
* AnimationFrame ID |
|
*/ |
|
this.rafId = 0; |
|
this.$element = $(selector).first(); |
|
extend(this.options, options); |
|
// tolerance 参数若为数值,转换为对象 |
|
var tolerance = this.options.tolerance; |
|
if (isNumber(tolerance)) { |
|
this.options.tolerance = { |
|
down: tolerance, |
|
up: tolerance, |
|
}; |
|
} |
|
this.enable(); |
|
}; |
|
/** |
|
* 滚动时的处理 |
|
*/ |
|
Headroom.prototype.onScroll = function onScroll () { |
|
var this$1 = this; |
|
|
|
this.rafId = window.requestAnimationFrame(function () { |
|
var currentScrollY = window.pageYOffset; |
|
var direction = currentScrollY > this$1.lastScrollY ? 'down' : 'up'; |
|
var tolerance = this$1.options.tolerance[direction]; |
|
var scrolled = Math.abs(currentScrollY - this$1.lastScrollY); |
|
var toleranceExceeded = scrolled >= tolerance; |
|
if (currentScrollY > this$1.lastScrollY && |
|
currentScrollY >= this$1.options.offset && |
|
toleranceExceeded) { |
|
this$1.unpin(); |
|
} |
|
else if ((currentScrollY < this$1.lastScrollY && toleranceExceeded) || |
|
currentScrollY <= this$1.options.offset) { |
|
this$1.pin(); |
|
} |
|
this$1.lastScrollY = currentScrollY; |
|
}); |
|
}; |
|
/** |
|
* 触发组件事件 |
|
* @param name |
|
*/ |
|
Headroom.prototype.triggerEvent = function triggerEvent (name) { |
|
componentEvent(name, 'headroom', this.$element, this); |
|
}; |
|
/** |
|
* 动画结束的回调 |
|
*/ |
|
Headroom.prototype.transitionEnd = function transitionEnd () { |
|
if (this.state === 'pinning') { |
|
this.state = 'pinned'; |
|
this.triggerEvent('pinned'); |
|
} |
|
if (this.state === 'unpinning') { |
|
this.state = 'unpinned'; |
|
this.triggerEvent('unpinned'); |
|
} |
|
}; |
|
/** |
|
* 使元素固定住 |
|
*/ |
|
Headroom.prototype.pin = function pin () { |
|
var this$1 = this; |
|
|
|
if (this.state === 'pinning' || |
|
this.state === 'pinned' || |
|
!this.$element.hasClass(this.options.initialClass)) { |
|
return; |
|
} |
|
this.triggerEvent('pin'); |
|
this.state = 'pinning'; |
|
this.$element |
|
.removeClass(this.options.unpinnedClass) |
|
.addClass(this.options.pinnedClass) |
|
.transitionEnd(function () { return this$1.transitionEnd(); }); |
|
}; |
|
/** |
|
* 使元素隐藏 |
|
*/ |
|
Headroom.prototype.unpin = function unpin () { |
|
var this$1 = this; |
|
|
|
if (this.state === 'unpinning' || |
|
this.state === 'unpinned' || |
|
!this.$element.hasClass(this.options.initialClass)) { |
|
return; |
|
} |
|
this.triggerEvent('unpin'); |
|
this.state = 'unpinning'; |
|
this.$element |
|
.removeClass(this.options.pinnedClass) |
|
.addClass(this.options.unpinnedClass) |
|
.transitionEnd(function () { return this$1.transitionEnd(); }); |
|
}; |
|
/** |
|
* 启用 headroom 插件 |
|
*/ |
|
Headroom.prototype.enable = function enable () { |
|
var this$1 = this; |
|
|
|
if (this.isEnable) { |
|
return; |
|
} |
|
this.isEnable = true; |
|
this.state = 'pinned'; |
|
this.$element |
|
.addClass(this.options.initialClass) |
|
.removeClass(this.options.pinnedClass) |
|
.removeClass(this.options.unpinnedClass); |
|
this.lastScrollY = window.pageYOffset; |
|
$window.on('scroll', function () { return this$1.onScroll(); }); |
|
}; |
|
/** |
|
* 禁用 headroom 插件 |
|
*/ |
|
Headroom.prototype.disable = function disable () { |
|
var this$1 = this; |
|
|
|
if (!this.isEnable) { |
|
return; |
|
} |
|
this.isEnable = false; |
|
this.$element |
|
.removeClass(this.options.initialClass) |
|
.removeClass(this.options.pinnedClass) |
|
.removeClass(this.options.unpinnedClass); |
|
$window.off('scroll', function () { return this$1.onScroll(); }); |
|
window.cancelAnimationFrame(this.rafId); |
|
}; |
|
/** |
|
* 获取当前状态。共包含四种状态:`pinning`、`pinned`、`unpinning`、`unpinned` |
|
*/ |
|
Headroom.prototype.getState = function getState () { |
|
return this.state; |
|
}; |
|
mdui.Headroom = Headroom; |
|
|
|
/** |
|
* 解析 DATA API 参数 |
|
* @param element 元素 |
|
* @param name 属性名 |
|
*/ |
|
function parseOptions(element, name) { |
|
var attr = $(element).attr(name); |
|
if (!attr) { |
|
return {}; |
|
} |
|
return new Function('', ("var json = " + attr + "; return JSON.parse(JSON.stringify(json));"))(); |
|
} |
|
|
|
var customAttr = 'mdui-headroom'; |
|
$(function () { |
|
mdui.mutation(("[" + customAttr + "]"), function () { |
|
new mdui.Headroom(this, parseOptions(this, customAttr)); |
|
}); |
|
}); |
|
|
|
var DEFAULT_OPTIONS$1 = { |
|
accordion: false, |
|
}; |
|
var CollapseAbstract = function CollapseAbstract(selector, options) { |
|
if ( options === void 0 ) options = {}; |
|
|
|
/** |
|
* 配置参数 |
|
*/ |
|
this.options = extend({}, DEFAULT_OPTIONS$1); |
|
// CSS 类名 |
|
var classPrefix = "mdui-" + (this.getNamespace()) + "-item"; |
|
this.classItem = classPrefix; |
|
this.classItemOpen = classPrefix + "-open"; |
|
this.classHeader = classPrefix + "-header"; |
|
this.classBody = classPrefix + "-body"; |
|
this.$element = $(selector).first(); |
|
extend(this.options, options); |
|
this.bindEvent(); |
|
}; |
|
/** |
|
* 绑定事件 |
|
*/ |
|
CollapseAbstract.prototype.bindEvent = function bindEvent () { |
|
// eslint-disable-next-line @typescript-eslint/no-this-alias |
|
var that = this; |
|
// 点击 header 时,打开/关闭 item |
|
this.$element.on('click', ("." + (this.classHeader)), function () { |
|
var $header = $(this); |
|
var $item = $header.parent(); |
|
var $items = that.getItems(); |
|
$items.each(function (_, item) { |
|
if ($item.is(item)) { |
|
that.toggle(item); |
|
} |
|
}); |
|
}); |
|
// 点击关闭按钮时,关闭 item |
|
this.$element.on('click', ("[mdui-" + (this.getNamespace()) + "-item-close]"), function () { |
|
var $target = $(this); |
|
var $item = $target.parents(("." + (that.classItem))).first(); |
|
that.close($item); |
|
}); |
|
}; |
|
/** |
|
* 指定 item 是否处于打开状态 |
|
* @param $item |
|
*/ |
|
CollapseAbstract.prototype.isOpen = function isOpen ($item) { |
|
return $item.hasClass(this.classItemOpen); |
|
}; |
|
/** |
|
* 获取所有 item |
|
*/ |
|
CollapseAbstract.prototype.getItems = function getItems () { |
|
return this.$element.children(("." + (this.classItem))); |
|
}; |
|
/** |
|
* 获取指定 item |
|
* @param item |
|
*/ |
|
CollapseAbstract.prototype.getItem = function getItem (item) { |
|
if (isNumber(item)) { |
|
return this.getItems().eq(item); |
|
} |
|
return $(item).first(); |
|
}; |
|
/** |
|
* 触发组件事件 |
|
* @param name 事件名 |
|
* @param $item 事件触发的目标 item |
|
*/ |
|
CollapseAbstract.prototype.triggerEvent = function triggerEvent (name, $item) { |
|
componentEvent(name, this.getNamespace(), $item, this); |
|
}; |
|
/** |
|
* 动画结束回调 |
|
* @param $content body 元素 |
|
* @param $item item 元素 |
|
*/ |
|
CollapseAbstract.prototype.transitionEnd = function transitionEnd ($content, $item) { |
|
if (this.isOpen($item)) { |
|
$content.transition(0).height('auto').reflow().transition(''); |
|
this.triggerEvent('opened', $item); |
|
} |
|
else { |
|
$content.height(''); |
|
this.triggerEvent('closed', $item); |
|
} |
|
}; |
|
/** |
|
* 打开指定面板项 |
|
* @param item 面板项的索引号、或 CSS 选择器、或 DOM 元素、或 JQ 对象 |
|
*/ |
|
CollapseAbstract.prototype.open = function open (item) { |
|
var this$1 = this; |
|
|
|
var $item = this.getItem(item); |
|
if (this.isOpen($item)) { |
|
return; |
|
} |
|
// 关闭其他项 |
|
if (this.options.accordion) { |
|
this.$element.children(("." + (this.classItemOpen))).each(function (_, element) { |
|
var $element = $(element); |
|
if (!$element.is($item)) { |
|
this$1.close($element); |
|
} |
|
}); |
|
} |
|
var $content = $item.children(("." + (this.classBody))); |
|
$content |
|
.height($content[0].scrollHeight) |
|
.transitionEnd(function () { return this$1.transitionEnd($content, $item); }); |
|
this.triggerEvent('open', $item); |
|
$item.addClass(this.classItemOpen); |
|
}; |
|
/** |
|
* 关闭指定面板项 |
|
* @param item 面板项的索引号、或 CSS 选择器、或 DOM 元素、或 JQ 对象 |
|
*/ |
|
CollapseAbstract.prototype.close = function close (item) { |
|
var this$1 = this; |
|
|
|
var $item = this.getItem(item); |
|
if (!this.isOpen($item)) { |
|
return; |
|
} |
|
var $content = $item.children(("." + (this.classBody))); |
|
this.triggerEvent('close', $item); |
|
$item.removeClass(this.classItemOpen); |
|
$content |
|
.transition(0) |
|
.height($content[0].scrollHeight) |
|
.reflow() |
|
.transition('') |
|
.height('') |
|
.transitionEnd(function () { return this$1.transitionEnd($content, $item); }); |
|
}; |
|
/** |
|
* 切换指定面板项的打开状态 |
|
* @param item 面板项的索引号、或 CSS 选择器、或 DOM 元素、或 JQ 对象 |
|
*/ |
|
CollapseAbstract.prototype.toggle = function toggle (item) { |
|
var $item = this.getItem(item); |
|
this.isOpen($item) ? this.close($item) : this.open($item); |
|
}; |
|
/** |
|
* 打开所有面板项 |
|
*/ |
|
CollapseAbstract.prototype.openAll = function openAll () { |
|
var this$1 = this; |
|
|
|
this.getItems().each(function (_, element) { return this$1.open(element); }); |
|
}; |
|
/** |
|
* 关闭所有面板项 |
|
*/ |
|
CollapseAbstract.prototype.closeAll = function closeAll () { |
|
var this$1 = this; |
|
|
|
this.getItems().each(function (_, element) { return this$1.close(element); }); |
|
}; |
|
|
|
var Collapse = /*@__PURE__*/(function (CollapseAbstract) { |
|
function Collapse () { |
|
CollapseAbstract.apply(this, arguments); |
|
} |
|
|
|
if ( CollapseAbstract ) Collapse.__proto__ = CollapseAbstract; |
|
Collapse.prototype = Object.create( CollapseAbstract && CollapseAbstract.prototype ); |
|
Collapse.prototype.constructor = Collapse; |
|
|
|
Collapse.prototype.getNamespace = function getNamespace () { |
|
return 'collapse'; |
|
}; |
|
|
|
return Collapse; |
|
}(CollapseAbstract)); |
|
mdui.Collapse = Collapse; |
|
|
|
var customAttr$1 = 'mdui-collapse'; |
|
$(function () { |
|
mdui.mutation(("[" + customAttr$1 + "]"), function () { |
|
new mdui.Collapse(this, parseOptions(this, customAttr$1)); |
|
}); |
|
}); |
|
|
|
var Panel = /*@__PURE__*/(function (CollapseAbstract) { |
|
function Panel () { |
|
CollapseAbstract.apply(this, arguments); |
|
} |
|
|
|
if ( CollapseAbstract ) Panel.__proto__ = CollapseAbstract; |
|
Panel.prototype = Object.create( CollapseAbstract && CollapseAbstract.prototype ); |
|
Panel.prototype.constructor = Panel; |
|
|
|
Panel.prototype.getNamespace = function getNamespace () { |
|
return 'panel'; |
|
}; |
|
|
|
return Panel; |
|
}(CollapseAbstract)); |
|
mdui.Panel = Panel; |
|
|
|
var customAttr$2 = 'mdui-panel'; |
|
$(function () { |
|
mdui.mutation(("[" + customAttr$2 + "]"), function () { |
|
new mdui.Panel(this, parseOptions(this, customAttr$2)); |
|
}); |
|
}); |
|
|
|
var Table = function Table(selector) { |
|
/** |
|
* 表头 tr 元素 |
|
*/ |
|
this.$thRow = $(); |
|
/** |
|
* 表格 body 中的 tr 元素 |
|
*/ |
|
this.$tdRows = $(); |
|
/** |
|
* 表头的 checkbox 元素 |
|
*/ |
|
this.$thCheckbox = $(); |
|
/** |
|
* 表格 body 中的 checkbox 元素 |
|
*/ |
|
this.$tdCheckboxs = $(); |
|
/** |
|
* 表格行是否可选择 |
|
*/ |
|
this.selectable = false; |
|
/** |
|
* 已选中的行数 |
|
*/ |
|
this.selectedRow = 0; |
|
this.$element = $(selector).first(); |
|
this.init(); |
|
}; |
|
/** |
|
* 初始化表格 |
|
*/ |
|
Table.prototype.init = function init () { |
|
this.$thRow = this.$element.find('thead tr'); |
|
this.$tdRows = this.$element.find('tbody tr'); |
|
this.selectable = this.$element.hasClass('mdui-table-selectable'); |
|
this.updateThCheckbox(); |
|
this.updateTdCheckbox(); |
|
this.updateNumericCol(); |
|
}; |
|
/** |
|
* 生成 checkbox 的 HTML 结构 |
|
* @param tag 标签名 |
|
*/ |
|
Table.prototype.createCheckboxHTML = function createCheckboxHTML (tag) { |
|
return ("<" + tag + " class=\"mdui-table-cell-checkbox\">" + |
|
'<label class="mdui-checkbox">' + |
|
'<input type="checkbox"/>' + |
|
'<i class="mdui-checkbox-icon"></i>' + |
|
'</label>' + |
|
"</" + tag + ">"); |
|
}; |
|
/** |
|
* 更新表头 checkbox 的状态 |
|
*/ |
|
Table.prototype.updateThCheckboxStatus = function updateThCheckboxStatus () { |
|
var checkbox = this.$thCheckbox[0]; |
|
var selectedRow = this.selectedRow; |
|
var tdRowsLength = this.$tdRows.length; |
|
checkbox.checked = selectedRow === tdRowsLength; |
|
checkbox.indeterminate = !!selectedRow && selectedRow !== tdRowsLength; |
|
}; |
|
/** |
|
* 更新表格行的 checkbox |
|
*/ |
|
Table.prototype.updateTdCheckbox = function updateTdCheckbox () { |
|
var this$1 = this; |
|
|
|
var rowSelectedClass = 'mdui-table-row-selected'; |
|
this.$tdRows.each(function (_, row) { |
|
var $row = $(row); |
|
// 移除旧的 checkbox |
|
$row.find('.mdui-table-cell-checkbox').remove(); |
|
if (!this$1.selectable) { |
|
return; |
|
} |
|
// 创建 DOM |
|
var $checkbox = $(this$1.createCheckboxHTML('td')) |
|
.prependTo($row) |
|
.find('input[type="checkbox"]'); |
|
// 默认选中的行 |
|
if ($row.hasClass(rowSelectedClass)) { |
|
$checkbox[0].checked = true; |
|
this$1.selectedRow++; |
|
} |
|
this$1.updateThCheckboxStatus(); |
|
// 绑定事件 |
|
$checkbox.on('change', function () { |
|
if ($checkbox[0].checked) { |
|
$row.addClass(rowSelectedClass); |
|
this$1.selectedRow++; |
|
} |
|
else { |
|
$row.removeClass(rowSelectedClass); |
|
this$1.selectedRow--; |
|
} |
|
this$1.updateThCheckboxStatus(); |
|
}); |
|
this$1.$tdCheckboxs = this$1.$tdCheckboxs.add($checkbox); |
|
}); |
|
}; |
|
/** |
|
* 更新表头的 checkbox |
|
*/ |
|
Table.prototype.updateThCheckbox = function updateThCheckbox () { |
|
var this$1 = this; |
|
|
|
// 移除旧的 checkbox |
|
this.$thRow.find('.mdui-table-cell-checkbox').remove(); |
|
if (!this.selectable) { |
|
return; |
|
} |
|
this.$thCheckbox = $(this.createCheckboxHTML('th')) |
|
.prependTo(this.$thRow) |
|
.find('input[type="checkbox"]') |
|
.on('change', function () { |
|
var isCheckedAll = this$1.$thCheckbox[0].checked; |
|
this$1.selectedRow = isCheckedAll ? this$1.$tdRows.length : 0; |
|
this$1.$tdCheckboxs.each(function (_, checkbox) { |
|
checkbox.checked = isCheckedAll; |
|
}); |
|
this$1.$tdRows.each(function (_, row) { |
|
isCheckedAll |
|
? $(row).addClass('mdui-table-row-selected') |
|
: $(row).removeClass('mdui-table-row-selected'); |
|
}); |
|
}); |
|
}; |
|
/** |
|
* 更新数值列 |
|
*/ |
|
Table.prototype.updateNumericCol = function updateNumericCol () { |
|
var this$1 = this; |
|
|
|
var numericClass = 'mdui-table-col-numeric'; |
|
this.$thRow.find('th').each(function (i, th) { |
|
var isNumericCol = $(th).hasClass(numericClass); |
|
this$1.$tdRows.each(function (_, row) { |
|
var $td = $(row).find('td').eq(i); |
|
isNumericCol |
|
? $td.addClass(numericClass) |
|
: $td.removeClass(numericClass); |
|
}); |
|
}); |
|
}; |
|
var dataName = '_mdui_table'; |
|
$(function () { |
|
mdui.mutation('.mdui-table', function () { |
|
var $element = $(this); |
|
if (!$element.data(dataName)) { |
|
$element.data(dataName, new Table($element)); |
|
} |
|
}); |
|
}); |
|
mdui.updateTables = function (selector) { |
|
var $elements = isUndefined(selector) ? $('.mdui-table') : $(selector); |
|
$elements.each(function (_, element) { |
|
var $element = $(element); |
|
var instance = $element.data(dataName); |
|
if (instance) { |
|
instance.init(); |
|
} |
|
else { |
|
$element.data(dataName, new Table($element)); |
|
} |
|
}); |
|
}; |
|
|
|
/** |
|
* touch 事件后的 500ms 内禁用 mousedown 事件 |
|
* |
|
* 不支持触控的屏幕上事件顺序为 mousedown -> mouseup -> click |
|
* 支持触控的屏幕上事件顺序为 touchstart -> touchend -> mousedown -> mouseup -> click |
|
* |
|
* 在每一个事件中都使用 TouchHandler.isAllow(event) 判断事件是否可执行 |
|
* 在 touchstart 和 touchmove、touchend、touchcancel |
|
* |
|
* (function () { |
|
* $document |
|
* .on(start, function (e) { |
|
* if (!isAllow(e)) { |
|
* return; |
|
* } |
|
* register(e); |
|
* console.log(e.type); |
|
* }) |
|
* .on(move, function (e) { |
|
* if (!isAllow(e)) { |
|
* return; |
|
* } |
|
* console.log(e.type); |
|
* }) |
|
* .on(end, function (e) { |
|
* if (!isAllow(e)) { |
|
* return; |
|
* } |
|
* console.log(e.type); |
|
* }) |
|
* .on(unlock, register); |
|
* })(); |
|
*/ |
|
var startEvent = 'touchstart mousedown'; |
|
var moveEvent = 'touchmove mousemove'; |
|
var endEvent = 'touchend mouseup'; |
|
var cancelEvent = 'touchcancel mouseleave'; |
|
var unlockEvent = 'touchend touchmove touchcancel'; |
|
var touches = 0; |
|
/** |
|
* 该事件是否被允许,在执行事件前调用该方法判断事件是否可以执行 |
|
* 若已触发 touch 事件,则阻止之后的鼠标事件 |
|
* @param event |
|
*/ |
|
function isAllow(event) { |
|
return !(touches && |
|
[ |
|
'mousedown', |
|
'mouseup', |
|
'mousemove', |
|
'click', |
|
'mouseover', |
|
'mouseout', |
|
'mouseenter', |
|
'mouseleave' ].indexOf(event.type) > -1); |
|
} |
|
/** |
|
* 在 touchstart 和 touchmove、touchend、touchcancel 事件中调用该方法注册事件 |
|
* @param event |
|
*/ |
|
function register(event) { |
|
if (event.type === 'touchstart') { |
|
// 触发了 touch 事件 |
|
touches += 1; |
|
} |
|
else if (['touchmove', 'touchend', 'touchcancel'].indexOf(event.type) > -1) { |
|
// touch 事件结束 500ms 后解除对鼠标事件的阻止 |
|
setTimeout(function () { |
|
if (touches) { |
|
touches -= 1; |
|
} |
|
}, 500); |
|
} |
|
} |
|
|
|
/** |
|
* Inspired by https://github.com/nolimits4web/Framework7/blob/master/src/js/fast-clicks.js |
|
* https://github.com/nolimits4web/Framework7/blob/master/LICENSE |
|
* |
|
* Inspired by https://github.com/fians/Waves |
|
*/ |
|
/** |
|
* 显示涟漪动画 |
|
* @param event |
|
* @param $ripple |
|
*/ |
|
function show(event, $ripple) { |
|
// 鼠标右键不产生涟漪 |
|
if (event instanceof MouseEvent && event.button === 2) { |
|
return; |
|
} |
|
// 点击位置坐标 |
|
var touchPosition = typeof TouchEvent !== 'undefined' && |
|
event instanceof TouchEvent && |
|
event.touches.length |
|
? event.touches[0] |
|
: event; |
|
var touchStartX = touchPosition.pageX; |
|
var touchStartY = touchPosition.pageY; |
|
// 涟漪位置 |
|
var offset = $ripple.offset(); |
|
var height = $ripple.innerHeight(); |
|
var width = $ripple.innerWidth(); |
|
var center = { |
|
x: touchStartX - offset.left, |
|
y: touchStartY - offset.top, |
|
}; |
|
var diameter = Math.max(Math.pow(Math.pow(height, 2) + Math.pow(width, 2), 0.5), 48); |
|
// 涟漪扩散动画 |
|
var translate = "translate3d(" + (-center.x + width / 2) + "px," + |
|
(-center.y + height / 2) + "px, 0) scale(1)"; |
|
// 涟漪的 DOM 结构,并缓存动画效果 |
|
$("<div class=\"mdui-ripple-wave\" " + |
|
"style=\"width:" + diameter + "px;height:" + diameter + "px;" + |
|
"margin-top:-" + (diameter / 2) + "px;margin-left:-" + (diameter / 2) + "px;" + |
|
"left:" + (center.x) + "px;top:" + (center.y) + "px;\"></div>") |
|
.data('_ripple_wave_translate', translate) |
|
.prependTo($ripple) |
|
.reflow() |
|
.transform(translate); |
|
} |
|
/** |
|
* 隐藏并移除涟漪 |
|
* @param $wave |
|
*/ |
|
function removeRipple($wave) { |
|
if (!$wave.length || $wave.data('_ripple_wave_removed')) { |
|
return; |
|
} |
|
$wave.data('_ripple_wave_removed', true); |
|
var removeTimer = setTimeout(function () { return $wave.remove(); }, 400); |
|
var translate = $wave.data('_ripple_wave_translate'); |
|
$wave |
|
.addClass('mdui-ripple-wave-fill') |
|
.transform(translate.replace('scale(1)', 'scale(1.01)')) |
|
.transitionEnd(function () { |
|
clearTimeout(removeTimer); |
|
$wave |
|
.addClass('mdui-ripple-wave-out') |
|
.transform(translate.replace('scale(1)', 'scale(1.01)')); |
|
removeTimer = setTimeout(function () { return $wave.remove(); }, 700); |
|
setTimeout(function () { |
|
$wave.transitionEnd(function () { |
|
clearTimeout(removeTimer); |
|
$wave.remove(); |
|
}); |
|
}, 0); |
|
}); |
|
} |
|
/** |
|
* 隐藏涟漪动画 |
|
* @param this |
|
*/ |
|
function hide() { |
|
var $ripple = $(this); |
|
$ripple.children('.mdui-ripple-wave').each(function (_, wave) { |
|
removeRipple($(wave)); |
|
}); |
|
$ripple.off((moveEvent + " " + endEvent + " " + cancelEvent), hide); |
|
} |
|
/** |
|
* 显示涟漪,并绑定 touchend 等事件 |
|
* @param event |
|
*/ |
|
function showRipple(event) { |
|
if (!isAllow(event)) { |
|
return; |
|
} |
|
register(event); |
|
// Chrome 59 点击滚动条时,会在 document 上触发事件 |
|
if (event.target === document) { |
|
return; |
|
} |
|
var $target = $(event.target); |
|
// 获取含 .mdui-ripple 类的元素 |
|
var $ripple = $target.hasClass('mdui-ripple') |
|
? $target |
|
: $target.parents('.mdui-ripple').first(); |
|
if (!$ripple.length) { |
|
return; |
|
} |
|
// 禁用状态的元素上不产生涟漪效果 |
|
if ($ripple.prop('disabled') || !isUndefined($ripple.attr('disabled'))) { |
|
return; |
|
} |
|
if (event.type === 'touchstart') { |
|
var hidden = false; |
|
// touchstart 触发指定时间后开始涟漪动画,避免手指滑动时也触发涟漪 |
|
var timer = setTimeout(function () { |
|
timer = 0; |
|
show(event, $ripple); |
|
}, 200); |
|
var hideRipple = function () { |
|
// 如果手指没有移动,且涟漪动画还没有开始,则开始涟漪动画 |
|
if (timer) { |
|
clearTimeout(timer); |
|
timer = 0; |
|
show(event, $ripple); |
|
} |
|
if (!hidden) { |
|
hidden = true; |
|
hide.call($ripple); |
|
} |
|
}; |
|
// 手指移动后,移除涟漪动画 |
|
var touchMove = function () { |
|
if (timer) { |
|
clearTimeout(timer); |
|
timer = 0; |
|
} |
|
hideRipple(); |
|
}; |
|
$ripple.on('touchmove', touchMove).on('touchend touchcancel', hideRipple); |
|
} |
|
else { |
|
show(event, $ripple); |
|
$ripple.on((moveEvent + " " + endEvent + " " + cancelEvent), hide); |
|
} |
|
} |
|
$(function () { |
|
$document.on(startEvent, showRipple).on(unlockEvent, register); |
|
}); |
|
|
|
var defaultData = { |
|
reInit: false, |
|
domLoadedEvent: false, |
|
}; |
|
/** |
|
* 输入框事件 |
|
* @param event |
|
* @param data |
|
*/ |
|
function inputEvent(event, data) { |
|
if ( data === void 0 ) data = {}; |
|
|
|
data = extend({}, defaultData, data); |
|
var input = event.target; |
|
var $input = $(input); |
|
var eventType = event.type; |
|
var value = $input.val(); |
|
// 文本框类型 |
|
var inputType = $input.attr('type') || ''; |
|
if (['checkbox', 'button', 'submit', 'range', 'radio', 'image'].indexOf(inputType) > -1) { |
|
return; |
|
} |
|
var $textfield = $input.parent('.mdui-textfield'); |
|
// 输入框是否聚焦 |
|
if (eventType === 'focus') { |
|
$textfield.addClass('mdui-textfield-focus'); |
|
} |
|
if (eventType === 'blur') { |
|
$textfield.removeClass('mdui-textfield-focus'); |
|
} |
|
// 输入框是否为空 |
|
if (eventType === 'blur' || eventType === 'input') { |
|
value |
|
? $textfield.addClass('mdui-textfield-not-empty') |
|
: $textfield.removeClass('mdui-textfield-not-empty'); |
|
} |
|
// 输入框是否禁用 |
|
input.disabled |
|
? $textfield.addClass('mdui-textfield-disabled') |
|
: $textfield.removeClass('mdui-textfield-disabled'); |
|
// 表单验证 |
|
if ((eventType === 'input' || eventType === 'blur') && |
|
!data.domLoadedEvent && |
|
input.validity) { |
|
input.validity.valid |
|
? $textfield.removeClass('mdui-textfield-invalid-html5') |
|
: $textfield.addClass('mdui-textfield-invalid-html5'); |
|
} |
|
// textarea 高度自动调整 |
|
if ($input.is('textarea')) { |
|
// IE bug:textarea 的值仅为多个换行,不含其他内容时,textarea 的高度不准确 |
|
// 此时,在计算高度前,在值的开头加入一个空格,计算完后,移除空格 |
|
var inputValue = value; |
|
var hasExtraSpace = false; |
|
if (inputValue.replace(/[\r\n]/g, '') === '') { |
|
$input.val(' ' + inputValue); |
|
hasExtraSpace = true; |
|
} |
|
// 设置 textarea 高度 |
|
$input.outerHeight(''); |
|
var height = $input.outerHeight(); |
|
var scrollHeight = input.scrollHeight; |
|
if (scrollHeight > height) { |
|
$input.outerHeight(scrollHeight); |
|
} |
|
// 计算完,还原 textarea 的值 |
|
if (hasExtraSpace) { |
|
$input.val(inputValue); |
|
} |
|
} |
|
// 实时字数统计 |
|
if (data.reInit) { |
|
$textfield.find('.mdui-textfield-counter').remove(); |
|
} |
|
var maxLength = $input.attr('maxlength'); |
|
if (maxLength) { |
|
if (data.reInit || data.domLoadedEvent) { |
|
$('<div class="mdui-textfield-counter">' + |
|
"<span class=\"mdui-textfield-counter-inputed\"></span> / " + maxLength + |
|
'</div>').appendTo($textfield); |
|
} |
|
$textfield |
|
.find('.mdui-textfield-counter-inputed') |
|
.text(value.length.toString()); |
|
} |
|
// 含 帮助文本、错误提示、字数统计 时,增加文本框底部内边距 |
|
if ($textfield.find('.mdui-textfield-helper').length || |
|
$textfield.find('.mdui-textfield-error').length || |
|
maxLength) { |
|
$textfield.addClass('mdui-textfield-has-bottom'); |
|
} |
|
} |
|
$(function () { |
|
// 绑定事件 |
|
$document.on('input focus blur', '.mdui-textfield-input', { useCapture: true }, inputEvent); |
|
// 可展开文本框展开 |
|
$document.on('click', '.mdui-textfield-expandable .mdui-textfield-icon', function () { |
|
$(this) |
|
.parents('.mdui-textfield') |
|
.addClass('mdui-textfield-expanded') |
|
.find('.mdui-textfield-input')[0] |
|
.focus(); |
|
}); |
|
// 可展开文本框关闭 |
|
$document.on('click', '.mdui-textfield-expanded .mdui-textfield-close', function () { |
|
$(this) |
|
.parents('.mdui-textfield') |
|
.removeClass('mdui-textfield-expanded') |
|
.find('.mdui-textfield-input') |
|
.val(''); |
|
}); |
|
/** |
|
* 初始化文本框 |
|
*/ |
|
mdui.mutation('.mdui-textfield', function () { |
|
$(this).find('.mdui-textfield-input').trigger('input', { |
|
domLoadedEvent: true, |
|
}); |
|
}); |
|
}); |
|
mdui.updateTextFields = function (selector) { |
|
var $elements = isUndefined(selector) ? $('.mdui-textfield') : $(selector); |
|
$elements.each(function (_, element) { |
|
$(element).find('.mdui-textfield-input').trigger('input', { |
|
reInit: true, |
|
}); |
|
}); |
|
}; |
|
|
|
/** |
|
* 滑块的值改变后修改滑块样式 |
|
* @param $slider |
|
*/ |
|
function updateValueStyle($slider) { |
|
var data = $slider.data(); |
|
var $track = data._slider_$track; |
|
var $fill = data._slider_$fill; |
|
var $thumb = data._slider_$thumb; |
|
var $input = data._slider_$input; |
|
var min = data._slider_min; |
|
var max = data._slider_max; |
|
var isDisabled = data._slider_disabled; |
|
var isDiscrete = data._slider_discrete; |
|
var $thumbText = data._slider_$thumbText; |
|
var value = $input.val(); |
|
var percent = ((value - min) / (max - min)) * 100; |
|
$fill.width((percent + "%")); |
|
$track.width(((100 - percent) + "%")); |
|
if (isDisabled) { |
|
$fill.css('padding-right', '6px'); |
|
$track.css('padding-left', '6px'); |
|
} |
|
$thumb.css('left', (percent + "%")); |
|
if (isDiscrete) { |
|
$thumbText.text(value); |
|
} |
|
percent === 0 |
|
? $slider.addClass('mdui-slider-zero') |
|
: $slider.removeClass('mdui-slider-zero'); |
|
} |
|
/** |
|
* 重新初始化滑块 |
|
* @param $slider |
|
*/ |
|
function reInit($slider) { |
|
var $track = $('<div class="mdui-slider-track"></div>'); |
|
var $fill = $('<div class="mdui-slider-fill"></div>'); |
|
var $thumb = $('<div class="mdui-slider-thumb"></div>'); |
|
var $input = $slider.find('input[type="range"]'); |
|
var isDisabled = $input[0].disabled; |
|
var isDiscrete = $slider.hasClass('mdui-slider-discrete'); |
|
// 禁用状态 |
|
isDisabled |
|
? $slider.addClass('mdui-slider-disabled') |
|
: $slider.removeClass('mdui-slider-disabled'); |
|
// 重新填充 HTML |
|
$slider.find('.mdui-slider-track').remove(); |
|
$slider.find('.mdui-slider-fill').remove(); |
|
$slider.find('.mdui-slider-thumb').remove(); |
|
$slider.append($track).append($fill).append($thumb); |
|
// 间续型滑块 |
|
var $thumbText = $(); |
|
if (isDiscrete) { |
|
$thumbText = $('<span></span>'); |
|
$thumb.empty().append($thumbText); |
|
} |
|
$slider.data('_slider_$track', $track); |
|
$slider.data('_slider_$fill', $fill); |
|
$slider.data('_slider_$thumb', $thumb); |
|
$slider.data('_slider_$input', $input); |
|
$slider.data('_slider_min', $input.attr('min')); |
|
$slider.data('_slider_max', $input.attr('max')); |
|
$slider.data('_slider_disabled', isDisabled); |
|
$slider.data('_slider_discrete', isDiscrete); |
|
$slider.data('_slider_$thumbText', $thumbText); |
|
// 设置默认值 |
|
updateValueStyle($slider); |
|
} |
|
var rangeSelector = '.mdui-slider input[type="range"]'; |
|
$(function () { |
|
// 滑块滑动事件 |
|
$document.on('input change', rangeSelector, function () { |
|
var $slider = $(this).parent(); |
|
updateValueStyle($slider); |
|
}); |
|
// 开始触摸滑块事件 |
|
$document.on(startEvent, rangeSelector, function (event) { |
|
if (!isAllow(event)) { |
|
return; |
|
} |
|
register(event); |
|
if (this.disabled) { |
|
return; |
|
} |
|
var $slider = $(this).parent(); |
|
$slider.addClass('mdui-slider-focus'); |
|
}); |
|
// 结束触摸滑块事件 |
|
$document.on(endEvent, rangeSelector, function (event) { |
|
if (!isAllow(event)) { |
|
return; |
|
} |
|
if (this.disabled) { |
|
return; |
|
} |
|
var $slider = $(this).parent(); |
|
$slider.removeClass('mdui-slider-focus'); |
|
}); |
|
$document.on(unlockEvent, rangeSelector, register); |
|
/** |
|
* 初始化滑块 |
|
*/ |
|
mdui.mutation('.mdui-slider', function () { |
|
reInit($(this)); |
|
}); |
|
}); |
|
mdui.updateSliders = function (selector) { |
|
var $elements = isUndefined(selector) ? $('.mdui-slider') : $(selector); |
|
$elements.each(function (_, element) { |
|
reInit($(element)); |
|
}); |
|
}; |
|
|
|
var DEFAULT_OPTIONS$2 = { |
|
trigger: 'hover', |
|
}; |
|
var Fab = function Fab(selector, options) { |
|
var this$1 = this; |
|
if ( options === void 0 ) options = {}; |
|
|
|
/** |
|
* 配置参数 |
|
*/ |
|
this.options = extend({}, DEFAULT_OPTIONS$2); |
|
/** |
|
* 当前 fab 的状态 |
|
*/ |
|
this.state = 'closed'; |
|
this.$element = $(selector).first(); |
|
extend(this.options, options); |
|
this.$btn = this.$element.find('.mdui-fab'); |
|
this.$dial = this.$element.find('.mdui-fab-dial'); |
|
this.$dialBtns = this.$dial.find('.mdui-fab'); |
|
if (this.options.trigger === 'hover') { |
|
this.$btn.on('touchstart mouseenter', function () { return this$1.open(); }); |
|
this.$element.on('mouseleave', function () { return this$1.close(); }); |
|
} |
|
if (this.options.trigger === 'click') { |
|
this.$btn.on(startEvent, function () { return this$1.open(); }); |
|
} |
|
// 触摸屏幕其他地方关闭快速拨号 |
|
$document.on(startEvent, function (event) { |
|
if ($(event.target).parents('.mdui-fab-wrapper').length) { |
|
return; |
|
} |
|
this$1.close(); |
|
}); |
|
}; |
|
/** |
|
* 触发组件事件 |
|
* @param name |
|
*/ |
|
Fab.prototype.triggerEvent = function triggerEvent (name) { |
|
componentEvent(name, 'fab', this.$element, this); |
|
}; |
|
/** |
|
* 当前是否为打开状态 |
|
*/ |
|
Fab.prototype.isOpen = function isOpen () { |
|
return this.state === 'opening' || this.state === 'opened'; |
|
}; |
|
/** |
|
* 打开快速拨号菜单 |
|
*/ |
|
Fab.prototype.open = function open () { |
|
var this$1 = this; |
|
|
|
if (this.isOpen()) { |
|
return; |
|
} |
|
// 为菜单中的按钮添加不同的 transition-delay |
|
this.$dialBtns.each(function (index, btn) { |
|
var delay = (15 * (this$1.$dialBtns.length - index)) + "ms"; |
|
btn.style.transitionDelay = delay; |
|
btn.style.webkitTransitionDelay = delay; |
|
}); |
|
this.$dial.css('height', 'auto').addClass('mdui-fab-dial-show'); |
|
// 如果按钮中存在 .mdui-fab-opened 的图标,则进行图标切换 |
|
if (this.$btn.find('.mdui-fab-opened').length) { |
|
this.$btn.addClass('mdui-fab-opened'); |
|
} |
|
this.state = 'opening'; |
|
this.triggerEvent('open'); |
|
// 打开顺序为从下到上逐个打开,最上面的打开后才表示动画完成 |
|
this.$dialBtns.first().transitionEnd(function () { |
|
if (this$1.$btn.hasClass('mdui-fab-opened')) { |
|
this$1.state = 'opened'; |
|
this$1.triggerEvent('opened'); |
|
} |
|
}); |
|
}; |
|
/** |
|
* 关闭快速拨号菜单 |
|
*/ |
|
Fab.prototype.close = function close () { |
|
var this$1 = this; |
|
|
|
if (!this.isOpen()) { |
|
return; |
|
} |
|
// 为菜单中的按钮添加不同的 transition-delay |
|
this.$dialBtns.each(function (index, btn) { |
|
var delay = (15 * index) + "ms"; |
|
btn.style.transitionDelay = delay; |
|
btn.style.webkitTransitionDelay = delay; |
|
}); |
|
this.$dial.removeClass('mdui-fab-dial-show'); |
|
this.$btn.removeClass('mdui-fab-opened'); |
|
this.state = 'closing'; |
|
this.triggerEvent('close'); |
|
// 从上往下依次关闭,最后一个关闭后才表示动画完成 |
|
this.$dialBtns.last().transitionEnd(function () { |
|
if (this$1.$btn.hasClass('mdui-fab-opened')) { |
|
return; |
|
} |
|
this$1.state = 'closed'; |
|
this$1.triggerEvent('closed'); |
|
this$1.$dial.css('height', 0); |
|
}); |
|
}; |
|
/** |
|
* 切换快速拨号菜单的打开状态 |
|
*/ |
|
Fab.prototype.toggle = function toggle () { |
|
this.isOpen() ? this.close() : this.open(); |
|
}; |
|
/** |
|
* 以动画的形式显示整个浮动操作按钮 |
|
*/ |
|
Fab.prototype.show = function show () { |
|
this.$element.removeClass('mdui-fab-hide'); |
|
}; |
|
/** |
|
* 以动画的形式隐藏整个浮动操作按钮 |
|
*/ |
|
Fab.prototype.hide = function hide () { |
|
this.$element.addClass('mdui-fab-hide'); |
|
}; |
|
/** |
|
* 返回当前快速拨号菜单的打开状态。共包含四种状态:`opening`、`opened`、`closing`、`closed` |
|
*/ |
|
Fab.prototype.getState = function getState () { |
|
return this.state; |
|
}; |
|
mdui.Fab = Fab; |
|
|
|
var customAttr$3 = 'mdui-fab'; |
|
$(function () { |
|
// mouseenter 不冒泡,无法进行事件委托,这里用 mouseover 代替。 |
|
// 不管是 click 、 mouseover 还是 touchstart ,都先初始化。 |
|
$document.on('touchstart mousedown mouseover', ("[" + customAttr$3 + "]"), function () { |
|
new mdui.Fab(this, parseOptions(this, customAttr$3)); |
|
}); |
|
}); |
|
|
|
/** |
|
* 最终生成的元素结构为: |
|
* <select class="mdui-select" mdui-select="{position: 'top'}" style="display: none;"> // $native |
|
* <option value="1">State 1</option> |
|
* <option value="2">State 2</option> |
|
* <option value="3" disabled="">State 3</option> |
|
* </select> |
|
* <div class="mdui-select mdui-select-position-top" style="" id="88dec0e4-d4a2-c6d0-0e7f-1ba4501e0553"> // $element |
|
* <span class="mdui-select-selected">State 1</span> // $selected |
|
* <div class="mdui-select-menu" style="transform-origin: center 100% 0px;"> // $menu |
|
* <div class="mdui-select-menu-item mdui-ripple" selected="">State 1</div> // $items |
|
* <div class="mdui-select-menu-item mdui-ripple">State 2</div> |
|
* <div class="mdui-select-menu-item mdui-ripple" disabled="">State 3</div> |
|
* </div> |
|
* </div> |
|
*/ |
|
var DEFAULT_OPTIONS$3 = { |
|
position: 'auto', |
|
gutter: 16, |
|
}; |
|
var Select = function Select(selector, options) { |
|
var this$1 = this; |
|
if ( options === void 0 ) options = {}; |
|
|
|
/** |
|
* 生成的 `<div class="mdui-select">` 元素的 JQ 对象 |
|
*/ |
|
this.$element = $(); |
|
/** |
|
* 配置参数 |
|
*/ |
|
this.options = extend({}, DEFAULT_OPTIONS$3); |
|
/** |
|
* select 的 size 属性的值,根据该值设置 select 的高度 |
|
*/ |
|
this.size = 0; |
|
/** |
|
* 占位元素,显示已选中菜单项的文本 |
|
*/ |
|
this.$selected = $(); |
|
/** |
|
* 菜单项的外层元素的 JQ 对象 |
|
*/ |
|
this.$menu = $(); |
|
/** |
|
* 菜单项数组的 JQ 对象 |
|
*/ |
|
this.$items = $(); |
|
/** |
|
* 当前选中的菜单项的索引号 |
|
*/ |
|
this.selectedIndex = 0; |
|
/** |
|
* 当前选中菜单项的文本 |
|
*/ |
|
this.selectedText = ''; |
|
/** |
|
* 当前选中菜单项的值 |
|
*/ |
|
this.selectedValue = ''; |
|
/** |
|
* 当前 select 的状态 |
|
*/ |
|
this.state = 'closed'; |
|
this.$native = $(selector).first(); |
|
this.$native.hide(); |
|
extend(this.options, options); |
|
// 为当前 select 生成唯一 ID |
|
this.uniqueID = $.guid(); |
|
// 生成 select |
|
this.handleUpdate(); |
|
// 点击 select 外面区域关闭 |
|
$document.on('click touchstart', function (event) { |
|
var $target = $(event.target); |
|
if (this$1.isOpen() && |
|
!$target.is(this$1.$element) && |
|
!contains(this$1.$element[0], $target[0])) { |
|
this$1.close(); |
|
} |
|
}); |
|
}; |
|
/** |
|
* 调整菜单位置 |
|
*/ |
|
Select.prototype.readjustMenu = function readjustMenu () { |
|
var windowHeight = $window.height(); |
|
// mdui-select 高度 |
|
var elementHeight = this.$element.height(); |
|
// 菜单项高度 |
|
var $itemFirst = this.$items.first(); |
|
var itemHeight = $itemFirst.height(); |
|
var itemMargin = parseInt($itemFirst.css('margin-top')); |
|
// 菜单高度 |
|
var menuWidth = this.$element.innerWidth() + 0.01; // 必须比真实宽度多一点,不然会出现省略号 |
|
var menuHeight = itemHeight * this.size + itemMargin * 2; |
|
// mdui-select 在窗口中的位置 |
|
var elementTop = this.$element[0].getBoundingClientRect().top; |
|
var transformOriginY; |
|
var menuMarginTop; |
|
if (this.options.position === 'bottom') { |
|
menuMarginTop = elementHeight; |
|
transformOriginY = '0px'; |
|
} |
|
else if (this.options.position === 'top') { |
|
menuMarginTop = -menuHeight - 1; |
|
transformOriginY = '100%'; |
|
} |
|
else { |
|
// 菜单高度不能超过窗口高度 |
|
var menuMaxHeight = windowHeight - this.options.gutter * 2; |
|
if (menuHeight > menuMaxHeight) { |
|
menuHeight = menuMaxHeight; |
|
} |
|
// 菜单的 margin-top |
|
menuMarginTop = -(itemMargin + |
|
this.selectedIndex * itemHeight + |
|
(itemHeight - elementHeight) / 2); |
|
var menuMaxMarginTop = -(itemMargin + |
|
(this.size - 1) * itemHeight + |
|
(itemHeight - elementHeight) / 2); |
|
if (menuMarginTop < menuMaxMarginTop) { |
|
menuMarginTop = menuMaxMarginTop; |
|
} |
|
// 菜单不能超出窗口 |
|
var menuTop = elementTop + menuMarginTop; |
|
if (menuTop < this.options.gutter) { |
|
// 不能超出窗口上方 |
|
menuMarginTop = -(elementTop - this.options.gutter); |
|
} |
|
else if (menuTop + menuHeight + this.options.gutter > windowHeight) { |
|
// 不能超出窗口下方 |
|
menuMarginTop = -(elementTop + |
|
menuHeight + |
|
this.options.gutter - |
|
windowHeight); |
|
} |
|
// transform 的 Y 轴坐标 |
|
transformOriginY = (this.selectedIndex * itemHeight + itemHeight / 2 + itemMargin) + "px"; |
|
} |
|
// 设置样式 |
|
this.$element.innerWidth(menuWidth); |
|
this.$menu |
|
.innerWidth(menuWidth) |
|
.height(menuHeight) |
|
.css({ |
|
'margin-top': menuMarginTop + 'px', |
|
'transform-origin': 'center ' + transformOriginY + ' 0', |
|
}); |
|
}; |
|
/** |
|
* select 是否为打开状态 |
|
*/ |
|
Select.prototype.isOpen = function isOpen () { |
|
return this.state === 'opening' || this.state === 'opened'; |
|
}; |
|
/** |
|
* 对原生 select 组件进行了修改后,需要调用该方法 |
|
*/ |
|
Select.prototype.handleUpdate = function handleUpdate () { |
|
var this$1 = this; |
|
|
|
if (this.isOpen()) { |
|
this.close(); |
|
} |
|
this.selectedValue = this.$native.val(); |
|
var itemsData = []; |
|
this.$items = $(); |
|
// 生成 HTML |
|
this.$native.find('option').each(function (index, option) { |
|
var text = option.textContent || ''; |
|
var value = option.value; |
|
var disabled = option.disabled; |
|
var selected = this$1.selectedValue === value; |
|
itemsData.push({ |
|
value: value, |
|
text: text, |
|
disabled: disabled, |
|
selected: selected, |
|
index: index, |
|
}); |
|
if (selected) { |
|
this$1.selectedText = text; |
|
this$1.selectedIndex = index; |
|
} |
|
this$1.$items = this$1.$items.add('<div class="mdui-select-menu-item mdui-ripple"' + |
|
(disabled ? ' disabled' : '') + |
|
(selected ? ' selected' : '') + |
|
">" + text + "</div>"); |
|
}); |
|
this.$selected = $(("<span class=\"mdui-select-selected\">" + (this.selectedText) + "</span>")); |
|
this.$element = $("<div class=\"mdui-select mdui-select-position-" + (this.options.position) + "\" " + |
|
"style=\"" + (this.$native.attr('style')) + "\" " + |
|
"id=\"" + (this.uniqueID) + "\"></div>") |
|
.show() |
|
.append(this.$selected); |
|
this.$menu = $('<div class="mdui-select-menu"></div>') |
|
.appendTo(this.$element) |
|
.append(this.$items); |
|
$(("#" + (this.uniqueID))).remove(); |
|
this.$native.after(this.$element); |
|
// 根据 select 的 size 属性设置高度 |
|
this.size = parseInt(this.$native.attr('size') || '0'); |
|
if (this.size <= 0) { |
|
this.size = this.$items.length; |
|
if (this.size > 8) { |
|
this.size = 8; |
|
} |
|
} |
|
// 点击选项时关闭下拉菜单 |
|
// eslint-disable-next-line @typescript-eslint/no-this-alias |
|
var that = this; |
|
this.$items.on('click', function () { |
|
if (that.state === 'closing') { |
|
return; |
|
} |
|
var $item = $(this); |
|
var index = $item.index(); |
|
var data = itemsData[index]; |
|
if (data.disabled) { |
|
return; |
|
} |
|
that.$selected.text(data.text); |
|
that.$native.val(data.value); |
|
that.$items.removeAttr('selected'); |
|
$item.attr('selected', ''); |
|
that.selectedIndex = data.index; |
|
that.selectedValue = data.value; |
|
that.selectedText = data.text; |
|
that.$native.trigger('change'); |
|
that.close(); |
|
}); |
|
// 点击 $element 时打开下拉菜单 |
|
this.$element.on('click', function (event) { |
|
var $target = $(event.target); |
|
// 在菜单上点击时不打开 |
|
if ($target.is('.mdui-select-menu') || |
|
$target.is('.mdui-select-menu-item')) { |
|
return; |
|
} |
|
this$1.toggle(); |
|
}); |
|
}; |
|
/** |
|
* 动画结束的回调 |
|
*/ |
|
Select.prototype.transitionEnd = function transitionEnd () { |
|
this.$element.removeClass('mdui-select-closing'); |
|
if (this.state === 'opening') { |
|
this.state = 'opened'; |
|
this.triggerEvent('opened'); |
|
this.$menu.css('overflow-y', 'auto'); |
|
} |
|
if (this.state === 'closing') { |
|
this.state = 'closed'; |
|
this.triggerEvent('closed'); |
|
// 恢复样式 |
|
this.$element.innerWidth(''); |
|
this.$menu.css({ |
|
'margin-top': '', |
|
height: '', |
|
width: '', |
|
}); |
|
} |
|
}; |
|
/** |
|
* 触发组件事件 |
|
* @param name |
|
*/ |
|
Select.prototype.triggerEvent = function triggerEvent (name) { |
|
componentEvent(name, 'select', this.$native, this); |
|
}; |
|
/** |
|
* 切换下拉菜单的打开状态 |
|
*/ |
|
Select.prototype.toggle = function toggle () { |
|
this.isOpen() ? this.close() : this.open(); |
|
}; |
|
/** |
|
* 打开下拉菜单 |
|
*/ |
|
Select.prototype.open = function open () { |
|
var this$1 = this; |
|
|
|
if (this.isOpen()) { |
|
return; |
|
} |
|
this.state = 'opening'; |
|
this.triggerEvent('open'); |
|
this.readjustMenu(); |
|
this.$element.addClass('mdui-select-open'); |
|
this.$menu.transitionEnd(function () { return this$1.transitionEnd(); }); |
|
}; |
|
/** |
|
* 关闭下拉菜单 |
|
*/ |
|
Select.prototype.close = function close () { |
|
var this$1 = this; |
|
|
|
if (!this.isOpen()) { |
|
return; |
|
} |
|
this.state = 'closing'; |
|
this.triggerEvent('close'); |
|
this.$menu.css('overflow-y', ''); |
|
this.$element |
|
.removeClass('mdui-select-open') |
|
.addClass('mdui-select-closing'); |
|
this.$menu.transitionEnd(function () { return this$1.transitionEnd(); }); |
|
}; |
|
/** |
|
* 获取当前菜单的状态。共包含四种状态:`opening`、`opened`、`closing`、`closed` |
|
*/ |
|
Select.prototype.getState = function getState () { |
|
return this.state; |
|
}; |
|
mdui.Select = Select; |
|
|
|
var customAttr$4 = 'mdui-select'; |
|
$(function () { |
|
mdui.mutation(("[" + customAttr$4 + "]"), function () { |
|
new mdui.Select(this, parseOptions(this, customAttr$4)); |
|
}); |
|
}); |
|
|
|
$(function () { |
|
// 滚动时隐藏应用栏 |
|
mdui.mutation('.mdui-appbar-scroll-hide', function () { |
|
new mdui.Headroom(this); |
|
}); |
|
// 滚动时只隐藏应用栏中的工具栏 |
|
mdui.mutation('.mdui-appbar-scroll-toolbar-hide', function () { |
|
new mdui.Headroom(this, { |
|
pinnedClass: 'mdui-headroom-pinned-toolbar', |
|
unpinnedClass: 'mdui-headroom-unpinned-toolbar', |
|
}); |
|
}); |
|
}); |
|
|
|
var DEFAULT_OPTIONS$4 = { |
|
trigger: 'click', |
|
loop: false, |
|
}; |
|
var Tab = function Tab(selector, options) { |
|
var this$1 = this; |
|
if ( options === void 0 ) options = {}; |
|
|
|
/** |
|
* 配置参数 |
|
*/ |
|
this.options = extend({}, DEFAULT_OPTIONS$4); |
|
/** |
|
* 当前激活的 tab 的索引号。为 -1 时表示没有激活的选项卡,或不存在选项卡 |
|
*/ |
|
this.activeIndex = -1; |
|
this.$element = $(selector).first(); |
|
extend(this.options, options); |
|
this.$tabs = this.$element.children('a'); |
|
this.$indicator = $('<div class="mdui-tab-indicator"></div>').appendTo(this.$element); |
|
// 根据 url hash 获取默认激活的选项卡 |
|
var hash = window.location.hash; |
|
if (hash) { |
|
this.$tabs.each(function (index, tab) { |
|
if ($(tab).attr('href') === hash) { |
|
this$1.activeIndex = index; |
|
return false; |
|
} |
|
return true; |
|
}); |
|
} |
|
// 含 .mdui-tab-active 的元素默认激活 |
|
if (this.activeIndex === -1) { |
|
this.$tabs.each(function (index, tab) { |
|
if ($(tab).hasClass('mdui-tab-active')) { |
|
this$1.activeIndex = index; |
|
return false; |
|
} |
|
return true; |
|
}); |
|
} |
|
// 存在选项卡时,默认激活第一个选项卡 |
|
if (this.$tabs.length && this.activeIndex === -1) { |
|
this.activeIndex = 0; |
|
} |
|
// 设置激活状态选项卡 |
|
this.setActive(); |
|
// 监听窗口大小变化事件,调整指示器位置 |
|
$window.on('resize', $.throttle(function () { return this$1.setIndicatorPosition(); }, 100)); |
|
// 监听点击选项卡事件 |
|
this.$tabs.each(function (_, tab) { |
|
this$1.bindTabEvent(tab); |
|
}); |
|
}; |
|
/** |
|
* 指定选项卡是否已禁用 |
|
* @param $tab |
|
*/ |
|
Tab.prototype.isDisabled = function isDisabled ($tab) { |
|
return $tab.attr('disabled') !== undefined; |
|
}; |
|
/** |
|
* 绑定在 Tab 上点击或悬浮的事件 |
|
* @param tab |
|
*/ |
|
Tab.prototype.bindTabEvent = function bindTabEvent (tab) { |
|
var this$1 = this; |
|
|
|
var $tab = $(tab); |
|
// 点击或鼠标移入触发的事件 |
|
var clickEvent = function () { |
|
// 禁用状态的选项卡无法选中 |
|
if (this$1.isDisabled($tab)) { |
|
return false; |
|
} |
|
this$1.activeIndex = this$1.$tabs.index(tab); |
|
this$1.setActive(); |
|
}; |
|
// 无论 trigger 是 click 还是 hover,都会响应 click 事件 |
|
$tab.on('click', clickEvent); |
|
// trigger 为 hover 时,额外响应 mouseenter 事件 |
|
if (this.options.trigger === 'hover') { |
|
$tab.on('mouseenter', clickEvent); |
|
} |
|
// 阻止链接的默认点击动作 |
|
$tab.on('click', function () { |
|
if (($tab.attr('href') || '').indexOf('#') === 0) { |
|
return false; |
|
} |
|
}); |
|
}; |
|
/** |
|
* 触发组件事件 |
|
* @param name |
|
* @param $element |
|
* @param parameters |
|
*/ |
|
Tab.prototype.triggerEvent = function triggerEvent (name, $element, parameters) { |
|
if ( parameters === void 0 ) parameters = {}; |
|
|
|
componentEvent(name, 'tab', $element, this, parameters); |
|
}; |
|
/** |
|
* 设置激活状态的选项卡 |
|
*/ |
|
Tab.prototype.setActive = function setActive () { |
|
var this$1 = this; |
|
|
|
this.$tabs.each(function (index, tab) { |
|
var $tab = $(tab); |
|
var targetId = $tab.attr('href') || ''; |
|
// 设置选项卡激活状态 |
|
if (index === this$1.activeIndex && !this$1.isDisabled($tab)) { |
|
if (!$tab.hasClass('mdui-tab-active')) { |
|
this$1.triggerEvent('change', this$1.$element, { |
|
index: this$1.activeIndex, |
|
id: targetId.substr(1), |
|
}); |
|
this$1.triggerEvent('show', $tab); |
|
$tab.addClass('mdui-tab-active'); |
|
} |
|
$(targetId).show(); |
|
this$1.setIndicatorPosition(); |
|
} |
|
else { |
|
$tab.removeClass('mdui-tab-active'); |
|
$(targetId).hide(); |
|
} |
|
}); |
|
}; |
|
/** |
|
* 设置选项卡指示器的位置 |
|
*/ |
|
Tab.prototype.setIndicatorPosition = function setIndicatorPosition () { |
|
// 选项卡数量为 0 时,不显示指示器 |
|
if (this.activeIndex === -1) { |
|
this.$indicator.css({ |
|
left: 0, |
|
width: 0, |
|
}); |
|
return; |
|
} |
|
var $activeTab = this.$tabs.eq(this.activeIndex); |
|
if (this.isDisabled($activeTab)) { |
|
return; |
|
} |
|
var activeTabOffset = $activeTab.offset(); |
|
this.$indicator.css({ |
|
left: ((activeTabOffset.left + |
|
this.$element[0].scrollLeft - |
|
this.$element[0].getBoundingClientRect().left) + "px"), |
|
width: (($activeTab.innerWidth()) + "px"), |
|
}); |
|
}; |
|
/** |
|
* 切换到下一个选项卡 |
|
*/ |
|
Tab.prototype.next = function next () { |
|
if (this.activeIndex === -1) { |
|
return; |
|
} |
|
if (this.$tabs.length > this.activeIndex + 1) { |
|
this.activeIndex++; |
|
} |
|
else if (this.options.loop) { |
|
this.activeIndex = 0; |
|
} |
|
this.setActive(); |
|
}; |
|
/** |
|
* 切换到上一个选项卡 |
|
*/ |
|
Tab.prototype.prev = function prev () { |
|
if (this.activeIndex === -1) { |
|
return; |
|
} |
|
if (this.activeIndex > 0) { |
|
this.activeIndex--; |
|
} |
|
else if (this.options.loop) { |
|
this.activeIndex = this.$tabs.length - 1; |
|
} |
|
this.setActive(); |
|
}; |
|
/** |
|
* 显示指定索引号、或指定id的选项卡 |
|
* @param index 索引号、或id |
|
*/ |
|
Tab.prototype.show = function show (index) { |
|
var this$1 = this; |
|
|
|
if (this.activeIndex === -1) { |
|
return; |
|
} |
|
if (isNumber(index)) { |
|
this.activeIndex = index; |
|
} |
|
else { |
|
this.$tabs.each(function (i, tab) { |
|
if (tab.id === index) { |
|
this$1.activeIndex === i; |
|
return false; |
|
} |
|
}); |
|
} |
|
this.setActive(); |
|
}; |
|
/** |
|
* 在父元素的宽度变化时,需要调用该方法重新调整指示器位置 |
|
* 在添加或删除选项卡时,需要调用该方法 |
|
*/ |
|
Tab.prototype.handleUpdate = function handleUpdate () { |
|
var this$1 = this; |
|
|
|
var $oldTabs = this.$tabs; // 旧的 tabs JQ对象 |
|
var $newTabs = this.$element.children('a'); // 新的 tabs JQ对象 |
|
var oldTabsElement = $oldTabs.get(); // 旧的 tabs 元素数组 |
|
var newTabsElement = $newTabs.get(); // 新的 tabs 元素数组 |
|
if (!$newTabs.length) { |
|
this.activeIndex = -1; |
|
this.$tabs = $newTabs; |
|
this.setIndicatorPosition(); |
|
return; |
|
} |
|
// 重新遍历选项卡,找出新增的选项卡 |
|
$newTabs.each(function (index, tab) { |
|
// 有新增的选项卡 |
|
if (oldTabsElement.indexOf(tab) < 0) { |
|
this$1.bindTabEvent(tab); |
|
if (this$1.activeIndex === -1) { |
|
this$1.activeIndex = 0; |
|
} |
|
else if (index <= this$1.activeIndex) { |
|
this$1.activeIndex++; |
|
} |
|
} |
|
}); |
|
// 找出被移除的选项卡 |
|
$oldTabs.each(function (index, tab) { |
|
// 有被移除的选项卡 |
|
if (newTabsElement.indexOf(tab) < 0) { |
|
if (index < this$1.activeIndex) { |
|
this$1.activeIndex--; |
|
} |
|
else if (index === this$1.activeIndex) { |
|
this$1.activeIndex = 0; |
|
} |
|
} |
|
}); |
|
this.$tabs = $newTabs; |
|
this.setActive(); |
|
}; |
|
mdui.Tab = Tab; |
|
|
|
var customAttr$5 = 'mdui-tab'; |
|
$(function () { |
|
mdui.mutation(("[" + customAttr$5 + "]"), function () { |
|
new mdui.Tab(this, parseOptions(this, customAttr$5)); |
|
}); |
|
}); |
|
|
|
/** |
|
* 在桌面设备上默认显示抽屉栏,不显示遮罩层 |
|
* 在手机和平板设备上默认不显示抽屉栏,始终显示遮罩层,且覆盖导航栏 |
|
*/ |
|
var DEFAULT_OPTIONS$5 = { |
|
overlay: false, |
|
swipe: false, |
|
}; |
|
var Drawer = function Drawer(selector, options) { |
|
var this$1 = this; |
|
if ( options === void 0 ) options = {}; |
|
|
|
/** |
|
* 配置参数 |
|
*/ |
|
this.options = extend({}, DEFAULT_OPTIONS$5); |
|
/** |
|
* 当前是否显示着遮罩层 |
|
*/ |
|
this.overlay = false; |
|
this.$element = $(selector).first(); |
|
extend(this.options, options); |
|
this.position = this.$element.hasClass('mdui-drawer-right') |
|
? 'right' |
|
: 'left'; |
|
if (this.$element.hasClass('mdui-drawer-close')) { |
|
this.state = 'closed'; |
|
} |
|
else if (this.$element.hasClass('mdui-drawer-open')) { |
|
this.state = 'opened'; |
|
} |
|
else if (this.isDesktop()) { |
|
this.state = 'opened'; |
|
} |
|
else { |
|
this.state = 'closed'; |
|
} |
|
// 浏览器窗口大小调整时 |
|
$window.on('resize', $.throttle(function () { |
|
if (this$1.isDesktop()) { |
|
// 由手机平板切换到桌面时 |
|
// 如果显示着遮罩,则隐藏遮罩 |
|
if (this$1.overlay && !this$1.options.overlay) { |
|
$.hideOverlay(); |
|
this$1.overlay = false; |
|
$.unlockScreen(); |
|
} |
|
// 没有强制关闭,则状态为打开状态 |
|
if (!this$1.$element.hasClass('mdui-drawer-close')) { |
|
this$1.state = 'opened'; |
|
} |
|
} |
|
else if (!this$1.overlay && this$1.state === 'opened') { |
|
// 由桌面切换到手机平板时。如果抽屉栏是打开着的且没有遮罩层,则关闭抽屉栏 |
|
if (this$1.$element.hasClass('mdui-drawer-open')) { |
|
$.showOverlay(); |
|
this$1.overlay = true; |
|
$.lockScreen(); |
|
$('.mdui-overlay').one('click', function () { return this$1.close(); }); |
|
} |
|
else { |
|
this$1.state = 'closed'; |
|
} |
|
} |
|
}, 100)); |
|
// 绑定关闭按钮事件 |
|
this.$element.find('[mdui-drawer-close]').each(function (_, close) { |
|
$(close).on('click', function () { return this$1.close(); }); |
|
}); |
|
this.swipeSupport(); |
|
}; |
|
/** |
|
* 是否是桌面设备 |
|
*/ |
|
Drawer.prototype.isDesktop = function isDesktop () { |
|
return $window.width() >= 1024; |
|
}; |
|
/** |
|
* 滑动手势支持 |
|
*/ |
|
Drawer.prototype.swipeSupport = function swipeSupport () { |
|
// eslint-disable-next-line @typescript-eslint/no-this-alias |
|
var that = this; |
|
// 抽屉栏滑动手势控制 |
|
var openNavEventHandler; |
|
var touchStartX; |
|
var touchStartY; |
|
var swipeStartX; |
|
var swiping = null; |
|
var maybeSwiping = false; |
|
var $body = $('body'); |
|
// 手势触发的范围 |
|
var swipeAreaWidth = 24; |
|
function setPosition(translateX) { |
|
var rtlTranslateMultiplier = that.position === 'right' ? -1 : 1; |
|
var transformCSS = "translate(" + (-1 * rtlTranslateMultiplier * translateX) + "px, 0) !important;"; |
|
var transitionCSS = 'initial !important;'; |
|
that.$element.css('cssText', ("transform: " + transformCSS + "; transition: " + transitionCSS + ";")); |
|
} |
|
function cleanPosition() { |
|
that.$element[0].style.transform = ''; |
|
that.$element[0].style.webkitTransform = ''; |
|
that.$element[0].style.transition = ''; |
|
that.$element[0].style.webkitTransition = ''; |
|
} |
|
function getMaxTranslateX() { |
|
return that.$element.width() + 10; |
|
} |
|
function getTranslateX(currentX) { |
|
return Math.min(Math.max(swiping === 'closing' |
|
? swipeStartX - currentX |
|
: getMaxTranslateX() + swipeStartX - currentX, 0), getMaxTranslateX()); |
|
} |
|
function onBodyTouchEnd(event) { |
|
if (swiping) { |
|
var touchX = event.changedTouches[0].pageX; |
|
if (that.position === 'right') { |
|
touchX = $body.width() - touchX; |
|
} |
|
var translateRatio = getTranslateX(touchX) / getMaxTranslateX(); |
|
maybeSwiping = false; |
|
var swipingState = swiping; |
|
swiping = null; |
|
if (swipingState === 'opening') { |
|
if (translateRatio < 0.92) { |
|
cleanPosition(); |
|
that.open(); |
|
} |
|
else { |
|
cleanPosition(); |
|
} |
|
} |
|
else { |
|
if (translateRatio > 0.08) { |
|
cleanPosition(); |
|
that.close(); |
|
} |
|
else { |
|
cleanPosition(); |
|
} |
|
} |
|
$.unlockScreen(); |
|
} |
|
else { |
|
maybeSwiping = false; |
|
} |
|
$body.off({ |
|
// eslint-disable-next-line @typescript-eslint/no-use-before-define |
|
touchmove: onBodyTouchMove, |
|
touchend: onBodyTouchEnd, |
|
// eslint-disable-next-line @typescript-eslint/no-use-before-define |
|
touchcancel: onBodyTouchMove, |
|
}); |
|
} |
|
function onBodyTouchMove(event) { |
|
var touchX = event.touches[0].pageX; |
|
if (that.position === 'right') { |
|
touchX = $body.width() - touchX; |
|
} |
|
var touchY = event.touches[0].pageY; |
|
if (swiping) { |
|
setPosition(getTranslateX(touchX)); |
|
} |
|
else if (maybeSwiping) { |
|
var dXAbs = Math.abs(touchX - touchStartX); |
|
var dYAbs = Math.abs(touchY - touchStartY); |
|
var threshold = 8; |
|
if (dXAbs > threshold && dYAbs <= threshold) { |
|
swipeStartX = touchX; |
|
swiping = that.state === 'opened' ? 'closing' : 'opening'; |
|
$.lockScreen(); |
|
setPosition(getTranslateX(touchX)); |
|
} |
|
else if (dXAbs <= threshold && dYAbs > threshold) { |
|
onBodyTouchEnd(); |
|
} |
|
} |
|
} |
|
function onBodyTouchStart(event) { |
|
touchStartX = event.touches[0].pageX; |
|
if (that.position === 'right') { |
|
touchStartX = $body.width() - touchStartX; |
|
} |
|
touchStartY = event.touches[0].pageY; |
|
if (that.state !== 'opened') { |
|
if (touchStartX > swipeAreaWidth || |
|
openNavEventHandler !== onBodyTouchStart) { |
|
return; |
|
} |
|
} |
|
maybeSwiping = true; |
|
$body.on({ |
|
touchmove: onBodyTouchMove, |
|
touchend: onBodyTouchEnd, |
|
touchcancel: onBodyTouchMove, |
|
}); |
|
} |
|
function enableSwipeHandling() { |
|
if (!openNavEventHandler) { |
|
$body.on('touchstart', onBodyTouchStart); |
|
openNavEventHandler = onBodyTouchStart; |
|
} |
|
} |
|
if (this.options.swipe) { |
|
enableSwipeHandling(); |
|
} |
|
}; |
|
/** |
|
* 触发组件事件 |
|
* @param name |
|
*/ |
|
Drawer.prototype.triggerEvent = function triggerEvent (name) { |
|
componentEvent(name, 'drawer', this.$element, this); |
|
}; |
|
/** |
|
* 动画结束回调 |
|
*/ |
|
Drawer.prototype.transitionEnd = function transitionEnd () { |
|
if (this.$element.hasClass('mdui-drawer-open')) { |
|
this.state = 'opened'; |
|
this.triggerEvent('opened'); |
|
} |
|
else { |
|
this.state = 'closed'; |
|
this.triggerEvent('closed'); |
|
} |
|
}; |
|
/** |
|
* 是否处于打开状态 |
|
*/ |
|
Drawer.prototype.isOpen = function isOpen () { |
|
return this.state === 'opening' || this.state === 'opened'; |
|
}; |
|
/** |
|
* 打开抽屉栏 |
|
*/ |
|
Drawer.prototype.open = function open () { |
|
var this$1 = this; |
|
|
|
if (this.isOpen()) { |
|
return; |
|
} |
|
this.state = 'opening'; |
|
this.triggerEvent('open'); |
|
if (!this.options.overlay) { |
|
$('body').addClass(("mdui-drawer-body-" + (this.position))); |
|
} |
|
this.$element |
|
.removeClass('mdui-drawer-close') |
|
.addClass('mdui-drawer-open') |
|
.transitionEnd(function () { return this$1.transitionEnd(); }); |
|
if (!this.isDesktop() || this.options.overlay) { |
|
this.overlay = true; |
|
$.showOverlay().one('click', function () { return this$1.close(); }); |
|
$.lockScreen(); |
|
} |
|
}; |
|
/** |
|
* 关闭抽屉栏 |
|
*/ |
|
Drawer.prototype.close = function close () { |
|
var this$1 = this; |
|
|
|
if (!this.isOpen()) { |
|
return; |
|
} |
|
this.state = 'closing'; |
|
this.triggerEvent('close'); |
|
if (!this.options.overlay) { |
|
$('body').removeClass(("mdui-drawer-body-" + (this.position))); |
|
} |
|
this.$element |
|
.addClass('mdui-drawer-close') |
|
.removeClass('mdui-drawer-open') |
|
.transitionEnd(function () { return this$1.transitionEnd(); }); |
|
if (this.overlay) { |
|
$.hideOverlay(); |
|
this.overlay = false; |
|
$.unlockScreen(); |
|
} |
|
}; |
|
/** |
|
* 切换抽屉栏打开/关闭状态 |
|
*/ |
|
Drawer.prototype.toggle = function toggle () { |
|
this.isOpen() ? this.close() : this.open(); |
|
}; |
|
/** |
|
* 返回当前抽屉栏的状态。共包含四种状态:`opening`、`opened`、`closing`、`closed` |
|
*/ |
|
Drawer.prototype.getState = function getState () { |
|
return this.state; |
|
}; |
|
mdui.Drawer = Drawer; |
|
|
|
var customAttr$6 = 'mdui-drawer'; |
|
$(function () { |
|
mdui.mutation(("[" + customAttr$6 + "]"), function () { |
|
var $element = $(this); |
|
var options = parseOptions(this, customAttr$6); |
|
var selector = options.target; |
|
// @ts-ignore |
|
delete options.target; |
|
var $drawer = $(selector).first(); |
|
var instance = new mdui.Drawer($drawer, options); |
|
$element.on('click', function () { return instance.toggle(); }); |
|
}); |
|
}); |
|
|
|
var container = {}; |
|
function queue(name, func) { |
|
if (isUndefined(container[name])) { |
|
container[name] = []; |
|
} |
|
if (isUndefined(func)) { |
|
return container[name]; |
|
} |
|
container[name].push(func); |
|
} |
|
/** |
|
* 从队列中移除第一个函数,并执行该函数 |
|
* @param name 队列满 |
|
*/ |
|
function dequeue(name) { |
|
if (isUndefined(container[name])) { |
|
return; |
|
} |
|
if (!container[name].length) { |
|
return; |
|
} |
|
var func = container[name].shift(); |
|
func(); |
|
} |
|
|
|
var DEFAULT_OPTIONS$6 = { |
|
history: true, |
|
overlay: true, |
|
modal: false, |
|
closeOnEsc: true, |
|
closeOnCancel: true, |
|
closeOnConfirm: true, |
|
destroyOnClosed: false, |
|
}; |
|
/** |
|
* 当前显示的对话框实例 |
|
*/ |
|
var currentInst = null; |
|
/** |
|
* 队列名 |
|
*/ |
|
var queueName = '_mdui_dialog'; |
|
/** |
|
* 窗口是否已锁定 |
|
*/ |
|
var isLockScreen = false; |
|
/** |
|
* 遮罩层元素 |
|
*/ |
|
var $overlay; |
|
var Dialog = function Dialog(selector, options) { |
|
var this$1 = this; |
|
if ( options === void 0 ) options = {}; |
|
|
|
/** |
|
* 配置参数 |
|
*/ |
|
this.options = extend({}, DEFAULT_OPTIONS$6); |
|
/** |
|
* 当前 dialog 的状态 |
|
*/ |
|
this.state = 'closed'; |
|
/** |
|
* dialog 元素是否是动态添加的 |
|
*/ |
|
this.append = false; |
|
this.$element = $(selector).first(); |
|
// 如果对话框元素没有在当前文档中,则需要添加 |
|
if (!contains(document.body, this.$element[0])) { |
|
this.append = true; |
|
$('body').append(this.$element); |
|
} |
|
extend(this.options, options); |
|
// 绑定取消按钮事件 |
|
this.$element.find('[mdui-dialog-cancel]').each(function (_, cancel) { |
|
$(cancel).on('click', function () { |
|
this$1.triggerEvent('cancel'); |
|
if (this$1.options.closeOnCancel) { |
|
this$1.close(); |
|
} |
|
}); |
|
}); |
|
// 绑定确认按钮事件 |
|
this.$element.find('[mdui-dialog-confirm]').each(function (_, confirm) { |
|
$(confirm).on('click', function () { |
|
this$1.triggerEvent('confirm'); |
|
if (this$1.options.closeOnConfirm) { |
|
this$1.close(); |
|
} |
|
}); |
|
}); |
|
// 绑定关闭按钮事件 |
|
this.$element.find('[mdui-dialog-close]').each(function (_, close) { |
|
$(close).on('click', function () { return this$1.close(); }); |
|
}); |
|
}; |
|
/** |
|
* 触发组件事件 |
|
* @param name |
|
*/ |
|
Dialog.prototype.triggerEvent = function triggerEvent (name) { |
|
componentEvent(name, 'dialog', this.$element, this); |
|
}; |
|
/** |
|
* 窗口宽度变化,或对话框内容变化时,调整对话框位置和对话框内的滚动条 |
|
*/ |
|
Dialog.prototype.readjust = function readjust () { |
|
if (!currentInst) { |
|
return; |
|
} |
|
var $element = currentInst.$element; |
|
var $title = $element.children('.mdui-dialog-title'); |
|
var $content = $element.children('.mdui-dialog-content'); |
|
var $actions = $element.children('.mdui-dialog-actions'); |
|
// 调整 dialog 的 top 和 height 值 |
|
$element.height(''); |
|
$content.height(''); |
|
var elementHeight = $element.height(); |
|
$element.css({ |
|
top: ((($window.height() - elementHeight) / 2) + "px"), |
|
height: (elementHeight + "px"), |
|
}); |
|
// 调整 mdui-dialog-content 的高度 |
|
$content.innerHeight(elementHeight - |
|
($title.innerHeight() || 0) - |
|
($actions.innerHeight() || 0)); |
|
}; |
|
/** |
|
* hashchange 事件触发时关闭对话框 |
|
*/ |
|
Dialog.prototype.hashchangeEvent = function hashchangeEvent () { |
|
if (window.location.hash.substring(1).indexOf('mdui-dialog') < 0) { |
|
currentInst.close(true); |
|
} |
|
}; |
|
/** |
|
* 点击遮罩层关闭对话框 |
|
* @param event |
|
*/ |
|
Dialog.prototype.overlayClick = function overlayClick (event) { |
|
if ($(event.target).hasClass('mdui-overlay') && |
|
currentInst) { |
|
currentInst.close(); |
|
} |
|
}; |
|
/** |
|
* 动画结束回调 |
|
*/ |
|
Dialog.prototype.transitionEnd = function transitionEnd () { |
|
if (this.$element.hasClass('mdui-dialog-open')) { |
|
this.state = 'opened'; |
|
this.triggerEvent('opened'); |
|
} |
|
else { |
|
this.state = 'closed'; |
|
this.triggerEvent('closed'); |
|
this.$element.hide(); |
|
// 所有对话框都关闭,且当前没有打开的对话框时,解锁屏幕 |
|
if (!queue(queueName).length && !currentInst && isLockScreen) { |
|
$.unlockScreen(); |
|
isLockScreen = false; |
|
} |
|
$window.off('resize', $.throttle(this.readjust, 100)); |
|
if (this.options.destroyOnClosed) { |
|
this.destroy(); |
|
} |
|
} |
|
}; |
|
/** |
|
* 打开指定对话框 |
|
*/ |
|
Dialog.prototype.doOpen = function doOpen () { |
|
var this$1 = this; |
|
|
|
currentInst = this; |
|
if (!isLockScreen) { |
|
$.lockScreen(); |
|
isLockScreen = true; |
|
} |
|
this.$element.show(); |
|
this.readjust(); |
|
$window.on('resize', $.throttle(this.readjust, 100)); |
|
// 打开消息框 |
|
this.state = 'opening'; |
|
this.triggerEvent('open'); |
|
this.$element |
|
.addClass('mdui-dialog-open') |
|
.transitionEnd(function () { return this$1.transitionEnd(); }); |
|
// 不存在遮罩层元素时,添加遮罩层 |
|
if (!$overlay) { |
|
$overlay = $.showOverlay(5100); |
|
} |
|
// 点击遮罩层时是否关闭对话框 |
|
if (this.options.modal) { |
|
$overlay.off('click', this.overlayClick); |
|
} |
|
else { |
|
$overlay.on('click', this.overlayClick); |
|
} |
|
// 是否显示遮罩层,不显示时,把遮罩层背景透明 |
|
$overlay.css('opacity', this.options.overlay ? '' : 0); |
|
if (this.options.history) { |
|
// 如果 hash 中原来就有 mdui-dialog,先删除,避免后退历史纪录后仍然有 mdui-dialog 导致无法关闭 |
|
// 包括 mdui-dialog 和 &mdui-dialog 和 ?mdui-dialog |
|
var hash = window.location.hash.substring(1); |
|
if (hash.indexOf('mdui-dialog') > -1) { |
|
hash = hash.replace(/[&?]?mdui-dialog/g, ''); |
|
} |
|
// 后退按钮关闭对话框 |
|
if (hash) { |
|
window.location.hash = "" + hash + (hash.indexOf('?') > -1 ? '&' : '?') + "mdui-dialog"; |
|
} |
|
else { |
|
window.location.hash = 'mdui-dialog'; |
|
} |
|
$window.on('hashchange', this.hashchangeEvent); |
|
} |
|
}; |
|
/** |
|
* 当前对话框是否为打开状态 |
|
*/ |
|
Dialog.prototype.isOpen = function isOpen () { |
|
return this.state === 'opening' || this.state === 'opened'; |
|
}; |
|
/** |
|
* 打开对话框 |
|
*/ |
|
Dialog.prototype.open = function open () { |
|
var this$1 = this; |
|
|
|
if (this.isOpen()) { |
|
return; |
|
} |
|
// 如果当前有正在打开或已经打开的对话框,或队列不为空,则先加入队列,等旧对话框开始关闭时再打开 |
|
if ((currentInst && |
|
(currentInst.state === 'opening' || currentInst.state === 'opened')) || |
|
queue(queueName).length) { |
|
queue(queueName, function () { return this$1.doOpen(); }); |
|
return; |
|
} |
|
this.doOpen(); |
|
}; |
|
/** |
|
* 关闭对话框 |
|
*/ |
|
Dialog.prototype.close = function close (historyBack) { |
|
var this$1 = this; |
|
if ( historyBack === void 0 ) historyBack = false; |
|
|
|
// historyBack 是否需要后退历史纪录,默认为 `false`。该参数仅内部使用 |
|
// 为 `false` 时是通过 js 关闭,需要后退一个历史记录 |
|
// 为 `true` 时是通过后退按钮关闭,不需要后退历史记录 |
|
// setTimeout 的作用是: |
|
// 当同时关闭一个对话框,并打开另一个对话框时,使打开对话框的操作先执行,以使需要打开的对话框先加入队列 |
|
setTimeout(function () { |
|
if (!this$1.isOpen()) { |
|
return; |
|
} |
|
currentInst = null; |
|
this$1.state = 'closing'; |
|
this$1.triggerEvent('close'); |
|
// 所有对话框都关闭,且当前没有打开的对话框时,隐藏遮罩 |
|
if (!queue(queueName).length && $overlay) { |
|
$.hideOverlay(); |
|
$overlay = null; |
|
// 若仍存在遮罩,恢复遮罩的 z-index |
|
$('.mdui-overlay').css('z-index', 2000); |
|
} |
|
this$1.$element |
|
.removeClass('mdui-dialog-open') |
|
.transitionEnd(function () { return this$1.transitionEnd(); }); |
|
if (this$1.options.history && !queue(queueName).length) { |
|
if (!historyBack) { |
|
window.history.back(); |
|
} |
|
$window.off('hashchange', this$1.hashchangeEvent); |
|
} |
|
// 关闭旧对话框,打开新对话框。 |
|
// 加一点延迟,仅仅为了视觉效果更好。不加延时也不影响功能 |
|
setTimeout(function () { |
|
dequeue(queueName); |
|
}, 100); |
|
}); |
|
}; |
|
/** |
|
* 切换对话框打开/关闭状态 |
|
*/ |
|
Dialog.prototype.toggle = function toggle () { |
|
this.isOpen() ? this.close() : this.open(); |
|
}; |
|
/** |
|
* 获取对话框状态。共包含四种状态:`opening`、`opened`、`closing`、`closed` |
|
*/ |
|
Dialog.prototype.getState = function getState () { |
|
return this.state; |
|
}; |
|
/** |
|
* 销毁对话框 |
|
*/ |
|
Dialog.prototype.destroy = function destroy () { |
|
if (this.append) { |
|
this.$element.remove(); |
|
} |
|
if (!queue(queueName).length && !currentInst) { |
|
if ($overlay) { |
|
$.hideOverlay(); |
|
$overlay = null; |
|
} |
|
if (isLockScreen) { |
|
$.unlockScreen(); |
|
isLockScreen = false; |
|
} |
|
} |
|
}; |
|
/** |
|
* 对话框内容变化时,需要调用该方法来调整对话框位置和滚动条高度 |
|
*/ |
|
Dialog.prototype.handleUpdate = function handleUpdate () { |
|
this.readjust(); |
|
}; |
|
|
|
// esc 按下时关闭对话框 |
|
$document.on('keydown', function (event) { |
|
if (currentInst && |
|
currentInst.options.closeOnEsc && |
|
currentInst.state === 'opened' && |
|
event.keyCode === 27) { |
|
currentInst.close(); |
|
} |
|
}); |
|
mdui.Dialog = Dialog; |
|
|
|
var customAttr$7 = 'mdui-dialog'; |
|
var dataName$1 = '_mdui_dialog'; |
|
$(function () { |
|
$document.on('click', ("[" + customAttr$7 + "]"), function () { |
|
var options = parseOptions(this, customAttr$7); |
|
var selector = options.target; |
|
// @ts-ignore |
|
delete options.target; |
|
var $dialog = $(selector).first(); |
|
var instance = $dialog.data(dataName$1); |
|
if (!instance) { |
|
instance = new mdui.Dialog($dialog, options); |
|
$dialog.data(dataName$1, instance); |
|
} |
|
instance.open(); |
|
}); |
|
}); |
|
|
|
var DEFAULT_BUTTON = { |
|
text: '', |
|
bold: false, |
|
close: true, |
|
// eslint-disable-next-line @typescript-eslint/no-empty-function |
|
onClick: function () { }, |
|
}; |
|
var DEFAULT_OPTIONS$7 = { |
|
title: '', |
|
content: '', |
|
buttons: [], |
|
stackedButtons: false, |
|
cssClass: '', |
|
history: true, |
|
overlay: true, |
|
modal: false, |
|
closeOnEsc: true, |
|
destroyOnClosed: true, |
|
// eslint-disable-next-line @typescript-eslint/no-empty-function |
|
onOpen: function () { }, |
|
// eslint-disable-next-line @typescript-eslint/no-empty-function |
|
onOpened: function () { }, |
|
// eslint-disable-next-line @typescript-eslint/no-empty-function |
|
onClose: function () { }, |
|
// eslint-disable-next-line @typescript-eslint/no-empty-function |
|
onClosed: function () { }, |
|
}; |
|
mdui.dialog = function (options) { |
|
var _a, _b; |
|
// 合并配置参数 |
|
options = extend({}, DEFAULT_OPTIONS$7, options); |
|
each(options.buttons, function (i, button) { |
|
options.buttons[i] = extend({}, DEFAULT_BUTTON, button); |
|
}); |
|
// 按钮的 HTML |
|
var buttonsHTML = ''; |
|
if ((_a = options.buttons) === null || _a === void 0 ? void 0 : _a.length) { |
|
buttonsHTML = "<div class=\"mdui-dialog-actions" + (options.stackedButtons ? ' mdui-dialog-actions-stacked' : '') + "\">"; |
|
each(options.buttons, function (_, button) { |
|
buttonsHTML += |
|
'<a href="javascript:void(0)" ' + |
|
"class=\"mdui-btn mdui-ripple mdui-text-color-primary " + (button.bold ? 'mdui-btn-bold' : '') + "\">" + (button.text) + "</a>"; |
|
}); |
|
buttonsHTML += '</div>'; |
|
} |
|
// Dialog 的 HTML |
|
var HTML = "<div class=\"mdui-dialog " + (options.cssClass) + "\">" + |
|
(options.title |
|
? ("<div class=\"mdui-dialog-title\">" + (options.title) + "</div>") |
|
: '') + |
|
(options.content |
|
? ("<div class=\"mdui-dialog-content\">" + (options.content) + "</div>") |
|
: '') + |
|
buttonsHTML + |
|
'</div>'; |
|
// 实例化 Dialog |
|
var instance = new mdui.Dialog(HTML, { |
|
history: options.history, |
|
overlay: options.overlay, |
|
modal: options.modal, |
|
closeOnEsc: options.closeOnEsc, |
|
destroyOnClosed: options.destroyOnClosed, |
|
}); |
|
// 绑定按钮事件 |
|
if ((_b = options.buttons) === null || _b === void 0 ? void 0 : _b.length) { |
|
instance.$element |
|
.find('.mdui-dialog-actions .mdui-btn') |
|
.each(function (index, button) { |
|
$(button).on('click', function () { |
|
options.buttons[index].onClick(instance); |
|
if (options.buttons[index].close) { |
|
instance.close(); |
|
} |
|
}); |
|
}); |
|
} |
|
// 绑定打开关闭事件 |
|
instance.$element |
|
.on('open.mdui.dialog', function () { |
|
options.onOpen(instance); |
|
}) |
|
.on('opened.mdui.dialog', function () { |
|
options.onOpened(instance); |
|
}) |
|
.on('close.mdui.dialog', function () { |
|
options.onClose(instance); |
|
}) |
|
.on('closed.mdui.dialog', function () { |
|
options.onClosed(instance); |
|
}); |
|
instance.open(); |
|
return instance; |
|
}; |
|
|
|
var DEFAULT_OPTIONS$8 = { |
|
confirmText: 'ok', |
|
history: true, |
|
modal: false, |
|
closeOnEsc: true, |
|
closeOnConfirm: true, |
|
}; |
|
mdui.alert = function (text, title, onConfirm, options) { |
|
if (isFunction(title)) { |
|
options = onConfirm; |
|
onConfirm = title; |
|
title = ''; |
|
} |
|
if (isUndefined(onConfirm)) { |
|
// eslint-disable-next-line @typescript-eslint/no-empty-function |
|
onConfirm = function () { }; |
|
} |
|
if (isUndefined(options)) { |
|
options = {}; |
|
} |
|
options = extend({}, DEFAULT_OPTIONS$8, options); |
|
return mdui.dialog({ |
|
title: title, |
|
content: text, |
|
buttons: [ |
|
{ |
|
text: options.confirmText, |
|
bold: false, |
|
close: options.closeOnConfirm, |
|
onClick: onConfirm, |
|
} ], |
|
cssClass: 'mdui-dialog-alert', |
|
history: options.history, |
|
modal: options.modal, |
|
closeOnEsc: options.closeOnEsc, |
|
}); |
|
}; |
|
|
|
var DEFAULT_OPTIONS$9 = { |
|
confirmText: 'ok', |
|
cancelText: 'cancel', |
|
history: true, |
|
modal: false, |
|
closeOnEsc: true, |
|
closeOnCancel: true, |
|
closeOnConfirm: true, |
|
}; |
|
mdui.confirm = function (text, title, onConfirm, onCancel, options) { |
|
if (isFunction(title)) { |
|
options = onCancel; |
|
onCancel = onConfirm; |
|
onConfirm = title; |
|
title = ''; |
|
} |
|
if (isUndefined(onConfirm)) { |
|
// eslint-disable-next-line @typescript-eslint/no-empty-function |
|
onConfirm = function () { }; |
|
} |
|
if (isUndefined(onCancel)) { |
|
// eslint-disable-next-line @typescript-eslint/no-empty-function |
|
onCancel = function () { }; |
|
} |
|
if (isUndefined(options)) { |
|
options = {}; |
|
} |
|
options = extend({}, DEFAULT_OPTIONS$9, options); |
|
return mdui.dialog({ |
|
title: title, |
|
content: text, |
|
buttons: [ |
|
{ |
|
text: options.cancelText, |
|
bold: false, |
|
close: options.closeOnCancel, |
|
onClick: onCancel, |
|
}, |
|
{ |
|
text: options.confirmText, |
|
bold: false, |
|
close: options.closeOnConfirm, |
|
onClick: onConfirm, |
|
} ], |
|
cssClass: 'mdui-dialog-confirm', |
|
history: options.history, |
|
modal: options.modal, |
|
closeOnEsc: options.closeOnEsc, |
|
}); |
|
}; |
|
|
|
var DEFAULT_OPTIONS$a = { |
|
confirmText: 'ok', |
|
cancelText: 'cancel', |
|
history: true, |
|
modal: false, |
|
closeOnEsc: true, |
|
closeOnCancel: true, |
|
closeOnConfirm: true, |
|
type: 'text', |
|
maxlength: 0, |
|
defaultValue: '', |
|
confirmOnEnter: false, |
|
}; |
|
mdui.prompt = function (label, title, onConfirm, onCancel, options) { |
|
if (isFunction(title)) { |
|
options = onCancel; |
|
onCancel = onConfirm; |
|
onConfirm = title; |
|
title = ''; |
|
} |
|
if (isUndefined(onConfirm)) { |
|
// eslint-disable-next-line @typescript-eslint/no-empty-function |
|
onConfirm = function () { }; |
|
} |
|
if (isUndefined(onCancel)) { |
|
// eslint-disable-next-line @typescript-eslint/no-empty-function |
|
onCancel = function () { }; |
|
} |
|
if (isUndefined(options)) { |
|
options = {}; |
|
} |
|
options = extend({}, DEFAULT_OPTIONS$a, options); |
|
var content = '<div class="mdui-textfield">' + |
|
(label ? ("<label class=\"mdui-textfield-label\">" + label + "</label>") : '') + |
|
(options.type === 'text' |
|
? ("<input class=\"mdui-textfield-input\" type=\"text\" value=\"" + (options.defaultValue) + "\" " + (options.maxlength ? 'maxlength="' + options.maxlength + '"' : '') + "/>") |
|
: '') + |
|
(options.type === 'textarea' |
|
? ("<textarea class=\"mdui-textfield-input\" " + (options.maxlength ? 'maxlength="' + options.maxlength + '"' : '') + ">" + (options.defaultValue) + "</textarea>") |
|
: '') + |
|
'</div>'; |
|
var onCancelClick = function (dialog) { |
|
var value = dialog.$element.find('.mdui-textfield-input').val(); |
|
onCancel(value, dialog); |
|
}; |
|
var onConfirmClick = function (dialog) { |
|
var value = dialog.$element.find('.mdui-textfield-input').val(); |
|
onConfirm(value, dialog); |
|
}; |
|
return mdui.dialog({ |
|
title: title, |
|
content: content, |
|
buttons: [ |
|
{ |
|
text: options.cancelText, |
|
bold: false, |
|
close: options.closeOnCancel, |
|
onClick: onCancelClick, |
|
}, |
|
{ |
|
text: options.confirmText, |
|
bold: false, |
|
close: options.closeOnConfirm, |
|
onClick: onConfirmClick, |
|
} ], |
|
cssClass: 'mdui-dialog-prompt', |
|
history: options.history, |
|
modal: options.modal, |
|
closeOnEsc: options.closeOnEsc, |
|
onOpen: function (dialog) { |
|
// 初始化输入框 |
|
var $input = dialog.$element.find('.mdui-textfield-input'); |
|
mdui.updateTextFields($input); |
|
// 聚焦到输入框 |
|
$input[0].focus(); |
|
// 捕捉文本框回车键,在单行文本框的情况下触发回调 |
|
if (options.type !== 'textarea' && options.confirmOnEnter === true) { |
|
$input.on('keydown', function (event) { |
|
if (event.keyCode === 13) { |
|
var value = dialog.$element.find('.mdui-textfield-input').val(); |
|
onConfirm(value, dialog); |
|
if (options.closeOnConfirm) { |
|
dialog.close(); |
|
} |
|
return false; |
|
} |
|
return; |
|
}); |
|
} |
|
// 如果是多行输入框,监听输入框的 input 事件,更新对话框高度 |
|
if (options.type === 'textarea') { |
|
$input.on('input', function () { return dialog.handleUpdate(); }); |
|
} |
|
// 有字符数限制时,加载完文本框后 DOM 会变化,需要更新对话框高度 |
|
if (options.maxlength) { |
|
dialog.handleUpdate(); |
|
} |
|
}, |
|
}); |
|
}; |
|
|
|
var DEFAULT_OPTIONS$b = { |
|
position: 'auto', |
|
delay: 0, |
|
content: '', |
|
}; |
|
var Tooltip = function Tooltip(selector, options) { |
|
if ( options === void 0 ) options = {}; |
|
|
|
/** |
|
* 配置参数 |
|
*/ |
|
this.options = extend({}, DEFAULT_OPTIONS$b); |
|
/** |
|
* 当前 tooltip 的状态 |
|
*/ |
|
this.state = 'closed'; |
|
/** |
|
* setTimeout 的返回值 |
|
*/ |
|
this.timeoutId = null; |
|
this.$target = $(selector).first(); |
|
extend(this.options, options); |
|
// 创建 Tooltip HTML |
|
this.$element = $(("<div class=\"mdui-tooltip\" id=\"" + ($.guid()) + "\">" + (this.options.content) + "</div>")).appendTo(document.body); |
|
// 绑定事件。元素处于 disabled 状态时无法触发鼠标事件,为了统一,把 touch 事件也禁用 |
|
// eslint-disable-next-line @typescript-eslint/no-this-alias |
|
var that = this; |
|
this.$target |
|
.on('touchstart mouseenter', function (event) { |
|
if (that.isDisabled(this)) { |
|
return; |
|
} |
|
if (!isAllow(event)) { |
|
return; |
|
} |
|
register(event); |
|
that.open(); |
|
}) |
|
.on('touchend mouseleave', function (event) { |
|
if (that.isDisabled(this)) { |
|
return; |
|
} |
|
if (!isAllow(event)) { |
|
return; |
|
} |
|
that.close(); |
|
}) |
|
.on(unlockEvent, function (event) { |
|
if (that.isDisabled(this)) { |
|
return; |
|
} |
|
register(event); |
|
}); |
|
}; |
|
/** |
|
* 元素是否已禁用 |
|
* @param element |
|
*/ |
|
Tooltip.prototype.isDisabled = function isDisabled (element) { |
|
return (element.disabled || |
|
$(element).attr('disabled') !== undefined); |
|
}; |
|
/** |
|
* 是否是桌面设备 |
|
*/ |
|
Tooltip.prototype.isDesktop = function isDesktop () { |
|
return $window.width() > 1024; |
|
}; |
|
/** |
|
* 设置 Tooltip 的位置 |
|
*/ |
|
Tooltip.prototype.setPosition = function setPosition () { |
|
var marginLeft; |
|
var marginTop; |
|
// 触发的元素 |
|
var targetProps = this.$target[0].getBoundingClientRect(); |
|
// 触发的元素和 Tooltip 之间的距离 |
|
var targetMargin = this.isDesktop() ? 14 : 24; |
|
// Tooltip 的宽度和高度 |
|
var tooltipWidth = this.$element[0].offsetWidth; |
|
var tooltipHeight = this.$element[0].offsetHeight; |
|
// Tooltip 的方向 |
|
var position = this.options.position; |
|
// 自动判断位置,加 2px,使 Tooltip 距离窗口边框至少有 2px 的间距 |
|
if (position === 'auto') { |
|
if (targetProps.top + |
|
targetProps.height + |
|
targetMargin + |
|
tooltipHeight + |
|
2 < |
|
$window.height()) { |
|
position = 'bottom'; |
|
} |
|
else if (targetMargin + tooltipHeight + 2 < targetProps.top) { |
|
position = 'top'; |
|
} |
|
else if (targetMargin + tooltipWidth + 2 < targetProps.left) { |
|
position = 'left'; |
|
} |
|
else if (targetProps.width + targetMargin + tooltipWidth + 2 < |
|
$window.width() - targetProps.left) { |
|
position = 'right'; |
|
} |
|
else { |
|
position = 'bottom'; |
|
} |
|
} |
|
// 设置位置 |
|
switch (position) { |
|
case 'bottom': |
|
marginLeft = -1 * (tooltipWidth / 2); |
|
marginTop = targetProps.height / 2 + targetMargin; |
|
this.$element.transformOrigin('top center'); |
|
break; |
|
case 'top': |
|
marginLeft = -1 * (tooltipWidth / 2); |
|
marginTop = |
|
-1 * (tooltipHeight + targetProps.height / 2 + targetMargin); |
|
this.$element.transformOrigin('bottom center'); |
|
break; |
|
case 'left': |
|
marginLeft = -1 * (tooltipWidth + targetProps.width / 2 + targetMargin); |
|
marginTop = -1 * (tooltipHeight / 2); |
|
this.$element.transformOrigin('center right'); |
|
break; |
|
case 'right': |
|
marginLeft = targetProps.width / 2 + targetMargin; |
|
marginTop = -1 * (tooltipHeight / 2); |
|
this.$element.transformOrigin('center left'); |
|
break; |
|
} |
|
var targetOffset = this.$target.offset(); |
|
this.$element.css({ |
|
top: ((targetOffset.top + targetProps.height / 2) + "px"), |
|
left: ((targetOffset.left + targetProps.width / 2) + "px"), |
|
'margin-left': (marginLeft + "px"), |
|
'margin-top': (marginTop + "px"), |
|
}); |
|
}; |
|
/** |
|
* 触发组件事件 |
|
* @param name |
|
*/ |
|
Tooltip.prototype.triggerEvent = function triggerEvent (name) { |
|
componentEvent(name, 'tooltip', this.$target, this); |
|
}; |
|
/** |
|
* 动画结束回调 |
|
*/ |
|
Tooltip.prototype.transitionEnd = function transitionEnd () { |
|
if (this.$element.hasClass('mdui-tooltip-open')) { |
|
this.state = 'opened'; |
|
this.triggerEvent('opened'); |
|
} |
|
else { |
|
this.state = 'closed'; |
|
this.triggerEvent('closed'); |
|
} |
|
}; |
|
/** |
|
* 当前 tooltip 是否为打开状态 |
|
*/ |
|
Tooltip.prototype.isOpen = function isOpen () { |
|
return this.state === 'opening' || this.state === 'opened'; |
|
}; |
|
/** |
|
* 执行打开 tooltip |
|
*/ |
|
Tooltip.prototype.doOpen = function doOpen () { |
|
var this$1 = this; |
|
|
|
this.state = 'opening'; |
|
this.triggerEvent('open'); |
|
this.$element |
|
.addClass('mdui-tooltip-open') |
|
.transitionEnd(function () { return this$1.transitionEnd(); }); |
|
}; |
|
/** |
|
* 打开 Tooltip |
|
* @param options 允许每次打开时设置不同的参数 |
|
*/ |
|
Tooltip.prototype.open = function open (options) { |
|
var this$1 = this; |
|
|
|
if (this.isOpen()) { |
|
return; |
|
} |
|
var oldOptions = extend({}, this.options); |
|
if (options) { |
|
extend(this.options, options); |
|
} |
|
// tooltip 的内容有更新 |
|
if (oldOptions.content !== this.options.content) { |
|
this.$element.html(this.options.content); |
|
} |
|
this.setPosition(); |
|
if (this.options.delay) { |
|
this.timeoutId = setTimeout(function () { return this$1.doOpen(); }, this.options.delay); |
|
} |
|
else { |
|
this.timeoutId = null; |
|
this.doOpen(); |
|
} |
|
}; |
|
/** |
|
* 关闭 Tooltip |
|
*/ |
|
Tooltip.prototype.close = function close () { |
|
var this$1 = this; |
|
|
|
if (this.timeoutId) { |
|
clearTimeout(this.timeoutId); |
|
this.timeoutId = null; |
|
} |
|
if (!this.isOpen()) { |
|
return; |
|
} |
|
this.state = 'closing'; |
|
this.triggerEvent('close'); |
|
this.$element |
|
.removeClass('mdui-tooltip-open') |
|
.transitionEnd(function () { return this$1.transitionEnd(); }); |
|
}; |
|
/** |
|
* 切换 Tooltip 的打开状态 |
|
*/ |
|
Tooltip.prototype.toggle = function toggle () { |
|
this.isOpen() ? this.close() : this.open(); |
|
}; |
|
/** |
|
* 获取 Tooltip 状态。共包含四种状态:`opening`、`opened`、`closing`、`closed` |
|
*/ |
|
Tooltip.prototype.getState = function getState () { |
|
return this.state; |
|
}; |
|
mdui.Tooltip = Tooltip; |
|
|
|
var customAttr$8 = 'mdui-tooltip'; |
|
var dataName$2 = '_mdui_tooltip'; |
|
$(function () { |
|
// mouseenter 不能冒泡,所以这里用 mouseover 代替 |
|
$document.on('touchstart mouseover', ("[" + customAttr$8 + "]"), function () { |
|
var $target = $(this); |
|
var instance = $target.data(dataName$2); |
|
if (!instance) { |
|
instance = new mdui.Tooltip(this, parseOptions(this, customAttr$8)); |
|
$target.data(dataName$2, instance); |
|
} |
|
}); |
|
}); |
|
|
|
var DEFAULT_OPTIONS$c = { |
|
message: '', |
|
timeout: 4000, |
|
position: 'bottom', |
|
buttonText: '', |
|
buttonColor: '', |
|
closeOnButtonClick: true, |
|
closeOnOutsideClick: true, |
|
// eslint-disable-next-line @typescript-eslint/no-empty-function |
|
onClick: function () { }, |
|
// eslint-disable-next-line @typescript-eslint/no-empty-function |
|
onButtonClick: function () { }, |
|
// eslint-disable-next-line @typescript-eslint/no-empty-function |
|
onOpen: function () { }, |
|
// eslint-disable-next-line @typescript-eslint/no-empty-function |
|
onOpened: function () { }, |
|
// eslint-disable-next-line @typescript-eslint/no-empty-function |
|
onClose: function () { }, |
|
// eslint-disable-next-line @typescript-eslint/no-empty-function |
|
onClosed: function () { }, |
|
}; |
|
/** |
|
* 当前打开着的 Snackbar |
|
*/ |
|
var currentInst$1 = null; |
|
/** |
|
* 队列名 |
|
*/ |
|
var queueName$1 = '_mdui_snackbar'; |
|
var Snackbar = function Snackbar(options) { |
|
/** |
|
* 配置参数 |
|
*/ |
|
this.options = extend({}, DEFAULT_OPTIONS$c); |
|
/** |
|
* 当前 Snackbar 的状态 |
|
*/ |
|
this.state = 'closed'; |
|
/** |
|
* setTimeout 的 ID |
|
*/ |
|
this.timeoutId = null; |
|
extend(this.options, options); |
|
// 按钮颜色 |
|
var buttonColorStyle = ''; |
|
var buttonColorClass = ''; |
|
if (this.options.buttonColor.indexOf('#') === 0 || |
|
this.options.buttonColor.indexOf('rgb') === 0) { |
|
buttonColorStyle = "style=\"color:" + (this.options.buttonColor) + "\""; |
|
} |
|
else if (this.options.buttonColor !== '') { |
|
buttonColorClass = "mdui-text-color-" + (this.options.buttonColor); |
|
} |
|
// 添加 HTML |
|
this.$element = $('<div class="mdui-snackbar">' + |
|
"<div class=\"mdui-snackbar-text\">" + (this.options.message) + "</div>" + |
|
(this.options.buttonText |
|
? ("<a href=\"javascript:void(0)\" class=\"mdui-snackbar-action mdui-btn mdui-ripple mdui-ripple-white " + buttonColorClass + "\" " + buttonColorStyle + ">" + (this.options.buttonText) + "</a>") |
|
: '') + |
|
'</div>').appendTo(document.body); |
|
// 设置位置 |
|
this.setPosition('close'); |
|
this.$element.reflow().addClass(("mdui-snackbar-" + (this.options.position))); |
|
}; |
|
/** |
|
* 点击 Snackbar 外面的区域关闭 |
|
* @param event |
|
*/ |
|
Snackbar.prototype.closeOnOutsideClick = function closeOnOutsideClick (event) { |
|
var $target = $(event.target); |
|
if (!$target.hasClass('mdui-snackbar') && |
|
!$target.parents('.mdui-snackbar').length) { |
|
currentInst$1.close(); |
|
} |
|
}; |
|
/** |
|
* 设置 Snackbar 的位置 |
|
* @param state |
|
*/ |
|
Snackbar.prototype.setPosition = function setPosition (state) { |
|
var snackbarHeight = this.$element[0].clientHeight; |
|
var position = this.options.position; |
|
var translateX; |
|
var translateY; |
|
// translateX |
|
if (position === 'bottom' || position === 'top') { |
|
translateX = '-50%'; |
|
} |
|
else { |
|
translateX = '0'; |
|
} |
|
// translateY |
|
if (state === 'open') { |
|
translateY = '0'; |
|
} |
|
else { |
|
if (position === 'bottom') { |
|
translateY = snackbarHeight; |
|
} |
|
if (position === 'top') { |
|
translateY = -snackbarHeight; |
|
} |
|
if (position === 'left-top' || position === 'right-top') { |
|
translateY = -snackbarHeight - 24; |
|
} |
|
if (position === 'left-bottom' || position === 'right-bottom') { |
|
translateY = snackbarHeight + 24; |
|
} |
|
} |
|
this.$element.transform(("translate(" + translateX + "," + translateY + "px")); |
|
}; |
|
/** |
|
* 打开 Snackbar |
|
*/ |
|
Snackbar.prototype.open = function open () { |
|
var this$1 = this; |
|
|
|
if (this.state === 'opening' || this.state === 'opened') { |
|
return; |
|
} |
|
// 如果当前有正在显示的 Snackbar,则先加入队列,等旧 Snackbar 关闭后再打开 |
|
if (currentInst$1) { |
|
queue(queueName$1, function () { return this$1.open(); }); |
|
return; |
|
} |
|
currentInst$1 = this; |
|
// 开始打开 |
|
this.state = 'opening'; |
|
this.options.onOpen(this); |
|
this.setPosition('open'); |
|
this.$element.transitionEnd(function () { |
|
if (this$1.state !== 'opening') { |
|
return; |
|
} |
|
this$1.state = 'opened'; |
|
this$1.options.onOpened(this$1); |
|
// 有按钮时绑定事件 |
|
if (this$1.options.buttonText) { |
|
this$1.$element.find('.mdui-snackbar-action').on('click', function () { |
|
this$1.options.onButtonClick(this$1); |
|
if (this$1.options.closeOnButtonClick) { |
|
this$1.close(); |
|
} |
|
}); |
|
} |
|
// 点击 snackbar 的事件 |
|
this$1.$element.on('click', function (event) { |
|
if (!$(event.target).hasClass('mdui-snackbar-action')) { |
|
this$1.options.onClick(this$1); |
|
} |
|
}); |
|
// 点击 Snackbar 外面的区域关闭 |
|
if (this$1.options.closeOnOutsideClick) { |
|
$document.on(startEvent, this$1.closeOnOutsideClick); |
|
} |
|
// 超时后自动关闭 |
|
if (this$1.options.timeout) { |
|
this$1.timeoutId = setTimeout(function () { return this$1.close(); }, this$1.options.timeout); |
|
} |
|
}); |
|
}; |
|
/** |
|
* 关闭 Snackbar |
|
*/ |
|
Snackbar.prototype.close = function close () { |
|
var this$1 = this; |
|
|
|
if (this.state === 'closing' || this.state === 'closed') { |
|
return; |
|
} |
|
if (this.timeoutId) { |
|
clearTimeout(this.timeoutId); |
|
} |
|
if (this.options.closeOnOutsideClick) { |
|
$document.off(startEvent, this.closeOnOutsideClick); |
|
} |
|
this.state = 'closing'; |
|
this.options.onClose(this); |
|
this.setPosition('close'); |
|
this.$element.transitionEnd(function () { |
|
if (this$1.state !== 'closing') { |
|
return; |
|
} |
|
currentInst$1 = null; |
|
this$1.state = 'closed'; |
|
this$1.options.onClosed(this$1); |
|
this$1.$element.remove(); |
|
dequeue(queueName$1); |
|
}); |
|
}; |
|
mdui.snackbar = function (message, options) { |
|
if ( options === void 0 ) options = {}; |
|
|
|
if (isString(message)) { |
|
options.message = message; |
|
} |
|
else { |
|
options = message; |
|
} |
|
var instance = new Snackbar(options); |
|
instance.open(); |
|
return instance; |
|
}; |
|
|
|
$(function () { |
|
// 切换导航项 |
|
$document.on('click', '.mdui-bottom-nav>a', function () { |
|
var $item = $(this); |
|
var $bottomNav = $item.parent(); |
|
$bottomNav.children('a').each(function (index, item) { |
|
var isThis = $item.is(item); |
|
if (isThis) { |
|
componentEvent('change', 'bottomNav', $bottomNav[0], undefined, { |
|
index: index, |
|
}); |
|
} |
|
isThis |
|
? $(item).addClass('mdui-bottom-nav-active') |
|
: $(item).removeClass('mdui-bottom-nav-active'); |
|
}); |
|
}); |
|
// 滚动时隐藏 mdui-bottom-nav-scroll-hide |
|
mdui.mutation('.mdui-bottom-nav-scroll-hide', function () { |
|
new mdui.Headroom(this, { |
|
pinnedClass: 'mdui-headroom-pinned-down', |
|
unpinnedClass: 'mdui-headroom-unpinned-down', |
|
}); |
|
}); |
|
}); |
|
|
|
/** |
|
* layer 的 HTML 结构 |
|
* @param index |
|
*/ |
|
function layerHTML(index) { |
|
if ( index === void 0 ) index = false; |
|
|
|
return ("<div class=\"mdui-spinner-layer " + (index ? ("mdui-spinner-layer-" + index) : '') + "\">" + |
|
'<div class="mdui-spinner-circle-clipper mdui-spinner-left">' + |
|
'<div class="mdui-spinner-circle"></div>' + |
|
'</div>' + |
|
'<div class="mdui-spinner-gap-patch">' + |
|
'<div class="mdui-spinner-circle"></div>' + |
|
'</div>' + |
|
'<div class="mdui-spinner-circle-clipper mdui-spinner-right">' + |
|
'<div class="mdui-spinner-circle"></div>' + |
|
'</div>' + |
|
'</div>'); |
|
} |
|
/** |
|
* 填充 HTML |
|
* @param spinner |
|
*/ |
|
function fillHTML(spinner) { |
|
var $spinner = $(spinner); |
|
var layer = $spinner.hasClass('mdui-spinner-colorful') |
|
? layerHTML(1) + layerHTML(2) + layerHTML(3) + layerHTML(4) |
|
: layerHTML(); |
|
$spinner.html(layer); |
|
} |
|
$(function () { |
|
// 页面加载完后自动填充 HTML 结构 |
|
mdui.mutation('.mdui-spinner', function () { |
|
fillHTML(this); |
|
}); |
|
}); |
|
mdui.updateSpinners = function (selector) { |
|
var $elements = isUndefined(selector) ? $('.mdui-spinner') : $(selector); |
|
$elements.each(function () { |
|
fillHTML(this); |
|
}); |
|
}; |
|
|
|
var DEFAULT_OPTIONS$d = { |
|
position: 'auto', |
|
align: 'auto', |
|
gutter: 16, |
|
fixed: false, |
|
covered: 'auto', |
|
subMenuTrigger: 'hover', |
|
subMenuDelay: 200, |
|
}; |
|
var Menu = function Menu(anchorSelector, menuSelector, options) { |
|
var this$1 = this; |
|
if ( options === void 0 ) options = {}; |
|
|
|
/** |
|
* 配置参数 |
|
*/ |
|
this.options = extend({}, DEFAULT_OPTIONS$d); |
|
/** |
|
* 当前菜单状态 |
|
*/ |
|
this.state = 'closed'; |
|
this.$anchor = $(anchorSelector).first(); |
|
this.$element = $(menuSelector).first(); |
|
// 触发菜单的元素 和 菜单必须是同级的元素,否则菜单可能不能定位 |
|
if (!this.$anchor.parent().is(this.$element.parent())) { |
|
throw new Error('anchorSelector and menuSelector must be siblings'); |
|
} |
|
extend(this.options, options); |
|
// 是否是级联菜单 |
|
this.isCascade = this.$element.hasClass('mdui-menu-cascade'); |
|
// covered 参数处理 |
|
this.isCovered = |
|
this.options.covered === 'auto' ? !this.isCascade : this.options.covered; |
|
// 点击触发菜单切换 |
|
this.$anchor.on('click', function () { return this$1.toggle(); }); |
|
// 点击菜单外面区域关闭菜单 |
|
$document.on('click touchstart', function (event) { |
|
var $target = $(event.target); |
|
if (this$1.isOpen() && |
|
!$target.is(this$1.$element) && |
|
!contains(this$1.$element[0], $target[0]) && |
|
!$target.is(this$1.$anchor) && |
|
!contains(this$1.$anchor[0], $target[0])) { |
|
this$1.close(); |
|
} |
|
}); |
|
// 点击不含子菜单的菜单条目关闭菜单 |
|
// eslint-disable-next-line @typescript-eslint/no-this-alias |
|
var that = this; |
|
$document.on('click', '.mdui-menu-item', function () { |
|
var $item = $(this); |
|
if (!$item.find('.mdui-menu').length && |
|
$item.attr('disabled') === undefined) { |
|
that.close(); |
|
} |
|
}); |
|
// 绑定点击或鼠标移入含子菜单的条目的事件 |
|
this.bindSubMenuEvent(); |
|
// 窗口大小变化时,重新调整菜单位置 |
|
$window.on('resize', $.throttle(function () { return this$1.readjust(); }, 100)); |
|
}; |
|
/** |
|
* 是否为打开状态 |
|
*/ |
|
Menu.prototype.isOpen = function isOpen () { |
|
return this.state === 'opening' || this.state === 'opened'; |
|
}; |
|
/** |
|
* 触发组件事件 |
|
* @param name |
|
*/ |
|
Menu.prototype.triggerEvent = function triggerEvent (name) { |
|
componentEvent(name, 'menu', this.$element, this); |
|
}; |
|
/** |
|
* 调整主菜单位置 |
|
*/ |
|
Menu.prototype.readjust = function readjust () { |
|
var menuLeft; |
|
var menuTop; |
|
// 菜单位置和方向 |
|
var position; |
|
var align; |
|
// window 窗口的宽度和高度 |
|
var windowHeight = $window.height(); |
|
var windowWidth = $window.width(); |
|
// 配置参数 |
|
var gutter = this.options.gutter; |
|
var isCovered = this.isCovered; |
|
var isFixed = this.options.fixed; |
|
// 动画方向参数 |
|
var transformOriginX; |
|
var transformOriginY; |
|
// 菜单的原始宽度和高度 |
|
var menuWidth = this.$element.width(); |
|
var menuHeight = this.$element.height(); |
|
// 触发菜单的元素在窗口中的位置 |
|
var anchorRect = this.$anchor[0].getBoundingClientRect(); |
|
var anchorTop = anchorRect.top; |
|
var anchorLeft = anchorRect.left; |
|
var anchorHeight = anchorRect.height; |
|
var anchorWidth = anchorRect.width; |
|
var anchorBottom = windowHeight - anchorTop - anchorHeight; |
|
var anchorRight = windowWidth - anchorLeft - anchorWidth; |
|
// 触发元素相对其拥有定位属性的父元素的位置 |
|
var anchorOffsetTop = this.$anchor[0].offsetTop; |
|
var anchorOffsetLeft = this.$anchor[0].offsetLeft; |
|
// 自动判断菜单位置 |
|
if (this.options.position === 'auto') { |
|
if (anchorBottom + (isCovered ? anchorHeight : 0) > menuHeight + gutter) { |
|
// 判断下方是否放得下菜单 |
|
position = 'bottom'; |
|
} |
|
else if (anchorTop + (isCovered ? anchorHeight : 0) > |
|
menuHeight + gutter) { |
|
// 判断上方是否放得下菜单 |
|
position = 'top'; |
|
} |
|
else { |
|
// 上下都放不下,居中显示 |
|
position = 'center'; |
|
} |
|
} |
|
else { |
|
position = this.options.position; |
|
} |
|
// 自动判断菜单对齐方式 |
|
if (this.options.align === 'auto') { |
|
if (anchorRight + anchorWidth > menuWidth + gutter) { |
|
// 判断右侧是否放得下菜单 |
|
align = 'left'; |
|
} |
|
else if (anchorLeft + anchorWidth > menuWidth + gutter) { |
|
// 判断左侧是否放得下菜单 |
|
align = 'right'; |
|
} |
|
else { |
|
// 左右都放不下,居中显示 |
|
align = 'center'; |
|
} |
|
} |
|
else { |
|
align = this.options.align; |
|
} |
|
// 设置菜单位置 |
|
if (position === 'bottom') { |
|
transformOriginY = '0'; |
|
menuTop = |
|
(isCovered ? 0 : anchorHeight) + |
|
(isFixed ? anchorTop : anchorOffsetTop); |
|
} |
|
else if (position === 'top') { |
|
transformOriginY = '100%'; |
|
menuTop = |
|
(isCovered ? anchorHeight : 0) + |
|
(isFixed ? anchorTop - menuHeight : anchorOffsetTop - menuHeight); |
|
} |
|
else { |
|
transformOriginY = '50%'; |
|
// =====================在窗口中居中 |
|
// 显示的菜单的高度,简单菜单高度不超过窗口高度,若超过了则在菜单内部显示滚动条 |
|
// 级联菜单内部不允许出现滚动条 |
|
var menuHeightTemp = menuHeight; |
|
// 简单菜单比窗口高时,限制菜单高度 |
|
if (!this.isCascade) { |
|
if (menuHeight + gutter * 2 > windowHeight) { |
|
menuHeightTemp = windowHeight - gutter * 2; |
|
this.$element.height(menuHeightTemp); |
|
} |
|
} |
|
menuTop = |
|
(windowHeight - menuHeightTemp) / 2 + |
|
(isFixed ? 0 : anchorOffsetTop - anchorTop); |
|
} |
|
this.$element.css('top', (menuTop + "px")); |
|
// 设置菜单对齐方式 |
|
if (align === 'left') { |
|
transformOriginX = '0'; |
|
menuLeft = isFixed ? anchorLeft : anchorOffsetLeft; |
|
} |
|
else if (align === 'right') { |
|
transformOriginX = '100%'; |
|
menuLeft = isFixed |
|
? anchorLeft + anchorWidth - menuWidth |
|
: anchorOffsetLeft + anchorWidth - menuWidth; |
|
} |
|
else { |
|
transformOriginX = '50%'; |
|
//=======================在窗口中居中 |
|
// 显示的菜单的宽度,菜单宽度不能超过窗口宽度 |
|
var menuWidthTemp = menuWidth; |
|
// 菜单比窗口宽,限制菜单宽度 |
|
if (menuWidth + gutter * 2 > windowWidth) { |
|
menuWidthTemp = windowWidth - gutter * 2; |
|
this.$element.width(menuWidthTemp); |
|
} |
|
menuLeft = |
|
(windowWidth - menuWidthTemp) / 2 + |
|
(isFixed ? 0 : anchorOffsetLeft - anchorLeft); |
|
} |
|
this.$element.css('left', (menuLeft + "px")); |
|
// 设置菜单动画方向 |
|
this.$element.transformOrigin((transformOriginX + " " + transformOriginY)); |
|
}; |
|
/** |
|
* 调整子菜单的位置 |
|
* @param $submenu |
|
*/ |
|
Menu.prototype.readjustSubmenu = function readjustSubmenu ($submenu) { |
|
var $item = $submenu.parent('.mdui-menu-item'); |
|
var submenuTop; |
|
var submenuLeft; |
|
// 子菜单位置和方向 |
|
var position; |
|
var align; |
|
// window 窗口的宽度和高度 |
|
var windowHeight = $window.height(); |
|
var windowWidth = $window.width(); |
|
// 动画方向参数 |
|
var transformOriginX; |
|
var transformOriginY; |
|
// 子菜单的原始宽度和高度 |
|
var submenuWidth = $submenu.width(); |
|
var submenuHeight = $submenu.height(); |
|
// 触发子菜单的菜单项的宽度高度 |
|
var itemRect = $item[0].getBoundingClientRect(); |
|
var itemWidth = itemRect.width; |
|
var itemHeight = itemRect.height; |
|
var itemLeft = itemRect.left; |
|
var itemTop = itemRect.top; |
|
// 判断菜单上下位置 |
|
if (windowHeight - itemTop > submenuHeight) { |
|
// 判断下方是否放得下菜单 |
|
position = 'bottom'; |
|
} |
|
else if (itemTop + itemHeight > submenuHeight) { |
|
// 判断上方是否放得下菜单 |
|
position = 'top'; |
|
} |
|
else { |
|
// 默认放在下方 |
|
position = 'bottom'; |
|
} |
|
// 判断菜单左右位置 |
|
if (windowWidth - itemLeft - itemWidth > submenuWidth) { |
|
// 判断右侧是否放得下菜单 |
|
align = 'left'; |
|
} |
|
else if (itemLeft > submenuWidth) { |
|
// 判断左侧是否放得下菜单 |
|
align = 'right'; |
|
} |
|
else { |
|
// 默认放在右侧 |
|
align = 'left'; |
|
} |
|
// 设置菜单位置 |
|
if (position === 'bottom') { |
|
transformOriginY = '0'; |
|
submenuTop = '0'; |
|
} |
|
else if (position === 'top') { |
|
transformOriginY = '100%'; |
|
submenuTop = -submenuHeight + itemHeight; |
|
} |
|
$submenu.css('top', (submenuTop + "px")); |
|
// 设置菜单对齐方式 |
|
if (align === 'left') { |
|
transformOriginX = '0'; |
|
submenuLeft = itemWidth; |
|
} |
|
else if (align === 'right') { |
|
transformOriginX = '100%'; |
|
submenuLeft = -submenuWidth; |
|
} |
|
$submenu.css('left', (submenuLeft + "px")); |
|
// 设置菜单动画方向 |
|
$submenu.transformOrigin((transformOriginX + " " + transformOriginY)); |
|
}; |
|
/** |
|
* 打开子菜单 |
|
* @param $submenu |
|
*/ |
|
Menu.prototype.openSubMenu = function openSubMenu ($submenu) { |
|
this.readjustSubmenu($submenu); |
|
$submenu |
|
.addClass('mdui-menu-open') |
|
.parent('.mdui-menu-item') |
|
.addClass('mdui-menu-item-active'); |
|
}; |
|
/** |
|
* 关闭子菜单,及其嵌套的子菜单 |
|
* @param $submenu |
|
*/ |
|
Menu.prototype.closeSubMenu = function closeSubMenu ($submenu) { |
|
// 关闭子菜单 |
|
$submenu |
|
.removeClass('mdui-menu-open') |
|
.addClass('mdui-menu-closing') |
|
.transitionEnd(function () { return $submenu.removeClass('mdui-menu-closing'); }) |
|
// 移除激活状态的样式 |
|
.parent('.mdui-menu-item') |
|
.removeClass('mdui-menu-item-active'); |
|
// 循环关闭嵌套的子菜单 |
|
$submenu.find('.mdui-menu').each(function (_, menu) { |
|
var $subSubmenu = $(menu); |
|
$subSubmenu |
|
.removeClass('mdui-menu-open') |
|
.addClass('mdui-menu-closing') |
|
.transitionEnd(function () { return $subSubmenu.removeClass('mdui-menu-closing'); }) |
|
.parent('.mdui-menu-item') |
|
.removeClass('mdui-menu-item-active'); |
|
}); |
|
}; |
|
/** |
|
* 切换子菜单状态 |
|
* @param $submenu |
|
*/ |
|
Menu.prototype.toggleSubMenu = function toggleSubMenu ($submenu) { |
|
$submenu.hasClass('mdui-menu-open') |
|
? this.closeSubMenu($submenu) |
|
: this.openSubMenu($submenu); |
|
}; |
|
/** |
|
* 绑定子菜单事件 |
|
*/ |
|
Menu.prototype.bindSubMenuEvent = function bindSubMenuEvent () { |
|
// eslint-disable-next-line @typescript-eslint/no-this-alias |
|
var that = this; |
|
// 点击打开子菜单 |
|
this.$element.on('click', '.mdui-menu-item', function (event) { |
|
var $item = $(this); |
|
var $target = $(event.target); |
|
// 禁用状态菜单不操作 |
|
if ($item.attr('disabled') !== undefined) { |
|
return; |
|
} |
|
// 没有点击在子菜单的菜单项上时,不操作(点在了子菜单的空白区域、或分隔线上) |
|
if ($target.is('.mdui-menu') || $target.is('.mdui-divider')) { |
|
return; |
|
} |
|
// 阻止冒泡,点击菜单项时只在最后一级的 mdui-menu-item 上生效,不向上冒泡 |
|
if (!$target.parents('.mdui-menu-item').first().is($item)) { |
|
return; |
|
} |
|
// 当前菜单的子菜单 |
|
var $submenu = $item.children('.mdui-menu'); |
|
// 先关闭除当前子菜单外的所有同级子菜单 |
|
$item |
|
.parent('.mdui-menu') |
|
.children('.mdui-menu-item') |
|
.each(function (_, item) { |
|
var $tmpSubmenu = $(item).children('.mdui-menu'); |
|
if ($tmpSubmenu.length && |
|
(!$submenu.length || !$tmpSubmenu.is($submenu))) { |
|
that.closeSubMenu($tmpSubmenu); |
|
} |
|
}); |
|
// 切换当前子菜单 |
|
if ($submenu.length) { |
|
that.toggleSubMenu($submenu); |
|
} |
|
}); |
|
if (this.options.subMenuTrigger === 'hover') { |
|
// 临时存储 setTimeout 对象 |
|
var timeout = null; |
|
var timeoutOpen = null; |
|
this.$element.on('mouseover mouseout', '.mdui-menu-item', function (event) { |
|
var $item = $(this); |
|
var eventType = event.type; |
|
var $relatedTarget = $(event.relatedTarget); |
|
// 禁用状态的菜单不操作 |
|
if ($item.attr('disabled') !== undefined) { |
|
return; |
|
} |
|
// 用 mouseover 模拟 mouseenter |
|
if (eventType === 'mouseover') { |
|
if (!$item.is($relatedTarget) && |
|
contains($item[0], $relatedTarget[0])) { |
|
return; |
|
} |
|
} |
|
// 用 mouseout 模拟 mouseleave |
|
else if (eventType === 'mouseout') { |
|
if ($item.is($relatedTarget) || |
|
contains($item[0], $relatedTarget[0])) { |
|
return; |
|
} |
|
} |
|
// 当前菜单项下的子菜单,未必存在 |
|
var $submenu = $item.children('.mdui-menu'); |
|
// 鼠标移入菜单项时,显示菜单项下的子菜单 |
|
if (eventType === 'mouseover') { |
|
if ($submenu.length) { |
|
// 当前子菜单准备打开时,如果当前子菜单正准备着关闭,不用再关闭了 |
|
var tmpClose = $submenu.data('timeoutClose.mdui.menu'); |
|
if (tmpClose) { |
|
clearTimeout(tmpClose); |
|
} |
|
// 如果当前子菜单已经打开,不操作 |
|
if ($submenu.hasClass('mdui-menu-open')) { |
|
return; |
|
} |
|
// 当前子菜单准备打开时,其他准备打开的子菜单不用再打开了 |
|
clearTimeout(timeoutOpen); |
|
// 准备打开当前子菜单 |
|
timeout = timeoutOpen = setTimeout(function () { return that.openSubMenu($submenu); }, that.options.subMenuDelay); |
|
$submenu.data('timeoutOpen.mdui.menu', timeout); |
|
} |
|
} |
|
// 鼠标移出菜单项时,关闭菜单项下的子菜单 |
|
else if (eventType === 'mouseout') { |
|
if ($submenu.length) { |
|
// 鼠标移出菜单项时,如果当前菜单项下的子菜单正准备打开,不用再打开了 |
|
var tmpOpen = $submenu.data('timeoutOpen.mdui.menu'); |
|
if (tmpOpen) { |
|
clearTimeout(tmpOpen); |
|
} |
|
// 准备关闭当前子菜单 |
|
timeout = setTimeout(function () { return that.closeSubMenu($submenu); }, that.options.subMenuDelay); |
|
$submenu.data('timeoutClose.mdui.menu', timeout); |
|
} |
|
} |
|
}); |
|
} |
|
}; |
|
/** |
|
* 动画结束回调 |
|
*/ |
|
Menu.prototype.transitionEnd = function transitionEnd () { |
|
this.$element.removeClass('mdui-menu-closing'); |
|
if (this.state === 'opening') { |
|
this.state = 'opened'; |
|
this.triggerEvent('opened'); |
|
} |
|
if (this.state === 'closing') { |
|
this.state = 'closed'; |
|
this.triggerEvent('closed'); |
|
// 关闭后,恢复菜单样式到默认状态,并恢复 fixed 定位 |
|
this.$element.css({ |
|
top: '', |
|
left: '', |
|
width: '', |
|
position: 'fixed', |
|
}); |
|
} |
|
}; |
|
/** |
|
* 切换菜单状态 |
|
*/ |
|
Menu.prototype.toggle = function toggle () { |
|
this.isOpen() ? this.close() : this.open(); |
|
}; |
|
/** |
|
* 打开菜单 |
|
*/ |
|
Menu.prototype.open = function open () { |
|
var this$1 = this; |
|
|
|
if (this.isOpen()) { |
|
return; |
|
} |
|
this.state = 'opening'; |
|
this.triggerEvent('open'); |
|
this.readjust(); |
|
this.$element |
|
// 菜单隐藏状态使用使用 fixed 定位。 |
|
.css('position', this.options.fixed ? 'fixed' : 'absolute') |
|
.addClass('mdui-menu-open') |
|
.transitionEnd(function () { return this$1.transitionEnd(); }); |
|
}; |
|
/** |
|
* 关闭菜单 |
|
*/ |
|
Menu.prototype.close = function close () { |
|
var this$1 = this; |
|
|
|
if (!this.isOpen()) { |
|
return; |
|
} |
|
this.state = 'closing'; |
|
this.triggerEvent('close'); |
|
// 菜单开始关闭时,关闭所有子菜单 |
|
this.$element.find('.mdui-menu').each(function (_, submenu) { |
|
this$1.closeSubMenu($(submenu)); |
|
}); |
|
this.$element |
|
.removeClass('mdui-menu-open') |
|
.addClass('mdui-menu-closing') |
|
.transitionEnd(function () { return this$1.transitionEnd(); }); |
|
}; |
|
mdui.Menu = Menu; |
|
|
|
var customAttr$9 = 'mdui-menu'; |
|
var dataName$3 = '_mdui_menu'; |
|
$(function () { |
|
$document.on('click', ("[" + customAttr$9 + "]"), function () { |
|
var $this = $(this); |
|
var instance = $this.data(dataName$3); |
|
if (!instance) { |
|
var options = parseOptions(this, customAttr$9); |
|
var menuSelector = options.target; |
|
// @ts-ignore |
|
delete options.target; |
|
instance = new mdui.Menu($this, menuSelector, options); |
|
$this.data(dataName$3, instance); |
|
instance.toggle(); |
|
} |
|
}); |
|
}); |
|
|
|
return mdui; |
|
|
|
}))); |
|
//# sourceMappingURL=mdui.js.map
|
|
|