hexo-theme-nexmoe
Version:
🔥 A special hexo theme.
1,705 lines (1,455 loc) • 240 kB
JavaScript
/* !
* mdui v0.4.3 (https://mdui.org)
* Copyright 2016-2019 zdhxiong
* Licensed under MIT
*/
/* jshint ignore:start */
(function(global, factory) {
typeof exports === 'object' && typeof module !== 'undefined' ? module.exports = factory()
: typeof define === 'function' && define.amd ? define(factory)
: global.mdui = factory();
}(this, () => {
/* jshint ignore:end */
const mdui = {};
/**
* =============================================================================
* ************ 浏览器兼容性问题修复 ************
* =============================================================================
*/
/**
* requestAnimationFrame
* cancelAnimationFrame
*/
(function() {
let lastTime = 0;
if (!window.requestAnimationFrame) {
window.requestAnimationFrame = window.webkitRequestAnimationFrame;
window.cancelAnimationFrame = window.webkitCancelAnimationFrame;
}
if (!window.requestAnimationFrame) {
window.requestAnimationFrame = function(callback, element) {
const currTime = new Date().getTime();
const timeToCall = Math.max(0, 16.7 - (currTime - lastTime));
const id = window.setTimeout(() => {
callback(currTime + timeToCall);
}, timeToCall);
lastTime = currTime + timeToCall;
return id;
};
}
if (!window.cancelAnimationFrame) {
window.cancelAnimationFrame = function(id) {
clearTimeout(id);
};
}
}());
/**
* JQ 1.0.0 (https://github.com/zdhxiong/mdui.JQ#readme)
* Copyright 2018-2018 zdhxiong
* Licensed under MIT
*/
const $ = (function() {
const JQ = function JQ(arr) {
const self = this;
for (let i = 0; i < arr.length; i += 1) {
self[i] = arr[i];
}
self.length = arr.length;
return this;
};
function $(selector) {
const arr = [];
if (!selector) {
return new JQ(arr);
}
if (selector instanceof JQ) {
return selector;
}
if (typeof selector === 'string') {
const html = selector.trim();
if (html[0] === '<' && html[html.length - 1] === '>') {
// 创建 HTML 字符串
let toCreate = 'div';
if (html.indexOf('<li') === 0) {
toCreate = 'ul';
}
if (html.indexOf('<tr') === 0) {
toCreate = 'tbody';
}
if (html.indexOf('<td') === 0 || html.indexOf('<th') === 0) {
toCreate = 'tr';
}
if (html.indexOf('<tbody') === 0) {
toCreate = 'table';
}
if (html.indexOf('<option') === 0) {
toCreate = 'select';
}
const tempParent = document.createElement(toCreate);
tempParent.innerHTML = html;
for (let i = 0; i < tempParent.childNodes.length; i += 1) {
arr.push(tempParent.childNodes[i]);
}
} else {
// 选择器
const elems = selector[0] === '#' && !selector.match(/[ .<>:~]/)
? [document.getElementById(selector.slice(1))]
: document.querySelectorAll(selector);
for (let i$1 = 0; i$1 < elems.length; i$1 += 1) {
if (elems[i$1]) {
arr.push(elems[i$1]);
}
}
}
} else if (typeof selector === 'function') {
// function
return $(document).ready(selector);
} else if (selector.nodeType || selector === window || selector === document) {
// Node
arr.push(selector);
} else if (selector.length > 0 && selector[0].nodeType) {
// NodeList
for (let i$2 = 0; i$2 < selector.length; i$2 += 1) {
arr.push(selector[i$2]);
}
}
return new JQ(arr);
}
$.fn = JQ.prototype;
function extend() {
const this$1 = this;
const args = []; let len = arguments.length;
while (len--) args[len] = arguments[len];
if (!args.length) {
return this;
}
// $.extend(obj)
if (args.length === 1) {
Object.keys(args[0]).forEach(prop => {
this$1[prop] = args[0][prop];
});
return this;
}
// $.extend({}, defaults[, obj])
const target = args.shift();
const loop = function(i) {
Object.keys(args[i]).forEach(prop => {
target[prop] = args[i][prop];
});
};
for (let i = 0; i < args.length; i += 1) loop(i);
return target;
}
$.fn.extend = extend;
$.extend = extend;
/**
* 判断一个节点名
* @param ele
* @param name
* @returns {boolean}
*/
function isNodeName(ele, name) {
return ele.nodeName && ele.nodeName.toLowerCase() === name.toLowerCase();
}
/**
* 除去 null 后的 object 类型
* @param obj
* @returns {*|boolean}
*/
function isObjectLike(obj) {
return typeof obj === 'object' && obj !== null;
}
function isFunction(fn) {
return typeof fn === 'function';
}
function isString(obj) {
return typeof obj === 'string';
}
function isWindow(win) {
return win && win === win.window;
}
function isDocument(doc) {
return doc && doc.nodeType === doc.DOCUMENT_NODE;
}
function isArrayLike(obj) {
return typeof obj.length === 'number';
}
/**
* 循环数组或对象
* @param obj
* @param callback
* @returns {*}
*/
function each(obj, callback) {
if (isArrayLike(obj)) {
for (let i = 0; i < obj.length; i += 1) {
if (callback.call(obj[i], i, obj[i]) === false) {
return obj;
}
}
} else {
const keys = Object.keys(obj);
for (let i$1 = 0; i$1 < keys.length; i$1 += 1) {
if (callback.call(obj[keys[i$1]], keys[i$1], obj[keys[i$1]]) === false) {
return obj;
}
}
}
return obj;
}
/**
* 遍历数组或对象,通过函数返回一个新的数组或对象,null 和 undefined 将被过滤掉。
* @param elems
* @param callback
* @returns {Array}
*/
function map(elems, callback) {
let ref,
value;
const ret = [];
each(elems, (i, elem) => {
value = callback(elem, i);
if (value !== null && value !== undefined) {
ret.push(value);
}
});
return (ref = []).concat.apply(ref, ret);
}
/**
* 把对象合并到第一个参数中,并返回第一个参数
* @param first
* @param second
* @returns {*}
*/
function merge(first, second) {
each(second, (i, val) => {
first.push(val);
});
return first;
}
/**
* 删除数组中重复元素
* @param arr {Array}
* @returns {Array}
*/
function unique(arr) {
const result = [];
for (let i = 0; i < arr.length; i += 1) {
if (result.indexOf(arr[i]) === -1) {
result.push(arr[i]);
}
}
return result;
}
const elementDisplay = {};
/**
* 获取元素的默认 display 样式值,用于 .show() 方法
* @param nodeName
* @returns {*}
*/
function defaultDisplay(nodeName) {
let element,
display;
if (!elementDisplay[nodeName]) {
element = document.createElement(nodeName);
document.body.appendChild(element);
display = getComputedStyle(element, '').getPropertyValue('display');
element.parentNode.removeChild(element);
if (display === 'none') {
display = 'block';
}
elementDisplay[nodeName] = display;
}
return elementDisplay[nodeName];
}
$.extend({
each: each,
merge: merge,
unique: unique,
map: map,
/**
* 一个 DOM 节点是否包含另一个 DOM 节点
* @param parent {Node} 父节点
* @param node {Node} 子节点
* @returns {Boolean}
*/
contains: function contains(parent, node) {
if (parent && !node) {
return document.documentElement.contains(parent);
}
return parent !== node && parent.contains(node);
},
/**
* 将数组或对象序列化
* @param obj
* @returns {String}
*/
param: function param(obj) {
if (!isObjectLike(obj)) {
return '';
}
const args = [];
function destructure(key, value) {
let keyTmp;
if (isObjectLike(value)) {
each(value, (i, v) => {
if (Array.isArray(value) && !isObjectLike(v)) {
keyTmp = '';
} else {
keyTmp = i;
}
destructure(key + '[' + keyTmp + ']', v);
});
} else {
if (value !== null && value !== '') {
keyTmp = '=' + encodeURIComponent(value);
} else {
keyTmp = '';
}
args.push(encodeURIComponent(key) + keyTmp);
}
}
each(obj, (key, value) => {
destructure(key, value);
});
return args.join('&');
}
});
$.fn.extend({
/**
* 遍历对象
* @param callback {Function}
* @return {JQ}
*/
each: function each$1(callback) {
return each(this, callback);
},
/**
* 通过遍历集合中的节点对象,通过函数返回一个新的对象,null 或 undefined 将被过滤掉。
* @param callback {Function}
* @returns {JQ}
*/
map: function map$1(callback) {
return new JQ(map(this, (el, i) => { return callback.call(el, i, el); }));
},
/**
* 获取指定 DOM 元素,没有 index 参数时,获取所有 DOM 的数组
* @param index {Number=}
* @returns {Node|Array}
*/
get: function get(index) {
return index === undefined
? [].slice.call(this)
: this[index >= 0 ? index : index + this.length];
},
/**
* array中提取的方法。从start开始,如果end 指出。提取不包含end位置的元素。
* @param args {start, end}
* @returns {JQ}
*/
slice: function slice() {
const args = []; let len = arguments.length;
while (len--) args[len] = arguments[len];
return new JQ([].slice.apply(this, args));
},
/**
* 筛选元素集合
* @param selector {String|JQ|Node|Function}
* @returns {JQ}
*/
filter: function filter(selector) {
if (isFunction(selector)) {
return this.map((index, ele) => { return selector.call(ele, index, ele) ? ele : undefined; });
}
const $selector = $(selector);
return this.map((index, ele) => { return $selector.index(ele) > -1 ? ele : undefined; });
},
/**
* 从元素集合中删除指定的元素
* @param selector {String|Node|JQ|Function}
* @return {JQ}
*/
not: function not(selector) {
const $excludes = this.filter(selector);
return this.map((index, ele) => { return $excludes.index(ele) > -1 ? undefined : ele; });
},
/**
* 获取元素相对于 document 的偏移
* @returns {Object}
*/
offset: function offset() {
if (this[0]) {
const offset = this[0].getBoundingClientRect();
return {
left: offset.left + window.pageXOffset,
top: offset.top + window.pageYOffset,
width: offset.width,
height: offset.height
};
}
return null;
},
/**
* 返回最近的用于定位的父元素
* @returns {*|JQ}
*/
offsetParent: function offsetParent() {
return this.map(function() {
let parent = this.offsetParent;
while (parent && $(parent).css('position') === 'static') {
parent = parent.offsetParent;
}
return parent || document.documentElement;
});
},
/**
* 获取元素相对于父元素的偏移
* @return {Object}
*/
position: function position() {
const self = this;
if (!self[0]) {
return null;
}
let offsetParent,
offset;
let parentOffset = {
top: 0,
left: 0
};
if (self.css('position') === 'fixed') {
offset = self[0].getBoundingClientRect();
} else {
offsetParent = self.offsetParent();
offset = self.offset();
if (!isNodeName(offsetParent[0], 'html')) {
parentOffset = offsetParent.offset();
}
parentOffset = {
top: parentOffset.top + offsetParent.css('borderTopWidth'),
left: parentOffset.left + offsetParent.css('borderLeftWidth')
};
}
return {
top: offset.top - parentOffset.top - self.css('marginTop'),
left: offset.left - parentOffset.left - self.css('marginLeft'),
width: offset.width,
height: offset.height
};
},
/**
* 显示指定元素
* @returns {JQ}
*/
show: function show() {
return this.each(function() {
if (this.style.display === 'none') {
this.style.display = '';
}
if (window.getComputedStyle(this, '').getPropertyValue('display') === 'none') {
this.style.display = defaultDisplay(this.nodeName);
}
});
},
/**
* 隐藏指定元素
* @returns {JQ}
*/
hide: function hide() {
return this.each(function() {
this.style.display = 'none';
});
},
/**
* 切换元素的显示状态
* @returns {JQ}
*/
toggle: function toggle() {
return this.each(function() {
this.style.display = this.style.display === 'none' ? '' : 'none';
});
},
/**
* 是否含有指定的 CSS 类
* @param className {String}
* @returns {boolean}
*/
hasClass: function hasClass(className) {
if (!this[0] || !className) {
return false;
}
return this[0].classList.contains(className);
},
/**
* 移除指定属性
* @param attr {String}
* @returns {JQ}
*/
removeAttr: function removeAttr(attr) {
return this.each(function() {
this.removeAttribute(attr);
});
},
/**
* 删除属性值
* @param name {String}
* @returns {JQ}
*/
removeProp: function removeProp(name) {
return this.each(function() {
try {
delete this[name];
} catch (e) {
// empty
}
});
},
/**
* 获取当前对象中第n个元素
* @param index {Number}
* @returns {JQ}
*/
eq: function eq(index) {
const ret = index === -1
? this.slice(index)
: this.slice(index, +index + 1);
return new JQ(ret);
},
/**
* 获取对象中第一个元素
* @returns {JQ}
*/
first: function first() {
return this.eq(0);
},
/**
* 获取对象中最后一个元素
* @returns {JQ}
*/
last: function last() {
return this.eq(-1);
},
/**
* 获取一个元素的位置。
* 当 elem 参数没有给出时,返回当前元素在兄弟节点中的位置。
* 有给出了 elem 参数时,返回 elem 元素在当前对象中的位置
* @param elem {Selector|Node=}
* @returns {Number}
*/
index: function index(elem) {
if (!elem) {
// 获取当前 JQ 对象的第一个元素在同辈元素中的位置
return this
.eq(0)
.parent()
.children()
.get()
.indexOf(this[0]);
}
if (isString(elem)) {
// 返回当前 JQ 对象的第一个元素在指定选择器对应的元素中的位置
return $(elem)
.eq(0)
.parent()
.children()
.get()
.indexOf(this[0]);
}
// 返回指定元素在当前 JQ 对象中的位置
return this
.get()
.indexOf(elem);
},
/**
* 根据选择器、DOM元素或 JQ 对象来检测匹配元素集合,
* 如果其中至少有一个元素符合这个给定的表达式就返回true
* @param selector {String|Node|NodeList|Array|JQ|Window}
* @returns boolean
*/
is: function is(selector) {
const self = this[0];
if (!self || selector === undefined || selector === null) {
return false;
}
if (isString(selector)) {
if (self === document || self === window) {
return false;
}
const matchesSelector = self.matches
|| self.matchesSelector
|| self.webkitMatchesSelector
|| self.mozMatchesSelector
|| self.oMatchesSelector
|| self.msMatchesSelector;
return matchesSelector.call(self, selector);
}
if (selector === document || selector === window) {
return self === selector;
}
if (selector.nodeType || isArrayLike(selector)) {
const $compareWith = selector.nodeType ? [selector] : selector;
for (let i = 0; i < $compareWith.length; i += 1) {
if ($compareWith[i] === self) {
return true;
}
}
return false;
}
return false;
},
/**
* 根据 CSS 选择器找到后代节点的集合
* @param selector {String}
* @returns {JQ}
*/
find: function find(selector) {
const foundElements = [];
this.each((i, _this) => {
const nodeType = _this.nodeType;
if (nodeType !== 1 && nodeType !== 9) {
// 不是 element 和 document 则跳过
return;
}
merge(foundElements, _this.querySelectorAll(selector));
});
return new JQ(foundElements);
},
/**
* 找到直接子元素的元素集合
* @param selector {String=}
* @returns {JQ}
*/
children: function children(selector) {
const children = [];
this.each((_, _this) => {
each(_this.childNodes, (__, childNode) => {
if (childNode.nodeType !== 1) {
return;
}
if (!selector || (selector && $(childNode).is(selector))) {
children.push(childNode);
}
});
});
return new JQ(unique(children));
},
/**
* 保留含有指定子元素的元素,去掉不含有指定子元素的元素
* @param selector {String|Node|JQ|NodeList|Array}
* @return {JQ}
*/
has: function has(selector) {
const $targets = isString(selector) ? this.find(selector) : $(selector);
const length = $targets.length;
return this.filter(function() {
for (let i = 0; i < length; i += 1) {
if ($.contains(this, $targets[i])) {
return true;
}
}
return false;
});
},
/**
* 取得同辈元素的集合
* @param selector {String=}
* @returns {JQ}
*/
siblings: function siblings(selector) {
return this.prevAll(selector).add(this.nextAll(selector));
},
/**
* 返回首先匹配到的父节点,包含父节点
* @param selector {String}
* @returns {JQ}
*/
closest: function closest(selector) {
let self = this;
if (!self.is(selector)) {
self = self.parents(selector).eq(0);
}
return self;
},
/**
* 删除所有匹配的元素
* @returns {JQ}
*/
remove: function remove() {
return this.each((i, _this) => {
if (_this.parentNode) {
_this.parentNode.removeChild(_this);
}
});
},
/**
* 添加匹配的元素到当前对象中
* @param selector {String|JQ}
* @returns {JQ}
*/
add: function add(selector) {
return new JQ(unique(merge(this.get(), $(selector))));
},
/**
* 删除子节点
* @returns {JQ}
*/
empty: function empty() {
return this.each(function() {
this.innerHTML = '';
});
},
/**
* 通过深度克隆来复制集合中的所有元素。
* (通过原生 cloneNode 方法深度克隆来复制集合中的所有元素。此方法不会有数据和事件处理程序复制到新的元素。这点和jquery中利用一个参数来确定是否复制数据和事件处理不相同。)
* @returns {JQ}
*/
clone: function clone() {
return this.map(function() {
return this.cloneNode(true);
});
},
/**
* 用新元素替换当前元素
* @param newContent {String|Node|NodeList|JQ}
* @returns {JQ}
*/
replaceWith: function replaceWith(newContent) {
return this.before(newContent).remove();
},
/**
* 将表单元素的值组合成键值对数组
* @returns {Array}
*/
serializeArray: function serializeArray() {
const result = [];
const elem = this[0];
if (!elem || !elem.elements) {
return result;
}
$([].slice.call(elem.elements)).each(function() {
const $elem = $(this);
const type = $elem.attr('type');
if (
this.nodeName.toLowerCase() !== 'fieldset'
&& !this.disabled
&& ['submit', 'reset', 'button'].indexOf(type) === -1
&& (['radio', 'checkbox'].indexOf(type) === -1 || this.checked)
) {
result.push({
name: $elem.attr('name'),
value: $elem.val()
});
}
});
return result;
},
/**
* 将表单元素或对象序列化
* @returns {String}
*/
serialize: function serialize() {
const result = [];
each(this.serializeArray(), (i, elem) => {
result.push(encodeURIComponent(elem.name) + '=' + encodeURIComponent(elem.value));
});
return result.join('&');
}
});
/**
* val - 获取或设置元素的值
* @param value {String=}
* @return {*|JQ}
*/
/**
* html - 获取或设置元素的 HTML
* @param value {String=}
* @return {*|JQ}
*/
/**
* text - 获取或设置元素的内容
* @param value {String=}
* @return {*|JQ}
*/
each(['val', 'html', 'text'], (nameIndex, name) => {
const props = {
0: 'value',
1: 'innerHTML',
2: 'textContent'
};
const defaults = {
0: undefined,
1: undefined,
2: null
};
$.fn[name] = function(value) {
if (value === undefined) {
// 获取值
return this[0] ? this[0][props[nameIndex]] : defaults[nameIndex];
}
// 设置值
return this.each((i, elem) => {
elem[props[nameIndex]] = value;
});
};
});
/**
* attr - 获取或设置元素的属性值
* @param {name|props|key,value=}
* @return {String|JQ}
*/
/**
* prop - 获取或设置元素的属性值
* @param {name|props|key,value=}
* @return {String|JQ}
*/
/**
* css - 获取或设置元素的样式
* @param {name|props|key,value=}
* @return {String|JQ}
*/
each(['attr', 'prop', 'css'], (nameIndex, name) => {
function set(elem, key, value) {
if (nameIndex === 0) {
elem.setAttribute(key, value);
} else if (nameIndex === 1) {
elem[key] = value;
} else {
elem.style[key] = value;
}
}
function get(elem, key) {
if (!elem) {
return undefined;
}
if (nameIndex === 0) {
return elem.getAttribute(key);
}
if (nameIndex === 1) {
return elem[key];
}
return window.getComputedStyle(elem, null).getPropertyValue(key);
}
$.fn[name] = function(key, value) {
const argLength = arguments.length;
if (argLength === 1 && isString(key)) {
// 获取值
return get(this[0], key);
}
// 设置值
return this.each((i, elem) => {
if (argLength === 2) {
set(elem, key, value);
} else {
each(key, (k, v) => {
set(elem, k, v);
});
}
});
};
});
/**
* addClass - 添加 CSS 类,多个类名用空格分割
* @param className {String}
* @return {JQ}
*/
/**
* removeClass - 移除 CSS 类,多个类名用空格分割
* @param className {String}
* @return {JQ}
*/
/**
* toggleClass - 切换 CSS 类名,多个类名用空格分割
* @param className {String}
* @return {JQ}
*/
each(['add', 'remove', 'toggle'], (nameIndex, name) => {
$.fn[name + 'Class'] = function(className) {
if (!className) {
return this;
}
const classes = className.split(' ');
return this.each((i, elem) => {
each(classes, (j, cls) => {
elem.classList[name](cls);
});
});
};
});
/**
* width - 获取元素的宽度
* @return {Number}
*/
/**
* height - 获取元素的高度
* @return {Number}
*/
each({
Width: 'width',
Height: 'height'
}, (prop, name) => {
$.fn[name] = function(val) {
if (val === undefined) {
// 获取
const elem = this[0];
if (isWindow(elem)) {
return elem['inner' + prop];
}
if (isDocument(elem)) {
return elem.documentElement['scroll' + prop];
}
const $elem = $(elem);
// IE10、IE11 在 box-sizing:border-box 时,不会包含 padding 和 border,这里进行修复
let IEFixValue = 0;
const isWidth = name === 'width';
if ('ActiveXObject' in window) { // 判断是 IE 浏览器
if ($elem.css('box-sizing') === 'border-box') {
IEFixValue = parseFloat($elem.css('padding-' + (isWidth ? 'left' : 'top')))
+ parseFloat($elem.css('padding-' + (isWidth ? 'right' : 'bottom')))
+ parseFloat($elem.css('border-' + (isWidth ? 'left' : 'top') + '-width'))
+ parseFloat($elem.css('border-' + (isWidth ? 'right' : 'bottom') + '-width'));
}
}
return parseFloat($(elem).css(name)) + IEFixValue;
}
// 设置
/* eslint no-restricted-globals: 0 */
if (!isNaN(Number(val)) && val !== '') {
val += 'px';
}
return this.css(name, val);
};
});
/**
* innerWidth - 获取元素的宽度,包含内边距
* @return {Number}
*/
/**
* innerHeight - 获取元素的高度,包含内边距
* @return {Number}
*/
each({
Width: 'width',
Height: 'height'
}, (prop, name) => {
$.fn['inner' + prop] = function() {
let value = this[name]();
const $elem = $(this[0]);
if ($elem.css('box-sizing') !== 'border-box') {
value += parseFloat($elem.css('padding-' + (name === 'width' ? 'left' : 'top')));
value += parseFloat($elem.css('padding-' + (name === 'width' ? 'right' : 'bottom')));
}
return value;
};
});
function dir(nodes, selector, nameIndex, node) {
const ret = [];
let elem;
nodes.each((j, _this) => {
elem = _this[node];
while (elem) {
if (nameIndex === 2) {
// prevUntil
if (!selector || (selector && $(elem).is(selector))) {
break;
}
ret.push(elem);
} else if (nameIndex === 0) {
// prev
if (!selector || (selector && $(elem).is(selector))) {
ret.push(elem);
}
break;
} else if (!selector || (selector && $(elem).is(selector))) {
// prevAll
ret.push(elem);
}
elem = elem[node];
}
});
return new JQ(unique(ret));
}
/**
* prev - 取得前一个匹配的元素
* @param selector {String=}
* @return {JQ}
*/
/**
* prevAll - 取得前面所有匹配的元素
* @param selector {String=}
* @return {JQ}
*/
/**
* prevUntil - 取得前面的所有元素,直到遇到匹配的元素,不包含匹配的元素
* @param selector {String=}
* @return {JQ}
*/
each(['', 'All', 'Until'], (nameIndex, name) => {
$.fn['prev' + name] = function(selector) {
// prevAll、prevUntil 需要把元素的顺序倒序处理,以便和 jQuery 的结果一致
const $nodes = nameIndex === 0 ? this : $(this.get().reverse());
return dir($nodes, selector, nameIndex, 'previousElementSibling');
};
});
/**
* next - 取得后一个匹配的元素
* @param selector {String=}
* @return {JQ}
*/
/**
* nextAll - 取得后面所有匹配的元素
* @param selector {String=}
* @return {JQ}
*/
/**
* nextUntil - 取得后面所有匹配的元素,直到遇到匹配的元素,不包含匹配的元素
* @param selector {String=}
* @return {JQ}
*/
each(['', 'All', 'Until'], (nameIndex, name) => {
$.fn['next' + name] = function(selector) {
return dir(this, selector, nameIndex, 'nextElementSibling');
};
});
/**
* parent - 取得匹配的直接父元素
* @param selector {String=}
* @return {JQ}
*/
/**
* parents - 取得所有匹配的父元素
* @param selector {String=}
* @return {JQ}
*/
/**
* parentUntil - 取得所有的父元素,直到遇到匹配的元素,不包含匹配的元素
* @param selector {String=}
* @return {JQ}
*/
each(['', 's', 'sUntil'], (nameIndex, name) => {
$.fn['parent' + name] = function(selector) {
// parents、parentsUntil 需要把元素的顺序反向处理,以便和 jQuery 的结果一致
const $nodes = nameIndex === 0 ? this : $(this.get().reverse());
return dir($nodes, selector, nameIndex, 'parentNode');
};
});
/**
* append - 在元素内部追加内容
* @param newChild {String|Node|NodeList|JQ}
* @return {JQ}
*/
/**
* prepend - 在元素内部前置内容
* @param newChild {String|Node|NodeList|JQ}
* @return {JQ}
*/
each(['append', 'prepend'], (nameIndex, name) => {
$.fn[name] = function(newChild) {
let newChilds;
const copyByClone = this.length > 1;
if (isString(newChild) && (newChild[0] !== '<' || newChild[newChild.length - 1] !== '>')) {
const tempDiv = document.createElement('div');
tempDiv.innerHTML = newChild;
newChilds = [].slice.call(tempDiv.childNodes);
} else {
newChilds = $(newChild).get();
}
if (nameIndex === 1) {
// prepend
newChilds.reverse();
}
return this.each((i, _this) => {
each(newChilds, (j, child) => {
// 一个元素要同时追加到多个元素中,需要先复制一份,然后追加
if (copyByClone && i > 0) {
child = child.cloneNode(true);
}
if (nameIndex === 0) {
// append
_this.appendChild(child);
} else {
// prepend
_this.insertBefore(child, _this.childNodes[0]);
}
});
});
};
});
/**
* insertBefore - 插入到指定元素的前面
* @param selector {String|Node|NodeList|JQ}
* @return {JQ}
*/
/**
* insertAfter - 插入到指定元素的后面
* @param selector {String|Node|NodeList|JQ}
* @return {JQ}
*/
each(['insertBefore', 'insertAfter'], (nameIndex, name) => {
$.fn[name] = function(selector) {
const $elem = $(selector);
return this.each((i, _this) => {
$elem.each((j, elem) => {
elem.parentNode.insertBefore(
$elem.length === 1 ? _this : _this.cloneNode(true),
nameIndex === 0 ? elem : elem.nextSibling
);
});
});
};
});
/**
* appendTo - 追加到指定元素内容
* @param selector {String|Node|NodeList|JQ}
* @return {JQ}
*/
/**
* prependTo - 前置到指定元素内部
* @param selector {String|Node|NodeList|JQ}
* @return {JQ}
*/
/**
* before - 插入到指定元素前面
* @param selector {String|Node|NodeList|JQ}
* @return {JQ}
*/
/**
* after - 插入到指定元素后面
* @param selector {String|Node|NodeList|JQ}
* @return {JQ}
*/
/**
* replaceAll - 替换掉指定元素
* @param selector {String|Node|NodeList|JQ}
* @return {JQ}
*/
each({
appendTo: 'append',
prependTo: 'prepend',
before: 'insertBefore',
after: 'insertAfter',
replaceAll: 'replaceWith'
}, (name, original) => {
$.fn[name] = function(selector) {
$(selector)[original](this);
return this;
};
});
const dataNS = 'mduiElementDataStorage';
$.extend({
/**
* 在指定元素上存储数据,或从指定元素上读取数据
* @param elem 必须, DOM 元素
* @param key 必须,键名
* @param value 可选,值
*/
data: function data(elem, key, value) {
let data = {};
if (value !== undefined) {
// 根据 key、value 设置值
data[key] = value;
} else if (isObjectLike(key)) {
// 根据键值对设置值
data = key;
} else if (key === undefined) {
// 获取所有值
const result = {};
each(elem.attributes, (i, attribute) => {
const name = attribute.name;
if (name.indexOf('data-') === 0) {
const prop = name.slice(5).replace(/-./g, u => { return u.charAt(1).toUpperCase(); });
result[prop] = attribute.value;
}
});
if (elem[dataNS]) {
each(elem[dataNS], (k, v) => {
result[k] = v;
});
}
return result;
} else if (elem[dataNS] && (key in elem[dataNS])) {
// 获取指定值
return elem[dataNS][key];
} else {
// 从 data- 中获取指定值
const dataKey = elem.getAttribute('data-' + key);
if (dataKey) {
return dataKey;
}
return undefined;
}
// 设置值
if (!elem[dataNS]) {
elem[dataNS] = {};
}
each(data, (k, v) => {
elem[dataNS][k] = v;
});
return undefined;
},
/**
* 移除指定元素上存放的数据
* @param elem 必须,DOM 元素
* @param key 必须,键名
*/
removeData: function removeData(elem, key) {
if (elem[dataNS] && elem[dataNS][key]) {
elem[dataNS][key] = null;
delete elem[dataNS][key];
}
}
});
$.fn.extend({
/**
* 在元素上读取或设置数据
* @param key 必须
* @param value
* @returns {*}
*/
data: function data(key, value) {
if (value === undefined) {
if (isObjectLike(key)) {
// 同时设置多个值
return this.each((i, elem) => {
$.data(elem, key);
});
}
if (this[0]) {
// 获取值
return $.data(this[0], key);
}
return undefined;
}
// 设置值
return this.each((i, elem) => {
$.data(elem, key, value);
});
},
/**
* 移除元素上存储的数据
* @param key 必须
* @returns {*}
*/
removeData: function removeData(key) {
return this.each((i, elem) => {
$.removeData(elem, key);
});
}
});
!(function() { try { return new e('test'); } catch (e) {} var e = function(e, t) { t = t || {bubbles: !1, cancelable: !1}; const n = document.createEvent('MouseEvent'); return n.initMouseEvent(e, t.bubbles, t.cancelable, window, 0, 0, 0, 0, 0, !1, !1, !1, !1, 0, null), n; }; e.prototype = Event.prototype, window.MouseEvent = e; }());
!(function() { function t(t, e) { e = e || {bubbles: !1, cancelable: !1, detail: void 0}; const n = document.createEvent('CustomEvent'); return n.initCustomEvent(t, e.bubbles, e.cancelable, e.detail), n; } typeof window.CustomEvent !== 'function' && (t.prototype = window.Event.prototype, window.CustomEvent = t); }());
// 存储事件
const handlers = {
// i: { // 元素ID
// j: { // 事件ID
// e: 事件名
// fn: 事件处理函数
// i: 事件ID
// proxy:
// sel: 选择器
// }
// }
};
// 元素ID
let mduiElementId = 1;
function fnFalse() {
return false;
}
/**
* 为元素赋予一个唯一的ID
* @param element
* @returns {number|*}
*/
function getElementId(element) {
if (!element.mduiElementId) {
mduiElementId += 1;
element.mduiElementId = mduiElementId;
}
return element.mduiElementId;
}
/**
* 获取匹配的事件
* @param element
* @param eventName
* @param func
* @param selector
* @returns {Array}
*/
function getHandlers(element, eventName, func, selector) {
return (handlers[getElementId(element)] || []).filter(handler => {
return handler
&& (!eventName || handler.e === eventName)
&& (!func || handler.fn.toString() === func.toString())
&& (!selector || handler.sel === selector);
});
}
/**
* 添加事件监听
* @param element
* @param eventName
* @param func
* @param data
* @param selector
*/
function add(element, eventName, func, data, selector) {
const elementId = getElementId(element);
if (!handlers[elementId]) {
handlers[elementId] = [];
}
// 传入 data.useCapture 来设置 useCapture: true
let useCapture = false;
if (isObjectLike(data) && data.useCapture) {
useCapture = true;
}
eventName.split(' ').forEach(event => {
const handler = {
e: event,
fn: func,
sel: selector,
i: handlers[elementId].length
};
function callFn(e, elem) {
// 因为鼠标事件模拟事件的 detail 属性是只读的,因此在 e._detail 中存储参数
/* eslint no-underscore-dangle: 0 */
const result = func.apply(elem, e._detail === undefined ? [e] : [e].concat(e._detail));
if (result === false) {
e.preventDefault();
e.stopPropagation();
}
}
function proxyfn(e) {
e._data = data;
if (selector) {
// 事件代理
$(element)
.find(selector)
.get()
.reverse()
.forEach(elem => {
if (elem === e.target || $.contains(elem, e.target)) {
callFn(e, elem);
}
});
} else {
// 不使用事件代理
callFn(e, element);
}
}
handler.proxy = proxyfn;
handlers[elementId].push(handler);
element.addEventListener(handler.e, proxyfn, useCapture);
});
}
/**
* 移除事件监听
* @param element
* @param eventName
* @param func
* @param selector
*/
function remove(element, eventName, func, selector) {
(eventName || '').split(' ').forEach(event => {
getHandlers(element, event, func, selector).forEach(handler => {
delete handlers[getElementId(element)][handler.i];
element.removeEventListener(handler.e, handler.proxy, false);
});
});
}
$.fn.extend({
/**
* DOM 加载完毕后调用的函数
* @param callback
* @returns {ready}
*/
ready: function ready(callback) {
if (/complete|loaded|interactive/.test(document.readyState) && document.body) {
callback($);
} else {
document.addEventListener('DOMContentLoaded', () => {
callback($);
}, false);
}
return this;
},
/**
* 绑定事件
*
* $().on({eventName: fn}, selector, data);
* $().on({eventName: fn}, selector)
* $().on({eventName: fn})
* $().on(eventName, selector, data, fn);
* $().on(eventName, selector, fn);
* $().on(eventName, data, fn);
* $().on(eventName, fn);
* $().on(eventName, false);
*
* @param eventName
* @param selector
* @param data
* @param callback
* @param one 是否是 one 方法,只在 JQ 内部使用
* @returns
*/
on: function on(eventName, selector, data, callback, one) {
const self = this;
// 默认
// $().on(event, selector, data, callback)
// event 使用 事件:函数 键值对
// event = {
// 'event1': callback1,
// 'event2': callback2
// }
//
// $().on(event, selector, data)
if (eventName && !isString(eventName)) {
each(eventName, (type, fn) => {
self.on(type, selector, data, fn);
});
return self;
}
// selector 不存在
// $().on(event, data, callback)
if (!isString(selector) && !isFunction(callback) && callback !== false) {
callback = data;
data = selector;
selector = undefined;
}
// data 不存在
// $().on(event, callback)
if (isFunction(data) || data === false) {
callback = data;
data = undefined;
}
// callback 为 false
// $().on(event, false)
if (callback === false) {
callback = fnFalse;
}
if (one === 1) {
const origCallback = callback;
callback = function() {
self.off(eventName, selector, callback);
/* eslint prefer-rest-params: 0 */
return origCallback.apply(this, arguments);
};
}
return this.each(function() {
add(this, eventName, callback, data, selector);
});
},
/**
* 绑定事件,只触发一次
* @param eventName
* @param selector
* @param data
* @param callback
*/
one: function one(eventName, selector, data, callback) {
const self = this;
if (!isString(eventName)) {
each(eventName, (type, fn) => {
type.split(' ').forEach(eName => {
self.on(eName, selector, data, fn, 1);
});
});
} else {
eventName.split(' ').forEach(eName => {