c-mdui-a
Version:
A fast way to build an application based on Material Design UI(MDUI).
2,008 lines (1,718 loc) • 204 kB
JavaScript
/*!
* mdui v0.4.2 (https://mdui.org)
* Copyright 2016-2018 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, (function() {
'use strict';
/* jshint ignore:end */
var mdui = {};
/**
* =============================================================================
* ************ 浏览器兼容性问题修复 ************
* =============================================================================
*/
/**
* requestAnimationFrame
* cancelAnimationFrame
*/
(function () {
var lastTime = 0;
if (!window.requestAnimationFrame) {
window.requestAnimationFrame = window.webkitRequestAnimationFrame;
window.cancelAnimationFrame = window.webkitCancelAnimationFrame;
}
if (!window.requestAnimationFrame) {
window.requestAnimationFrame = function (callback, element) {
var currTime = new Date().getTime();
var timeToCall = Math.max(0, 16.7 - (currTime - lastTime));
var id = window.setTimeout(function () {
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
*/
var $ = (function () {
'use strict';
var JQ = function JQ(arr) {
var self = this;
for (var i = 0; i < arr.length; i += 1) {
self[i] = arr[i];
}
self.length = arr.length;
return this;
};
function $$1(selector) {
var arr = [];
if (!selector) {
return new JQ(arr);
}
if (selector instanceof JQ) {
return selector;
}
if (typeof selector === 'string') {
var html = selector.trim();
if (html[0] === '<' && html[html.length - 1] === '>') {
// 创建 HTML 字符串
var 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';
}
var tempParent = document.createElement(toCreate);
tempParent.innerHTML = html;
for (var i = 0; i < tempParent.childNodes.length; i += 1) {
arr.push(tempParent.childNodes[i]);
}
} else {
// 选择器
var elems = selector[0] === '#' && !selector.match(/[ .<>:~]/)
? [document.getElementById(selector.slice(1))]
: document.querySelectorAll(selector);
for (var 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 $$1(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 (var i$2 = 0; i$2 < selector.length; i$2 += 1) {
arr.push(selector[i$2]);
}
}
return new JQ(arr);
}
$$1.fn = JQ.prototype;
function extend() {
var this$1 = this;
var args = [], 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(function (prop) {
this$1[prop] = args[0][prop];
});
return this;
}
// $.extend({}, defaults[, obj])
var target = args.shift();
var loop = function ( i ) {
Object.keys(args[i]).forEach(function (prop) {
target[prop] = args[i][prop];
});
};
for (var i = 0; i < args.length; i += 1) loop( i );
return target;
}
$$1.fn.extend = extend;
$$1.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 (var i = 0; i < obj.length; i += 1) {
if (callback.call(obj[i], i, obj[i]) === false) {
return obj;
}
}
} else {
var keys = Object.keys(obj);
for (var 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) {
var ref;
var value;
var ret = [];
each(elems, function (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, function (i, val) {
first.push(val);
});
return first;
}
/**
* 删除数组中重复元素
* @param arr {Array}
* @returns {Array}
*/
function unique(arr) {
var result = [];
for (var i = 0; i < arr.length; i += 1) {
if (result.indexOf(arr[i]) === -1) {
result.push(arr[i]);
}
}
return result;
}
var elementDisplay = {};
/**
* 获取元素的默认 display 样式值,用于 .show() 方法
* @param nodeName
* @returns {*}
*/
function defaultDisplay(nodeName) {
var element;
var 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];
}
$$1.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 '';
}
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 = "=" + (encodeURIComponent(value));
} else {
keyTmp = '';
}
args.push(encodeURIComponent(key) + keyTmp);
}
}
each(obj, function (key, value) {
destructure(key, value);
});
return args.join('&');
},
});
$$1.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, function (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() {
var args = [], 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(function (index, ele) { return (selector.call(ele, index, ele) ? ele : undefined); });
}
var $selector = $$1(selector);
return this.map(function (index, ele) { return ($selector.index(ele) > -1 ? ele : undefined); });
},
/**
* 从元素集合中删除指定的元素
* @param selector {String|Node|JQ|Function}
* @return {JQ}
*/
not: function not(selector) {
var $excludes = this.filter(selector);
return this.map(function (index, ele) { return ($excludes.index(ele) > -1 ? undefined : ele); });
},
/**
* 获取元素相对于 document 的偏移
* @returns {Object}
*/
offset: function offset() {
if (this[0]) {
var 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 () {
var parent = this.offsetParent;
while (parent && $$1(parent).css('position') === 'static') {
parent = parent.offsetParent;
}
return parent || document.documentElement;
});
},
/**
* 获取元素相对于父元素的偏移
* @return {Object}
*/
position: function position() {
var self = this;
if (!self[0]) {
return null;
}
var offsetParent;
var offset;
var 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) {
var 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 $$1(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) {
var self = this[0];
if (!self || selector === undefined || selector === null) {
return false;
}
if (isString(selector)) {
if (self === document || self === window) {
return false;
}
var 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)) {
var $compareWith = selector.nodeType ? [selector] : selector;
for (var 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) {
var foundElements = [];
this.each(function (i, _this) {
var 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) {
var children = [];
this.each(function (_, _this) {
each(_this.childNodes, function (__, childNode) {
if (childNode.nodeType !== 1) {
return;
}
if (!selector || (selector && $$1(childNode).is(selector))) {
children.push(childNode);
}
});
});
return new JQ(unique(children));
},
/**
* 保留含有指定子元素的元素,去掉不含有指定子元素的元素
* @param selector {String|Node|JQ|NodeList|Array}
* @return {JQ}
*/
has: function has(selector) {
var $targets = isString(selector) ? this.find(selector) : $$1(selector);
var length = $targets.length;
return this.filter(function () {
var this$1 = this;
for (var i = 0; i < length; i += 1) {
if ($$1.contains(this$1, $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) {
var self = this;
if (!self.is(selector)) {
self = self.parents(selector).eq(0);
}
return self;
},
/**
* 删除所有匹配的元素
* @returns {JQ}
*/
remove: function remove() {
return this.each(function (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(), $$1(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() {
var result = [];
var elem = this[0];
if (!elem || !elem.elements) {
return result;
}
$$1([].slice.call(elem.elements)).each(function () {
var $elem = $$1(this);
var 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() {
var result = [];
each(this.serializeArray(), function (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'], function (nameIndex, name) {
var props = {
0: 'value',
1: 'innerHTML',
2: 'textContent',
};
var defaults = {
0: undefined,
1: undefined,
2: null,
};
$$1.fn[name] = function (value) {
if (value === undefined) {
// 获取值
return this[0] ? this[0][props[nameIndex]] : defaults[nameIndex];
}
// 设置值
return this.each(function (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'], function (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);
}
$$1.fn[name] = function (key, value) {
var argLength = arguments.length;
if (argLength === 1 && isString(key)) {
// 获取值
return get(this[0], key);
}
// 设置值
return this.each(function (i, elem) {
if (argLength === 2) {
set(elem, key, value);
} else {
each(key, function (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'], function (nameIndex, name) {
$$1.fn[(name + "Class")] = function (className) {
if (!className) {
return this;
}
var classes = className.split(' ');
return this.each(function (i, elem) {
each(classes, function (j, cls) {
elem.classList[name](cls);
});
});
};
});
/**
* width - 获取元素的宽度
* @return {Number}
*/
/**
* height - 获取元素的高度
* @return {Number}
*/
each({
Width: 'width',
Height: 'height',
}, function (prop, name) {
$$1.fn[name] = function (val) {
if (val === undefined) {
// 获取
var elem = this[0];
if (isWindow(elem)) {
return elem[("inner" + prop)];
}
if (isDocument(elem)) {
return elem.documentElement[("scroll" + prop)];
}
var $elem = $$1(elem);
// IE10、IE11 在 box-sizing:border-box 时,不会包含 padding 和 border,这里进行修复
var IEFixValue = 0;
var 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($$1(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',
}, function (prop, name) {
$$1.fn[("inner" + prop)] = function () {
var value = this[name]();
var $elem = $$1(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) {
var ret = [];
var elem;
nodes.each(function (j, _this) {
elem = _this[node];
while (elem) {
if (nameIndex === 2) {
// prevUntil
if (!selector || (selector && $$1(elem).is(selector))) {
break;
}
ret.push(elem);
} else if (nameIndex === 0) {
// prev
if (!selector || (selector && $$1(elem).is(selector))) {
ret.push(elem);
}
break;
} else if (!selector || (selector && $$1(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'], function (nameIndex, name) {
$$1.fn[("prev" + name)] = function (selector) {
// prevAll、prevUntil 需要把元素的顺序倒序处理,以便和 jQuery 的结果一致
var $nodes = nameIndex === 0 ? this : $$1(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'], function (nameIndex, name) {
$$1.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'], function (nameIndex, name) {
$$1.fn[("parent" + name)] = function (selector) {
// parents、parentsUntil 需要把元素的顺序反向处理,以便和 jQuery 的结果一致
var $nodes = nameIndex === 0 ? this : $$1(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'], function (nameIndex, name) {
$$1.fn[name] = function (newChild) {
var newChilds;
var copyByClone = this.length > 1;
if (isString(newChild)) {
var tempDiv = document.createElement('div');
tempDiv.innerHTML = newChild;
newChilds = [].slice.call(tempDiv.childNodes);
} else {
newChilds = $$1(newChild).get();
}
if (nameIndex === 1) {
// prepend
newChilds.reverse();
}
return this.each(function (i, _this) {
each(newChilds, function (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'], function (nameIndex, name) {
$$1.fn[name] = function (selector) {
var $elem = $$1(selector);
return this.each(function (i, _this) {
$elem.each(function (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',
}, function (name, original) {
$$1.fn[name] = function (selector) {
$$1(selector)[original](this);
return this;
};
});
var dataNS = 'mduiElementDataStorage';
$$1.extend({
/**
* 在指定元素上存储数据,或从指定元素上读取数据
* @param elem 必须, DOM 元素
* @param key 必须,键名
* @param value 可选,值
*/
data: function data(elem, key, value) {
var data = {};
if (value !== undefined) {
// 根据 key、value 设置值
data[key] = value;
} else if (isObjectLike(key)) {
// 根据键值对设置值
data = key;
} else if (key === undefined) {
// 获取所有值
var result = {};
each(elem.attributes, function (i, attribute) {
var name = attribute.name;
if (name.indexOf('data-') === 0) {
var prop = name.slice(5).replace(/-./g, function (u) { return u.charAt(1).toUpperCase(); });
result[prop] = attribute.value;
}
});
if (elem[dataNS]) {
each(elem[dataNS], function (k, v) {
result[k] = v;
});
}
return result;
} else if (elem[dataNS] && (key in elem[dataNS])) {
// 获取指定值
return elem[dataNS][key];
} else {
// 从 data- 中获取指定值
var dataKey = elem.getAttribute(("data-" + key));
if (dataKey) {
return dataKey;
}
return undefined;
}
// 设置值
if (!elem[dataNS]) {
elem[dataNS] = {};
}
each(data, function (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];
}
},
});
$$1.fn.extend({
/**
* 在元素上读取或设置数据
* @param key 必须
* @param value
* @returns {*}
*/
data: function data(key, value) {
if (value === undefined) {
if (isObjectLike(key)) {
// 同时设置多个值
return this.each(function (i, elem) {
$$1.data(elem, key);
});
}
if (this[0]) {
// 获取值
return $$1.data(this[0], key);
}
return undefined;
}
// 设置值
return this.each(function (i, elem) {
$$1.data(elem, key, value);
});
},
/**
* 移除元素上存储的数据
* @param key 必须
* @returns {*}
*/
removeData: function removeData(key) {
return this.each(function (i, elem) {
$$1.removeData(elem, key);
});
},
});
!function(){!function(){try{return new e("test"),!1}catch(e){}var e=function(e,n){n=n||{bubbles:!1,cancelable:!1};var t=document.createEvent("MouseEvent");return t.initMouseEvent(e,n.bubbles,n.cancelable,window,0,0,0,0,0,!1,!1,!1,!1,0,null),t};e.prototype=Event.prototype,window.MouseEvent=e;}();}();
!function(){!function(){if("function"==typeof window.CustomEvent){ return!1; }function t(t,n){n=n||{bubbles:!1,cancelable:!1,detail:void 0};var e=document.createEvent("CustomEvent");return e.initCustomEvent(t,n.bubbles,n.cancelable,n.detail),e}t.prototype=window.Event.prototype,window.CustomEvent=t;}();}();
// 存储事件
var handlers = {
// i: { // 元素ID
// j: { // 事件ID
// e: 事件名
// fn: 事件处理函数
// i: 事件ID
// proxy:
// sel: 选择器
// }
// }
};
// 元素ID
var 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(function (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) {
var elementId = getElementId(element);
if (!handlers[elementId]) {
handlers[elementId] = [];
}
// 传入 data.useCapture 来设置 useCapture: true
var useCapture = false;
if (isObjectLike(data) && data.useCapture) {
useCapture = true;
}
eventName.split(' ').forEach(function (event) {
var handler = {
e: event,
fn: func,
sel: selector,
i: handlers[elementId].length,
};
function callFn(e, elem) {
// 因为鼠标事件模拟事件的 detail 属性是只读的,因此在 e._detail 中存储参数
/* eslint no-underscore-dangle: 0 */
var 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) {
// 事件代理
$$1(element)
.find(selector)
.get()
.reverse()
.forEach(function (elem) {
if (elem === e.target || $$1.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(function (event) {
getHandlers(element, event, func, selector).forEach(function (handler) {
delete handlers[getElementId(element)][handler.i];
element.removeEventListener(handler.e, handler.proxy, false);
});
});
}
$$1.fn.extend({
/**
* DOM 加载完毕后调用的函数
* @param callback
* @returns {ready}
*/
ready: function ready(callback) {
if (/complete|loaded|interactive/.test(document.readyState) && document.body) {
callback($$1);
} else {
document.addEventListener('DOMContentLoaded', function () {
callback($$1);
}, 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) {
var self = this;
// 默认
// $().on(event, selector, data, callback)
// event 使用 事件:函数 键值对
// event = {
// 'event1': callback1,
// 'event2': callback2
// }
//
// $().on(event, selector, data)
if (eventName && !isString(eventName)) {
each(eventName, function (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) {
var 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) {
var self = this;
if (!isString(eventName)) {
each(eventName, function (type, fn) {
type.split(' ').forEach(function (eName) {
self.on(eName, selector, data, fn, 1);
});
});
} else {
eventName.split(' ').forEach(function (eName) {
self.on(eName, selector, data, callback, 1);
});
}
return this;
},
/**
* 取消绑定事件
*
* $().off(eventName, selector);
* $().off(eventName, callback);
* $().off(eventName, false);
*
*/
off: function off(eventName, selector, callback) {
var self = this;
// event 使用 事件:函数 键值对
// event = {
// 'event1': callback1,
// 'event2': callback2
// }
//
// $().off(event, selector)
if (eventName && !isString(eventName)) {
each(eventName, function (type, fn) {
self.off(type, selector, fn);
});
return self;
}
// selector 不存在
// $().off(event, callback)
if (!isString(selector) && !isFunction(callback) && callback !== false) {
callback = selector;
selector = undefined;
}
// callback 为 false
// $().off(event, false)
if (callback === false) {
callback = fnFalse;
}
return self.each(function () {
remove(this, eventName, callback, selector);
});
},
/**
* 触发一个事件
* @param eventName
* @param data
* @returns {*|JQ}
*/
trigger: function trigger(eventName, data) {
var isMouseEvent = ['click', 'mousedown', 'mouseup', 'mousemove'].indexOf(eventName) > -1;
var evt;
if (isMouseEvent) {
// Note: MouseEvent 无法传入 detail 参数
evt = new MouseEvent(eventName, {
bubbles: true,
cancelable: true,
});
} else {
evt = new CustomEvent(eventName, {
detail: data,
bubbles: true,
cancelable: true,
});
}
evt._detail = data;
return this.each(function () {
this.dispatchEvent(evt);
});
},
});
var globalOptions = {};
var jsonpID = 0;
// 全局事件名
var ajaxEvent = {
ajaxStart: 'start.mdui.ajax',
ajaxSuccess: 'success.mdui.ajax',
ajaxError: 'error.mdui.ajax',
ajaxComplete: 'complete.mdui.ajax',
};
/**
* 判断此请求方法是否通过查询字符串提交参数
* @param method 请求方法,大写
* @returns {boolean}
*/
function isQueryStringData(method) {
return ['GET', 'HEAD'].indexOf(method) >= 0;
}
/**
* 添加参数到 URL 上,且 URL 中不存在 ? 时,自动把第一个 & 替换为 ?
* @param url
* @param query 参数 key=value
* @returns {string}
*/
function appendQuery(url, query) {
return ((url + "&" + query)).replace(/[&?]{1,2}/, '?');
}
$$1.extend({
/**
* 为 ajax 请求设置全局配置参数
* @param options
*/
ajaxSetup: function ajaxSetup(options) {
$$1.extend(globalOptions, options || {});
},
/**
* 发送 ajax 请求
* @param options
*/
ajax: function ajax(options) {
// 配置参数
var defaults = {
// 请求方式
method: 'GET',
// 请求的数据,查询字符串或对象
data: false,
// 是否把数据转换为查询字符串发送,为 false 时不进行自动转换。
processData: true,
// 是否为异步请求
async: true,
// 是否从缓存中读取,只对 GET/HEAD 请求有效,dataType 为 jsonp 时为 false
cache: true,
// HTTP 访问认证的用户名
username: '',
// HTTP 访问认证的密码
password: '',
// 一个键值对,随着请求一起发送
headers: {},
// 设置 XHR 对象
xhrFields: {},
// 一个 HTTP 代码和函数的对象
statusCode: {},
// 预期服务器返回的数据类型 text、json、jsonp
dataType: 'text',
// jsonp 请求的回调函数名称
jsonp: 'callback',
// (string 或 Function)使用指定的回调函数名代替自动生成的回调函数名
jsonpCallback: function () {
jsonpID += 1;
return ("mduijsonp_" + (Date.now()) + "_" + jsonpID);
},
// 发送信息至服务器时内容编码类型
contentType: 'application/x-www-form-urlencoded',
// 设置请求超时时间(毫秒)
timeout: 0,
// 是否在 document 上触发全局 ajax 事件
global: true,
// beforeSend: function (XMLHttpRequest) 请求发送前执行,返回 false 可取消本次 ajax 请求
// success: function (data, textStatus, XMLHttpRequest) 请求成功时调用
// error: function (XMLHttpRequest, textStatus) 请求失败时调用
// statusCode: {404: function ()}
// 200-299之间的状态码表示成功,参数和 success 回调一样;其他状态码表示失败,参数和 error 回调一样
// complete: function (XMLHttpRequest, textStatus) 请求完成后回调函数 (请求成功或失败之后均调用)
};
// 回调函数
var callbacks = [
'beforeSend',
'success',
'error',
'statusCode',
'complete' ];
// 是否已取消请求
var isCanceled = false;
// 保存全局配置
var globals = globalOptions;
// 事件参数
var eventParams = {};
// 合并全局参数到默认参数,全局回调函数不覆盖
each(globals, function (key, value) {
if (callbacks.indexOf(key) < 0) {
defaults[key] = value;
}
});
// 参数合并
options = $$1.extend({}, defaults, options);
/**
* 触发全局事件
* @param event string 事件名
* @param xhr XMLHttpRequest 事件参数
*/
function triggerEvent(event, xhr) {
if (options.global) {
$$1(document).trigger(event, xhr);
}
}
/**
* 触发 XHR 回调和事件
* @param callback string 回调函数名称
* @param args
*/
function triggerCallback(callback) {
var args = [], len = arguments.length - 1;
while ( len-- > 0 ) args[ len ] = arguments[ len + 1 ];
var result1;
var result2;
if (callback) {
// 全局回调
if (callback in globals) {
result1 = globals[callback].apply(globals, args);
}
// 自定义回调
if (options[callback]) {
result2 = options[callback].apply(options, args);
}
// beforeSend 回调返回 false 时取消 ajax 请求
if (callback === 'beforeSend' && (result1 === false || result2 === false)) {
isCanceled = true;
}
}
}
// 请求方式转为大写
var method = options.method.toUpperCase();
// 默认使用当前页面 URL
if (!options.url) {
options.url = window.location.toString();
}
// 需要发送的数据
// GET/HEAD 请求和 processData 为 true 时,转换为查询字符串格式,特殊格式不转换
var sendData;
if (
(isQueryStringData(method) || options.processData)
&& options.data
&& [ArrayBuffer, Blob, Document, FormData].indexOf(options.data.constructor) < 0
) {
sendData = isString(options.data) ? options.data : $$1.param(options.data);
} else {
sendData = options.data;
}
// 对于 GET、HEAD 类型的请求,把 data 数据添加到 URL 中
if (isQueryStringData(method) && sendData) {
// 查询字符串拼接到 URL 中
options.url = appendQuery(options.url, sendData);
sendData = null;
}
// JSONP
if (options.dataType === 'jsonp') {
// URL 中添加自动生成的回调函数名
var callbackName = isFunction(options.jsonpCallback)
? options.jsonpCallback()
: options.jsonpCallback;
var requestUrl = appendQuery(options.url, ((options.jsonp) + "=" + callbackName));
eventParams.options = options;
triggerEvent(ajaxEvent.ajaxStart, eventParams);
triggerCallback('beforeSend', null);
if (isCanceled) {
return undefined;
}
var abortTimeout;
// 创建 script
var script = document.createElement('script');
script.type = 'text/javascript';
// 创建 script 失败
script.onerror = function () {
if (abortTimeout) {
clearTimeout(abortTimeout);
}
triggerEvent(ajaxEvent.ajaxError, eventParams);
triggerCallback('error', null, 'scripterror');
triggerEvent(ajaxEvent.ajaxComplete, eventParams);
triggerCallback('complete', null, 'scripterror');
};
script.src = requestUrl;