/** 2.7.1 | MIT Licensed */;/** * Layui * Classic modular front-end UI library * MIT Licensed */ ;!function(win){ "use strict"; var doc = win.document, config = { modules: {} //记录模块物理路径 ,status: {} //记录模块加载状态 ,timeout: 10 //符合规范的模块请求最长等待秒数 ,event: {} //记录模块自定义事件 } ,Layui = function(){ this.v = '2.7.1'; // layui 版本号 } //识别预先可能定义的指定全局对象 ,GLOBAL = win.LAYUI_GLOBAL || {} //获取 layui 所在目录 ,getPath = function(){ var jsPath = doc.currentScript ? doc.currentScript.src : function(){ var js = doc.scripts ,last = js.length - 1 ,src; for(var i = last; i > 0; i--){ if(js[i].readyState === 'interactive'){ src = js[i].src; break; } } return src || js[last].src; }(); return config.dir = GLOBAL.dir || jsPath.substring(0, jsPath.lastIndexOf('/') + 1); }() //异常提示 ,error = function(msg, type){ type = type || 'log'; win.console && console[type] && console[type]('layui error hint: ' + msg); } ,isOpera = typeof opera !== 'undefined' && opera.toString() === '[object Opera]' //内置模块 ,modules = config.builtin = { lay: 'lay' //基础 DOM 操作 ,layer: 'layer' //弹层 ,laydate: 'laydate' //日期 ,laypage: 'laypage' //分页 ,laytpl: 'laytpl' //模板引擎 ,layedit: 'layedit' //富文本编辑器 ,form: 'form' //表单集 ,upload: 'upload' //上传 ,dropdown: 'dropdown' //下拉菜单 ,transfer: 'transfer' //穿梭框 ,tree: 'tree' //树结构 ,table: 'table' //表格 ,element: 'element' //常用元素操作 ,rate: 'rate' //评分组件 ,colorpicker: 'colorpicker' //颜色选择器 ,slider: 'slider' //滑块 ,carousel: 'carousel' //轮播 ,flow: 'flow' //流加载 ,util: 'util' //工具块 ,code: 'code' //代码修饰器 ,jquery: 'jquery' //DOM 库(第三方) ,all: 'all' ,'layui.all': 'layui.all' //聚合标识(功能性的,非真实模块) }; //记录基础数据 Layui.prototype.cache = config; //定义模块 Layui.prototype.define = function(deps, factory){ var that = this ,type = typeof deps === 'function' ,callback = function(){ var setApp = function(app, exports){ layui[app] = exports; config.status[app] = true; }; typeof factory === 'function' && factory(function(app, exports){ setApp(app, exports); config.callback[app] = function(){ factory(setApp); } }); return this; }; type && ( factory = deps, deps = [] ); that.use(deps, callback, null, 'define'); return that; }; //使用特定模块 Layui.prototype.use = function(apps, callback, exports, from){ var that = this ,dir = config.dir = config.dir ? config.dir : getPath ,head = doc.getElementsByTagName('head')[0]; apps = function(){ if(typeof apps === 'string'){ return [apps]; } //当第一个参数为 function 时,则自动加载所有内置模块,且执行的回调即为该 function 参数; else if(typeof apps === 'function'){ callback = apps; return ['all']; } return apps; }(); //如果页面已经存在 jQuery 1.7+ 库且所定义的模块依赖 jQuery,则不加载内部 jquery 模块 if(win.jQuery && jQuery.fn.on){ that.each(apps, function(index, item){ if(item === 'jquery'){ apps.splice(index, 1); } }); layui.jquery = layui.$ = jQuery; } var item = apps[0] ,timeout = 0; exports = exports || []; //静态资源host config.host = config.host || (dir.match(/\/\/([\s\S]+?)\//)||['//'+ location.host +'/'])[0]; //加载完毕 function onScriptLoad(e, url){ var readyRegExp = navigator.platform === 'PLaySTATION 3' ? /^complete$/ : /^(complete|loaded)$/ if (e.type === 'load' || (readyRegExp.test((e.currentTarget || e.srcElement).readyState))) { config.modules[item] = url; head.removeChild(node); (function poll() { if(++timeout > config.timeout * 1000 / 4){ return error(item + ' is not a valid module', 'error'); }; config.status[item] ? onCallback() : setTimeout(poll, 4); }()); } } //回调 function onCallback(){ exports.push(layui[item]); apps.length > 1 ? that.use(apps.slice(1), callback, exports, from) : ( typeof callback === 'function' && function(){ //保证文档加载完毕再执行回调 if(layui.jquery && typeof layui.jquery === 'function' && from !== 'define'){ return layui.jquery(function(){ callback.apply(layui, exports); }); } callback.apply(layui, exports); }() ); } //如果引入了聚合板,内置的模块则不必重复加载 if( apps.length === 0 || (layui['layui.all'] && modules[item]) ){ return onCallback(), that; } //获取加载的模块 URL //如果是内置模块,则按照 dir 参数拼接模块路径 //如果是扩展模块,则判断模块路径值是否为 {/} 开头, //如果路径值是 {/} 开头,则模块路径即为后面紧跟的字符。 //否则,则按照 base 参数拼接模块路径 var url = ( modules[item] ? (dir + 'modules/') : (/^\{\/\}/.test(that.modules[item]) ? '' : (config.base || '')) ) + (that.modules[item] || item) + '.js'; url = url.replace(/^\{\/\}/, ''); //如果扩展模块(即:非内置模块)对象已经存在,则不必再加载 if(!config.modules[item] && layui[item]){ config.modules[item] = url; //并记录起该扩展模块的 url } //首次加载模块 if(!config.modules[item]){ var node = doc.createElement('script'); node.async = true; node.charset = 'utf-8'; node.src = url + function(){ var version = config.version === true ? (config.v || (new Date()).getTime()) : (config.version||''); return version ? ('?v=' + version) : ''; }(); head.appendChild(node); if(node.attachEvent && !(node.attachEvent.toString && node.attachEvent.toString().indexOf('[native code') < 0) && !isOpera){ node.attachEvent('onreadystatechange', function(e){ onScriptLoad(e, url); }); } else { node.addEventListener('load', function(e){ onScriptLoad(e, url); }, false); } config.modules[item] = url; } else { //缓存 (function poll() { if(++timeout > config.timeout * 1000 / 4){ return error(item + ' is not a valid module', 'error'); }; (typeof config.modules[item] === 'string' && config.status[item]) ? onCallback() : setTimeout(poll, 4); }()); } return that; }; // 弃用原有的指定模块,以便重新扩展新的同名模块 Layui.prototype.disuse = function(apps){ var that = this; apps = that.isArray(apps) ? apps : [apps]; that.each(apps, function (index, item) { if (!config.status[item]) { return error('module ' + item + ' is not exist'); } delete that[item]; delete modules[item]; delete that.modules[item]; delete config.status[item]; delete config.modules[item]; }); }; //获取节点的 style 属性值 Layui.prototype.getStyle = function(node, name){ var style = node.currentStyle ? node.currentStyle : win.getComputedStyle(node, null); return style[style.getPropertyValue ? 'getPropertyValue' : 'getAttribute'](name); }; //css外部加载器 Layui.prototype.link = function(href, fn, cssname){ var that = this ,head = doc.getElementsByTagName('head')[0] ,link = doc.createElement('link'); if(typeof fn === 'string') cssname = fn; var app = (cssname || href).replace(/\.|\//g, '') ,id = link.id = 'layuicss-'+ app ,STAUTS_NAME = 'creating' ,timeout = 0; link.rel = 'stylesheet'; link.href = href + (config.debug ? '?v='+new Date().getTime() : ''); link.media = 'all'; if(!doc.getElementById(id)){ head.appendChild(link); } if(typeof fn !== 'function') return that; //轮询 css 是否加载完毕 (function poll(status) { var delay = 100 ,getLinkElem = doc.getElementById(id); //获取动态插入的 link 元素 //如果轮询超过指定秒数,则视为请求文件失败或 css 文件不符合规范 if(++timeout > config.timeout * 1000 / delay){ return error(href + ' timeout'); }; //css 加载就绪 if(parseInt(that.getStyle(getLinkElem, 'width')) === 1989){ //如果参数来自于初始轮询(即未加载就绪时的),则移除 link 标签状态 if(status === STAUTS_NAME) getLinkElem.removeAttribute('lay-status'); //如果 link 标签的状态仍为「创建中」,则继续进入轮询,直到状态改变,则执行回调 getLinkElem.getAttribute('lay-status') === STAUTS_NAME ? setTimeout(poll, delay) : fn(); } else { getLinkElem.setAttribute('lay-status', STAUTS_NAME); setTimeout(function(){ poll(STAUTS_NAME); }, delay); } }()); //轮询css是否加载完毕 /* (function poll() { if(++timeout > config.timeout * 1000 / 100){ return error(href + ' timeout'); }; parseInt(that.getStyle(doc.getElementById(id), 'width')) === 1989 ? function(){ fn(); }() : setTimeout(poll, 100); }()); */ return that; }; //css 内部加载器 Layui.prototype.addcss = function(firename, fn, cssname){ return layui.link(config.dir + 'css/' + firename, fn, cssname); }; //存储模块的回调 config.callback = {}; //重新执行模块的工厂函数 Layui.prototype.factory = function(modName){ if(layui[modName]){ return typeof config.callback[modName] === 'function' ? config.callback[modName] : null; } }; //图片预加载 Layui.prototype.img = function(url, callback, error) { var img = new Image(); img.src = url; if(img.complete){ return callback(img); } img.onload = function(){ img.onload = null; typeof callback === 'function' && callback(img); }; img.onerror = function(e){ img.onerror = null; typeof error === 'function' && error(e); }; }; //全局配置 Layui.prototype.config = function(options){ options = options || {}; for(var key in options){ config[key] = options[key]; } return this; }; //记录全部模块 Layui.prototype.modules = function(){ var clone = {}; for(var o in modules){ clone[o] = modules[o]; } return clone; }(); //拓展模块 Layui.prototype.extend = function(options){ var that = this; //验证模块是否被占用 options = options || {}; for(var o in options){ if(that[o] || that.modules[o]){ error(o+ ' Module already exists', 'error'); } else { that.modules[o] = options[o]; } } return that; }; // location.hash 路由解析 Layui.prototype.router = Layui.prototype.hash = function(hash){ var that = this ,hash = hash || location.hash ,data = { path: [] ,search: {} ,hash: (hash.match(/[^#](#.*$)/) || [])[1] || '' }; if(!/^#\//.test(hash)) return data; //禁止非路由规范 hash = hash.replace(/^#\//, ''); data.href = '/' + hash; hash = hash.replace(/([^#])(#.*$)/, '$1').split('/') || []; //提取 Hash 结构 that.each(hash, function(index, item){ /^\w+=/.test(item) ? function(){ item = item.split('='); data.search[item[0]] = item[1]; }() : data.path.push(item); }); return data; }; //URL 解析 Layui.prototype.url = function(href){ var that = this ,data = { //提取 url 路径 pathname: function(){ var pathname = href ? function(){ var str = (href.match(/\.[^.]+?\/.+/) || [])[0] || ''; return str.replace(/^[^\/]+/, '').replace(/\?.+/, ''); }() : location.pathname; return pathname.replace(/^\//, '').split('/'); }() //提取 url 参数 ,search: function(){ var obj = {} ,search = (href ? function(){ var str = (href.match(/\?.+/) || [])[0] || ''; return str.replace(/\#.+/, ''); }() : location.search ).replace(/^\?+/, '').split('&'); //去除 ?,按 & 分割参数 //遍历分割后的参数 that.each(search, function(index, item){ var _index = item.indexOf('=') ,key = function(){ //提取 key if(_index < 0){ return item.substr(0, item.length); } else if(_index === 0){ return false; } else { return item.substr(0, _index); } }(); //提取 value if(key){ obj[key] = _index > 0 ? item.substr(_index + 1) : null; } }); return obj; }() //提取 Hash ,hash: that.router(function(){ return href ? ((href.match(/#.+/) || [])[0] || '/') : location.hash; }()) }; return data; }; //本地持久性存储 Layui.prototype.data = function(table, settings, storage){ table = table || 'layui'; storage = storage || localStorage; if(!win.JSON || !win.JSON.parse) return; //如果settings为null,则删除表 if(settings === null){ return delete storage[table]; } settings = typeof settings === 'object' ? settings : {key: settings}; try{ var data = JSON.parse(storage[table]); } catch(e){ var data = {}; } if('value' in settings) data[settings.key] = settings.value; if(settings.remove) delete data[settings.key]; storage[table] = JSON.stringify(data); return settings.key ? data[settings.key] : data; }; //本地会话性存储 Layui.prototype.sessionData = function(table, settings){ return this.data(table, settings, sessionStorage); } //设备信息 Layui.prototype.device = function(key){ var agent = navigator.userAgent.toLowerCase() //获取版本号 ,getVersion = function(label){ var exp = new RegExp(label + '/([^\\s\\_\\-]+)'); label = (agent.match(exp)||[])[1]; return label || false; } //返回结果集 ,result = { os: function(){ //底层操作系统 if(/windows/.test(agent)){ return 'windows'; } else if(/linux/.test(agent)){ return 'linux'; } else if(/iphone|ipod|ipad|ios/.test(agent)){ return 'ios'; } else if(/mac/.test(agent)){ return 'mac'; } }() ,ie: function(){ //ie版本 return (!!win.ActiveXObject || "ActiveXObject" in win) ? ( (agent.match(/msie\s(\d+)/) || [])[1] || '11' //由于ie11并没有msie的标识 ) : false; }() ,weixin: getVersion('micromessenger') //是否微信 }; //任意的key if(key && !result[key]){ result[key] = getVersion(key); } //移动设备 result.android = /android/.test(agent); result.ios = result.os === 'ios'; result.mobile = (result.android || result.ios) ? true : false; return result; }; //提示 Layui.prototype.hint = function(){ return { error: error }; }; //typeof 类型细分 -> string/number/boolean/undefined/null、object/array/function/… Layui.prototype._typeof = Layui.prototype.type = function(operand){ if(operand === null) return String(operand); //细分引用类型 return (typeof operand === 'object' || typeof operand === 'function') ? function(){ var type = Object.prototype.toString.call(operand).match(/\s(.+)\]$/) || [] //匹配类型字符 ,classType = 'Function|Array|Date|RegExp|Object|Error|Symbol'; //常见类型字符 type = type[1] || 'Object'; //除匹配到的类型外,其他对象均返回 object return new RegExp('\\b('+ classType + ')\\b').test(type) ? type.toLowerCase() : 'object'; }() : typeof operand; }; //对象是否具备数组结构(此处为兼容 jQuery 对象) Layui.prototype._isArray = Layui.prototype.isArray = function(obj){ var that = this ,len ,type = that.type(obj); if(!obj || (typeof obj !== 'object') || obj === win) return false; len = 'length' in obj && obj.length; //兼容 ie return type === 'array' || len === 0 || ( typeof len === 'number' && len > 0 && (len - 1) in obj //兼容 jQuery 对象 ); }; //遍历 Layui.prototype.each = function(obj, fn){ var key ,that = this ,callFn = function(key, obj){ //回调 return fn.call(obj[key], key, obj[key]) }; if(typeof fn !== 'function') return that; obj = obj || []; //优先处理数组结构 if(that.isArray(obj)){ for(key = 0; key < obj.length; key++){ if(callFn(key, obj)) break; } } else { for(key in obj){ if(callFn(key, obj)) break; } } return that; }; // 将数组中的成员对象按照某个 key 的 value 值进行排序 Layui.prototype.sort = function(arr, key, desc){ var that = this ,clone = JSON.parse( JSON.stringify(arr || []) ); // 若未传入 key,则直接返回原对象 if(that.type(arr) === 'object' && !key){ return clone; } else if(typeof arr !== 'object'){ //若 arr 非对象 return [clone]; } // 开始排序 clone.sort(function(o1, o2){ var v1 = o1[key] ,v2 = o2[key]; /* * 特殊数据 * 若比较的成员均非对象 */ // 若比较的成员均为数字 if(!isNaN(o1) && !isNaN(o2)) return o1 - o2; // 若比较的成员只存在某一个非对象 if(!isNaN(o1) && isNaN(o2)){ if(key && typeof o2 === 'object'){ v1 = o1; } else { return -1; } } else if (isNaN(o1) && !isNaN(o2)){ if(key && typeof o1 === 'object'){ v2 = o2; } else { return 1; } } /* * 正常数据 * 即成员均为对象,也传入了对比依据: key * 若 value 为数字,按「大小」排序;若 value 非数字,则按「字典序」排序 */ // value 是否为数字 var isNum = [!isNaN(v1), !isNaN(v2)]; // 若为数字比较 if(isNum[0] && isNum[1]){ if(v1 && (!v2 && v2 !== 0)){ //数字 vs 空 return 1; } else if((!v1 && v1 !== 0) && v2){ //空 vs 数字 return -1; } else { //数字 vs 数字 return v1 - v2; } }; /** * 字典序排序 */ // 若为非数字比较 if(!isNum[0] && !isNum[1]){ // 字典序比较 if(v1 > v2){ return 1; } else if (v1 < v2) { return -1; } else { return 0; } } // 若为混合比较 if(isNum[0] || !isNum[1]){ //数字 vs 非数字 return -1; } else if(!isNum[0] || isNum[1]) { //非数字 vs 数字 return 1; } }); desc && clone.reverse(); // 倒序 return clone; }; // 不复制 将数组中的成员对象按照某个 key 的 value 值进行排序 Layui.prototype.thissort = function(arr, key, desc){ var that = this ,clone = (arr || []); // 若未传入 key,则直接返回原对象 if(that.type(arr) === 'object' && !key){ return clone; } else if(typeof arr !== 'object'){ //若 arr 非对象 return [clone]; } // 开始排序 clone.sort(function(o1, o2){ var v1 = o1[key] ,v2 = o2[key]; /* * 特殊数据 * 若比较的成员均非对象 */ // 若比较的成员均为数字 if(!isNaN(o1) && !isNaN(o2)) return o1 - o2; // 若比较的成员只存在某一个非对象 if(!isNaN(o1) && isNaN(o2)){ if(key && typeof o2 === 'object'){ v1 = o1; } else { return -1; } } else if (isNaN(o1) && !isNaN(o2)){ if(key && typeof o1 === 'object'){ v2 = o2; } else { return 1; } } /* * 正常数据 * 即成员均为对象,也传入了对比依据: key * 若 value 为数字,按「大小」排序;若 value 非数字,则按「字典序」排序 */ // value 是否为数字 var isNum = [!isNaN(v1), !isNaN(v2)]; // 若为数字比较 if(isNum[0] && isNum[1]){ if(v1 && (!v2 && v2 !== 0)){ //数字 vs 空 return 1; } else if((!v1 && v1 !== 0) && v2){ //空 vs 数字 return -1; } else { //数字 vs 数字 return v1 - v2; } }; /** * 字典序排序 */ // 若为非数字比较 if(!isNum[0] && !isNum[1]){ // 字典序比较 if(v1 > v2){ return 1; } else if (v1 < v2) { return -1; } else { return 0; } } // 若为混合比较 if(isNum[0] || !isNum[1]){ //数字 vs 非数字 return -1; } else if(!isNum[0] || isNum[1]) { //非数字 vs 数字 return 1; } }); desc && clone.reverse(); // 倒序 return clone; }; //阻止事件冒泡 Layui.prototype.stope = function(thisEvent){ thisEvent = thisEvent || win.event; try { thisEvent.stopPropagation() } catch(e){ thisEvent.cancelBubble = true; } }; //字符常理 var EV_REMOVE = 'LAYUI-EVENT-REMOVE'; //自定义模块事件 Layui.prototype.onevent = function(modName, events, callback){ if(typeof modName !== 'string' || typeof callback !== 'function') return this; return Layui.event(modName, events, null, callback); }; //执行自定义模块事件 Layui.prototype.event = Layui.event = function(modName, events, params, fn){ var that = this ,result = null ,filter = (events || '').match(/\((.*)\)$/)||[] //提取事件过滤器字符结构,如:select(xxx) ,eventName = (modName + '.'+ events).replace(filter[0], '') //获取事件名称,如:form.select ,filterName = filter[1] || '' //获取过滤器名称,,如:xxx ,callback = function(_, item){ var res = item && item.call(that, params); res === false && result === null && (result = false); }; //如果参数传入特定字符,则执行移除事件 if(params === EV_REMOVE){ delete (that.cache.event[eventName] || {})[filterName]; return that; } //添加事件 if(fn){ config.event[eventName] = config.event[eventName] || {}; //这里不再对重复事件做支持 //config.event[eventName][filterName] ? config.event[eventName][filterName].push(fn) : config.event[eventName][filterName] = [fn]; return this; } //执行事件回调 layui.each(config.event[eventName], function(key, item){ //执行当前模块的全部事件 if(filterName === '{*}'){ layui.each(item, callback); return; } //执行指定事件 key === '' && layui.each(item, callback); (filterName && key === filterName) && layui.each(item, callback); }); return result; }; //新增模块事件 Layui.prototype.on = function(events, modName, callback){ var that = this; return that.onevent.call(that, modName, events, callback); } //移除模块事件 Layui.prototype.off = function(events, modName){ var that = this; return that.event.call(that, modName, events, EV_REMOVE); }; //exports layui win.layui = new Layui(); }(window); //gulp build: layui-footer /** * 用于打包聚合版,该文件不会存在于构建后的目录 */ layui.define(function(exports){ var cache = layui.cache; layui.config({ dir: cache.dir.replace(/lay\/dest\/$/, '') }); exports('layui.all', layui.v); }); /** lay 基础 DOM 操作 | MIT Licensed */ ;!function(window){ //gulp build: lay-header "use strict"; var MOD_NAME = 'lay' //模块名 ,document = window.document //DOM查找 ,lay = function(selector){ return new LAY(selector); } //DOM构造器 ,LAY = function(selector){ var index = 0 ,nativeDOM = typeof selector === 'object' ? [selector] : ( this.selector = selector ,document.querySelectorAll(selector || null) ); for(; index < nativeDOM.length; index++){ this.push(nativeDOM[index]); } }; /* lay 对象操作 */ LAY.prototype = []; LAY.prototype.constructor = LAY; //普通对象深度扩展 lay.extend = function(){ var ai = 1 ,length ,args = arguments ,clone = function(target, obj){ target = target || (layui.type(obj) === 'array' ? [] : {}); //目标对象 for(var i in obj){ //如果值为普通对象,则进入递归,继续深度合并 target[i] = (obj[i] && obj[i].constructor === Object) ? clone(target[i], obj[i]) : obj[i]; } return target; } args[0] = typeof args[0] === 'object' ? args[0] : {}; length = args.length for(; ai < length; ai++){ if(typeof args[ai] === 'object'){ clone(args[0], args[ai]); } } return args[0]; }; //lay 模块版本 lay.v = '1.0.8'; //ie版本 lay.ie = function(){ var agent = navigator.userAgent.toLowerCase(); return (!!window.ActiveXObject || "ActiveXObject" in window) ? ( (agent.match(/msie\s(\d+)/) || [])[1] || '11' //由于 ie11 并没有 msie 的标识 ) : false; }(); /** * 获取 layui 常见方法,以便用于组件单独版 */ lay.layui = layui || {}; lay.getPath = layui.cache.dir; //获取当前 JS 所在目录 lay.stope = layui.stope; //中止冒泡 lay.each = function(){ //遍历 layui.each.apply(layui, arguments); return this; }; //数字前置补零 lay.digit = function(num, length){ if(!(typeof num === 'string' || typeof num === 'number')) return ''; var str = ''; num = String(num); length = length || 2; for(var i = num.length; i < length; i++){ str += '0'; } return num < Math.pow(10, length) ? str + num : num; }; //创建元素 lay.elem = function(elemName, attr){ var elem = document.createElement(elemName); lay.each(attr || {}, function(key, value){ elem.setAttribute(key, value); }); return elem; }; //当前页面是否存在滚动条 lay.hasScrollbar = function(){ return document.body.scrollHeight > (window.innerHeight || document.documentElement.clientHeight); }; //元素定位 lay.position = function(elem, elemView, obj){ if(!elemView) return; obj = obj || {}; //如果绑定的是 document 或 body 元素,则直接获取鼠标坐标 if(elem === document || elem === lay('body')[0]){ obj.clickType = 'right'; } //绑定绑定元素的坐标 var rect = obj.clickType === 'right' ? function(){ var e = obj.e || window.event || {}; return { left: e.clientX ,top: e.clientY ,right: e.clientX ,bottom: e.clientY } }() : elem.getBoundingClientRect() ,elemWidth = elemView.offsetWidth //控件的宽度 ,elemHeight = elemView.offsetHeight //控件的高度 //滚动条高度 ,scrollArea = function(type){ type = type ? 'scrollLeft' : 'scrollTop'; return document.body[type] | document.documentElement[type]; } //窗口宽高 ,winArea = function(type){ return document.documentElement[type ? 'clientWidth' : 'clientHeight'] }, margin = 5, left = rect.left, top = rect.bottom; //相对元素居中 if(obj.align === 'center'){ left = left - (elemWidth - elem.offsetWidth)/2; } else if(obj.align === 'right'){ left = left - elemWidth + elem.offsetWidth; } //判断右侧是否超出边界 if(left + elemWidth + margin > winArea('width')){ left = winArea('width') - elemWidth - margin; //如果超出右侧,则将面板向右靠齐 } //左侧是否超出边界 if(left < margin) left = margin; //判断底部和顶部是否超出边界 if(top + elemHeight + margin > winArea()){ //优先顶部是否有足够区域显示完全 if(rect.top > elemHeight + margin){ top = rect.top - elemHeight - margin*2; //顶部有足够的区域显示 } else { //如果面板是鼠标右键弹出,且顶部没有足够区域显示,则将面板向底部靠齐 if(obj.clickType === 'right'){ top = winArea() - elemHeight - margin*2; if(top < 0) top = 0; //不能溢出窗口顶部 } else { top = margin; // 位置计算逻辑完备性处理 } } } //定位类型 var position = obj.position; if(position) elemView.style.position = position; //设置坐标 elemView.style.left = left + (position === 'fixed' ? 0 : scrollArea(1)) + 'px'; elemView.style.top = top + (position === 'fixed' ? 0 : scrollArea()) + 'px'; //防止页面无滚动条时,又因为弹出面板而出现滚动条导致的坐标计算偏差 if(!lay.hasScrollbar()){ var rect1 = elemView.getBoundingClientRect(); //如果弹出面板的溢出窗口底部,则表示将出现滚动条,此时需要重新计算坐标 if(!obj.SYSTEM_RELOAD && (rect1.bottom + margin) > winArea()){ obj.SYSTEM_RELOAD = true; setTimeout(function(){ lay.position(elem, elemView, obj); }, 50); } } }; //获取元素上的参数配置上 lay.options = function(elem, attr){ var othis = lay(elem) ,attrName = attr || 'lay-options'; try { return new Function('return '+ (othis.attr(attrName) || '{}'))(); } catch(ev) { hint.error('parseerror:'+ ev, 'error'); return {}; } }; //元素是否属于顶级元素(document 或 body) lay.isTopElem = function(elem){ var topElems = [document, lay('body')[0]] ,matched = false; lay.each(topElems, function(index, item){ if(item === elem){ return matched = true } }); return matched; }; //追加字符 LAY.addStr = function(str, new_str){ str = str.replace(/\s+/, ' '); new_str = new_str.replace(/\s+/, ' ').split(' '); lay.each(new_str, function(ii, item){ if(!new RegExp('\\b'+ item + '\\b').test(str)){ str = str + ' ' + item; } }); return str.replace(/^\s|\s$/, ''); }; //移除值 LAY.removeStr = function(str, new_str){ str = str.replace(/\s+/, ' '); new_str = new_str.replace(/\s+/, ' ').split(' '); lay.each(new_str, function(ii, item){ var exp = new RegExp('\\b'+ item + '\\b') if(exp.test(str)){ str = str.replace(exp, ''); } }); return str.replace(/\s+/, ' ').replace(/^\s|\s$/, ''); }; //查找子元素 LAY.prototype.find = function(selector){ var that = this; var index = 0, arr = [] ,isObject = typeof selector === 'object'; this.each(function(i, item){ var nativeDOM = isObject ? item.contains(selector) : item.querySelectorAll(selector || null); for(; index < nativeDOM.length; index++){ arr.push(nativeDOM[index]); } that.shift(); }); if(!isObject){ that.selector = (that.selector ? that.selector + ' ' : '') + selector } lay.each(arr, function(i, item){ that.push(item); }); return that; }; //DOM遍历 LAY.prototype.each = function(fn){ return lay.each.call(this, this, fn); }; //添加css类 LAY.prototype.addClass = function(className, type){ return this.each(function(index, item){ item.className = LAY[type ? 'removeStr' : 'addStr'](item.className, className) }); }; //移除 css 类 LAY.prototype.removeClass = function(className){ return this.addClass(className, true); }; //是否包含 css 类 LAY.prototype.hasClass = function(className){ var has = false; this.each(function(index, item){ if(new RegExp('\\b'+ className +'\\b').test(item.className)){ has = true; } }); return has; }; //添加或获取 css style LAY.prototype.css = function(key, value){ var that = this ,parseValue = function(v){ return isNaN(v) ? v : (v +'px'); }; return (typeof key === 'string' && value === undefined) ? function(){ if(that.length > 0) return that[0].style[key]; }() : that.each(function(index, item){ typeof key === 'object' ? lay.each(key, function(thisKey, thisValue){ item.style[thisKey] = parseValue(thisValue); }) : item.style[key] = parseValue(value); }); }; //添加或获取宽度 LAY.prototype.width = function(value){ var that = this; return value === undefined ? function(){ if(that.length > 0) return that[0].offsetWidth; //此处还需做兼容 }() : that.each(function(index, item){ that.css('width', value); }); }; //添加或获取高度 LAY.prototype.height = function(value){ var that = this; return value === undefined ? function(){ if(that.length > 0) return that[0].offsetHeight; //此处还需做兼容 }() : that.each(function(index, item){ that.css('height', value); }); }; //添加或获取属性 LAY.prototype.attr = function(key, value){ var that = this; return value === undefined ? function(){ if(that.length > 0) return that[0].getAttribute(key); }() : that.each(function(index, item){ item.setAttribute(key, value); }); }; //移除属性 LAY.prototype.removeAttr = function(key){ return this.each(function(index, item){ item.removeAttribute(key); }); }; //设置或获取 HTML 内容 LAY.prototype.html = function(html){ var that = this; return html === undefined ? function(){ if(that.length > 0) return that[0].innerHTML; }() : this.each(function(index, item){ item.innerHTML = html; }); }; //设置或获取值 LAY.prototype.val = function(value){ var that = this; return value === undefined ? function(){ if(that.length > 0) return that[0].value; }() : this.each(function(index, item){ item.value = value; }); }; //追加内容 LAY.prototype.append = function(elem){ return this.each(function(index, item){ typeof elem === 'object' ? item.appendChild(elem) : item.innerHTML = item.innerHTML + elem; }); }; //移除内容 LAY.prototype.remove = function(elem){ return this.each(function(index, item){ elem ? item.removeChild(elem) : item.parentNode.removeChild(item); }); }; //事件绑定 LAY.prototype.on = function(eventName, fn){ return this.each(function(index, item){ item.attachEvent ? item.attachEvent('on' + eventName, function(e){ e.target = e.srcElement; fn.call(item, e); }) : item.addEventListener(eventName, fn, false); }); }; //解除事件 LAY.prototype.off = function(eventName, fn){ return this.each(function(index, item){ item.detachEvent ? item.detachEvent('on'+ eventName, fn) : item.removeEventListener(eventName, fn, false); }); }; //暴露 lay 到全局作用域 window.lay = lay; //如果在 layui 体系中 if(window.layui && layui.define){ layui.define(function(exports){ //layui 加载 exports(MOD_NAME, lay); }); } }(window, window.document);/** * laytpl 模板引擎 */ layui.define(function(exports){ "use strict"; var config = { open: '{{', close: '}}' }; var tool = { exp: function(str){ return new RegExp(str, 'g'); }, //匹配满足规则内容 query: function(type, _, __){ var types = [ '#([\\s\\S])+?', //js语句 '([^{#}])*?' //普通字段 ][type || 0]; return exp((_||'') + config.open + types + config.close + (__||'')); }, escape: function(html){ var exp = /[<"'>]|&(?=#[a-zA-Z0-9]+)/g; if(html === undefined || html === null) return ''; html += ''; if(!exp.test(html)) return html; return html.replace(/&(?!#?[a-zA-Z0-9]+;)/g, '&') .replace(//g, '>') .replace(/'/g, ''').replace(/"/g, '"'); }, error: function(e, tplog){ var error = 'Laytpl Error: '; typeof console === 'object' && console.error(error + e + '\n'+ (tplog || '')); return error + e; } }; var exp = tool.exp, Tpl = function(tpl){ this.tpl = tpl; }; Tpl.pt = Tpl.prototype; window.errors = 0; //编译模版 Tpl.pt.parse = function(tpl, data){ var that = this, tplog = tpl; var jss = exp('^'+config.open+'#', ''), jsse = exp(config.close+'$', ''); tpl = tpl.replace(/\s+|\r|\t|\n/g, ' ') .replace(exp(config.open+'#'), config.open+'# ') .replace(exp(config.close+'}'), '} '+config.close).replace(/\\/g, '\\\\') //不匹配指定区域的内容 .replace(exp(config.open + '!(.+?)!' + config.close), function(str){ str = str.replace(exp('^'+ config.open + '!'), '') .replace(exp('!'+ config.close), '') .replace(exp(config.open + '|' + config.close), function(tag){ return tag.replace(/(.)/g, '\\$1') }); return str }) //匹配 JS 语法 .replace(/(?="|')/g, '\\').replace(tool.query(), function(str){ str = str.replace(jss, '').replace(jsse, ''); return '";' + str.replace(/\\(.)/g, '$1') + ';view+="'; }) //匹配普通输出语句 .replace(tool.query(1), function(str){ var start = '"+laytpl.escape('; if(str.replace(/\s/g, '') === config.open+config.close){ return ''; } str = str.replace(exp(config.open+'|'+config.close), ''); if(/^=/.test(str)){ str = str.replace(/^=/, ''); } else if(/^-/.test(str)){ str = str.replace(/^-/, ''); start = '"+('; } return start + str.replace(/\\(.)/g, '$1') + ')+"'; }); tpl = '"use strict";var view = "' + tpl + '";return view;'; try{ that.cache = tpl = new Function('d, laytpl', tpl); return tpl(data, tool); } catch(e){ delete that.cache; return tool.error(e, tplog); } }; Tpl.pt.render = function(data, callback){ var that = this, tpl; if(!data) return tool.error('no data'); tpl = that.cache ? that.cache(data, tool) : that.parse(that.tpl, data); if(!callback) return tpl; callback(tpl); }; var laytpl = function(tpl){ if(typeof tpl !== 'string') return tool.error('Template not found'); return new Tpl(tpl); }; laytpl.config = function(options){ options = options || {}; for(var i in options){ config[i] = options[i]; } }; laytpl.v = '1.2.0'; exports('laytpl', laytpl); });/** * laypage 分页组件 */ layui.define(function(exports){ "use strict"; var doc = document ,id = 'getElementById' ,tag = 'getElementsByTagName' //字符常量 ,MOD_NAME = 'laypage', DISABLED = 'layui-disabled' //构造器 ,Class = function(options){ var that = this; that.config = options || {}; that.config.index = ++laypage.index; that.render(true); }; //判断传入的容器类型 Class.prototype.type = function(){ var config = this.config; if(typeof config.elem === 'object'){ return config.elem.length === undefined ? 2 : 3; } }; // 分页视图 Class.prototype.view = function(){ var that = this; var config = that.config; // 连续页码个数 var groups = config.groups = 'groups' in config ? (Number(config.groups) || 0) : 5; // 排版 config.layout = typeof config.layout === 'object' ? config.layout : ['prev', 'page', 'next']; config.count = Number(config.count) || 0; // 数据总数 config.curr = Number(config.curr) || 1; // 当前页 // 每页条数的选择项 config.limits = typeof config.limits === 'object' ? config.limits : [10, 20, 30, 40, 50]; // 默认条数 config.limit = Number(config.limit) || 10; //总页数 config.pages = Math.ceil(config.count/config.limit) || 1; // 当前页不能超过总页数 if(config.curr > config.pages){ config.curr = config.pages; } else if(config.curr < 1) { // 当前分页不能小于 1 config.curr = 1; } //连续分页个数不能低于 0 且不能大于总页数 if(groups < 0){ groups = 1; } else if (groups > config.pages){ groups = config.pages; } config.prev = 'prev' in config ? config.prev : '上一页'; //上一页文本 config.next = 'next' in config ? config.next : '下一页'; //下一页文本 //计算当前组 var index = config.pages > groups ? Math.ceil( (config.curr + (groups > 1 ? 1 : 0)) / (groups > 0 ? groups : 1) ) : 1 //视图片段 ,views = { //上一页 prev: function(){ return config.prev ? ''+ config.prev +'' : ''; }() //页码 ,page: function(){ var pager = []; //数据量为0时,不输出页码 if(config.count < 1){ return ''; } //首页 if(index > 1 && config.first !== false && groups !== 0){ pager.push(''+ (config.first || 1) +''); } //计算当前页码组的起始页 var halve = Math.floor((groups-1)/2) //页码数等分 ,start = index > 1 ? config.curr - halve : 1 ,end = index > 1 ? (function(){ var max = config.curr + (groups - halve - 1); return max > config.pages ? config.pages : max; }()) : groups; //防止最后一组出现“不规定”的连续页码数 if(end - start < groups - 1){ start = end - groups + 1; } //输出左分割符 if(config.first !== false && start > 2){ pager.push('') } //输出连续页码 for(; start <= end; start++){ if(start === config.curr){ //当前页 pager.push(''+ start +''); } else { pager.push(''+ start +''); } } //输出输出右分隔符 & 末页 if(config.pages > groups && config.pages > end && config.last !== false){ if(end + 1 < config.pages){ pager.push(''); } if(groups !== 0){ pager.push(''+ (config.last || config.pages) +''); } } return pager.join(''); }() //下一页 ,next: function(){ return config.next ? ''+ config.next +'' : ''; }() //数据总数 ,count: '共 '+ config.count +' 条' //每页条数 ,limit: function(){ var options = [''; }() //刷新当前页 ,refresh: ['' ,'' ,''].join('') //跳页区域 ,skip: function(){ return ['到第' ,'' ,'页' ,''].join(''); }() }; return ['
' ,function(){ var plate = []; layui.each(config.layout, function(index, item){ if(views[item]){ plate.push(views[item]) } }); return plate.join(''); }() ,'
'].join(''); }; //跳页的回调 Class.prototype.jump = function(elem, isskip){ if(!elem) return; var that = this ,config = that.config ,childs = elem.children ,btn = elem[tag]('button')[0] ,input = elem[tag]('input')[0] ,select = elem[tag]('select')[0] ,skip = function(){ var curr = Number(input.value.replace(/\s|\D/g, '')); if(curr){ config.curr = curr; that.render(); } }; if(isskip) return skip(); //页码 for(var i = 0, len = childs.length; i < len; i++){ if(childs[i].nodeName.toLowerCase() === 'a'){ laypage.on(childs[i], 'click', function(){ var curr = Number(this.getAttribute('data-page')); if(curr < 1 || curr > config.pages) return; config.curr = curr; that.render(); }); } } //条数 if(select){ laypage.on(select, 'change', function(){ var value = this.value; if(config.curr*value > config.count){ config.curr = Math.ceil(config.count/value); } config.limit = value; that.render(); }); } //确定 if(btn){ laypage.on(btn, 'click', function(){ skip(); }); } }; //输入页数字控制 Class.prototype.skip = function(elem){ if(!elem) return; var that = this, input = elem[tag]('input')[0]; if(!input) return; laypage.on(input, 'keyup', function(e){ var value = this.value ,keyCode = e.keyCode; if(/^(37|38|39|40)$/.test(keyCode)) return; if(/\D/.test(value)){ this.value = value.replace(/\D/, ''); } if(keyCode === 13){ that.jump(elem, true) } }); }; //渲染分页 Class.prototype.render = function(load){ var that = this ,config = that.config ,type = that.type() ,view = that.view(); if(type === 2){ config.elem && (config.elem.innerHTML = view); } else if(type === 3){ config.elem.html(view); } else { if(doc[id](config.elem)){ doc[id](config.elem).innerHTML = view; } } config.jump && config.jump(config, load); var elem = doc[id]('layui-laypage-' + config.index); that.jump(elem); if(config.hash && !load){ location.hash = '!'+ config.hash +'='+ config.curr; } that.skip(elem); }; //外部接口 var laypage = { //分页渲染 render: function(options){ var o = new Class(options); return o.index; } ,index: layui.laypage ? (layui.laypage.index + 10000) : 0 ,on: function(elem, even, fn){ elem.attachEvent ? elem.attachEvent('on'+ even, function(e){ //for ie e.target = e.srcElement; fn.call(elem, e); }) : elem.addEventListener(even, fn, false); return this; } } exports(MOD_NAME, laypage); });/** layDate 日期与时间控件 | MIT Licensed */ ;!function(window, document){ "use strict"; var isLayui = window.layui && layui.define, ready = { getPath: (window.lay && lay.getPath) ? lay.getPath : '' //载入 CSS 依赖 ,link: function(href, fn, cssname){ //未设置路径,则不主动加载 css if(!laydate.path) return; //加载 css if(window.lay && lay.layui){ lay.layui.link(laydate.path + href, fn, cssname); } } } //识别预先可能定义的指定全局对象 ,GLOBAL = window.LAYUI_GLOBAL || {} //外部调用 ,laydate = { v: '5.3.1' //layDate 版本号 ,config: { weekStart: 0, // 默认周日一周的开始 } //全局配置项 ,index: (window.laydate && window.laydate.v) ? 100000 : 0 ,path: GLOBAL.laydate_dir || ready.getPath //设置全局项 ,set: function(options){ var that = this; that.config = lay.extend({}, that.config, options); return that; } //主体CSS等待事件 ,ready: function(fn){ var cssname = 'laydate', ver = '' ,path = (isLayui ? 'modules/laydate/' : 'theme/') + 'default/laydate.css?v='+ laydate.v + ver; isLayui ? layui.addcss(path, fn, cssname) : ready.link(path, fn, cssname); return this; } } //操作当前实例 ,thisModule = function(){ var that = this ,options = that.config ,id = options.id; thisModule.that[id] = that; //记录当前实例对象 return { //提示框 hint: function(content){ that.hint.call(that, content); } ,config: that.config }; } //字符常量 ,MOD_NAME = 'laydate', ELEM = '.layui-laydate', THIS = 'layui-this', SHOW = 'layui-show', HIDE = 'layui-hide', DISABLED = 'laydate-disabled', LIMIT_YEAR = [100, 200000] ,ELEM_STATIC = 'layui-laydate-static', ELEM_LIST = 'layui-laydate-list', ELEM_SELECTED = 'laydate-selected', ELEM_HINT = 'layui-laydate-hint', ELEM_PREV = 'laydate-day-prev', ELEM_NEXT = 'laydate-day-next', ELEM_FOOTER = 'layui-laydate-footer', ELEM_CONFIRM = '.laydate-btns-confirm', ELEM_TIME_TEXT = 'laydate-time-text', ELEM_TIME_BTN = 'laydate-btns-time', ELEM_PREVIEW = 'layui-laydate-preview' //组件构造器 ,Class = function(options){ var that = this; that.index = ++laydate.index; that.config = lay.extend({}, that.config, laydate.config, options); //初始化 id 参数 options = that.config; options.id = ('id' in options) ? options.id : that.index; //初始化 laydate.ready(function(){ that.init(); }); } //日期格式字符 ,dateType = 'yyyy|y|MM|M|dd|d|HH|H|mm|m|ss|s'; //将日期格式字符转换为数组 thisModule.formatArr = function(format){ return (format || '').match(new RegExp(dateType + '|.', 'g')) || [] }; /* 组件操作 */ //是否闰年 Class.isLeapYear = function(year){ return (year % 4 === 0 && year % 100 !== 0) || year % 400 === 0; }; //默认配置 Class.prototype.config = { type: 'date' //控件类型,支持:year/month/date/time/datetime ,range: false //是否开启范围选择,即双控件 ,format: 'yyyy-MM-dd' //默认日期格式 ,value: null //默认日期,支持传入new Date(),或者符合format参数设定的日期格式字符 ,isInitValue: true //用于控制是否自动向元素填充初始值(需配合 value 参数使用) ,min: '1900-1-1' //有效最小日期,年月日必须用“-”分割,时分秒必须用“:”分割。注意:它并不是遵循 format 设定的格式。 ,max: '2099-12-31' //有效最大日期,同上 ,trigger: 'click' //呼出控件的事件 ,show: false //是否直接显示,如果设置 true,则默认直接显示控件 ,showBottom: true //是否显示底部栏 ,isPreview: true //是否显示值预览 ,btns: ['clear', 'now', 'confirm'] //右下角显示的按钮,会按照数组顺序排列 ,lang: 'cn' //语言,只支持cn/en,即中文和英文 ,theme: 'default' //主题 ,position: null //控件定位方式定位, 默认absolute,支持:fixed/absolute/static ,calendar: false //是否开启公历重要节日,仅支持中文版 ,mark: {} //日期备注,如重要事件或活动标记 ,zIndex: null //控件层叠顺序 ,done: null //控件选择完毕后的回调,点击清空/现在/确定也均会触发 ,change: null //日期时间改变后的回调 }; //多语言 Class.prototype.lang = function(){ var that = this ,options = that.config ,text = { cn: { weeks: ['日', '一', '二', '三', '四', '五', '六'] ,time: ['时', '分', '秒'] ,timeTips: '选择时间' ,startTime: '开始时间' ,endTime: '结束时间' ,dateTips: '返回日期' ,month: ['一', '二', '三', '四', '五', '六', '七', '八', '九', '十', '十一', '十二'] ,tools: { confirm: '确定' ,clear: '清空' ,now: '现在' } ,timeout: '结束时间不能早于开始时间
请重新选择' ,invalidDate: '不在有效日期或时间范围内' ,formatError: ['日期格式不合法
必须遵循下述格式:
', '
已为你重置'] ,preview: '当前选中的结果' } ,en: { weeks: ['Su', 'Mo', 'Tu', 'We', 'Th', 'Fr', 'Sa'] ,time: ['Hours', 'Minutes', 'Seconds'] ,timeTips: 'Select Time' ,startTime: 'Start Time' ,endTime: 'End Time' ,dateTips: 'Select Date' ,month: ['Jan', 'Feb', 'Mar', 'Apr', 'May', 'Jun', 'Jul', 'Aug', 'Sep', 'Oct', 'Nov', 'Dec'] ,tools: { confirm: 'Confirm' ,clear: 'Clear' ,now: 'Now' } ,timeout: 'End time cannot be less than start Time
Please re-select' ,invalidDate: 'Invalid date' ,formatError: ['The date format error
Must be followed:
', '
It has been reset'] ,preview: 'The selected result' } }; return text[options.lang] || text['cn']; }; //初始准备 Class.prototype.init = function(){ var that = this ,options = that.config ,isStatic = options.position === 'static' ,format = { year: 'yyyy' ,month: 'yyyy-MM' ,date: 'yyyy-MM-dd' ,time: 'HH:mm:ss' ,datetime: 'yyyy-MM-dd HH:mm:ss' }; options.elem = lay(options.elem); options.eventElem = lay(options.eventElem); if(!options.elem[0]) return; //日期范围分隔符 that.rangeStr = options.range ? ( typeof options.range === 'string' ? options.range : '-' ) : ''; //若 range 参数为数组,则表示为开始日期和结束日期的 input 对象 if(layui.type(options.range) === 'array'){ that.rangeElem = [ lay(options.range[0]), lay(options.range[1]) ]; } //若 type 设置非法,则初始化为 date 类型 if(!format[options.type]){ window.console && console.error && console.error('laydate type error:\''+ options.type + '\' is not supported') options.type = 'date'; } //根据不同 type,初始化默认 format if(options.format === format.date){ options.format = format[options.type] || format.date; } //将日期格式转化成数组 that.format = thisModule.formatArr(options.format); // 设置了一周的开始是周几,此处做一个控制 if (options.weekStart) { if (!/^[0-6]$/.test(options.weekStart)) { var lang = that.lang(); options.weekStart = lang.weeks.indexOf(options.weekStart); if (options.weekStart === -1) options.weekStart = 0; } } //生成正则表达式 that.EXP_IF = ''; that.EXP_SPLIT = ''; lay.each(that.format, function(i, item){ var EXP = new RegExp(dateType).test(item) ? '\\d{'+ function(){ if(new RegExp(dateType).test(that.format[i === 0 ? i + 1 : i - 1]||'')){ if(/^yyyy|y$/.test(item)) return 4; return item.length; } if(/^yyyy$/.test(item)) return '1,4'; if(/^y$/.test(item)) return '1,308'; return '1,2'; }() +'}' : '\\' + item; that.EXP_IF = that.EXP_IF + EXP; that.EXP_SPLIT = that.EXP_SPLIT + '(' + EXP + ')'; }); //验证日期格式正则 that.EXP_IF_ONE = new RegExp('^'+ that.EXP_IF +'$'); //验证单个日期格式 that.EXP_IF = new RegExp('^'+ ( options.range ? that.EXP_IF + '\\s\\'+ that.rangeStr + '\\s' + that.EXP_IF : that.EXP_IF ) +'$'); that.EXP_SPLIT = new RegExp('^'+ that.EXP_SPLIT +'$', ''); //如果不是 input|textarea 元素,则默认采用 click 事件 if(!that.isInput(options.elem[0])){ if(options.trigger === 'focus'){ options.trigger = 'click'; } } //设置唯一KEY if(!options.elem.attr('lay-key')){ options.elem.attr('lay-key', that.index); options.eventElem.attr('lay-key', that.index); } //记录重要日期 options.mark = lay.extend({}, (options.calendar && options.lang === 'cn') ? { '0-1-1': '元旦' ,'0-2-14': '情人' ,'0-3-8': '妇女' ,'0-3-12': '植树' ,'0-4-1': '愚人' ,'0-5-1': '劳动' ,'0-5-4': '青年' ,'0-6-1': '儿童' ,'0-9-10': '教师' ,'0-10-1': '国庆' ,'0-12-25': '圣诞' } : {}, options.mark); //获取限制内日期 lay.each(['min', 'max'], function(i, item){ var ymd = [], hms = []; if(typeof options[item] === 'number'){ //如果为数字 var day = options[item] ,tDate = new Date() ,time = that.newDate({ //今天的最大毫秒数 year: tDate.getFullYear() ,month: tDate.getMonth() ,date: tDate.getDate() ,hours: '23' ,minutes: '59' ,seconds: '59' }).getTime() ,STAMP = 86400000 //代表一天的毫秒数 ,thisDate = new Date( day ? ( day < STAMP ? time + day*STAMP : day //如果数字小于一天的毫秒数,则数字为天数,否则为毫秒数 ) : time ); ymd = [thisDate.getFullYear(), thisDate.getMonth() + 1, thisDate.getDate()]; hms = [thisDate.getHours(), thisDate.getMinutes(), thisDate.getSeconds()]; } else { ymd = (options[item].match(/\d+-\d+-\d+/) || [''])[0].split('-'); hms = (options[item].match(/\d+:\d+:\d+/) || [''])[0].split(':'); } options[item] = { year: ymd[0] | 0 || new Date().getFullYear() ,month: ymd[1] ? (ymd[1] | 0) - 1 : new Date().getMonth() ,date: ymd[2] | 0 || new Date().getDate() ,hours: hms[0] | 0 ,minutes: hms[1] | 0 ,seconds: hms[2] | 0 }; }); that.elemID = 'layui-laydate'+ options.elem.attr('lay-key'); if(options.show || isStatic) that.render(); isStatic || that.events(); //默认赋值 if(options.value && options.isInitValue){ if(layui.type(options.value) === 'date'){ that.setValue(that.parse(0, that.systemDate(options.value))); } else { that.setValue(options.value); } } }; //控件主体渲染 Class.prototype.render = function(){ var that = this ,options = that.config ,lang = that.lang() ,isStatic = options.position === 'static' //主面板 ,elem = that.elem = lay.elem('div', { id: that.elemID ,"class": [ 'layui-laydate' ,options.range ? ' layui-laydate-range' : '' ,isStatic ? (' '+ ELEM_STATIC) : '' ,options.theme && options.theme !== 'default' && !/^#/.test(options.theme) ? (' laydate-theme-' + options.theme) : '' ].join('') }) //主区域 ,elemMain = that.elemMain = [] ,elemHeader = that.elemHeader = [] ,elemCont = that.elemCont = [] ,elemTable = that.table = [] //底部区域 ,divFooter = that.footer = lay.elem('div', { "class": ELEM_FOOTER }); if(options.zIndex) elem.style.zIndex = options.zIndex; //单双日历区域 lay.each(new Array(2), function(i){ if(!options.range && i > 0){ return true; } //头部区域 var divHeader = lay.elem('div', { "class": 'layui-laydate-header' }) //左右切换 ,headerChild = [function(){ //上一年 var elem = lay.elem('i', { "class": 'layui-icon laydate-icon laydate-prev-y' }); elem.innerHTML = ''; return elem; }(), function(){ //上一月 var elem = lay.elem('i', { "class": 'layui-icon laydate-icon laydate-prev-m' }); elem.innerHTML = ''; return elem; }(), function(){ //年月选择 var elem = lay.elem('div', { "class": 'laydate-set-ym' }), spanY = lay.elem('span'), spanM = lay.elem('span'); elem.appendChild(spanY); elem.appendChild(spanM); return elem; }(), function(){ //下一月 var elem = lay.elem('i', { "class": 'layui-icon laydate-icon laydate-next-m' }); elem.innerHTML = ''; return elem; }(), function(){ //下一年 var elem = lay.elem('i', { "class": 'layui-icon laydate-icon laydate-next-y' }); elem.innerHTML = ''; return elem; }()] //日历内容区域 ,divContent = lay.elem('div', { "class": 'layui-laydate-content' }) ,table = lay.elem('table') ,thead = lay.elem('thead'), theadTr = lay.elem('tr'); //生成年月选择 lay.each(headerChild, function(i, item){ divHeader.appendChild(item); }); //生成表格 thead.appendChild(theadTr); lay.each(new Array(6), function(i){ //表体 var tr = table.insertRow(0); lay.each(new Array(7), function(j){ if(i === 0){ var th = lay.elem('th'); th.innerHTML = lang.weeks[(j + options.weekStart) % 7]; theadTr.appendChild(th); } tr.insertCell(j); }); }); table.insertBefore(thead, table.children[0]); //表头 divContent.appendChild(table); elemMain[i] = lay.elem('div', { "class": 'layui-laydate-main laydate-main-list-'+ i }); elemMain[i].appendChild(divHeader); elemMain[i].appendChild(divContent); elemHeader.push(headerChild); elemCont.push(divContent); elemTable.push(table); }); //生成底部栏 lay(divFooter).html(function(){ var html = [], btns = []; if(options.type === 'datetime'){ html.push(''+ lang.timeTips +''); } if(!(!options.range && options.type === 'datetime')){ html.push('') } lay.each(options.btns, function(i, item){ var title = lang.tools[item] || 'btn'; if(options.range && item === 'now') return; if(isStatic && item === 'clear') title = options.lang === 'cn' ? '重置' : 'Reset'; btns.push(''+ title +''); }); html.push(''); return html.join(''); }()); //插入到主区域 lay.each(elemMain, function(i, main){ elem.appendChild(main); }); options.showBottom && elem.appendChild(divFooter); //生成自定义主题 if(/^#/.test(options.theme)){ var style = lay.elem('style') ,styleText = [ '#{{id}} .layui-laydate-header{background-color:{{theme}};}' ,'#{{id}} .layui-this{background-color:{{theme}} !important;}' ].join('').replace(/{{id}}/g, that.elemID).replace(/{{theme}}/g, options.theme); if('styleSheet' in style){ style.setAttribute('type', 'text/css'); style.styleSheet.cssText = styleText; } else { style.innerHTML = styleText; } lay(elem).addClass('laydate-theme-molv'); elem.appendChild(style); } //移除上一个控件 that.remove(Class.thisElemDate); //记录当前执行的实例索引 laydate.thisId = options.id; //如果是静态定位,则插入到指定的容器中,否则,插入到body isStatic ? options.elem.append(elem) : ( document.body.appendChild(elem) ,that.position() //定位 ); that.checkDate().calendar(null, 0, 'init'); //初始校验 that.changeEvent(); //日期切换 Class.thisElemDate = that.elemID; typeof options.ready === 'function' && options.ready(lay.extend({}, options.dateTime, { month: options.dateTime.month + 1 })); that.preview(); }; //控件移除 Class.prototype.remove = function(prev){ var that = this ,options = that.config ,elem = lay('#'+ (prev || that.elemID)); if(!elem[0]) return that; if(!elem.hasClass(ELEM_STATIC)){ that.checkDate(function(){ elem.remove(); //delete options.dateTime; //delete that.endDate; delete laydate.thisId; }); } return that; }; //定位算法 Class.prototype.position = function(){ var that = this ,options = that.config; lay.position(that.bindElem || options.elem[0], that.elem, { position: options.position }); return that; }; //提示 Class.prototype.hint = function(content){ var that = this ,options = that.config ,div = lay.elem('div', { "class": ELEM_HINT }); if(!that.elem) return; div.innerHTML = content || ''; lay(that.elem).find('.'+ ELEM_HINT).remove(); that.elem.appendChild(div); clearTimeout(that.hinTimer); that.hinTimer = setTimeout(function(){ lay(that.elem).find('.'+ ELEM_HINT).remove(); }, 3000); }; //获取递增/减后的年月 Class.prototype.getAsYM = function(Y, M, type){ type ? M-- : M++; if(M < 0){ M = 11; Y--; } if(M > 11){ M = 0; Y++; } return [Y, M]; }; //系统日期 Class.prototype.systemDate = function(newDate){ var thisDate = newDate || new Date(); return { year: thisDate.getFullYear() //年 ,month: thisDate.getMonth() //月 ,date: thisDate.getDate() //日 ,hours: newDate ? newDate.getHours() : 0 //时 ,minutes: newDate ? newDate.getMinutes() : 0 //分 ,seconds: newDate ? newDate.getSeconds() : 0 //秒 } }; //日期校验 Class.prototype.checkDate = function(fn){ var that = this ,thisDate = new Date() ,options = that.config ,lang = that.lang() ,dateTime = options.dateTime = options.dateTime || that.systemDate() ,thisMaxDate, error ,elem = that.bindElem || options.elem[0] ,valType = that.isInput(elem) ? 'val' : 'html' ,value = function(){ //如果传入了开始和结束日期的 input 对象,则将其拼接为日期范围字符 if(that.rangeElem){ var vals = [that.rangeElem[0].val(), that.rangeElem[1].val()]; if(vals[0] && vals[1]){ return vals.join(' ' + that.rangeStr + ' '); } } return that.isInput(elem) ? elem.value : (options.position === 'static' ? '' : lay(elem).attr('lay-date')); }() //校验日期有效数字 ,checkValid = function(dateTime){ if(dateTime.year > LIMIT_YEAR[1]) dateTime.year = LIMIT_YEAR[1], error = true; //不能超过20万年 if(dateTime.month > 11) dateTime.month = 11, error = true; if(dateTime.hours > 23) dateTime.hours = 0, error = true; if(dateTime.minutes > 59) dateTime.minutes = 0, dateTime.hours++, error = true; if(dateTime.seconds > 59) dateTime.seconds = 0, dateTime.minutes++, error = true; //计算当前月的最后一天 thisMaxDate = laydate.getEndDate(dateTime.month + 1, dateTime.year); if(dateTime.date > thisMaxDate) dateTime.date = thisMaxDate, error = true; } //获得初始化日期值 ,initDate = function(dateTime, value, index){ var startEnd = ['startTime', 'endTime']; value = (value.match(that.EXP_SPLIT) || []).slice(1); index = index || 0; if(options.range){ that[startEnd[index]] = that[startEnd[index]] || {}; } lay.each(that.format, function(i, item){ var thisv = parseFloat(value[i]); if(value[i].length < item.length) error = true; if(/yyyy|y/.test(item)){ //年 if(thisv < LIMIT_YEAR[0]) thisv = LIMIT_YEAR[0], error = true; //年不能低于100年 dateTime.year = thisv; } else if(/MM|M/.test(item)){ //月 if(thisv < 1) thisv = 1, error = true; dateTime.month = thisv - 1; } else if(/dd|d/.test(item)){ //日 if(thisv < 1) thisv = 1, error = true; dateTime.date = thisv; } else if(/HH|H/.test(item)){ //时 if(thisv < 1) thisv = 0, error = true; dateTime.hours = thisv; options.range && (that[startEnd[index]].hours = thisv); } else if(/mm|m/.test(item)){ //分 if(thisv < 1) thisv = 0, error = true; dateTime.minutes = thisv; options.range && (that[startEnd[index]].minutes = thisv); } else if(/ss|s/.test(item)){ //秒 if(thisv < 1) thisv = 0, error = true; dateTime.seconds = thisv; options.range && (that[startEnd[index]].seconds = thisv); } }); checkValid(dateTime); }; if(fn === 'limit') return checkValid(dateTime), that; value = value || options.value; if(typeof value === 'string'){ value = value.replace(/\s+/g, ' ').replace(/^\s|\s$/g, ''); } //如果开启范围,则计算结束日期 var getEndDate = function(){ if(options.range){ that.endDate = that.endDate || lay.extend({}, options.dateTime, function(){ var obj = {} ,dateTime = options.dateTime ,EYM = that.getAsYM(dateTime.year, dateTime.month); //初始右侧面板的年月 if(options.type === 'year'){ obj.year = dateTime.year + 1; } else if(options.type !== 'time'){ obj.year = EYM[0]; obj.month = EYM[1]; } //初始右侧面板的时间 if(options.type === 'datetime' || options.type === 'time'){ obj.hours = 23; obj.minutes = obj.seconds = 59; } return obj; }()); } }; getEndDate(); if(typeof value === 'string' && value){ if(that.EXP_IF.test(value)){ //校验日期格式 if(options.range){ value = value.split(' '+ that.rangeStr +' '); lay.each([options.dateTime, that.endDate], function(i, item){ initDate(item, value[i], i); }); } else { initDate(dateTime, value); } } else { //格式不合法 that.hint(lang.formatError[0] + ( options.range ? (options.format + ' '+ that.rangeStr +' ' + options.format) : options.format ) + lang.formatError[1]); error = true; } } else if(value && layui.type(value) === 'date'){ //若值为日期对象 options.dateTime = that.systemDate(value); } else { //重置开始日期 options.dateTime = that.systemDate(); delete that.startTime; //重置结束日期 delete that.endDate; //删除原有的结束日期 getEndDate(); //并重新获得新的结束日期 delete that.endTime; } //从日期范围表单中获取初始值 (function(){ if(that.rangeElem){ var vals = [that.rangeElem[0].val(), that.rangeElem[1].val()] ,arrDate = [options.dateTime, that.endDate]; lay.each(vals, function(_i, _v){ if(that.EXP_IF_ONE.test(_v)){ //校验日期格式 initDate(arrDate[_i], _v, _i); } }); } })(); //校验日期有效数字 checkValid(dateTime); if(options.range) checkValid(that.endDate); //如果初始值格式错误,则纠正初始值 if(error && value){ that.setValue( options.range ? (that.endDate ? that.parse() : '') : that.parse() ); } //如果当前日期不在设定的最大小日期区间,则自动纠正在可选区域 var getDateTime = function(obj){ return that.newDate(obj).getTime(); }; //校验主面板是否在可选日期区间 if(getDateTime(dateTime) > getDateTime(options.max)){ //若超出最大日期 dateTime = options.dateTime = lay.extend({}, options.max); } else if(getDateTime(dateTime) < getDateTime(options.min)){ //若少于最小日期 dateTime = options.dateTime = lay.extend({}, options.min); } //校验右侧面板是否在可选日期区间 if(options.range){ if(getDateTime(that.endDate) < getDateTime(options.min) || getDateTime(that.endDate) > getDateTime(options.max)){ that.endDate = lay.extend({}, options.max); } } fn && fn(); return that; }; //公历重要日期与自定义备注 Class.prototype.mark = function(td, YMD){ var that = this ,mark, options = that.config; lay.each(options.mark, function(key, title){ var keys = key.split('-'); if((keys[0] == YMD[0] || keys[0] == 0) //每年的每月 && (keys[1] == YMD[1] || keys[1] == 0) //每月的每日 && keys[2] == YMD[2]){ //特定日 mark = title || YMD[2]; } }); mark && td.html(''+ mark +''); return that; }; //无效日期范围的标记 Class.prototype.limit = function(elem, date, index, time){ var that = this ,options = that.config, timestrap = {} ,dateTime = options[index > 41 ? 'endDate' : 'dateTime'] ,isOut, thisDateTime = lay.extend({}, dateTime, date || {}); lay.each({ now: thisDateTime ,min: options.min ,max: options.max }, function(key, item){ timestrap[key] = that.newDate(lay.extend({ year: item.year ,month: item.month ,date: item.date }, function(){ var hms = {}; lay.each(time, function(i, keys){ hms[keys] = item[keys]; }); return hms; }())).getTime(); //time:是否比较时分秒 }); isOut = timestrap.now < timestrap.min || timestrap.now > timestrap.max; elem && elem[isOut ? 'addClass' : 'removeClass'](DISABLED); return isOut; }; //当前日期对象 Class.prototype.thisDateTime = function(index){ var that = this ,options = that.config; return index ? that.endDate: options.dateTime; }; //日历表 Class.prototype.calendar = function(value, index, type){ var that = this ,options = that.config ,index = index ? 1 : 0 ,dateTime = value || that.thisDateTime(index) ,thisDate = new Date(), startWeek, prevMaxDate, thisMaxDate ,lang = that.lang() ,isAlone = options.type !== 'date' && options.type !== 'datetime' ,tds = lay(that.table[index]).find('td') ,elemYM = lay(that.elemHeader[index][2]).find('span'); if(dateTime.year < LIMIT_YEAR[0]) dateTime.year = LIMIT_YEAR[0], that.hint(lang.invalidDate); if(dateTime.year > LIMIT_YEAR[1]) dateTime.year = LIMIT_YEAR[1], that.hint(lang.invalidDate); //记录初始值 if(!that.firstDate){ that.firstDate = lay.extend({}, dateTime); } //计算当前月第一天的星期 thisDate.setFullYear(dateTime.year, dateTime.month, 1); startWeek = (thisDate.getDay() + (7 - options.weekStart)) % 7; prevMaxDate = laydate.getEndDate(dateTime.month || 12, dateTime.year); //计算上个月的最后一天 thisMaxDate = laydate.getEndDate(dateTime.month + 1, dateTime.year); //计算当前月的最后一天 //赋值日 lay.each(tds, function(index_, item){ var YMD = [dateTime.year, dateTime.month], st = 0; item = lay(item); item.removeAttr("class"); if(index_ < startWeek){ st = prevMaxDate - startWeek + index_; item.addClass('laydate-day-prev'); YMD = that.getAsYM(dateTime.year, dateTime.month, 'sub'); } else if(index_ >= startWeek && index_ < thisMaxDate + startWeek){ st = index_ - startWeek; st + 1 === dateTime.date && item.addClass(THIS); } else { st = index_ - thisMaxDate - startWeek; item.addClass('laydate-day-next'); YMD = that.getAsYM(dateTime.year, dateTime.month); } YMD[1]++; YMD[2] = st + 1; item.attr('lay-ymd', YMD.join('-')).html(YMD[2]); that.mark(item, YMD).limit(item, { year: YMD[0] ,month: YMD[1] - 1 ,date: YMD[2] }, index_); }); //同步头部年月 lay(elemYM[0]).attr('lay-ym', dateTime.year + '-' + (dateTime.month + 1)); lay(elemYM[1]).attr('lay-ym', dateTime.year + '-' + (dateTime.month + 1)); if(options.lang === 'cn'){ lay(elemYM[0]).attr('lay-type', 'year').html(dateTime.year + ' 年') lay(elemYM[1]).attr('lay-type', 'month').html((dateTime.month + 1) + ' 月'); } else { lay(elemYM[0]).attr('lay-type', 'month').html(lang.month[dateTime.month]); lay(elemYM[1]).attr('lay-type', 'year').html(dateTime.year); } //初始默认选择器 if(isAlone){ //年、月等独立选择器 if(options.range){ if(value){ that.listYM = [ [options.dateTime.year, options.dateTime.month + 1] ,[that.endDate.year, that.endDate.month + 1] ]; that.list(options.type, 0).list(options.type, 1); //同步按钮可点状态 options.type === 'time' ? that.setBtnStatus('时间' ,lay.extend({}, that.systemDate(), that.startTime) ,lay.extend({}, that.systemDate(), that.endTime) ) : that.setBtnStatus(true); } } else { that.listYM = [[dateTime.year, dateTime.month + 1]]; that.list(options.type, 0); } } //初始赋值双日历 if(options.range && type === 'init' && !value){ //执行渲染第二个日历 that.calendar(that.endDate, 1); } //通过检测当前有效日期,来设定确定按钮是否可点 if(!options.range){ that.limit(lay(that.footer).find(ELEM_CONFIRM), null, 0, ['hours', 'minutes', 'seconds']); } //同步按钮可点状态 that.setBtnStatus(); return that; }; //生成年月时分秒列表 Class.prototype.list = function(type, index){ var that = this ,options = that.config ,dateTime = options.dateTime ,lang = that.lang() ,isAlone = options.range && options.type !== 'date' && options.type !== 'datetime' //独立范围选择器 ,ul = lay.elem('ul', { "class": ELEM_LIST + ' ' + ({ year: 'laydate-year-list' ,month: 'laydate-month-list' ,time: 'laydate-time-list' })[type] }) ,elemHeader = that.elemHeader[index] ,elemYM = lay(elemHeader[2]).find('span') ,elemCont = that.elemCont[index || 0] ,haveList = lay(elemCont).find('.'+ ELEM_LIST)[0] ,isCN = options.lang === 'cn' ,text = isCN ? '年' : '' ,listYM = that.listYM[index] || {} ,hms = ['hours', 'minutes', 'seconds'] ,startEnd = ['startTime', 'endTime'][index]; if(listYM[0] < 1) listYM[0] = 1; //生成年列表 if(type === 'year'){ var yearNum, startY = yearNum = listYM[0] - 7; if(startY < 1) startY = yearNum = 1; lay.each(new Array(15), function(i){ var li = lay.elem('li', { 'lay-ym': yearNum }) ,ymd = { year: yearNum ,month: 0 ,date: 1 }; yearNum == listYM[0] && lay(li).addClass(THIS); li.innerHTML = yearNum + text; ul.appendChild(li); /* if(yearNum < that.firstDate.year){ ymd.month = options.min.month; ymd.date = options.min.date; } else if(yearNum >= that.firstDate.year){ ymd.month = options.max.month; ymd.date = options.max.date; } */ that.limit(lay(li), ymd, index); yearNum++; }); lay(elemYM[isCN ? 0 : 1]).attr('lay-ym', (yearNum - 8) + '-' + listYM[1]) .html((startY + text) + ' - ' + (yearNum - 1 + text)); } //生成月列表 else if(type === 'month'){ lay.each(new Array(12), function(i){ var li = lay.elem('li', { 'lay-ym': i }) ,ymd = { year: listYM[0] ,month: i ,date: 1 }; i + 1 == listYM[1] && lay(li).addClass(THIS); li.innerHTML = lang.month[i] + (isCN ? '月' : ''); ul.appendChild(li); /* if(listYM[0] < that.firstDate.year){ ymd.date = options.min.date; } else if(listYM[0] >= that.firstDate.year){ ymd.date = options.max.date; } */ that.limit(lay(li), ymd, index); }); lay(elemYM[isCN ? 0 : 1]).attr('lay-ym', listYM[0] + '-' + listYM[1]) .html(listYM[0] + text); } //生成时间列表 else if(type === 'time'){ //检测时分秒状态是否在有效日期时间范围内 var setTimeStatus = function(){ lay(ul).find('ol').each(function(i, ol){ lay(ol).find('li').each(function(ii, li){ that.limit(lay(li), [{ hours: ii }, { hours: that[startEnd].hours ,minutes: ii }, { hours: that[startEnd].hours ,minutes: that[startEnd].minutes ,seconds: ii }][i], index, [['hours'], ['hours', 'minutes'], ['hours', 'minutes', 'seconds']][i]); }); }); if(!options.range){ that.limit(lay(that.footer).find(ELEM_CONFIRM), that[startEnd], 0, ['hours', 'minutes', 'seconds']); } }; //初始化时间对象 if(options.range){ if(!that[startEnd]){ that[startEnd] = startEnd === 'startTime' ? dateTime : that.endDate; } } else { that[startEnd] = dateTime; } //生成时分秒 lay.each([24, 60, 60], function(i, item){ var li = lay.elem('li'), childUL = ['

'+ lang.time[i] +'

    ']; lay.each(new Array(item), function(ii){ childUL.push(''+ lay.digit(ii, 2) +''); }); li.innerHTML = childUL.join('') + '
'; ul.appendChild(li); }); setTimeStatus(); } //插入容器 if(haveList) elemCont.removeChild(haveList); elemCont.appendChild(ul); //年月面板 - 选择事件 if(type === 'year' || type === 'month'){ //显示切换箭头 lay(that.elemMain[index]).addClass('laydate-ym-show'); //选中 lay(ul).find('li').on('click', function(){ var ym = lay(this).attr('lay-ym') | 0; if(lay(this).hasClass(DISABLED)) return; if(index === 0){ dateTime[type] = ym; that.limit(lay(that.footer).find(ELEM_CONFIRM), null, 0); } else { //范围选择 that.endDate[type] = ym; } //当为年选择器或者年月选择器 var isYearOrMonth = options.type === 'year' || options.type === 'month'; if(isYearOrMonth){ lay(ul).find('.'+ THIS).removeClass(THIS); lay(this).addClass(THIS); //如果为年月选择器,点击了年列表,则切换到月选择器 if(options.type === 'month' && type === 'year'){ that.listYM[index][0] = ym; isAlone && ((index ? that.endDate : dateTime).year = ym); that.list('month', index); } } else { that.checkDate('limit').calendar(null, index); that.closeList(); } that.setBtnStatus(); //同步按钮可点状态 //若为月选择器,只有当选择月份时才自动关闭; //若为年选择器,选择年份即自动关闭 //且在范围未开启时 if(!options.range){ if((options.type === 'month' && type === 'month') || (options.type === 'year' && type === 'year')){ that.setValue(that.parse()).remove().done(); } } that.done(null, 'change'); lay(that.footer).find('.'+ ELEM_TIME_BTN).removeClass(DISABLED); }); } else { //时间选择面板 - 选择事件 var span = lay.elem('span', { "class": ELEM_TIME_TEXT }) //滚动条定位 ,scroll = function(){ lay(ul).find('ol').each(function(i){ var ol = this ,li = lay(ol).find('li') ol.scrollTop = 30*(that[startEnd][hms[i]] - 2); if(ol.scrollTop <= 0){ li.each(function(ii, item){ if(!lay(this).hasClass(DISABLED)){ ol.scrollTop = 30*(ii - 2); return true; } }); } }); } ,haveSpan = lay(elemHeader[2]).find('.'+ ELEM_TIME_TEXT); scroll(); span.innerHTML = options.range ? [lang.startTime,lang.endTime][index] : lang.timeTips; lay(that.elemMain[index]).addClass('laydate-time-show'); if(haveSpan[0]) haveSpan.remove(); elemHeader[2].appendChild(span); lay(ul).find('ol').each(function(i){ var ol = this; //选择时分秒 lay(ol).find('li').on('click', function(){ var value = this.innerHTML | 0; if(lay(this).hasClass(DISABLED)) return; if(options.range){ that[startEnd][hms[i]] = value; } else { dateTime[hms[i]] = value; } lay(ol).find('.'+ THIS).removeClass(THIS); lay(this).addClass(THIS); setTimeStatus(); scroll(); (that.endDate || options.type === 'time') && that.done(null, 'change'); //同步按钮可点状态 that.setBtnStatus(); }); }); } return that; }; //记录列表切换后的年月 Class.prototype.listYM = []; //关闭列表 Class.prototype.closeList = function(){ var that = this ,options = that.config; lay.each(that.elemCont, function(index, item){ lay(this).find('.'+ ELEM_LIST).remove(); lay(that.elemMain[index]).removeClass('laydate-ym-show laydate-time-show'); }); lay(that.elem).find('.'+ ELEM_TIME_TEXT).remove(); }; //检测结束日期是否超出开始日期 Class.prototype.setBtnStatus = function(tips, start, end){ var that = this ,options = that.config ,lang = that.lang() ,isOut, elemBtn = lay(that.footer).find(ELEM_CONFIRM); if(options.range && options.type !== 'time'){ start = start || options.dateTime; end = end || that.endDate; isOut = that.newDate(start).getTime() > that.newDate(end).getTime(); //如果不在有效日期内,直接禁用按钮,否则比较开始和结束日期 (that.limit(null, start) || that.limit(null, end)) ? elemBtn.addClass(DISABLED) : elemBtn[isOut ? 'addClass' : 'removeClass'](DISABLED); //是否异常提示 if(tips && isOut) that.hint( typeof tips === 'string' ? lang.timeout.replace(/日期/g, tips) : lang.timeout ); } }; //转义为规定格式的日期字符 Class.prototype.parse = function(state, date){ var that = this ,options = that.config ,dateTime = date || (state == 'end' ? lay.extend({}, that.endDate, that.endTime) : ( options.range ? lay.extend({}, options.dateTime, that.startTime) : options.dateTime) ) ,format = laydate.parse(dateTime, that.format, 1); //返回日期范围字符 if(options.range && state === undefined){ return format + ' '+ that.rangeStr +' ' + that.parse('end'); } return format; }; //创建指定日期时间对象 Class.prototype.newDate = function(dateTime){ dateTime = dateTime || {}; return new Date( dateTime.year || 1 ,dateTime.month || 0 ,dateTime.date || 1 ,dateTime.hours || 0 ,dateTime.minutes || 0 ,dateTime.seconds || 0 ); }; //赋值 Class.prototype.setValue = function(value){ var that = this ,options = that.config ,elem = that.bindElem || options.elem[0]; //静态展现则不作默认赋值 if(options.position === 'static') return that; value = value || ''; //绑定的元素是否为 input if(that.isInput(elem)){ lay(elem).val(value); } else { //如果 range 传入了开始和结束的 input 对象,则分别对其赋值 var rangeElem = that.rangeElem; if(rangeElem){ if(layui.type(value) !== 'array'){ value = value.split(' '+ that.rangeStr +' '); } rangeElem[0].val(value[0] || ''); rangeElem[1].val(value[1] || ''); } else { if(lay(elem).find('*').length === 0){ lay(elem).html(value); } lay(elem).attr('lay-date', value); } } return that; }; //预览 Class.prototype.preview = function(){ var that = this ,options = that.config; if(!options.isPreview) return; var elemPreview = lay(that.elem).find('.'+ ELEM_PREVIEW) ,value = options.range ? (that.endDate ? that.parse() : '') : that.parse(); //显示预览 elemPreview.html(value).css({ 'color': '#5FB878' }); setTimeout(function(){ elemPreview.css({ 'color': '#666' }); }, 300); }; //执行 done/change 回调 Class.prototype.done = function(param, type){ var that = this ,options = that.config ,start = lay.extend({}, lay.extend(options.dateTime, that.startTime)) ,end = lay.extend({}, lay.extend(that.endDate, that.endTime)) lay.each([start, end], function(i, item){ if(!('month' in item)) return; lay.extend(item, { month: item.month + 1 }); }); that.preview(); param = param || [that.parse(), start, end]; typeof options[type || 'done'] === 'function' && options[type || 'done'].apply(options, param); return that; }; //选择日期 Class.prototype.choose = function(td, index){ var that = this ,options = that.config ,dateTime = that.thisDateTime(index) ,tds = lay(that.elem).find('td') ,YMD = td.attr('lay-ymd').split('-'); YMD = { year: YMD[0] | 0 ,month: (YMD[1] | 0) - 1 ,date: YMD[2] | 0 }; if(td.hasClass(DISABLED)) return; lay.extend(dateTime, YMD); //同步 dateTime //范围选择 if(options.range){ //补充时分秒 lay.each(['startTime', 'endTime'], function(i, item){ that[item] = that[item] || { hours: i ? 23: 0 ,minutes: i ? 59: 0 ,seconds: i ? 59: 0 }; }); that.calendar(null, index).done(null, 'change'); } else if(options.position === 'static'){ //直接嵌套的选中 that.calendar().done().done(null, 'change'); //同时执行 done 和 change 回调 } else if(options.type === 'date'){ that.setValue(that.parse()).remove().done(); } else if(options.type === 'datetime'){ that.calendar().done(null, 'change'); } }; //底部按钮 Class.prototype.tool = function(btn, type){ var that = this ,options = that.config ,lang = that.lang() ,dateTime = options.dateTime ,isStatic = options.position === 'static' ,active = { //选择时间 datetime: function(){ if(lay(btn).hasClass(DISABLED)) return; that.list('time', 0); options.range && that.list('time', 1); lay(btn).attr('lay-type', 'date').html(that.lang().dateTips); } //选择日期 ,date: function(){ that.closeList(); lay(btn).attr('lay-type', 'datetime').html(that.lang().timeTips); } //清空、重置 ,clear: function(){ isStatic && ( lay.extend(dateTime, that.firstDate) ,that.calendar() ) options.range && ( delete options.dateTime ,delete that.endDate ,delete that.startTime ,delete that.endTime ); that.setValue('').remove(); that.done(['', {}, {}]); } //现在 ,now: function(){ var thisDate = new Date(); lay.extend(dateTime, that.systemDate(), { hours: thisDate.getHours() ,minutes: thisDate.getMinutes() ,seconds: thisDate.getSeconds() }); that.setValue(that.parse()).remove(); isStatic && that.calendar(); that.done(); } //确定 ,confirm: function(){ if(options.range){ if(lay(btn).hasClass(DISABLED)) return that.hint( options.type === 'time' ? lang.timeout.replace(/日期/g, '时间') : lang.timeout ); } else { if(lay(btn).hasClass(DISABLED)) return that.hint(lang.invalidDate); } that.setValue(that.parse()).remove(); that.done(); } }; active[type] && active[type](); }; //统一切换处理 Class.prototype.change = function(index){ var that = this ,options = that.config ,dateTime = that.thisDateTime(index) ,isAlone = options.range && (options.type === 'year' || options.type === 'month') ,elemCont = that.elemCont[index || 0] ,listYM = that.listYM[index] ,addSubYeay = function(type){ var isYear = lay(elemCont).find('.laydate-year-list')[0] ,isMonth = lay(elemCont).find('.laydate-month-list')[0]; //切换年列表 if(isYear){ listYM[0] = type ? listYM[0] - 15 : listYM[0] + 15; that.list('year', index); } if(isMonth){ //切换月面板中的年 type ? listYM[0]-- : listYM[0]++; that.list('month', index); } if(isYear || isMonth){ lay.extend(dateTime, { year: listYM[0] }); if(isAlone) dateTime.year = listYM[0]; options.range || that.done(null, 'change'); options.range || that.limit(lay(that.footer).find(ELEM_CONFIRM), { year: listYM[0] }); } that.setBtnStatus(); return isYear || isMonth; }; return { prevYear: function(){ if(addSubYeay('sub')) return; dateTime.year--; that.checkDate('limit').calendar(null, index); that.done(null, 'change'); } ,prevMonth: function(){ var YM = that.getAsYM(dateTime.year, dateTime.month, 'sub'); lay.extend(dateTime, { year: YM[0] ,month: YM[1] }); that.checkDate('limit').calendar(null, index); that.done(null, 'change'); } ,nextMonth: function(){ var YM = that.getAsYM(dateTime.year, dateTime.month); lay.extend(dateTime, { year: YM[0] ,month: YM[1] }); that.checkDate('limit').calendar(null, index); that.done(null, 'change'); } ,nextYear: function(){ if(addSubYeay()) return; dateTime.year++ that.checkDate('limit').calendar(null, index); that.done(null, 'change'); } }; }; //日期切换事件 Class.prototype.changeEvent = function(){ var that = this ,options = that.config; //日期选择事件 lay(that.elem).on('click', function(e){ lay.stope(e); }).on('mousedown', function(e){ lay.stope(e); }); //年月切换 lay.each(that.elemHeader, function(i, header){ //上一年 lay(header[0]).on('click', function(e){ that.change(i).prevYear(); }); //上一月 lay(header[1]).on('click', function(e){ that.change(i).prevMonth(); }); //选择年月 lay(header[2]).find('span').on('click', function(e){ var othis = lay(this) ,layYM = othis.attr('lay-ym') ,layType = othis.attr('lay-type'); if(!layYM) return; layYM = layYM.split('-'); that.listYM[i] = [layYM[0] | 0, layYM[1] | 0]; that.list(layType, i); lay(that.footer).find('.'+ ELEM_TIME_BTN).addClass(DISABLED); }); //下一月 lay(header[3]).on('click', function(e){ that.change(i).nextMonth(); }); //下一年 lay(header[4]).on('click', function(e){ that.change(i).nextYear(); }); }); //点击日期 lay.each(that.table, function(i, table){ var tds = lay(table).find('td'); tds.on('click', function(){ that.choose(lay(this), i); }); }); //点击底部按钮 lay(that.footer).find('span').on('click', function(){ var type = lay(this).attr('lay-type'); that.tool(this, type); }); }; //是否输入框 Class.prototype.isInput = function(elem){ return /input|textarea/.test(elem.tagName.toLocaleLowerCase()) || /INPUT|TEXTAREA/.test(elem.tagName); }; //绑定的元素事件处理 Class.prototype.events = function(){ var that = this ,options = that.config //绑定呼出控件事件 ,showEvent = function(elem, bind){ elem.on(options.trigger, function(){ //已经打开的面板避免重新渲染 if(laydate.thisId === options.id) return; bind && (that.bindElem = this); that.render(); }); }; if(!options.elem[0] || options.elem[0].eventHandler) return; showEvent(options.elem, 'bind'); showEvent(options.eventElem); options.elem[0].eventHandler = true; }; //记录所有实例 thisModule.that = {}; //记录所有实例对象 //获取当前实例对象 thisModule.getThis = function(id){ var that = thisModule.that[id]; if(!that && isLayui) layui.hint().error(id ? (MOD_NAME +' instance with ID \''+ id +'\' not found') : 'ID argument required'); return that; }; //初始执行 ready.run = function(lay){ //绑定关闭控件事件 lay(document).on('mousedown', function(e){ if(!laydate.thisId) return; var that = thisModule.getThis(laydate.thisId); if(!that) return; var options = that.config; if( e.target === options.elem[0] || e.target === options.eventElem[0] || e.target === lay(options.closeStop)[0] ) return; that.remove(); }).on('keydown', function(e){ if(!laydate.thisId) return; var that = thisModule.getThis(laydate.thisId); if(!that) return; // 回车触发确认 if(that.config.position === 'static') return; if(e.keyCode === 13){ if(lay('#'+ that.elemID)[0] && that.elemID === Class.thisElemDate){ e.preventDefault(); lay(that.footer).find(ELEM_CONFIRM)[0].click(); } } }); //自适应定位 lay(window).on('resize', function(){ if(!laydate.thisId) return; var that = thisModule.getThis(laydate.thisId); if(!that) return; if(!that.elem || !lay(ELEM)[0]){ return false; } that.position(); }); }; //核心接口 laydate.render = function(options){ var inst = new Class(options); return thisModule.call(inst); }; //将指定对象转化为日期值 laydate.parse = function(dateTime, format, one){ dateTime = dateTime || {}; //如果 format 是字符型,则转换为数组格式 if(typeof format === 'string'){ format = thisModule.formatArr(format); } format = (format || []).concat(); //转义为规定格式 lay.each(format, function(i, item){ if(/yyyy|y/.test(item)){ //年 format[i] = lay.digit(dateTime.year, item.length); } else if(/MM|M/.test(item)){ //月 format[i] = lay.digit(dateTime.month + (one || 0), item.length); } else if(/dd|d/.test(item)){ //日 format[i] = lay.digit(dateTime.date, item.length); } else if(/HH|H/.test(item)){ //时 format[i] = lay.digit(dateTime.hours, item.length); } else if(/mm|m/.test(item)){ //分 format[i] = lay.digit(dateTime.minutes, item.length); } else if(/ss|s/.test(item)){ //秒 format[i] = lay.digit(dateTime.seconds, item.length); } }); return format.join(''); }; //得到某月的最后一天 laydate.getEndDate = function(month, year){ var thisDate = new Date(); //设置日期为下个月的第一天 thisDate.setFullYear( year || thisDate.getFullYear() ,month || (thisDate.getMonth() + 1) ,1); //减去一天,得到当前月最后一天 return new Date(thisDate.getTime() - 1000*60*60*24).getDate(); }; //加载方式 isLayui ? ( laydate.ready() ,layui.define('lay', function(exports){ //layui 加载 laydate.path = layui.cache.dir; ready.run(lay); exports(MOD_NAME, laydate); }) ) : ( (typeof define === 'function' && define.amd) ? define(function(){ //requirejs 加载 ready.run(lay); return laydate; }) : function(){ //普通 script 标签加载 laydate.ready(); ready.run(window.lay); window.laydate = laydate; }() ); }(window, window.document); /*! * jQuery JavaScript Library v1.12.4 * http://jquery.com/ * * Includes Sizzle.js * http://sizzlejs.com/ * * Copyright jQuery Foundation and other contributors * Released under the MIT license * http://jquery.org/license * * Date: 2016-05-20T17:17Z */ (function( global, factory ) { if ( typeof module === "object" && typeof module.exports === "object" ) { // For CommonJS and CommonJS-like environments where a proper `window` // is present, execute the factory and get jQuery. // For environments that do not have a `window` with a `document` // (such as Node.js), expose a factory as module.exports. // This accentuates the need for the creation of a real `window`. // e.g. var jQuery = require("jquery")(window); // See ticket #14549 for more info. module.exports = global.document ? factory( global, true ) : function( w ) { if ( !w.document ) { throw new Error( "jQuery requires a window with a document" ); } return factory( w ); }; } else { factory( global ); } // Pass this if window is not defined yet }(typeof window !== "undefined" ? window : this, function( window, noGlobal ) { // Support: Firefox 18+ // Can't be in strict mode, several libs including ASP.NET trace // the stack via arguments.caller.callee and Firefox dies if // you try to trace through "use strict" call chains. (#13335) //"use strict"; var deletedIds = []; var document = window.document; var slice = deletedIds.slice; var concat = deletedIds.concat; var push = deletedIds.push; var indexOf = deletedIds.indexOf; var class2type = {}; var toString = class2type.toString; var hasOwn = class2type.hasOwnProperty; var support = {}; var version = "1.12.4", // Define a local copy of jQuery jQuery = function( selector, context ) { // The jQuery object is actually just the init constructor 'enhanced' // Need init if jQuery is called (just allow error to be thrown if not included) return new jQuery.fn.init( selector, context ); }, // Support: Android<4.1, IE<9 // Make sure we trim BOM and NBSP rtrim = /^[\s\uFEFF\xA0]+|[\s\uFEFF\xA0]+$/g, // Matches dashed string for camelizing rmsPrefix = /^-ms-/, rdashAlpha = /-([\da-z])/gi, // Used by jQuery.camelCase as callback to replace() fcamelCase = function( all, letter ) { return letter.toUpperCase(); }; jQuery.fn = jQuery.prototype = { // The current version of jQuery being used jquery: version, constructor: jQuery, // Start with an empty selector selector: "", // The default length of a jQuery object is 0 length: 0, toArray: function() { return slice.call( this ); }, // Get the Nth element in the matched element set OR // Get the whole matched element set as a clean array get: function( num ) { return num != null ? // Return just the one element from the set ( num < 0 ? this[ num + this.length ] : this[ num ] ) : // Return all the elements in a clean array slice.call( this ); }, // Take an array of elements and push it onto the stack // (returning the new matched element set) pushStack: function( elems ) { // Build a new jQuery matched element set var ret = jQuery.merge( this.constructor(), elems ); // Add the old object onto the stack (as a reference) ret.prevObject = this; ret.context = this.context; // Return the newly-formed element set return ret; }, // Execute a callback for every element in the matched set. each: function( callback ) { return jQuery.each( this, callback ); }, map: function( callback ) { return this.pushStack( jQuery.map( this, function( elem, i ) { return callback.call( elem, i, elem ); } ) ); }, slice: function() { return this.pushStack( slice.apply( this, arguments ) ); }, first: function() { return this.eq( 0 ); }, last: function() { return this.eq( -1 ); }, eq: function( i ) { var len = this.length, j = +i + ( i < 0 ? len : 0 ); return this.pushStack( j >= 0 && j < len ? [ this[ j ] ] : [] ); }, end: function() { return this.prevObject || this.constructor(); }, // For internal use only. // Behaves like an Array's method, not like a jQuery method. push: push, sort: deletedIds.sort, splice: deletedIds.splice }; jQuery.extend = jQuery.fn.extend = function() { var src, copyIsArray, copy, name, options, clone, target = arguments[ 0 ] || {}, i = 1, length = arguments.length, deep = false; // Handle a deep copy situation if ( typeof target === "boolean" ) { deep = target; // skip the boolean and the target target = arguments[ i ] || {}; i++; } // Handle case when target is a string or something (possible in deep copy) if ( typeof target !== "object" && !jQuery.isFunction( target ) ) { target = {}; } // extend jQuery itself if only one argument is passed if ( i === length ) { target = this; i--; } for ( ; i < length; i++ ) { // Only deal with non-null/undefined values if ( ( options = arguments[ i ] ) != null ) { // Extend the base object for ( name in options ) { src = target[ name ]; copy = options[ name ]; // Prevent never-ending loop if ( target === copy ) { continue; } // Recurse if we're merging plain objects or arrays if ( deep && copy && ( jQuery.isPlainObject( copy ) || ( copyIsArray = jQuery.isArray( copy ) ) ) ) { if ( copyIsArray ) { copyIsArray = false; clone = src && jQuery.isArray( src ) ? src : []; } else { clone = src && jQuery.isPlainObject( src ) ? src : {}; } // Never move original objects, clone them target[ name ] = jQuery.extend( deep, clone, copy ); // Don't bring in undefined values } else if ( copy !== undefined ) { target[ name ] = copy; } } } } // Return the modified object return target; }; jQuery.extend( { // Unique for each copy of jQuery on the page expando: "jQuery" + ( version + Math.random() ).replace( /\D/g, "" ), // Assume jQuery is ready without the ready module isReady: true, error: function( msg ) { throw new Error( msg ); }, noop: function() {}, // See test/unit/core.js for details concerning isFunction. // Since version 1.3, DOM methods and functions like alert // aren't supported. They return false on IE (#2968). isFunction: function( obj ) { return jQuery.type( obj ) === "function"; }, isArray: Array.isArray || function( obj ) { return jQuery.type( obj ) === "array"; }, isWindow: function( obj ) { /* jshint eqeqeq: false */ return obj != null && obj == obj.window; }, isNumeric: function( obj ) { // parseFloat NaNs numeric-cast false positives (null|true|false|"") // ...but misinterprets leading-number strings, particularly hex literals ("0x...") // subtraction forces infinities to NaN // adding 1 corrects loss of precision from parseFloat (#15100) var realStringObj = obj && obj.toString(); return !jQuery.isArray( obj ) && ( realStringObj - parseFloat( realStringObj ) + 1 ) >= 0; }, isEmptyObject: function( obj ) { var name; for ( name in obj ) { return false; } return true; }, isPlainObject: function( obj ) { var key; // Must be an Object. // Because of IE, we also have to check the presence of the constructor property. // Make sure that DOM nodes and window objects don't pass through, as well if ( !obj || jQuery.type( obj ) !== "object" || obj.nodeType || jQuery.isWindow( obj ) ) { return false; } try { // Not own constructor property must be Object if ( obj.constructor && !hasOwn.call( obj, "constructor" ) && !hasOwn.call( obj.constructor.prototype, "isPrototypeOf" ) ) { return false; } } catch ( e ) { // IE8,9 Will throw exceptions on certain host objects #9897 return false; } // Support: IE<9 // Handle iteration over inherited properties before own properties. if ( !support.ownFirst ) { for ( key in obj ) { return hasOwn.call( obj, key ); } } // Own properties are enumerated firstly, so to speed up, // if last one is own, then all properties are own. for ( key in obj ) {} return key === undefined || hasOwn.call( obj, key ); }, type: function( obj ) { if ( obj == null ) { return obj + ""; } return typeof obj === "object" || typeof obj === "function" ? class2type[ toString.call( obj ) ] || "object" : typeof obj; }, // Workarounds based on findings by Jim Driscoll // http://weblogs.java.net/blog/driscoll/archive/2009/09/08/eval-javascript-global-context globalEval: function( data ) { if ( data && jQuery.trim( data ) ) { // We use execScript on Internet Explorer // We use an anonymous function so that context is window // rather than jQuery in Firefox ( window.execScript || function( data ) { window[ "eval" ].call( window, data ); // jscs:ignore requireDotNotation } )( data ); } }, // Convert dashed to camelCase; used by the css and data modules // Microsoft forgot to hump their vendor prefix (#9572) camelCase: function( string ) { return string.replace( rmsPrefix, "ms-" ).replace( rdashAlpha, fcamelCase ); }, nodeName: function( elem, name ) { return elem.nodeName && elem.nodeName.toLowerCase() === name.toLowerCase(); }, each: function( obj, callback ) { var length, i = 0; if ( isArrayLike( obj ) ) { length = obj.length; for ( ; i < length; i++ ) { if ( callback.call( obj[ i ], i, obj[ i ] ) === false ) { break; } } } else { for ( i in obj ) { if ( callback.call( obj[ i ], i, obj[ i ] ) === false ) { break; } } } return obj; }, // Support: Android<4.1, IE<9 trim: function( text ) { return text == null ? "" : ( text + "" ).replace( rtrim, "" ); }, // results is for internal usage only makeArray: function( arr, results ) { var ret = results || []; if ( arr != null ) { if ( isArrayLike( Object( arr ) ) ) { jQuery.merge( ret, typeof arr === "string" ? [ arr ] : arr ); } else { push.call( ret, arr ); } } return ret; }, inArray: function( elem, arr, i ) { var len; if ( arr ) { if ( indexOf ) { return indexOf.call( arr, elem, i ); } len = arr.length; i = i ? i < 0 ? Math.max( 0, len + i ) : i : 0; for ( ; i < len; i++ ) { // Skip accessing in sparse arrays if ( i in arr && arr[ i ] === elem ) { return i; } } } return -1; }, merge: function( first, second ) { var len = +second.length, j = 0, i = first.length; while ( j < len ) { first[ i++ ] = second[ j++ ]; } // Support: IE<9 // Workaround casting of .length to NaN on otherwise arraylike objects (e.g., NodeLists) if ( len !== len ) { while ( second[ j ] !== undefined ) { first[ i++ ] = second[ j++ ]; } } first.length = i; return first; }, grep: function( elems, callback, invert ) { var callbackInverse, matches = [], i = 0, length = elems.length, callbackExpect = !invert; // Go through the array, only saving the items // that pass the validator function for ( ; i < length; i++ ) { callbackInverse = !callback( elems[ i ], i ); if ( callbackInverse !== callbackExpect ) { matches.push( elems[ i ] ); } } return matches; }, // arg is for internal usage only map: function( elems, callback, arg ) { var length, value, i = 0, ret = []; // Go through the array, translating each of the items to their new values if ( isArrayLike( elems ) ) { length = elems.length; for ( ; i < length; i++ ) { value = callback( elems[ i ], i, arg ); if ( value != null ) { ret.push( value ); } } // Go through every key on the object, } else { for ( i in elems ) { value = callback( elems[ i ], i, arg ); if ( value != null ) { ret.push( value ); } } } // Flatten any nested arrays return concat.apply( [], ret ); }, // A global GUID counter for objects guid: 1, // Bind a function to a context, optionally partially applying any // arguments. proxy: function( fn, context ) { var args, proxy, tmp; if ( typeof context === "string" ) { tmp = fn[ context ]; context = fn; fn = tmp; } // Quick check to determine if target is callable, in the spec // this throws a TypeError, but we will just return undefined. if ( !jQuery.isFunction( fn ) ) { return undefined; } // Simulated bind args = slice.call( arguments, 2 ); proxy = function() { return fn.apply( context || this, args.concat( slice.call( arguments ) ) ); }; // Set the guid of unique handler to the same of original handler, so it can be removed proxy.guid = fn.guid = fn.guid || jQuery.guid++; return proxy; }, now: function() { return +( new Date() ); }, // jQuery.support is not used in Core but other projects attach their // properties to it so it needs to exist. support: support } ); // JSHint would error on this code due to the Symbol not being defined in ES5. // Defining this global in .jshintrc would create a danger of using the global // unguarded in another place, it seems safer to just disable JSHint for these // three lines. /* jshint ignore: start */ if ( typeof Symbol === "function" ) { jQuery.fn[ Symbol.iterator ] = deletedIds[ Symbol.iterator ]; } /* jshint ignore: end */ // Populate the class2type map jQuery.each( "Boolean Number String Function Array Date RegExp Object Error Symbol".split( " " ), function( i, name ) { class2type[ "[object " + name + "]" ] = name.toLowerCase(); } ); function isArrayLike( obj ) { // Support: iOS 8.2 (not reproducible in simulator) // `in` check used to prevent JIT error (gh-2145) // hasOwn isn't used here due to false negatives // regarding Nodelist length in IE var length = !!obj && "length" in obj && obj.length, type = jQuery.type( obj ); if ( type === "function" || jQuery.isWindow( obj ) ) { return false; } return type === "array" || length === 0 || typeof length === "number" && length > 0 && ( length - 1 ) in obj; } var Sizzle = /*! * Sizzle CSS Selector Engine v2.2.1 * http://sizzlejs.com/ * * Copyright jQuery Foundation and other contributors * Released under the MIT license * http://jquery.org/license * * Date: 2015-10-17 */ (function( window ) { var i, support, Expr, getText, isXML, tokenize, compile, select, outermostContext, sortInput, hasDuplicate, // Local document vars setDocument, document, docElem, documentIsHTML, rbuggyQSA, rbuggyMatches, matches, contains, // Instance-specific data expando = "sizzle" + 1 * new Date(), preferredDoc = window.document, dirruns = 0, done = 0, classCache = createCache(), tokenCache = createCache(), compilerCache = createCache(), sortOrder = function( a, b ) { if ( a === b ) { hasDuplicate = true; } return 0; }, // General-purpose constants MAX_NEGATIVE = 1 << 31, // Instance methods hasOwn = ({}).hasOwnProperty, arr = [], pop = arr.pop, push_native = arr.push, push = arr.push, slice = arr.slice, // Use a stripped-down indexOf as it's faster than native // http://jsperf.com/thor-indexof-vs-for/5 indexOf = function( list, elem ) { var i = 0, len = list.length; for ( ; i < len; i++ ) { if ( list[i] === elem ) { return i; } } return -1; }, booleans = "checked|selected|async|autofocus|autoplay|controls|defer|disabled|hidden|ismap|loop|multiple|open|readonly|required|scoped", // Regular expressions // http://www.w3.org/TR/css3-selectors/#whitespace whitespace = "[\\x20\\t\\r\\n\\f]", // http://www.w3.org/TR/CSS21/syndata.html#value-def-identifier identifier = "(?:\\\\.|[\\w-]|[^\\x00-\\xa0])+", // Attribute selectors: http://www.w3.org/TR/selectors/#attribute-selectors attributes = "\\[" + whitespace + "*(" + identifier + ")(?:" + whitespace + // Operator (capture 2) "*([*^$|!~]?=)" + whitespace + // "Attribute values must be CSS identifiers [capture 5] or strings [capture 3 or capture 4]" "*(?:'((?:\\\\.|[^\\\\'])*)'|\"((?:\\\\.|[^\\\\\"])*)\"|(" + identifier + "))|)" + whitespace + "*\\]", pseudos = ":(" + identifier + ")(?:\\((" + // To reduce the number of selectors needing tokenize in the preFilter, prefer arguments: // 1. quoted (capture 3; capture 4 or capture 5) "('((?:\\\\.|[^\\\\'])*)'|\"((?:\\\\.|[^\\\\\"])*)\")|" + // 2. simple (capture 6) "((?:\\\\.|[^\\\\()[\\]]|" + attributes + ")*)|" + // 3. anything else (capture 2) ".*" + ")\\)|)", // Leading and non-escaped trailing whitespace, capturing some non-whitespace characters preceding the latter rwhitespace = new RegExp( whitespace + "+", "g" ), rtrim = new RegExp( "^" + whitespace + "+|((?:^|[^\\\\])(?:\\\\.)*)" + whitespace + "+$", "g" ), rcomma = new RegExp( "^" + whitespace + "*," + whitespace + "*" ), rcombinators = new RegExp( "^" + whitespace + "*([>+~]|" + whitespace + ")" + whitespace + "*" ), rattributeQuotes = new RegExp( "=" + whitespace + "*([^\\]'\"]*?)" + whitespace + "*\\]", "g" ), rpseudo = new RegExp( pseudos ), ridentifier = new RegExp( "^" + identifier + "$" ), matchExpr = { "ID": new RegExp( "^#(" + identifier + ")" ), "CLASS": new RegExp( "^\\.(" + identifier + ")" ), "TAG": new RegExp( "^(" + identifier + "|[*])" ), "ATTR": new RegExp( "^" + attributes ), "PSEUDO": new RegExp( "^" + pseudos ), "CHILD": new RegExp( "^:(only|first|last|nth|nth-last)-(child|of-type)(?:\\(" + whitespace + "*(even|odd|(([+-]|)(\\d*)n|)" + whitespace + "*(?:([+-]|)" + whitespace + "*(\\d+)|))" + whitespace + "*\\)|)", "i" ), "bool": new RegExp( "^(?:" + booleans + ")$", "i" ), // For use in libraries implementing .is() // We use this for POS matching in `select` "needsContext": new RegExp( "^" + whitespace + "*[>+~]|:(even|odd|eq|gt|lt|nth|first|last)(?:\\(" + whitespace + "*((?:-\\d)?\\d*)" + whitespace + "*\\)|)(?=[^-]|$)", "i" ) }, rinputs = /^(?:input|select|textarea|button)$/i, rheader = /^h\d$/i, rnative = /^[^{]+\{\s*\[native \w/, // Easily-parseable/retrievable ID or TAG or CLASS selectors rquickExpr = /^(?:#([\w-]+)|(\w+)|\.([\w-]+))$/, rsibling = /[+~]/, rescape = /'|\\/g, // CSS escapes http://www.w3.org/TR/CSS21/syndata.html#escaped-characters runescape = new RegExp( "\\\\([\\da-f]{1,6}" + whitespace + "?|(" + whitespace + ")|.)", "ig" ), funescape = function( _, escaped, escapedWhitespace ) { var high = "0x" + escaped - 0x10000; // NaN means non-codepoint // Support: Firefox<24 // Workaround erroneous numeric interpretation of +"0x" return high !== high || escapedWhitespace ? escaped : high < 0 ? // BMP codepoint String.fromCharCode( high + 0x10000 ) : // Supplemental Plane codepoint (surrogate pair) String.fromCharCode( high >> 10 | 0xD800, high & 0x3FF | 0xDC00 ); }, // Used for iframes // See setDocument() // Removing the function wrapper causes a "Permission Denied" // error in IE unloadHandler = function() { setDocument(); }; // Optimize for push.apply( _, NodeList ) try { push.apply( (arr = slice.call( preferredDoc.childNodes )), preferredDoc.childNodes ); // Support: Android<4.0 // Detect silently failing push.apply arr[ preferredDoc.childNodes.length ].nodeType; } catch ( e ) { push = { apply: arr.length ? // Leverage slice if possible function( target, els ) { push_native.apply( target, slice.call(els) ); } : // Support: IE<9 // Otherwise append directly function( target, els ) { var j = target.length, i = 0; // Can't trust NodeList.length while ( (target[j++] = els[i++]) ) {} target.length = j - 1; } }; } function Sizzle( selector, context, results, seed ) { var m, i, elem, nid, nidselect, match, groups, newSelector, newContext = context && context.ownerDocument, // nodeType defaults to 9, since context defaults to document nodeType = context ? context.nodeType : 9; results = results || []; // Return early from calls with invalid selector or context if ( typeof selector !== "string" || !selector || nodeType !== 1 && nodeType !== 9 && nodeType !== 11 ) { return results; } // Try to shortcut find operations (as opposed to filters) in HTML documents if ( !seed ) { if ( ( context ? context.ownerDocument || context : preferredDoc ) !== document ) { setDocument( context ); } context = context || document; if ( documentIsHTML ) { // If the selector is sufficiently simple, try using a "get*By*" DOM method // (excepting DocumentFragment context, where the methods don't exist) if ( nodeType !== 11 && (match = rquickExpr.exec( selector )) ) { // ID selector if ( (m = match[1]) ) { // Document context if ( nodeType === 9 ) { if ( (elem = context.getElementById( m )) ) { // Support: IE, Opera, Webkit // TODO: identify versions // getElementById can match elements by name instead of ID if ( elem.id === m ) { results.push( elem ); return results; } } else { return results; } // Element context } else { // Support: IE, Opera, Webkit // TODO: identify versions // getElementById can match elements by name instead of ID if ( newContext && (elem = newContext.getElementById( m )) && contains( context, elem ) && elem.id === m ) { results.push( elem ); return results; } } // Type selector } else if ( match[2] ) { push.apply( results, context.getElementsByTagName( selector ) ); return results; // Class selector } else if ( (m = match[3]) && support.getElementsByClassName && context.getElementsByClassName ) { push.apply( results, context.getElementsByClassName( m ) ); return results; } } // Take advantage of querySelectorAll if ( support.qsa && !compilerCache[ selector + " " ] && (!rbuggyQSA || !rbuggyQSA.test( selector )) ) { if ( nodeType !== 1 ) { newContext = context; newSelector = selector; // qSA looks outside Element context, which is not what we want // Thanks to Andrew Dupont for this workaround technique // Support: IE <=8 // Exclude object elements } else if ( context.nodeName.toLowerCase() !== "object" ) { // Capture the context ID, setting it first if necessary if ( (nid = context.getAttribute( "id" )) ) { nid = nid.replace( rescape, "\\$&" ); } else { context.setAttribute( "id", (nid = expando) ); } // Prefix every selector in the list groups = tokenize( selector ); i = groups.length; nidselect = ridentifier.test( nid ) ? "#" + nid : "[id='" + nid + "']"; while ( i-- ) { groups[i] = nidselect + " " + toSelector( groups[i] ); } newSelector = groups.join( "," ); // Expand context for sibling selectors newContext = rsibling.test( selector ) && testContext( context.parentNode ) || context; } if ( newSelector ) { try { push.apply( results, newContext.querySelectorAll( newSelector ) ); return results; } catch ( qsaError ) { } finally { if ( nid === expando ) { context.removeAttribute( "id" ); } } } } } } // All others return select( selector.replace( rtrim, "$1" ), context, results, seed ); } /** * Create key-value caches of limited size * @returns {function(string, object)} Returns the Object data after storing it on itself with * property name the (space-suffixed) string and (if the cache is larger than Expr.cacheLength) * deleting the oldest entry */ function createCache() { var keys = []; function cache( key, value ) { // Use (key + " ") to avoid collision with native prototype properties (see Issue #157) if ( keys.push( key + " " ) > Expr.cacheLength ) { // Only keep the most recent entries delete cache[ keys.shift() ]; } return (cache[ key + " " ] = value); } return cache; } /** * Mark a function for special use by Sizzle * @param {Function} fn The function to mark */ function markFunction( fn ) { fn[ expando ] = true; return fn; } /** * Support testing using an element * @param {Function} fn Passed the created div and expects a boolean result */ function assert( fn ) { var div = document.createElement("div"); try { return !!fn( div ); } catch (e) { return false; } finally { // Remove from its parent by default if ( div.parentNode ) { div.parentNode.removeChild( div ); } // release memory in IE div = null; } } /** * Adds the same handler for all of the specified attrs * @param {String} attrs Pipe-separated list of attributes * @param {Function} handler The method that will be applied */ function addHandle( attrs, handler ) { var arr = attrs.split("|"), i = arr.length; while ( i-- ) { Expr.attrHandle[ arr[i] ] = handler; } } /** * Checks document order of two siblings * @param {Element} a * @param {Element} b * @returns {Number} Returns less than 0 if a precedes b, greater than 0 if a follows b */ function siblingCheck( a, b ) { var cur = b && a, diff = cur && a.nodeType === 1 && b.nodeType === 1 && ( ~b.sourceIndex || MAX_NEGATIVE ) - ( ~a.sourceIndex || MAX_NEGATIVE ); // Use IE sourceIndex if available on both nodes if ( diff ) { return diff; } // Check if b follows a if ( cur ) { while ( (cur = cur.nextSibling) ) { if ( cur === b ) { return -1; } } } return a ? 1 : -1; } /** * Returns a function to use in pseudos for input types * @param {String} type */ function createInputPseudo( type ) { return function( elem ) { var name = elem.nodeName.toLowerCase(); return name === "input" && elem.type === type; }; } /** * Returns a function to use in pseudos for buttons * @param {String} type */ function createButtonPseudo( type ) { return function( elem ) { var name = elem.nodeName.toLowerCase(); return (name === "input" || name === "button") && elem.type === type; }; } /** * Returns a function to use in pseudos for positionals * @param {Function} fn */ function createPositionalPseudo( fn ) { return markFunction(function( argument ) { argument = +argument; return markFunction(function( seed, matches ) { var j, matchIndexes = fn( [], seed.length, argument ), i = matchIndexes.length; // Match elements found at the specified indexes while ( i-- ) { if ( seed[ (j = matchIndexes[i]) ] ) { seed[j] = !(matches[j] = seed[j]); } } }); }); } /** * Checks a node for validity as a Sizzle context * @param {Element|Object=} context * @returns {Element|Object|Boolean} The input node if acceptable, otherwise a falsy value */ function testContext( context ) { return context && typeof context.getElementsByTagName !== "undefined" && context; } // Expose support vars for convenience support = Sizzle.support = {}; /** * Detects XML nodes * @param {Element|Object} elem An element or a document * @returns {Boolean} True iff elem is a non-HTML XML node */ isXML = Sizzle.isXML = function( elem ) { // documentElement is verified for cases where it doesn't yet exist // (such as loading iframes in IE - #4833) var documentElement = elem && (elem.ownerDocument || elem).documentElement; return documentElement ? documentElement.nodeName !== "HTML" : false; }; /** * Sets document-related variables once based on the current document * @param {Element|Object} [doc] An element or document object to use to set the document * @returns {Object} Returns the current document */ setDocument = Sizzle.setDocument = function( node ) { var hasCompare, parent, doc = node ? node.ownerDocument || node : preferredDoc; // Return early if doc is invalid or already selected if ( doc === document || doc.nodeType !== 9 || !doc.documentElement ) { return document; } // Update global variables document = doc; docElem = document.documentElement; documentIsHTML = !isXML( document ); // Support: IE 9-11, Edge // Accessing iframe documents after unload throws "permission denied" errors (jQuery #13936) if ( (parent = document.defaultView) && parent.top !== parent ) { // Support: IE 11 if ( parent.addEventListener ) { parent.addEventListener( "unload", unloadHandler, false ); // Support: IE 9 - 10 only } else if ( parent.attachEvent ) { parent.attachEvent( "onunload", unloadHandler ); } } /* Attributes ---------------------------------------------------------------------- */ // Support: IE<8 // Verify that getAttribute really returns attributes and not properties // (excepting IE8 booleans) support.attributes = assert(function( div ) { div.className = "i"; return !div.getAttribute("className"); }); /* getElement(s)By* ---------------------------------------------------------------------- */ // Check if getElementsByTagName("*") returns only elements support.getElementsByTagName = assert(function( div ) { div.appendChild( document.createComment("") ); return !div.getElementsByTagName("*").length; }); // Support: IE<9 support.getElementsByClassName = rnative.test( document.getElementsByClassName ); // Support: IE<10 // Check if getElementById returns elements by name // The broken getElementById methods don't pick up programatically-set names, // so use a roundabout getElementsByName test support.getById = assert(function( div ) { docElem.appendChild( div ).id = expando; return !document.getElementsByName || !document.getElementsByName( expando ).length; }); // ID find and filter if ( support.getById ) { Expr.find["ID"] = function( id, context ) { if ( typeof context.getElementById !== "undefined" && documentIsHTML ) { var m = context.getElementById( id ); return m ? [ m ] : []; } }; Expr.filter["ID"] = function( id ) { var attrId = id.replace( runescape, funescape ); return function( elem ) { return elem.getAttribute("id") === attrId; }; }; } else { // Support: IE6/7 // getElementById is not reliable as a find shortcut delete Expr.find["ID"]; Expr.filter["ID"] = function( id ) { var attrId = id.replace( runescape, funescape ); return function( elem ) { var node = typeof elem.getAttributeNode !== "undefined" && elem.getAttributeNode("id"); return node && node.value === attrId; }; }; } // Tag Expr.find["TAG"] = support.getElementsByTagName ? function( tag, context ) { if ( typeof context.getElementsByTagName !== "undefined" ) { return context.getElementsByTagName( tag ); // DocumentFragment nodes don't have gEBTN } else if ( support.qsa ) { return context.querySelectorAll( tag ); } } : function( tag, context ) { var elem, tmp = [], i = 0, // By happy coincidence, a (broken) gEBTN appears on DocumentFragment nodes too results = context.getElementsByTagName( tag ); // Filter out possible comments if ( tag === "*" ) { while ( (elem = results[i++]) ) { if ( elem.nodeType === 1 ) { tmp.push( elem ); } } return tmp; } return results; }; // Class Expr.find["CLASS"] = support.getElementsByClassName && function( className, context ) { if ( typeof context.getElementsByClassName !== "undefined" && documentIsHTML ) { return context.getElementsByClassName( className ); } }; /* QSA/matchesSelector ---------------------------------------------------------------------- */ // QSA and matchesSelector support // matchesSelector(:active) reports false when true (IE9/Opera 11.5) rbuggyMatches = []; // qSa(:focus) reports false when true (Chrome 21) // We allow this because of a bug in IE8/9 that throws an error // whenever `document.activeElement` is accessed on an iframe // So, we allow :focus to pass through QSA all the time to avoid the IE error // See http://bugs.jquery.com/ticket/13378 rbuggyQSA = []; if ( (support.qsa = rnative.test( document.querySelectorAll )) ) { // Build QSA regex // Regex strategy adopted from Diego Perini assert(function( div ) { // Select is set to empty string on purpose // This is to test IE's treatment of not explicitly // setting a boolean content attribute, // since its presence should be enough // http://bugs.jquery.com/ticket/12359 docElem.appendChild( div ).innerHTML = "" + ""; // Support: IE8, Opera 11-12.16 // Nothing should be selected when empty strings follow ^= or $= or *= // The test attribute must be unknown in Opera but "safe" for WinRT // http://msdn.microsoft.com/en-us/library/ie/hh465388.aspx#attribute_section if ( div.querySelectorAll("[msallowcapture^='']").length ) { rbuggyQSA.push( "[*^$]=" + whitespace + "*(?:''|\"\")" ); } // Support: IE8 // Boolean attributes and "value" are not treated correctly if ( !div.querySelectorAll("[selected]").length ) { rbuggyQSA.push( "\\[" + whitespace + "*(?:value|" + booleans + ")" ); } // Support: Chrome<29, Android<4.4, Safari<7.0+, iOS<7.0+, PhantomJS<1.9.8+ if ( !div.querySelectorAll( "[id~=" + expando + "-]" ).length ) { rbuggyQSA.push("~="); } // Webkit/Opera - :checked should return selected option elements // http://www.w3.org/TR/2011/REC-css3-selectors-20110929/#checked // IE8 throws error here and will not see later tests if ( !div.querySelectorAll(":checked").length ) { rbuggyQSA.push(":checked"); } // Support: Safari 8+, iOS 8+ // https://bugs.webkit.org/show_bug.cgi?id=136851 // In-page `selector#id sibing-combinator selector` fails if ( !div.querySelectorAll( "a#" + expando + "+*" ).length ) { rbuggyQSA.push(".#.+[+~]"); } }); assert(function( div ) { // Support: Windows 8 Native Apps // The type and name attributes are restricted during .innerHTML assignment var input = document.createElement("input"); input.setAttribute( "type", "hidden" ); div.appendChild( input ).setAttribute( "name", "D" ); // Support: IE8 // Enforce case-sensitivity of name attribute if ( div.querySelectorAll("[name=d]").length ) { rbuggyQSA.push( "name" + whitespace + "*[*^$|!~]?=" ); } // FF 3.5 - :enabled/:disabled and hidden elements (hidden elements are still enabled) // IE8 throws error here and will not see later tests if ( !div.querySelectorAll(":enabled").length ) { rbuggyQSA.push( ":enabled", ":disabled" ); } // Opera 10-11 does not throw on post-comma invalid pseudos div.querySelectorAll("*,:x"); rbuggyQSA.push(",.*:"); }); } if ( (support.matchesSelector = rnative.test( (matches = docElem.matches || docElem.webkitMatchesSelector || docElem.mozMatchesSelector || docElem.oMatchesSelector || docElem.msMatchesSelector) )) ) { assert(function( div ) { // Check to see if it's possible to do matchesSelector // on a disconnected node (IE 9) support.disconnectedMatch = matches.call( div, "div" ); // This should fail with an exception // Gecko does not error, returns false instead matches.call( div, "[s!='']:x" ); rbuggyMatches.push( "!=", pseudos ); }); } rbuggyQSA = rbuggyQSA.length && new RegExp( rbuggyQSA.join("|") ); rbuggyMatches = rbuggyMatches.length && new RegExp( rbuggyMatches.join("|") ); /* Contains ---------------------------------------------------------------------- */ hasCompare = rnative.test( docElem.compareDocumentPosition ); // Element contains another // Purposefully self-exclusive // As in, an element does not contain itself contains = hasCompare || rnative.test( docElem.contains ) ? function( a, b ) { var adown = a.nodeType === 9 ? a.documentElement : a, bup = b && b.parentNode; return a === bup || !!( bup && bup.nodeType === 1 && ( adown.contains ? adown.contains( bup ) : a.compareDocumentPosition && a.compareDocumentPosition( bup ) & 16 )); } : function( a, b ) { if ( b ) { while ( (b = b.parentNode) ) { if ( b === a ) { return true; } } } return false; }; /* Sorting ---------------------------------------------------------------------- */ // Document order sorting sortOrder = hasCompare ? function( a, b ) { // Flag for duplicate removal if ( a === b ) { hasDuplicate = true; return 0; } // Sort on method existence if only one input has compareDocumentPosition var compare = !a.compareDocumentPosition - !b.compareDocumentPosition; if ( compare ) { return compare; } // Calculate position if both inputs belong to the same document compare = ( a.ownerDocument || a ) === ( b.ownerDocument || b ) ? a.compareDocumentPosition( b ) : // Otherwise we know they are disconnected 1; // Disconnected nodes if ( compare & 1 || (!support.sortDetached && b.compareDocumentPosition( a ) === compare) ) { // Choose the first element that is related to our preferred document if ( a === document || a.ownerDocument === preferredDoc && contains(preferredDoc, a) ) { return -1; } if ( b === document || b.ownerDocument === preferredDoc && contains(preferredDoc, b) ) { return 1; } // Maintain original order return sortInput ? ( indexOf( sortInput, a ) - indexOf( sortInput, b ) ) : 0; } return compare & 4 ? -1 : 1; } : function( a, b ) { // Exit early if the nodes are identical if ( a === b ) { hasDuplicate = true; return 0; } var cur, i = 0, aup = a.parentNode, bup = b.parentNode, ap = [ a ], bp = [ b ]; // Parentless nodes are either documents or disconnected if ( !aup || !bup ) { return a === document ? -1 : b === document ? 1 : aup ? -1 : bup ? 1 : sortInput ? ( indexOf( sortInput, a ) - indexOf( sortInput, b ) ) : 0; // If the nodes are siblings, we can do a quick check } else if ( aup === bup ) { return siblingCheck( a, b ); } // Otherwise we need full lists of their ancestors for comparison cur = a; while ( (cur = cur.parentNode) ) { ap.unshift( cur ); } cur = b; while ( (cur = cur.parentNode) ) { bp.unshift( cur ); } // Walk down the tree looking for a discrepancy while ( ap[i] === bp[i] ) { i++; } return i ? // Do a sibling check if the nodes have a common ancestor siblingCheck( ap[i], bp[i] ) : // Otherwise nodes in our document sort first ap[i] === preferredDoc ? -1 : bp[i] === preferredDoc ? 1 : 0; }; return document; }; Sizzle.matches = function( expr, elements ) { return Sizzle( expr, null, null, elements ); }; Sizzle.matchesSelector = function( elem, expr ) { // Set document vars if needed if ( ( elem.ownerDocument || elem ) !== document ) { setDocument( elem ); } // Make sure that attribute selectors are quoted expr = expr.replace( rattributeQuotes, "='$1']" ); if ( support.matchesSelector && documentIsHTML && !compilerCache[ expr + " " ] && ( !rbuggyMatches || !rbuggyMatches.test( expr ) ) && ( !rbuggyQSA || !rbuggyQSA.test( expr ) ) ) { try { var ret = matches.call( elem, expr ); // IE 9's matchesSelector returns false on disconnected nodes if ( ret || support.disconnectedMatch || // As well, disconnected nodes are said to be in a document // fragment in IE 9 elem.document && elem.document.nodeType !== 11 ) { return ret; } } catch (e) {} } return Sizzle( expr, document, null, [ elem ] ).length > 0; }; Sizzle.contains = function( context, elem ) { // Set document vars if needed if ( ( context.ownerDocument || context ) !== document ) { setDocument( context ); } return contains( context, elem ); }; Sizzle.attr = function( elem, name ) { // Set document vars if needed if ( ( elem.ownerDocument || elem ) !== document ) { setDocument( elem ); } var fn = Expr.attrHandle[ name.toLowerCase() ], // Don't get fooled by Object.prototype properties (jQuery #13807) val = fn && hasOwn.call( Expr.attrHandle, name.toLowerCase() ) ? fn( elem, name, !documentIsHTML ) : undefined; return val !== undefined ? val : support.attributes || !documentIsHTML ? elem.getAttribute( name ) : (val = elem.getAttributeNode(name)) && val.specified ? val.value : null; }; Sizzle.error = function( msg ) { throw new Error( "Syntax error, unrecognized expression: " + msg ); }; /** * Document sorting and removing duplicates * @param {ArrayLike} results */ Sizzle.uniqueSort = function( results ) { var elem, duplicates = [], j = 0, i = 0; // Unless we *know* we can detect duplicates, assume their presence hasDuplicate = !support.detectDuplicates; sortInput = !support.sortStable && results.slice( 0 ); results.sort( sortOrder ); if ( hasDuplicate ) { while ( (elem = results[i++]) ) { if ( elem === results[ i ] ) { j = duplicates.push( i ); } } while ( j-- ) { results.splice( duplicates[ j ], 1 ); } } // Clear input after sorting to release objects // See https://github.com/jquery/sizzle/pull/225 sortInput = null; return results; }; /** * Utility function for retrieving the text value of an array of DOM nodes * @param {Array|Element} elem */ getText = Sizzle.getText = function( elem ) { var node, ret = "", i = 0, nodeType = elem.nodeType; if ( !nodeType ) { // If no nodeType, this is expected to be an array while ( (node = elem[i++]) ) { // Do not traverse comment nodes ret += getText( node ); } } else if ( nodeType === 1 || nodeType === 9 || nodeType === 11 ) { // Use textContent for elements // innerText usage removed for consistency of new lines (jQuery #11153) if ( typeof elem.textContent === "string" ) { return elem.textContent; } else { // Traverse its children for ( elem = elem.firstChild; elem; elem = elem.nextSibling ) { ret += getText( elem ); } } } else if ( nodeType === 3 || nodeType === 4 ) { return elem.nodeValue; } // Do not include comment or processing instruction nodes return ret; }; Expr = Sizzle.selectors = { // Can be adjusted by the user cacheLength: 50, createPseudo: markFunction, match: matchExpr, attrHandle: {}, find: {}, relative: { ">": { dir: "parentNode", first: true }, " ": { dir: "parentNode" }, "+": { dir: "previousSibling", first: true }, "~": { dir: "previousSibling" } }, preFilter: { "ATTR": function( match ) { match[1] = match[1].replace( runescape, funescape ); // Move the given value to match[3] whether quoted or unquoted match[3] = ( match[3] || match[4] || match[5] || "" ).replace( runescape, funescape ); if ( match[2] === "~=" ) { match[3] = " " + match[3] + " "; } return match.slice( 0, 4 ); }, "CHILD": function( match ) { /* matches from matchExpr["CHILD"] 1 type (only|nth|...) 2 what (child|of-type) 3 argument (even|odd|\d*|\d*n([+-]\d+)?|...) 4 xn-component of xn+y argument ([+-]?\d*n|) 5 sign of xn-component 6 x of xn-component 7 sign of y-component 8 y of y-component */ match[1] = match[1].toLowerCase(); if ( match[1].slice( 0, 3 ) === "nth" ) { // nth-* requires argument if ( !match[3] ) { Sizzle.error( match[0] ); } // numeric x and y parameters for Expr.filter.CHILD // remember that false/true cast respectively to 0/1 match[4] = +( match[4] ? match[5] + (match[6] || 1) : 2 * ( match[3] === "even" || match[3] === "odd" ) ); match[5] = +( ( match[7] + match[8] ) || match[3] === "odd" ); // other types prohibit arguments } else if ( match[3] ) { Sizzle.error( match[0] ); } return match; }, "PSEUDO": function( match ) { var excess, unquoted = !match[6] && match[2]; if ( matchExpr["CHILD"].test( match[0] ) ) { return null; } // Accept quoted arguments as-is if ( match[3] ) { match[2] = match[4] || match[5] || ""; // Strip excess characters from unquoted arguments } else if ( unquoted && rpseudo.test( unquoted ) && // Get excess from tokenize (recursively) (excess = tokenize( unquoted, true )) && // advance to the next closing parenthesis (excess = unquoted.indexOf( ")", unquoted.length - excess ) - unquoted.length) ) { // excess is a negative index match[0] = match[0].slice( 0, excess ); match[2] = unquoted.slice( 0, excess ); } // Return only captures needed by the pseudo filter method (type and argument) return match.slice( 0, 3 ); } }, filter: { "TAG": function( nodeNameSelector ) { var nodeName = nodeNameSelector.replace( runescape, funescape ).toLowerCase(); return nodeNameSelector === "*" ? function() { return true; } : function( elem ) { return elem.nodeName && elem.nodeName.toLowerCase() === nodeName; }; }, "CLASS": function( className ) { var pattern = classCache[ className + " " ]; return pattern || (pattern = new RegExp( "(^|" + whitespace + ")" + className + "(" + whitespace + "|$)" )) && classCache( className, function( elem ) { return pattern.test( typeof elem.className === "string" && elem.className || typeof elem.getAttribute !== "undefined" && elem.getAttribute("class") || "" ); }); }, "ATTR": function( name, operator, check ) { return function( elem ) { var result = Sizzle.attr( elem, name ); if ( result == null ) { return operator === "!="; } if ( !operator ) { return true; } result += ""; return operator === "=" ? result === check : operator === "!=" ? result !== check : operator === "^=" ? check && result.indexOf( check ) === 0 : operator === "*=" ? check && result.indexOf( check ) > -1 : operator === "$=" ? check && result.slice( -check.length ) === check : operator === "~=" ? ( " " + result.replace( rwhitespace, " " ) + " " ).indexOf( check ) > -1 : operator === "|=" ? result === check || result.slice( 0, check.length + 1 ) === check + "-" : false; }; }, "CHILD": function( type, what, argument, first, last ) { var simple = type.slice( 0, 3 ) !== "nth", forward = type.slice( -4 ) !== "last", ofType = what === "of-type"; return first === 1 && last === 0 ? // Shortcut for :nth-*(n) function( elem ) { return !!elem.parentNode; } : function( elem, context, xml ) { var cache, uniqueCache, outerCache, node, nodeIndex, start, dir = simple !== forward ? "nextSibling" : "previousSibling", parent = elem.parentNode, name = ofType && elem.nodeName.toLowerCase(), useCache = !xml && !ofType, diff = false; if ( parent ) { // :(first|last|only)-(child|of-type) if ( simple ) { while ( dir ) { node = elem; while ( (node = node[ dir ]) ) { if ( ofType ? node.nodeName.toLowerCase() === name : node.nodeType === 1 ) { return false; } } // Reverse direction for :only-* (if we haven't yet done so) start = dir = type === "only" && !start && "nextSibling"; } return true; } start = [ forward ? parent.firstChild : parent.lastChild ]; // non-xml :nth-child(...) stores cache data on `parent` if ( forward && useCache ) { // Seek `elem` from a previously-cached index // ...in a gzip-friendly way node = parent; outerCache = node[ expando ] || (node[ expando ] = {}); // Support: IE <9 only // Defend against cloned attroperties (jQuery gh-1709) uniqueCache = outerCache[ node.uniqueID ] || (outerCache[ node.uniqueID ] = {}); cache = uniqueCache[ type ] || []; nodeIndex = cache[ 0 ] === dirruns && cache[ 1 ]; diff = nodeIndex && cache[ 2 ]; node = nodeIndex && parent.childNodes[ nodeIndex ]; while ( (node = ++nodeIndex && node && node[ dir ] || // Fallback to seeking `elem` from the start (diff = nodeIndex = 0) || start.pop()) ) { // When found, cache indexes on `parent` and break if ( node.nodeType === 1 && ++diff && node === elem ) { uniqueCache[ type ] = [ dirruns, nodeIndex, diff ]; break; } } } else { // Use previously-cached element index if available if ( useCache ) { // ...in a gzip-friendly way node = elem; outerCache = node[ expando ] || (node[ expando ] = {}); // Support: IE <9 only // Defend against cloned attroperties (jQuery gh-1709) uniqueCache = outerCache[ node.uniqueID ] || (outerCache[ node.uniqueID ] = {}); cache = uniqueCache[ type ] || []; nodeIndex = cache[ 0 ] === dirruns && cache[ 1 ]; diff = nodeIndex; } // xml :nth-child(...) // or :nth-last-child(...) or :nth(-last)?-of-type(...) if ( diff === false ) { // Use the same loop as above to seek `elem` from the start while ( (node = ++nodeIndex && node && node[ dir ] || (diff = nodeIndex = 0) || start.pop()) ) { if ( ( ofType ? node.nodeName.toLowerCase() === name : node.nodeType === 1 ) && ++diff ) { // Cache the index of each encountered element if ( useCache ) { outerCache = node[ expando ] || (node[ expando ] = {}); // Support: IE <9 only // Defend against cloned attroperties (jQuery gh-1709) uniqueCache = outerCache[ node.uniqueID ] || (outerCache[ node.uniqueID ] = {}); uniqueCache[ type ] = [ dirruns, diff ]; } if ( node === elem ) { break; } } } } } // Incorporate the offset, then check against cycle size diff -= last; return diff === first || ( diff % first === 0 && diff / first >= 0 ); } }; }, "PSEUDO": function( pseudo, argument ) { // pseudo-class names are case-insensitive // http://www.w3.org/TR/selectors/#pseudo-classes // Prioritize by case sensitivity in case custom pseudos are added with uppercase letters // Remember that setFilters inherits from pseudos var args, fn = Expr.pseudos[ pseudo ] || Expr.setFilters[ pseudo.toLowerCase() ] || Sizzle.error( "unsupported pseudo: " + pseudo ); // The user may use createPseudo to indicate that // arguments are needed to create the filter function // just as Sizzle does if ( fn[ expando ] ) { return fn( argument ); } // But maintain support for old signatures if ( fn.length > 1 ) { args = [ pseudo, pseudo, "", argument ]; return Expr.setFilters.hasOwnProperty( pseudo.toLowerCase() ) ? markFunction(function( seed, matches ) { var idx, matched = fn( seed, argument ), i = matched.length; while ( i-- ) { idx = indexOf( seed, matched[i] ); seed[ idx ] = !( matches[ idx ] = matched[i] ); } }) : function( elem ) { return fn( elem, 0, args ); }; } return fn; } }, pseudos: { // Potentially complex pseudos "not": markFunction(function( selector ) { // Trim the selector passed to compile // to avoid treating leading and trailing // spaces as combinators var input = [], results = [], matcher = compile( selector.replace( rtrim, "$1" ) ); return matcher[ expando ] ? markFunction(function( seed, matches, context, xml ) { var elem, unmatched = matcher( seed, null, xml, [] ), i = seed.length; // Match elements unmatched by `matcher` while ( i-- ) { if ( (elem = unmatched[i]) ) { seed[i] = !(matches[i] = elem); } } }) : function( elem, context, xml ) { input[0] = elem; matcher( input, null, xml, results ); // Don't keep the element (issue #299) input[0] = null; return !results.pop(); }; }), "has": markFunction(function( selector ) { return function( elem ) { return Sizzle( selector, elem ).length > 0; }; }), "contains": markFunction(function( text ) { text = text.replace( runescape, funescape ); return function( elem ) { return ( elem.textContent || elem.innerText || getText( elem ) ).indexOf( text ) > -1; }; }), // "Whether an element is represented by a :lang() selector // is based solely on the element's language value // being equal to the identifier C, // or beginning with the identifier C immediately followed by "-". // The matching of C against the element's language value is performed case-insensitively. // The identifier C does not have to be a valid language name." // http://www.w3.org/TR/selectors/#lang-pseudo "lang": markFunction( function( lang ) { // lang value must be a valid identifier if ( !ridentifier.test(lang || "") ) { Sizzle.error( "unsupported lang: " + lang ); } lang = lang.replace( runescape, funescape ).toLowerCase(); return function( elem ) { var elemLang; do { if ( (elemLang = documentIsHTML ? elem.lang : elem.getAttribute("xml:lang") || elem.getAttribute("lang")) ) { elemLang = elemLang.toLowerCase(); return elemLang === lang || elemLang.indexOf( lang + "-" ) === 0; } } while ( (elem = elem.parentNode) && elem.nodeType === 1 ); return false; }; }), // Miscellaneous "target": function( elem ) { var hash = window.location && window.location.hash; return hash && hash.slice( 1 ) === elem.id; }, "root": function( elem ) { return elem === docElem; }, "focus": function( elem ) { return elem === document.activeElement && (!document.hasFocus || document.hasFocus()) && !!(elem.type || elem.href || ~elem.tabIndex); }, // Boolean properties "enabled": function( elem ) { return elem.disabled === false; }, "disabled": function( elem ) { return elem.disabled === true; }, "checked": function( elem ) { // In CSS3, :checked should return both checked and selected elements // http://www.w3.org/TR/2011/REC-css3-selectors-20110929/#checked var nodeName = elem.nodeName.toLowerCase(); return (nodeName === "input" && !!elem.checked) || (nodeName === "option" && !!elem.selected); }, "selected": function( elem ) { // Accessing this property makes selected-by-default // options in Safari work properly if ( elem.parentNode ) { elem.parentNode.selectedIndex; } return elem.selected === true; }, // Contents "empty": function( elem ) { // http://www.w3.org/TR/selectors/#empty-pseudo // :empty is negated by element (1) or content nodes (text: 3; cdata: 4; entity ref: 5), // but not by others (comment: 8; processing instruction: 7; etc.) // nodeType < 6 works because attributes (2) do not appear as children for ( elem = elem.firstChild; elem; elem = elem.nextSibling ) { if ( elem.nodeType < 6 ) { return false; } } return true; }, "parent": function( elem ) { return !Expr.pseudos["empty"]( elem ); }, // Element/input types "header": function( elem ) { return rheader.test( elem.nodeName ); }, "input": function( elem ) { return rinputs.test( elem.nodeName ); }, "button": function( elem ) { var name = elem.nodeName.toLowerCase(); return name === "input" && elem.type === "button" || name === "button"; }, "text": function( elem ) { var attr; return elem.nodeName.toLowerCase() === "input" && elem.type === "text" && // Support: IE<8 // New HTML5 attribute values (e.g., "search") appear with elem.type === "text" ( (attr = elem.getAttribute("type")) == null || attr.toLowerCase() === "text" ); }, // Position-in-collection "first": createPositionalPseudo(function() { return [ 0 ]; }), "last": createPositionalPseudo(function( matchIndexes, length ) { return [ length - 1 ]; }), "eq": createPositionalPseudo(function( matchIndexes, length, argument ) { return [ argument < 0 ? argument + length : argument ]; }), "even": createPositionalPseudo(function( matchIndexes, length ) { var i = 0; for ( ; i < length; i += 2 ) { matchIndexes.push( i ); } return matchIndexes; }), "odd": createPositionalPseudo(function( matchIndexes, length ) { var i = 1; for ( ; i < length; i += 2 ) { matchIndexes.push( i ); } return matchIndexes; }), "lt": createPositionalPseudo(function( matchIndexes, length, argument ) { var i = argument < 0 ? argument + length : argument; for ( ; --i >= 0; ) { matchIndexes.push( i ); } return matchIndexes; }), "gt": createPositionalPseudo(function( matchIndexes, length, argument ) { var i = argument < 0 ? argument + length : argument; for ( ; ++i < length; ) { matchIndexes.push( i ); } return matchIndexes; }) } }; Expr.pseudos["nth"] = Expr.pseudos["eq"]; // Add button/input type pseudos for ( i in { radio: true, checkbox: true, file: true, password: true, image: true } ) { Expr.pseudos[ i ] = createInputPseudo( i ); } for ( i in { submit: true, reset: true } ) { Expr.pseudos[ i ] = createButtonPseudo( i ); } // Easy API for creating new setFilters function setFilters() {} setFilters.prototype = Expr.filters = Expr.pseudos; Expr.setFilters = new setFilters(); tokenize = Sizzle.tokenize = function( selector, parseOnly ) { var matched, match, tokens, type, soFar, groups, preFilters, cached = tokenCache[ selector + " " ]; if ( cached ) { return parseOnly ? 0 : cached.slice( 0 ); } soFar = selector; groups = []; preFilters = Expr.preFilter; while ( soFar ) { // Comma and first run if ( !matched || (match = rcomma.exec( soFar )) ) { if ( match ) { // Don't consume trailing commas as valid soFar = soFar.slice( match[0].length ) || soFar; } groups.push( (tokens = []) ); } matched = false; // Combinators if ( (match = rcombinators.exec( soFar )) ) { matched = match.shift(); tokens.push({ value: matched, // Cast descendant combinators to space type: match[0].replace( rtrim, " " ) }); soFar = soFar.slice( matched.length ); } // Filters for ( type in Expr.filter ) { if ( (match = matchExpr[ type ].exec( soFar )) && (!preFilters[ type ] || (match = preFilters[ type ]( match ))) ) { matched = match.shift(); tokens.push({ value: matched, type: type, matches: match }); soFar = soFar.slice( matched.length ); } } if ( !matched ) { break; } } // Return the length of the invalid excess // if we're just parsing // Otherwise, throw an error or return tokens return parseOnly ? soFar.length : soFar ? Sizzle.error( selector ) : // Cache the tokens tokenCache( selector, groups ).slice( 0 ); }; function toSelector( tokens ) { var i = 0, len = tokens.length, selector = ""; for ( ; i < len; i++ ) { selector += tokens[i].value; } return selector; } function addCombinator( matcher, combinator, base ) { var dir = combinator.dir, checkNonElements = base && dir === "parentNode", doneName = done++; return combinator.first ? // Check against closest ancestor/preceding element function( elem, context, xml ) { while ( (elem = elem[ dir ]) ) { if ( elem.nodeType === 1 || checkNonElements ) { return matcher( elem, context, xml ); } } } : // Check against all ancestor/preceding elements function( elem, context, xml ) { var oldCache, uniqueCache, outerCache, newCache = [ dirruns, doneName ]; // We can't set arbitrary data on XML nodes, so they don't benefit from combinator caching if ( xml ) { while ( (elem = elem[ dir ]) ) { if ( elem.nodeType === 1 || checkNonElements ) { if ( matcher( elem, context, xml ) ) { return true; } } } } else { while ( (elem = elem[ dir ]) ) { if ( elem.nodeType === 1 || checkNonElements ) { outerCache = elem[ expando ] || (elem[ expando ] = {}); // Support: IE <9 only // Defend against cloned attroperties (jQuery gh-1709) uniqueCache = outerCache[ elem.uniqueID ] || (outerCache[ elem.uniqueID ] = {}); if ( (oldCache = uniqueCache[ dir ]) && oldCache[ 0 ] === dirruns && oldCache[ 1 ] === doneName ) { // Assign to newCache so results back-propagate to previous elements return (newCache[ 2 ] = oldCache[ 2 ]); } else { // Reuse newcache so results back-propagate to previous elements uniqueCache[ dir ] = newCache; // A match means we're done; a fail means we have to keep checking if ( (newCache[ 2 ] = matcher( elem, context, xml )) ) { return true; } } } } } }; } function elementMatcher( matchers ) { return matchers.length > 1 ? function( elem, context, xml ) { var i = matchers.length; while ( i-- ) { if ( !matchers[i]( elem, context, xml ) ) { return false; } } return true; } : matchers[0]; } function multipleContexts( selector, contexts, results ) { var i = 0, len = contexts.length; for ( ; i < len; i++ ) { Sizzle( selector, contexts[i], results ); } return results; } function condense( unmatched, map, filter, context, xml ) { var elem, newUnmatched = [], i = 0, len = unmatched.length, mapped = map != null; for ( ; i < len; i++ ) { if ( (elem = unmatched[i]) ) { if ( !filter || filter( elem, context, xml ) ) { newUnmatched.push( elem ); if ( mapped ) { map.push( i ); } } } } return newUnmatched; } function setMatcher( preFilter, selector, matcher, postFilter, postFinder, postSelector ) { if ( postFilter && !postFilter[ expando ] ) { postFilter = setMatcher( postFilter ); } if ( postFinder && !postFinder[ expando ] ) { postFinder = setMatcher( postFinder, postSelector ); } return markFunction(function( seed, results, context, xml ) { var temp, i, elem, preMap = [], postMap = [], preexisting = results.length, // Get initial elements from seed or context elems = seed || multipleContexts( selector || "*", context.nodeType ? [ context ] : context, [] ), // Prefilter to get matcher input, preserving a map for seed-results synchronization matcherIn = preFilter && ( seed || !selector ) ? condense( elems, preMap, preFilter, context, xml ) : elems, matcherOut = matcher ? // If we have a postFinder, or filtered seed, or non-seed postFilter or preexisting results, postFinder || ( seed ? preFilter : preexisting || postFilter ) ? // ...intermediate processing is necessary [] : // ...otherwise use results directly results : matcherIn; // Find primary matches if ( matcher ) { matcher( matcherIn, matcherOut, context, xml ); } // Apply postFilter if ( postFilter ) { temp = condense( matcherOut, postMap ); postFilter( temp, [], context, xml ); // Un-match failing elements by moving them back to matcherIn i = temp.length; while ( i-- ) { if ( (elem = temp[i]) ) { matcherOut[ postMap[i] ] = !(matcherIn[ postMap[i] ] = elem); } } } if ( seed ) { if ( postFinder || preFilter ) { if ( postFinder ) { // Get the final matcherOut by condensing this intermediate into postFinder contexts temp = []; i = matcherOut.length; while ( i-- ) { if ( (elem = matcherOut[i]) ) { // Restore matcherIn since elem is not yet a final match temp.push( (matcherIn[i] = elem) ); } } postFinder( null, (matcherOut = []), temp, xml ); } // Move matched elements from seed to results to keep them synchronized i = matcherOut.length; while ( i-- ) { if ( (elem = matcherOut[i]) && (temp = postFinder ? indexOf( seed, elem ) : preMap[i]) > -1 ) { seed[temp] = !(results[temp] = elem); } } } // Add elements to results, through postFinder if defined } else { matcherOut = condense( matcherOut === results ? matcherOut.splice( preexisting, matcherOut.length ) : matcherOut ); if ( postFinder ) { postFinder( null, results, matcherOut, xml ); } else { push.apply( results, matcherOut ); } } }); } function matcherFromTokens( tokens ) { var checkContext, matcher, j, len = tokens.length, leadingRelative = Expr.relative[ tokens[0].type ], implicitRelative = leadingRelative || Expr.relative[" "], i = leadingRelative ? 1 : 0, // The foundational matcher ensures that elements are reachable from top-level context(s) matchContext = addCombinator( function( elem ) { return elem === checkContext; }, implicitRelative, true ), matchAnyContext = addCombinator( function( elem ) { return indexOf( checkContext, elem ) > -1; }, implicitRelative, true ), matchers = [ function( elem, context, xml ) { var ret = ( !leadingRelative && ( xml || context !== outermostContext ) ) || ( (checkContext = context).nodeType ? matchContext( elem, context, xml ) : matchAnyContext( elem, context, xml ) ); // Avoid hanging onto element (issue #299) checkContext = null; return ret; } ]; for ( ; i < len; i++ ) { if ( (matcher = Expr.relative[ tokens[i].type ]) ) { matchers = [ addCombinator(elementMatcher( matchers ), matcher) ]; } else { matcher = Expr.filter[ tokens[i].type ].apply( null, tokens[i].matches ); // Return special upon seeing a positional matcher if ( matcher[ expando ] ) { // Find the next relative operator (if any) for proper handling j = ++i; for ( ; j < len; j++ ) { if ( Expr.relative[ tokens[j].type ] ) { break; } } return setMatcher( i > 1 && elementMatcher( matchers ), i > 1 && toSelector( // If the preceding token was a descendant combinator, insert an implicit any-element `*` tokens.slice( 0, i - 1 ).concat({ value: tokens[ i - 2 ].type === " " ? "*" : "" }) ).replace( rtrim, "$1" ), matcher, i < j && matcherFromTokens( tokens.slice( i, j ) ), j < len && matcherFromTokens( (tokens = tokens.slice( j )) ), j < len && toSelector( tokens ) ); } matchers.push( matcher ); } } return elementMatcher( matchers ); } function matcherFromGroupMatchers( elementMatchers, setMatchers ) { var bySet = setMatchers.length > 0, byElement = elementMatchers.length > 0, superMatcher = function( seed, context, xml, results, outermost ) { var elem, j, matcher, matchedCount = 0, i = "0", unmatched = seed && [], setMatched = [], contextBackup = outermostContext, // We must always have either seed elements or outermost context elems = seed || byElement && Expr.find["TAG"]( "*", outermost ), // Use integer dirruns iff this is the outermost matcher dirrunsUnique = (dirruns += contextBackup == null ? 1 : Math.random() || 0.1), len = elems.length; if ( outermost ) { outermostContext = context === document || context || outermost; } // Add elements passing elementMatchers directly to results // Support: IE<9, Safari // Tolerate NodeList properties (IE: "length"; Safari: ) matching elements by id for ( ; i !== len && (elem = elems[i]) != null; i++ ) { if ( byElement && elem ) { j = 0; if ( !context && elem.ownerDocument !== document ) { setDocument( elem ); xml = !documentIsHTML; } while ( (matcher = elementMatchers[j++]) ) { if ( matcher( elem, context || document, xml) ) { results.push( elem ); break; } } if ( outermost ) { dirruns = dirrunsUnique; } } // Track unmatched elements for set filters if ( bySet ) { // They will have gone through all possible matchers if ( (elem = !matcher && elem) ) { matchedCount--; } // Lengthen the array for every element, matched or not if ( seed ) { unmatched.push( elem ); } } } // `i` is now the count of elements visited above, and adding it to `matchedCount` // makes the latter nonnegative. matchedCount += i; // Apply set filters to unmatched elements // NOTE: This can be skipped if there are no unmatched elements (i.e., `matchedCount` // equals `i`), unless we didn't visit _any_ elements in the above loop because we have // no element matchers and no seed. // Incrementing an initially-string "0" `i` allows `i` to remain a string only in that // case, which will result in a "00" `matchedCount` that differs from `i` but is also // numerically zero. if ( bySet && i !== matchedCount ) { j = 0; while ( (matcher = setMatchers[j++]) ) { matcher( unmatched, setMatched, context, xml ); } if ( seed ) { // Reintegrate element matches to eliminate the need for sorting if ( matchedCount > 0 ) { while ( i-- ) { if ( !(unmatched[i] || setMatched[i]) ) { setMatched[i] = pop.call( results ); } } } // Discard index placeholder values to get only actual matches setMatched = condense( setMatched ); } // Add matches to results push.apply( results, setMatched ); // Seedless set matches succeeding multiple successful matchers stipulate sorting if ( outermost && !seed && setMatched.length > 0 && ( matchedCount + setMatchers.length ) > 1 ) { Sizzle.uniqueSort( results ); } } // Override manipulation of globals by nested matchers if ( outermost ) { dirruns = dirrunsUnique; outermostContext = contextBackup; } return unmatched; }; return bySet ? markFunction( superMatcher ) : superMatcher; } compile = Sizzle.compile = function( selector, match /* Internal Use Only */ ) { var i, setMatchers = [], elementMatchers = [], cached = compilerCache[ selector + " " ]; if ( !cached ) { // Generate a function of recursive functions that can be used to check each element if ( !match ) { match = tokenize( selector ); } i = match.length; while ( i-- ) { cached = matcherFromTokens( match[i] ); if ( cached[ expando ] ) { setMatchers.push( cached ); } else { elementMatchers.push( cached ); } } // Cache the compiled function cached = compilerCache( selector, matcherFromGroupMatchers( elementMatchers, setMatchers ) ); // Save selector and tokenization cached.selector = selector; } return cached; }; /** * A low-level selection function that works with Sizzle's compiled * selector functions * @param {String|Function} selector A selector or a pre-compiled * selector function built with Sizzle.compile * @param {Element} context * @param {Array} [results] * @param {Array} [seed] A set of elements to match against */ select = Sizzle.select = function( selector, context, results, seed ) { var i, tokens, token, type, find, compiled = typeof selector === "function" && selector, match = !seed && tokenize( (selector = compiled.selector || selector) ); results = results || []; // Try to minimize operations if there is only one selector in the list and no seed // (the latter of which guarantees us context) if ( match.length === 1 ) { // Reduce context if the leading compound selector is an ID tokens = match[0] = match[0].slice( 0 ); if ( tokens.length > 2 && (token = tokens[0]).type === "ID" && support.getById && context.nodeType === 9 && documentIsHTML && Expr.relative[ tokens[1].type ] ) { context = ( Expr.find["ID"]( token.matches[0].replace(runescape, funescape), context ) || [] )[0]; if ( !context ) { return results; // Precompiled matchers will still verify ancestry, so step up a level } else if ( compiled ) { context = context.parentNode; } selector = selector.slice( tokens.shift().value.length ); } // Fetch a seed set for right-to-left matching i = matchExpr["needsContext"].test( selector ) ? 0 : tokens.length; while ( i-- ) { token = tokens[i]; // Abort if we hit a combinator if ( Expr.relative[ (type = token.type) ] ) { break; } if ( (find = Expr.find[ type ]) ) { // Search, expanding context for leading sibling combinators if ( (seed = find( token.matches[0].replace( runescape, funescape ), rsibling.test( tokens[0].type ) && testContext( context.parentNode ) || context )) ) { // If seed is empty or no tokens remain, we can return early tokens.splice( i, 1 ); selector = seed.length && toSelector( tokens ); if ( !selector ) { push.apply( results, seed ); return results; } break; } } } } // Compile and execute a filtering function if one is not provided // Provide `match` to avoid retokenization if we modified the selector above ( compiled || compile( selector, match ) )( seed, context, !documentIsHTML, results, !context || rsibling.test( selector ) && testContext( context.parentNode ) || context ); return results; }; // One-time assignments // Sort stability support.sortStable = expando.split("").sort( sortOrder ).join("") === expando; // Support: Chrome 14-35+ // Always assume duplicates if they aren't passed to the comparison function support.detectDuplicates = !!hasDuplicate; // Initialize against the default document setDocument(); // Support: Webkit<537.32 - Safari 6.0.3/Chrome 25 (fixed in Chrome 27) // Detached nodes confoundingly follow *each other* support.sortDetached = assert(function( div1 ) { // Should return 1, but returns 4 (following) return div1.compareDocumentPosition( document.createElement("div") ) & 1; }); // Support: IE<8 // Prevent attribute/property "interpolation" // http://msdn.microsoft.com/en-us/library/ms536429%28VS.85%29.aspx if ( !assert(function( div ) { div.innerHTML = ""; return div.firstChild.getAttribute("href") === "#" ; }) ) { addHandle( "type|href|height|width", function( elem, name, isXML ) { if ( !isXML ) { return elem.getAttribute( name, name.toLowerCase() === "type" ? 1 : 2 ); } }); } // Support: IE<9 // Use defaultValue in place of getAttribute("value") if ( !support.attributes || !assert(function( div ) { div.innerHTML = ""; div.firstChild.setAttribute( "value", "" ); return div.firstChild.getAttribute( "value" ) === ""; }) ) { addHandle( "value", function( elem, name, isXML ) { if ( !isXML && elem.nodeName.toLowerCase() === "input" ) { return elem.defaultValue; } }); } // Support: IE<9 // Use getAttributeNode to fetch booleans when getAttribute lies if ( !assert(function( div ) { return div.getAttribute("disabled") == null; }) ) { addHandle( booleans, function( elem, name, isXML ) { var val; if ( !isXML ) { return elem[ name ] === true ? name.toLowerCase() : (val = elem.getAttributeNode( name )) && val.specified ? val.value : null; } }); } return Sizzle; })( window ); jQuery.find = Sizzle; jQuery.expr = Sizzle.selectors; jQuery.expr[ ":" ] = jQuery.expr.pseudos; jQuery.uniqueSort = jQuery.unique = Sizzle.uniqueSort; jQuery.text = Sizzle.getText; jQuery.isXMLDoc = Sizzle.isXML; jQuery.contains = Sizzle.contains; var dir = function( elem, dir, until ) { var matched = [], truncate = until !== undefined; while ( ( elem = elem[ dir ] ) && elem.nodeType !== 9 ) { if ( elem.nodeType === 1 ) { if ( truncate && jQuery( elem ).is( until ) ) { break; } matched.push( elem ); } } return matched; }; var siblings = function( n, elem ) { var matched = []; for ( ; n; n = n.nextSibling ) { if ( n.nodeType === 1 && n !== elem ) { matched.push( n ); } } return matched; }; var rneedsContext = jQuery.expr.match.needsContext; var rsingleTag = ( /^<([\w-]+)\s*\/?>(?:<\/\1>|)$/ ); var risSimple = /^.[^:#\[\.,]*$/; // Implement the identical functionality for filter and not function winnow( elements, qualifier, not ) { if ( jQuery.isFunction( qualifier ) ) { return jQuery.grep( elements, function( elem, i ) { /* jshint -W018 */ return !!qualifier.call( elem, i, elem ) !== not; } ); } if ( qualifier.nodeType ) { return jQuery.grep( elements, function( elem ) { return ( elem === qualifier ) !== not; } ); } if ( typeof qualifier === "string" ) { if ( risSimple.test( qualifier ) ) { return jQuery.filter( qualifier, elements, not ); } qualifier = jQuery.filter( qualifier, elements ); } return jQuery.grep( elements, function( elem ) { return ( jQuery.inArray( elem, qualifier ) > -1 ) !== not; } ); } jQuery.filter = function( expr, elems, not ) { var elem = elems[ 0 ]; if ( not ) { expr = ":not(" + expr + ")"; } return elems.length === 1 && elem.nodeType === 1 ? jQuery.find.matchesSelector( elem, expr ) ? [ elem ] : [] : jQuery.find.matches( expr, jQuery.grep( elems, function( elem ) { return elem.nodeType === 1; } ) ); }; jQuery.fn.extend( { find: function( selector ) { var i, ret = [], self = this, len = self.length; if ( typeof selector !== "string" ) { return this.pushStack( jQuery( selector ).filter( function() { for ( i = 0; i < len; i++ ) { if ( jQuery.contains( self[ i ], this ) ) { return true; } } } ) ); } for ( i = 0; i < len; i++ ) { jQuery.find( selector, self[ i ], ret ); } // Needed because $( selector, context ) becomes $( context ).find( selector ) ret = this.pushStack( len > 1 ? jQuery.unique( ret ) : ret ); ret.selector = this.selector ? this.selector + " " + selector : selector; return ret; }, filter: function( selector ) { return this.pushStack( winnow( this, selector || [], false ) ); }, not: function( selector ) { return this.pushStack( winnow( this, selector || [], true ) ); }, is: function( selector ) { return !!winnow( this, // If this is a positional/relative selector, check membership in the returned set // so $("p:first").is("p:last") won't return true for a doc with two "p". typeof selector === "string" && rneedsContext.test( selector ) ? jQuery( selector ) : selector || [], false ).length; } } ); // Initialize a jQuery object // A central reference to the root jQuery(document) var rootjQuery, // A simple way to check for HTML strings // Prioritize #id over to avoid XSS via location.hash (#9521) // Strict HTML recognition (#11290: must start with <) rquickExpr = /^(?:\s*(<[\w\W]+>)[^>]*|#([\w-]*))$/, init = jQuery.fn.init = function( selector, context, root ) { var match, elem; // HANDLE: $(""), $(null), $(undefined), $(false) if ( !selector ) { return this; } // init accepts an alternate rootjQuery // so migrate can support jQuery.sub (gh-2101) root = root || rootjQuery; // Handle HTML strings if ( typeof selector === "string" ) { if ( selector.charAt( 0 ) === "<" && selector.charAt( selector.length - 1 ) === ">" && selector.length >= 3 ) { // Assume that strings that start and end with <> are HTML and skip the regex check match = [ null, selector, null ]; } else { match = rquickExpr.exec( selector ); } // Match html or make sure no context is specified for #id if ( match && ( match[ 1 ] || !context ) ) { // HANDLE: $(html) -> $(array) if ( match[ 1 ] ) { context = context instanceof jQuery ? context[ 0 ] : context; // scripts is true for back-compat // Intentionally let the error be thrown if parseHTML is not present jQuery.merge( this, jQuery.parseHTML( match[ 1 ], context && context.nodeType ? context.ownerDocument || context : document, true ) ); // HANDLE: $(html, props) if ( rsingleTag.test( match[ 1 ] ) && jQuery.isPlainObject( context ) ) { for ( match in context ) { // Properties of context are called as methods if possible if ( jQuery.isFunction( this[ match ] ) ) { this[ match ]( context[ match ] ); // ...and otherwise set as attributes } else { this.attr( match, context[ match ] ); } } } return this; // HANDLE: $(#id) } else { elem = document.getElementById( match[ 2 ] ); // Check parentNode to catch when Blackberry 4.6 returns // nodes that are no longer in the document #6963 if ( elem && elem.parentNode ) { // Handle the case where IE and Opera return items // by name instead of ID if ( elem.id !== match[ 2 ] ) { return rootjQuery.find( selector ); } // Otherwise, we inject the element directly into the jQuery object this.length = 1; this[ 0 ] = elem; } this.context = document; this.selector = selector; return this; } // HANDLE: $(expr, $(...)) } else if ( !context || context.jquery ) { return ( context || root ).find( selector ); // HANDLE: $(expr, context) // (which is just equivalent to: $(context).find(expr) } else { return this.constructor( context ).find( selector ); } // HANDLE: $(DOMElement) } else if ( selector.nodeType ) { this.context = this[ 0 ] = selector; this.length = 1; return this; // HANDLE: $(function) // Shortcut for document ready } else if ( jQuery.isFunction( selector ) ) { return typeof root.ready !== "undefined" ? root.ready( selector ) : // Execute immediately if ready is not present selector( jQuery ); } if ( selector.selector !== undefined ) { this.selector = selector.selector; this.context = selector.context; } return jQuery.makeArray( selector, this ); }; // Give the init function the jQuery prototype for later instantiation init.prototype = jQuery.fn; // Initialize central reference rootjQuery = jQuery( document ); var rparentsprev = /^(?:parents|prev(?:Until|All))/, // methods guaranteed to produce a unique set when starting from a unique set guaranteedUnique = { children: true, contents: true, next: true, prev: true }; jQuery.fn.extend( { has: function( target ) { var i, targets = jQuery( target, this ), len = targets.length; return this.filter( function() { for ( i = 0; i < len; i++ ) { if ( jQuery.contains( this, targets[ i ] ) ) { return true; } } } ); }, closest: function( selectors, context ) { var cur, i = 0, l = this.length, matched = [], pos = rneedsContext.test( selectors ) || typeof selectors !== "string" ? jQuery( selectors, context || this.context ) : 0; for ( ; i < l; i++ ) { for ( cur = this[ i ]; cur && cur !== context; cur = cur.parentNode ) { // Always skip document fragments if ( cur.nodeType < 11 && ( pos ? pos.index( cur ) > -1 : // Don't pass non-elements to Sizzle cur.nodeType === 1 && jQuery.find.matchesSelector( cur, selectors ) ) ) { matched.push( cur ); break; } } } return this.pushStack( matched.length > 1 ? jQuery.uniqueSort( matched ) : matched ); }, // Determine the position of an element within // the matched set of elements index: function( elem ) { // No argument, return index in parent if ( !elem ) { return ( this[ 0 ] && this[ 0 ].parentNode ) ? this.first().prevAll().length : -1; } // index in selector if ( typeof elem === "string" ) { return jQuery.inArray( this[ 0 ], jQuery( elem ) ); } // Locate the position of the desired element return jQuery.inArray( // If it receives a jQuery object, the first element is used elem.jquery ? elem[ 0 ] : elem, this ); }, add: function( selector, context ) { return this.pushStack( jQuery.uniqueSort( jQuery.merge( this.get(), jQuery( selector, context ) ) ) ); }, addBack: function( selector ) { return this.add( selector == null ? this.prevObject : this.prevObject.filter( selector ) ); } } ); function sibling( cur, dir ) { do { cur = cur[ dir ]; } while ( cur && cur.nodeType !== 1 ); return cur; } jQuery.each( { parent: function( elem ) { var parent = elem.parentNode; return parent && parent.nodeType !== 11 ? parent : null; }, parents: function( elem ) { return dir( elem, "parentNode" ); }, parentsUntil: function( elem, i, until ) { return dir( elem, "parentNode", until ); }, next: function( elem ) { return sibling( elem, "nextSibling" ); }, prev: function( elem ) { return sibling( elem, "previousSibling" ); }, nextAll: function( elem ) { return dir( elem, "nextSibling" ); }, prevAll: function( elem ) { return dir( elem, "previousSibling" ); }, nextUntil: function( elem, i, until ) { return dir( elem, "nextSibling", until ); }, prevUntil: function( elem, i, until ) { return dir( elem, "previousSibling", until ); }, siblings: function( elem ) { return siblings( ( elem.parentNode || {} ).firstChild, elem ); }, children: function( elem ) { return siblings( elem.firstChild ); }, contents: function( elem ) { return jQuery.nodeName( elem, "iframe" ) ? elem.contentDocument || elem.contentWindow.document : jQuery.merge( [], elem.childNodes ); } }, function( name, fn ) { jQuery.fn[ name ] = function( until, selector ) { var ret = jQuery.map( this, fn, until ); if ( name.slice( -5 ) !== "Until" ) { selector = until; } if ( selector && typeof selector === "string" ) { ret = jQuery.filter( selector, ret ); } if ( this.length > 1 ) { // Remove duplicates if ( !guaranteedUnique[ name ] ) { ret = jQuery.uniqueSort( ret ); } // Reverse order for parents* and prev-derivatives if ( rparentsprev.test( name ) ) { ret = ret.reverse(); } } return this.pushStack( ret ); }; } ); var rnotwhite = ( /\S+/g ); // Convert String-formatted options into Object-formatted ones function createOptions( options ) { var object = {}; jQuery.each( options.match( rnotwhite ) || [], function( _, flag ) { object[ flag ] = true; } ); return object; } /* * Create a callback list using the following parameters: * * options: an optional list of space-separated options that will change how * the callback list behaves or a more traditional option object * * By default a callback list will act like an event callback list and can be * "fired" multiple times. * * Possible options: * * once: will ensure the callback list can only be fired once (like a Deferred) * * memory: will keep track of previous values and will call any callback added * after the list has been fired right away with the latest "memorized" * values (like a Deferred) * * unique: will ensure a callback can only be added once (no duplicate in the list) * * stopOnFalse: interrupt callings when a callback returns false * */ jQuery.Callbacks = function( options ) { // Convert options from String-formatted to Object-formatted if needed // (we check in cache first) options = typeof options === "string" ? createOptions( options ) : jQuery.extend( {}, options ); var // Flag to know if list is currently firing firing, // Last fire value for non-forgettable lists memory, // Flag to know if list was already fired fired, // Flag to prevent firing locked, // Actual callback list list = [], // Queue of execution data for repeatable lists queue = [], // Index of currently firing callback (modified by add/remove as needed) firingIndex = -1, // Fire callbacks fire = function() { // Enforce single-firing locked = options.once; // Execute callbacks for all pending executions, // respecting firingIndex overrides and runtime changes fired = firing = true; for ( ; queue.length; firingIndex = -1 ) { memory = queue.shift(); while ( ++firingIndex < list.length ) { // Run callback and check for early termination if ( list[ firingIndex ].apply( memory[ 0 ], memory[ 1 ] ) === false && options.stopOnFalse ) { // Jump to end and forget the data so .add doesn't re-fire firingIndex = list.length; memory = false; } } } // Forget the data if we're done with it if ( !options.memory ) { memory = false; } firing = false; // Clean up if we're done firing for good if ( locked ) { // Keep an empty list if we have data for future add calls if ( memory ) { list = []; // Otherwise, this object is spent } else { list = ""; } } }, // Actual Callbacks object self = { // Add a callback or a collection of callbacks to the list add: function() { if ( list ) { // If we have memory from a past run, we should fire after adding if ( memory && !firing ) { firingIndex = list.length - 1; queue.push( memory ); } ( function add( args ) { jQuery.each( args, function( _, arg ) { if ( jQuery.isFunction( arg ) ) { if ( !options.unique || !self.has( arg ) ) { list.push( arg ); } } else if ( arg && arg.length && jQuery.type( arg ) !== "string" ) { // Inspect recursively add( arg ); } } ); } )( arguments ); if ( memory && !firing ) { fire(); } } return this; }, // Remove a callback from the list remove: function() { jQuery.each( arguments, function( _, arg ) { var index; while ( ( index = jQuery.inArray( arg, list, index ) ) > -1 ) { list.splice( index, 1 ); // Handle firing indexes if ( index <= firingIndex ) { firingIndex--; } } } ); return this; }, // Check if a given callback is in the list. // If no argument is given, return whether or not list has callbacks attached. has: function( fn ) { return fn ? jQuery.inArray( fn, list ) > -1 : list.length > 0; }, // Remove all callbacks from the list empty: function() { if ( list ) { list = []; } return this; }, // Disable .fire and .add // Abort any current/pending executions // Clear all callbacks and values disable: function() { locked = queue = []; list = memory = ""; return this; }, disabled: function() { return !list; }, // Disable .fire // Also disable .add unless we have memory (since it would have no effect) // Abort any pending executions lock: function() { locked = true; if ( !memory ) { self.disable(); } return this; }, locked: function() { return !!locked; }, // Call all callbacks with the given context and arguments fireWith: function( context, args ) { if ( !locked ) { args = args || []; args = [ context, args.slice ? args.slice() : args ]; queue.push( args ); if ( !firing ) { fire(); } } return this; }, // Call all the callbacks with the given arguments fire: function() { self.fireWith( this, arguments ); return this; }, // To know if the callbacks have already been called at least once fired: function() { return !!fired; } }; return self; }; jQuery.extend( { Deferred: function( func ) { var tuples = [ // action, add listener, listener list, final state [ "resolve", "done", jQuery.Callbacks( "once memory" ), "resolved" ], [ "reject", "fail", jQuery.Callbacks( "once memory" ), "rejected" ], [ "notify", "progress", jQuery.Callbacks( "memory" ) ] ], state = "pending", promise = { state: function() { return state; }, always: function() { deferred.done( arguments ).fail( arguments ); return this; }, then: function( /* fnDone, fnFail, fnProgress */ ) { var fns = arguments; return jQuery.Deferred( function( newDefer ) { jQuery.each( tuples, function( i, tuple ) { var fn = jQuery.isFunction( fns[ i ] ) && fns[ i ]; // deferred[ done | fail | progress ] for forwarding actions to newDefer deferred[ tuple[ 1 ] ]( function() { var returned = fn && fn.apply( this, arguments ); if ( returned && jQuery.isFunction( returned.promise ) ) { returned.promise() .progress( newDefer.notify ) .done( newDefer.resolve ) .fail( newDefer.reject ); } else { newDefer[ tuple[ 0 ] + "With" ]( this === promise ? newDefer.promise() : this, fn ? [ returned ] : arguments ); } } ); } ); fns = null; } ).promise(); }, // Get a promise for this deferred // If obj is provided, the promise aspect is added to the object promise: function( obj ) { return obj != null ? jQuery.extend( obj, promise ) : promise; } }, deferred = {}; // Keep pipe for back-compat promise.pipe = promise.then; // Add list-specific methods jQuery.each( tuples, function( i, tuple ) { var list = tuple[ 2 ], stateString = tuple[ 3 ]; // promise[ done | fail | progress ] = list.add promise[ tuple[ 1 ] ] = list.add; // Handle state if ( stateString ) { list.add( function() { // state = [ resolved | rejected ] state = stateString; // [ reject_list | resolve_list ].disable; progress_list.lock }, tuples[ i ^ 1 ][ 2 ].disable, tuples[ 2 ][ 2 ].lock ); } // deferred[ resolve | reject | notify ] deferred[ tuple[ 0 ] ] = function() { deferred[ tuple[ 0 ] + "With" ]( this === deferred ? promise : this, arguments ); return this; }; deferred[ tuple[ 0 ] + "With" ] = list.fireWith; } ); // Make the deferred a promise promise.promise( deferred ); // Call given func if any if ( func ) { func.call( deferred, deferred ); } // All done! return deferred; }, // Deferred helper when: function( subordinate /* , ..., subordinateN */ ) { var i = 0, resolveValues = slice.call( arguments ), length = resolveValues.length, // the count of uncompleted subordinates remaining = length !== 1 || ( subordinate && jQuery.isFunction( subordinate.promise ) ) ? length : 0, // the master Deferred. // If resolveValues consist of only a single Deferred, just use that. deferred = remaining === 1 ? subordinate : jQuery.Deferred(), // Update function for both resolve and progress values updateFunc = function( i, contexts, values ) { return function( value ) { contexts[ i ] = this; values[ i ] = arguments.length > 1 ? slice.call( arguments ) : value; if ( values === progressValues ) { deferred.notifyWith( contexts, values ); } else if ( !( --remaining ) ) { deferred.resolveWith( contexts, values ); } }; }, progressValues, progressContexts, resolveContexts; // add listeners to Deferred subordinates; treat others as resolved if ( length > 1 ) { progressValues = new Array( length ); progressContexts = new Array( length ); resolveContexts = new Array( length ); for ( ; i < length; i++ ) { if ( resolveValues[ i ] && jQuery.isFunction( resolveValues[ i ].promise ) ) { resolveValues[ i ].promise() .progress( updateFunc( i, progressContexts, progressValues ) ) .done( updateFunc( i, resolveContexts, resolveValues ) ) .fail( deferred.reject ); } else { --remaining; } } } // if we're not waiting on anything, resolve the master if ( !remaining ) { deferred.resolveWith( resolveContexts, resolveValues ); } return deferred.promise(); } } ); // The deferred used on DOM ready var readyList; jQuery.fn.ready = function( fn ) { // Add the callback jQuery.ready.promise().done( fn ); return this; }; jQuery.extend( { // Is the DOM ready to be used? Set to true once it occurs. isReady: false, // A counter to track how many items to wait for before // the ready event fires. See #6781 readyWait: 1, // Hold (or release) the ready event holdReady: function( hold ) { if ( hold ) { jQuery.readyWait++; } else { jQuery.ready( true ); } }, // Handle when the DOM is ready ready: function( wait ) { // Abort if there are pending holds or we're already ready if ( wait === true ? --jQuery.readyWait : jQuery.isReady ) { return; } // Remember that the DOM is ready jQuery.isReady = true; // If a normal DOM Ready event fired, decrement, and wait if need be if ( wait !== true && --jQuery.readyWait > 0 ) { return; } // If there are functions bound, to execute readyList.resolveWith( document, [ jQuery ] ); // Trigger any bound ready events if ( jQuery.fn.triggerHandler ) { jQuery( document ).triggerHandler( "ready" ); jQuery( document ).off( "ready" ); } } } ); /** * Clean-up method for dom ready events */ function detach() { if ( document.addEventListener ) { document.removeEventListener( "DOMContentLoaded", completed ); window.removeEventListener( "load", completed ); } else { document.detachEvent( "onreadystatechange", completed ); window.detachEvent( "onload", completed ); } } /** * The ready event handler and self cleanup method */ function completed() { // readyState === "complete" is good enough for us to call the dom ready in oldIE if ( document.addEventListener || window.event.type === "load" || document.readyState === "complete" ) { detach(); jQuery.ready(); } } jQuery.ready.promise = function( obj ) { if ( !readyList ) { readyList = jQuery.Deferred(); // Catch cases where $(document).ready() is called // after the browser event has already occurred. // Support: IE6-10 // Older IE sometimes signals "interactive" too soon if ( document.readyState === "complete" || ( document.readyState !== "loading" && !document.documentElement.doScroll ) ) { // Handle it asynchronously to allow scripts the opportunity to delay ready window.setTimeout( jQuery.ready ); // Standards-based browsers support DOMContentLoaded } else if ( document.addEventListener ) { // Use the handy event callback document.addEventListener( "DOMContentLoaded", completed ); // A fallback to window.onload, that will always work window.addEventListener( "load", completed ); // If IE event model is used } else { // Ensure firing before onload, maybe late but safe also for iframes document.attachEvent( "onreadystatechange", completed ); // A fallback to window.onload, that will always work window.attachEvent( "onload", completed ); // If IE and not a frame // continually check to see if the document is ready var top = false; try { top = window.frameElement == null && document.documentElement; } catch ( e ) {} if ( top && top.doScroll ) { ( function doScrollCheck() { if ( !jQuery.isReady ) { try { // Use the trick by Diego Perini // http://javascript.nwbox.com/IEContentLoaded/ top.doScroll( "left" ); } catch ( e ) { return window.setTimeout( doScrollCheck, 50 ); } // detach all dom ready events detach(); // and execute any waiting functions jQuery.ready(); } } )(); } } } return readyList.promise( obj ); }; // Kick off the DOM ready check even if the user does not jQuery.ready.promise(); // Support: IE<9 // Iteration over object's inherited properties before its own var i; for ( i in jQuery( support ) ) { break; } support.ownFirst = i === "0"; // Note: most support tests are defined in their respective modules. // false until the test is run support.inlineBlockNeedsLayout = false; // Execute ASAP in case we need to set body.style.zoom jQuery( function() { // Minified: var a,b,c,d var val, div, body, container; body = document.getElementsByTagName( "body" )[ 0 ]; if ( !body || !body.style ) { // Return for frameset docs that don't have a body return; } // Setup div = document.createElement( "div" ); container = document.createElement( "div" ); container.style.cssText = "position:absolute;border:0;width:0;height:0;top:0;left:-9999px"; body.appendChild( container ).appendChild( div ); if ( typeof div.style.zoom !== "undefined" ) { // Support: IE<8 // Check if natively block-level elements act like inline-block // elements when setting their display to 'inline' and giving // them layout div.style.cssText = "display:inline;margin:0;border:0;padding:1px;width:1px;zoom:1"; support.inlineBlockNeedsLayout = val = div.offsetWidth === 3; if ( val ) { // Prevent IE 6 from affecting layout for positioned elements #11048 // Prevent IE from shrinking the body in IE 7 mode #12869 // Support: IE<8 body.style.zoom = 1; } } body.removeChild( container ); } ); ( function() { var div = document.createElement( "div" ); // Support: IE<9 support.deleteExpando = true; try { delete div.test; } catch ( e ) { support.deleteExpando = false; } // Null elements to avoid leaks in IE. div = null; } )(); var acceptData = function( elem ) { var noData = jQuery.noData[ ( elem.nodeName + " " ).toLowerCase() ], nodeType = +elem.nodeType || 1; // Do not set data on non-element DOM nodes because it will not be cleared (#8335). return nodeType !== 1 && nodeType !== 9 ? false : // Nodes accept data unless otherwise specified; rejection can be conditional !noData || noData !== true && elem.getAttribute( "classid" ) === noData; }; var rbrace = /^(?:\{[\w\W]*\}|\[[\w\W]*\])$/, rmultiDash = /([A-Z])/g; function dataAttr( elem, key, data ) { // If nothing was found internally, try to fetch any // data from the HTML5 data-* attribute if ( data === undefined && elem.nodeType === 1 ) { var name = "data-" + key.replace( rmultiDash, "-$1" ).toLowerCase(); data = elem.getAttribute( name ); if ( typeof data === "string" ) { try { data = data === "true" ? true : data === "false" ? false : data === "null" ? null : // Only convert to a number if it doesn't change the string +data + "" === data ? +data : rbrace.test( data ) ? jQuery.parseJSON( data ) : data; } catch ( e ) {} // Make sure we set the data so it isn't changed later jQuery.data( elem, key, data ); } else { data = undefined; } } return data; } // checks a cache object for emptiness function isEmptyDataObject( obj ) { var name; for ( name in obj ) { // if the public data object is empty, the private is still empty if ( name === "data" && jQuery.isEmptyObject( obj[ name ] ) ) { continue; } if ( name !== "toJSON" ) { return false; } } return true; } function internalData( elem, name, data, pvt /* Internal Use Only */ ) { if ( !acceptData( elem ) ) { return; } var ret, thisCache, internalKey = jQuery.expando, // We have to handle DOM nodes and JS objects differently because IE6-7 // can't GC object references properly across the DOM-JS boundary isNode = elem.nodeType, // Only DOM nodes need the global jQuery cache; JS object data is // attached directly to the object so GC can occur automatically cache = isNode ? jQuery.cache : elem, // Only defining an ID for JS objects if its cache already exists allows // the code to shortcut on the same path as a DOM node with no cache id = isNode ? elem[ internalKey ] : elem[ internalKey ] && internalKey; // Avoid doing any more work than we need to when trying to get data on an // object that has no data at all if ( ( !id || !cache[ id ] || ( !pvt && !cache[ id ].data ) ) && data === undefined && typeof name === "string" ) { return; } if ( !id ) { // Only DOM nodes need a new unique ID for each element since their data // ends up in the global cache if ( isNode ) { id = elem[ internalKey ] = deletedIds.pop() || jQuery.guid++; } else { id = internalKey; } } if ( !cache[ id ] ) { // Avoid exposing jQuery metadata on plain JS objects when the object // is serialized using JSON.stringify cache[ id ] = isNode ? {} : { toJSON: jQuery.noop }; } // An object can be passed to jQuery.data instead of a key/value pair; this gets // shallow copied over onto the existing cache if ( typeof name === "object" || typeof name === "function" ) { if ( pvt ) { cache[ id ] = jQuery.extend( cache[ id ], name ); } else { cache[ id ].data = jQuery.extend( cache[ id ].data, name ); } } thisCache = cache[ id ]; // jQuery data() is stored in a separate object inside the object's internal data // cache in order to avoid key collisions between internal data and user-defined // data. if ( !pvt ) { if ( !thisCache.data ) { thisCache.data = {}; } thisCache = thisCache.data; } if ( data !== undefined ) { thisCache[ jQuery.camelCase( name ) ] = data; } // Check for both converted-to-camel and non-converted data property names // If a data property was specified if ( typeof name === "string" ) { // First Try to find as-is property data ret = thisCache[ name ]; // Test for null|undefined property data if ( ret == null ) { // Try to find the camelCased property ret = thisCache[ jQuery.camelCase( name ) ]; } } else { ret = thisCache; } return ret; } function internalRemoveData( elem, name, pvt ) { if ( !acceptData( elem ) ) { return; } var thisCache, i, isNode = elem.nodeType, // See jQuery.data for more information cache = isNode ? jQuery.cache : elem, id = isNode ? elem[ jQuery.expando ] : jQuery.expando; // If there is already no cache entry for this object, there is no // purpose in continuing if ( !cache[ id ] ) { return; } if ( name ) { thisCache = pvt ? cache[ id ] : cache[ id ].data; if ( thisCache ) { // Support array or space separated string names for data keys if ( !jQuery.isArray( name ) ) { // try the string as a key before any manipulation if ( name in thisCache ) { name = [ name ]; } else { // split the camel cased version by spaces unless a key with the spaces exists name = jQuery.camelCase( name ); if ( name in thisCache ) { name = [ name ]; } else { name = name.split( " " ); } } } else { // If "name" is an array of keys... // When data is initially created, via ("key", "val") signature, // keys will be converted to camelCase. // Since there is no way to tell _how_ a key was added, remove // both plain key and camelCase key. #12786 // This will only penalize the array argument path. name = name.concat( jQuery.map( name, jQuery.camelCase ) ); } i = name.length; while ( i-- ) { delete thisCache[ name[ i ] ]; } // If there is no data left in the cache, we want to continue // and let the cache object itself get destroyed if ( pvt ? !isEmptyDataObject( thisCache ) : !jQuery.isEmptyObject( thisCache ) ) { return; } } } // See jQuery.data for more information if ( !pvt ) { delete cache[ id ].data; // Don't destroy the parent cache unless the internal data object // had been the only thing left in it if ( !isEmptyDataObject( cache[ id ] ) ) { return; } } // Destroy the cache if ( isNode ) { jQuery.cleanData( [ elem ], true ); // Use delete when supported for expandos or `cache` is not a window per isWindow (#10080) /* jshint eqeqeq: false */ } else if ( support.deleteExpando || cache != cache.window ) { /* jshint eqeqeq: true */ delete cache[ id ]; // When all else fails, undefined } else { cache[ id ] = undefined; } } jQuery.extend( { cache: {}, // The following elements (space-suffixed to avoid Object.prototype collisions) // throw uncatchable exceptions if you attempt to set expando properties noData: { "applet ": true, "embed ": true, // ...but Flash objects (which have this classid) *can* handle expandos "object ": "clsid:D27CDB6E-AE6D-11cf-96B8-444553540000" }, hasData: function( elem ) { elem = elem.nodeType ? jQuery.cache[ elem[ jQuery.expando ] ] : elem[ jQuery.expando ]; return !!elem && !isEmptyDataObject( elem ); }, data: function( elem, name, data ) { return internalData( elem, name, data ); }, removeData: function( elem, name ) { return internalRemoveData( elem, name ); }, // For internal use only. _data: function( elem, name, data ) { return internalData( elem, name, data, true ); }, _removeData: function( elem, name ) { return internalRemoveData( elem, name, true ); } } ); jQuery.fn.extend( { data: function( key, value ) { var i, name, data, elem = this[ 0 ], attrs = elem && elem.attributes; // Special expections of .data basically thwart jQuery.access, // so implement the relevant behavior ourselves // Gets all values if ( key === undefined ) { if ( this.length ) { data = jQuery.data( elem ); if ( elem.nodeType === 1 && !jQuery._data( elem, "parsedAttrs" ) ) { i = attrs.length; while ( i-- ) { // Support: IE11+ // The attrs elements can be null (#14894) if ( attrs[ i ] ) { name = attrs[ i ].name; if ( name.indexOf( "data-" ) === 0 ) { name = jQuery.camelCase( name.slice( 5 ) ); dataAttr( elem, name, data[ name ] ); } } } jQuery._data( elem, "parsedAttrs", true ); } } return data; } // Sets multiple values if ( typeof key === "object" ) { return this.each( function() { jQuery.data( this, key ); } ); } return arguments.length > 1 ? // Sets one value this.each( function() { jQuery.data( this, key, value ); } ) : // Gets one value // Try to fetch any internally stored data first elem ? dataAttr( elem, key, jQuery.data( elem, key ) ) : undefined; }, removeData: function( key ) { return this.each( function() { jQuery.removeData( this, key ); } ); } } ); jQuery.extend( { queue: function( elem, type, data ) { var queue; if ( elem ) { type = ( type || "fx" ) + "queue"; queue = jQuery._data( elem, type ); // Speed up dequeue by getting out quickly if this is just a lookup if ( data ) { if ( !queue || jQuery.isArray( data ) ) { queue = jQuery._data( elem, type, jQuery.makeArray( data ) ); } else { queue.push( data ); } } return queue || []; } }, dequeue: function( elem, type ) { type = type || "fx"; var queue = jQuery.queue( elem, type ), startLength = queue.length, fn = queue.shift(), hooks = jQuery._queueHooks( elem, type ), next = function() { jQuery.dequeue( elem, type ); }; // If the fx queue is dequeued, always remove the progress sentinel if ( fn === "inprogress" ) { fn = queue.shift(); startLength--; } if ( fn ) { // Add a progress sentinel to prevent the fx queue from being // automatically dequeued if ( type === "fx" ) { queue.unshift( "inprogress" ); } // clear up the last queue stop function delete hooks.stop; fn.call( elem, next, hooks ); } if ( !startLength && hooks ) { hooks.empty.fire(); } }, // not intended for public consumption - generates a queueHooks object, // or returns the current one _queueHooks: function( elem, type ) { var key = type + "queueHooks"; return jQuery._data( elem, key ) || jQuery._data( elem, key, { empty: jQuery.Callbacks( "once memory" ).add( function() { jQuery._removeData( elem, type + "queue" ); jQuery._removeData( elem, key ); } ) } ); } } ); jQuery.fn.extend( { queue: function( type, data ) { var setter = 2; if ( typeof type !== "string" ) { data = type; type = "fx"; setter--; } if ( arguments.length < setter ) { return jQuery.queue( this[ 0 ], type ); } return data === undefined ? this : this.each( function() { var queue = jQuery.queue( this, type, data ); // ensure a hooks for this queue jQuery._queueHooks( this, type ); if ( type === "fx" && queue[ 0 ] !== "inprogress" ) { jQuery.dequeue( this, type ); } } ); }, dequeue: function( type ) { return this.each( function() { jQuery.dequeue( this, type ); } ); }, clearQueue: function( type ) { return this.queue( type || "fx", [] ); }, // Get a promise resolved when queues of a certain type // are emptied (fx is the type by default) promise: function( type, obj ) { var tmp, count = 1, defer = jQuery.Deferred(), elements = this, i = this.length, resolve = function() { if ( !( --count ) ) { defer.resolveWith( elements, [ elements ] ); } }; if ( typeof type !== "string" ) { obj = type; type = undefined; } type = type || "fx"; while ( i-- ) { tmp = jQuery._data( elements[ i ], type + "queueHooks" ); if ( tmp && tmp.empty ) { count++; tmp.empty.add( resolve ); } } resolve(); return defer.promise( obj ); } } ); ( function() { var shrinkWrapBlocksVal; support.shrinkWrapBlocks = function() { if ( shrinkWrapBlocksVal != null ) { return shrinkWrapBlocksVal; } // Will be changed later if needed. shrinkWrapBlocksVal = false; // Minified: var b,c,d var div, body, container; body = document.getElementsByTagName( "body" )[ 0 ]; if ( !body || !body.style ) { // Test fired too early or in an unsupported environment, exit. return; } // Setup div = document.createElement( "div" ); container = document.createElement( "div" ); container.style.cssText = "position:absolute;border:0;width:0;height:0;top:0;left:-9999px"; body.appendChild( container ).appendChild( div ); // Support: IE6 // Check if elements with layout shrink-wrap their children if ( typeof div.style.zoom !== "undefined" ) { // Reset CSS: box-sizing; display; margin; border div.style.cssText = // Support: Firefox<29, Android 2.3 // Vendor-prefix box-sizing "-webkit-box-sizing:content-box;-moz-box-sizing:content-box;" + "box-sizing:content-box;display:block;margin:0;border:0;" + "padding:1px;width:1px;zoom:1"; div.appendChild( document.createElement( "div" ) ).style.width = "5px"; shrinkWrapBlocksVal = div.offsetWidth !== 3; } body.removeChild( container ); return shrinkWrapBlocksVal; }; } )(); var pnum = ( /[+-]?(?:\d*\.|)\d+(?:[eE][+-]?\d+|)/ ).source; var rcssNum = new RegExp( "^(?:([+-])=|)(" + pnum + ")([a-z%]*)$", "i" ); var cssExpand = [ "Top", "Right", "Bottom", "Left" ]; var isHidden = function( elem, el ) { // isHidden might be called from jQuery#filter function; // in that case, element will be second argument elem = el || elem; return jQuery.css( elem, "display" ) === "none" || !jQuery.contains( elem.ownerDocument, elem ); }; function adjustCSS( elem, prop, valueParts, tween ) { var adjusted, scale = 1, maxIterations = 20, currentValue = tween ? function() { return tween.cur(); } : function() { return jQuery.css( elem, prop, "" ); }, initial = currentValue(), unit = valueParts && valueParts[ 3 ] || ( jQuery.cssNumber[ prop ] ? "" : "px" ), // Starting value computation is required for potential unit mismatches initialInUnit = ( jQuery.cssNumber[ prop ] || unit !== "px" && +initial ) && rcssNum.exec( jQuery.css( elem, prop ) ); if ( initialInUnit && initialInUnit[ 3 ] !== unit ) { // Trust units reported by jQuery.css unit = unit || initialInUnit[ 3 ]; // Make sure we update the tween properties later on valueParts = valueParts || []; // Iteratively approximate from a nonzero starting point initialInUnit = +initial || 1; do { // If previous iteration zeroed out, double until we get *something*. // Use string for doubling so we don't accidentally see scale as unchanged below scale = scale || ".5"; // Adjust and apply initialInUnit = initialInUnit / scale; jQuery.style( elem, prop, initialInUnit + unit ); // Update scale, tolerating zero or NaN from tween.cur() // Break the loop if scale is unchanged or perfect, or if we've just had enough. } while ( scale !== ( scale = currentValue() / initial ) && scale !== 1 && --maxIterations ); } if ( valueParts ) { initialInUnit = +initialInUnit || +initial || 0; // Apply relative offset (+=/-=) if specified adjusted = valueParts[ 1 ] ? initialInUnit + ( valueParts[ 1 ] + 1 ) * valueParts[ 2 ] : +valueParts[ 2 ]; if ( tween ) { tween.unit = unit; tween.start = initialInUnit; tween.end = adjusted; } } return adjusted; } // Multifunctional method to get and set values of a collection // The value/s can optionally be executed if it's a function var access = function( elems, fn, key, value, chainable, emptyGet, raw ) { var i = 0, length = elems.length, bulk = key == null; // Sets many values if ( jQuery.type( key ) === "object" ) { chainable = true; for ( i in key ) { access( elems, fn, i, key[ i ], true, emptyGet, raw ); } // Sets one value } else if ( value !== undefined ) { chainable = true; if ( !jQuery.isFunction( value ) ) { raw = true; } if ( bulk ) { // Bulk operations run against the entire set if ( raw ) { fn.call( elems, value ); fn = null; // ...except when executing function values } else { bulk = fn; fn = function( elem, key, value ) { return bulk.call( jQuery( elem ), value ); }; } } if ( fn ) { for ( ; i < length; i++ ) { fn( elems[ i ], key, raw ? value : value.call( elems[ i ], i, fn( elems[ i ], key ) ) ); } } } return chainable ? elems : // Gets bulk ? fn.call( elems ) : length ? fn( elems[ 0 ], key ) : emptyGet; }; var rcheckableType = ( /^(?:checkbox|radio)$/i ); var rtagName = ( /<([\w:-]+)/ ); var rscriptType = ( /^$|\/(?:java|ecma)script/i ); var rleadingWhitespace = ( /^\s+/ ); var nodeNames = "abbr|article|aside|audio|bdi|canvas|data|datalist|" + "details|dialog|figcaption|figure|footer|header|hgroup|main|" + "mark|meter|nav|output|picture|progress|section|summary|template|time|video"; function createSafeFragment( document ) { var list = nodeNames.split( "|" ), safeFrag = document.createDocumentFragment(); if ( safeFrag.createElement ) { while ( list.length ) { safeFrag.createElement( list.pop() ); } } return safeFrag; } ( function() { var div = document.createElement( "div" ), fragment = document.createDocumentFragment(), input = document.createElement( "input" ); // Setup div.innerHTML = "
a"; // IE strips leading whitespace when .innerHTML is used support.leadingWhitespace = div.firstChild.nodeType === 3; // Make sure that tbody elements aren't automatically inserted // IE will insert them into empty tables support.tbody = !div.getElementsByTagName( "tbody" ).length; // Make sure that link elements get serialized correctly by innerHTML // This requires a wrapper element in IE support.htmlSerialize = !!div.getElementsByTagName( "link" ).length; // Makes sure cloning an html5 element does not cause problems // Where outerHTML is undefined, this still works support.html5Clone = document.createElement( "nav" ).cloneNode( true ).outerHTML !== "<:nav>"; // Check if a disconnected checkbox will retain its checked // value of true after appended to the DOM (IE6/7) input.type = "checkbox"; input.checked = true; fragment.appendChild( input ); support.appendChecked = input.checked; // Make sure textarea (and checkbox) defaultValue is properly cloned // Support: IE6-IE11+ div.innerHTML = ""; support.noCloneChecked = !!div.cloneNode( true ).lastChild.defaultValue; // #11217 - WebKit loses check when the name is after the checked attribute fragment.appendChild( div ); // Support: Windows Web Apps (WWA) // `name` and `type` must use .setAttribute for WWA (#14901) input = document.createElement( "input" ); input.setAttribute( "type", "radio" ); input.setAttribute( "checked", "checked" ); input.setAttribute( "name", "t" ); div.appendChild( input ); // Support: Safari 5.1, iOS 5.1, Android 4.x, Android 2.3 // old WebKit doesn't clone checked state correctly in fragments support.checkClone = div.cloneNode( true ).cloneNode( true ).lastChild.checked; // Support: IE<9 // Cloned elements keep attachEvent handlers, we use addEventListener on IE9+ support.noCloneEvent = !!div.addEventListener; // Support: IE<9 // Since attributes and properties are the same in IE, // cleanData must set properties to undefined rather than use removeAttribute div[ jQuery.expando ] = 1; support.attributes = !div.getAttribute( jQuery.expando ); } )(); // We have to close these tags to support XHTML (#13200) var wrapMap = { option: [ 1, "" ], legend: [ 1, "
", "
" ], area: [ 1, "", "" ], // Support: IE8 param: [ 1, "", "" ], thead: [ 1, "", "
" ], tr: [ 2, "", "
" ], col: [ 2, "", "
" ], td: [ 3, "", "
" ], // IE6-8 can't serialize link, script, style, or any html5 (NoScope) tags, // unless wrapped in a div with non-breaking characters in front of it. _default: support.htmlSerialize ? [ 0, "", "" ] : [ 1, "X
", "
" ] }; // Support: IE8-IE9 wrapMap.optgroup = wrapMap.option; wrapMap.tbody = wrapMap.tfoot = wrapMap.colgroup = wrapMap.caption = wrapMap.thead; wrapMap.th = wrapMap.td; function getAll( context, tag ) { var elems, elem, i = 0, found = typeof context.getElementsByTagName !== "undefined" ? context.getElementsByTagName( tag || "*" ) : typeof context.querySelectorAll !== "undefined" ? context.querySelectorAll( tag || "*" ) : undefined; if ( !found ) { for ( found = [], elems = context.childNodes || context; ( elem = elems[ i ] ) != null; i++ ) { if ( !tag || jQuery.nodeName( elem, tag ) ) { found.push( elem ); } else { jQuery.merge( found, getAll( elem, tag ) ); } } } return tag === undefined || tag && jQuery.nodeName( context, tag ) ? jQuery.merge( [ context ], found ) : found; } // Mark scripts as having already been evaluated function setGlobalEval( elems, refElements ) { var elem, i = 0; for ( ; ( elem = elems[ i ] ) != null; i++ ) { jQuery._data( elem, "globalEval", !refElements || jQuery._data( refElements[ i ], "globalEval" ) ); } } var rhtml = /<|&#?\w+;/, rtbody = / from table fragments if ( !support.tbody ) { // String was a , *may* have spurious elem = tag === "table" && !rtbody.test( elem ) ? tmp.firstChild : // String was a bare or wrap[ 1 ] === "
" && !rtbody.test( elem ) ? tmp : 0; j = elem && elem.childNodes.length; while ( j-- ) { if ( jQuery.nodeName( ( tbody = elem.childNodes[ j ] ), "tbody" ) && !tbody.childNodes.length ) { elem.removeChild( tbody ); } } } jQuery.merge( nodes, tmp.childNodes ); // Fix #12392 for WebKit and IE > 9 tmp.textContent = ""; // Fix #12392 for oldIE while ( tmp.firstChild ) { tmp.removeChild( tmp.firstChild ); } // Remember the top-level container for proper cleanup tmp = safe.lastChild; } } } // Fix #11356: Clear elements from fragment if ( tmp ) { safe.removeChild( tmp ); } // Reset defaultChecked for any radios and checkboxes // about to be appended to the DOM in IE 6/7 (#8060) if ( !support.appendChecked ) { jQuery.grep( getAll( nodes, "input" ), fixDefaultChecked ); } i = 0; while ( ( elem = nodes[ i++ ] ) ) { // Skip elements already in the context collection (trac-4087) if ( selection && jQuery.inArray( elem, selection ) > -1 ) { if ( ignored ) { ignored.push( elem ); } continue; } contains = jQuery.contains( elem.ownerDocument, elem ); // Append to fragment tmp = getAll( safe.appendChild( elem ), "script" ); // Preserve script evaluation history if ( contains ) { setGlobalEval( tmp ); } // Capture executables if ( scripts ) { j = 0; while ( ( elem = tmp[ j++ ] ) ) { if ( rscriptType.test( elem.type || "" ) ) { scripts.push( elem ); } } } } tmp = null; return safe; } ( function() { var i, eventName, div = document.createElement( "div" ); // Support: IE<9 (lack submit/change bubble), Firefox (lack focus(in | out) events) for ( i in { submit: true, change: true, focusin: true } ) { eventName = "on" + i; if ( !( support[ i ] = eventName in window ) ) { // Beware of CSP restrictions (https://developer.mozilla.org/en/Security/CSP) div.setAttribute( eventName, "t" ); support[ i ] = div.attributes[ eventName ].expando === false; } } // Null elements to avoid leaks in IE. div = null; } )(); var rformElems = /^(?:input|select|textarea)$/i, rkeyEvent = /^key/, rmouseEvent = /^(?:mouse|pointer|contextmenu|drag|drop)|click/, rfocusMorph = /^(?:focusinfocus|focusoutblur)$/, rtypenamespace = /^([^.]*)(?:\.(.+)|)/; function returnTrue() { return true; } function returnFalse() { return false; } // Support: IE9 // See #13393 for more info function safeActiveElement() { try { return document.activeElement; } catch ( err ) { } } function on( elem, types, selector, data, fn, one ) { var origFn, type; // Types can be a map of types/handlers if ( typeof types === "object" ) { // ( types-Object, selector, data ) if ( typeof selector !== "string" ) { // ( types-Object, data ) data = data || selector; selector = undefined; } for ( type in types ) { on( elem, type, selector, data, types[ type ], one ); } return elem; } if ( data == null && fn == null ) { // ( types, fn ) fn = selector; data = selector = undefined; } else if ( fn == null ) { if ( typeof selector === "string" ) { // ( types, selector, fn ) fn = data; data = undefined; } else { // ( types, data, fn ) fn = data; data = selector; selector = undefined; } } if ( fn === false ) { fn = returnFalse; } else if ( !fn ) { return elem; } if ( one === 1 ) { origFn = fn; fn = function( event ) { // Can use an empty set, since event contains the info jQuery().off( event ); return origFn.apply( this, arguments ); }; // Use same guid so caller can remove using origFn fn.guid = origFn.guid || ( origFn.guid = jQuery.guid++ ); } return elem.each( function() { jQuery.event.add( this, types, fn, data, selector ); } ); } /* * Helper functions for managing events -- not part of the public interface. * Props to Dean Edwards' addEvent library for many of the ideas. */ jQuery.event = { global: {}, add: function( elem, types, handler, data, selector ) { var tmp, events, t, handleObjIn, special, eventHandle, handleObj, handlers, type, namespaces, origType, elemData = jQuery._data( elem ); // Don't attach events to noData or text/comment nodes (but allow plain objects) if ( !elemData ) { return; } // Caller can pass in an object of custom data in lieu of the handler if ( handler.handler ) { handleObjIn = handler; handler = handleObjIn.handler; selector = handleObjIn.selector; } // Make sure that the handler has a unique ID, used to find/remove it later if ( !handler.guid ) { handler.guid = jQuery.guid++; } // Init the element's event structure and main handler, if this is the first if ( !( events = elemData.events ) ) { events = elemData.events = {}; } if ( !( eventHandle = elemData.handle ) ) { eventHandle = elemData.handle = function( e ) { // Discard the second event of a jQuery.event.trigger() and // when an event is called after a page has unloaded return typeof jQuery !== "undefined" && ( !e || jQuery.event.triggered !== e.type ) ? jQuery.event.dispatch.apply( eventHandle.elem, arguments ) : undefined; }; // Add elem as a property of the handle fn to prevent a memory leak // with IE non-native events eventHandle.elem = elem; } // Handle multiple events separated by a space types = ( types || "" ).match( rnotwhite ) || [ "" ]; t = types.length; while ( t-- ) { tmp = rtypenamespace.exec( types[ t ] ) || []; type = origType = tmp[ 1 ]; namespaces = ( tmp[ 2 ] || "" ).split( "." ).sort(); // There *must* be a type, no attaching namespace-only handlers if ( !type ) { continue; } // If event changes its type, use the special event handlers for the changed type special = jQuery.event.special[ type ] || {}; // If selector defined, determine special event api type, otherwise given type type = ( selector ? special.delegateType : special.bindType ) || type; // Update special based on newly reset type special = jQuery.event.special[ type ] || {}; // handleObj is passed to all event handlers handleObj = jQuery.extend( { type: type, origType: origType, data: data, handler: handler, guid: handler.guid, selector: selector, needsContext: selector && jQuery.expr.match.needsContext.test( selector ), namespace: namespaces.join( "." ) }, handleObjIn ); // Init the event handler queue if we're the first if ( !( handlers = events[ type ] ) ) { handlers = events[ type ] = []; handlers.delegateCount = 0; // Only use addEventListener/attachEvent if the special events handler returns false if ( !special.setup || special.setup.call( elem, data, namespaces, eventHandle ) === false ) { // Bind the global event handler to the element if ( elem.addEventListener ) { elem.addEventListener( type, eventHandle, false ); } else if ( elem.attachEvent ) { elem.attachEvent( "on" + type, eventHandle ); } } } if ( special.add ) { special.add.call( elem, handleObj ); if ( !handleObj.handler.guid ) { handleObj.handler.guid = handler.guid; } } // Add to the element's handler list, delegates in front if ( selector ) { handlers.splice( handlers.delegateCount++, 0, handleObj ); } else { handlers.push( handleObj ); } // Keep track of which events have ever been used, for event optimization jQuery.event.global[ type ] = true; } // Nullify elem to prevent memory leaks in IE elem = null; }, // Detach an event or set of events from an element remove: function( elem, types, handler, selector, mappedTypes ) { var j, handleObj, tmp, origCount, t, events, special, handlers, type, namespaces, origType, elemData = jQuery.hasData( elem ) && jQuery._data( elem ); if ( !elemData || !( events = elemData.events ) ) { return; } // Once for each type.namespace in types; type may be omitted types = ( types || "" ).match( rnotwhite ) || [ "" ]; t = types.length; while ( t-- ) { tmp = rtypenamespace.exec( types[ t ] ) || []; type = origType = tmp[ 1 ]; namespaces = ( tmp[ 2 ] || "" ).split( "." ).sort(); // Unbind all events (on this namespace, if provided) for the element if ( !type ) { for ( type in events ) { jQuery.event.remove( elem, type + types[ t ], handler, selector, true ); } continue; } special = jQuery.event.special[ type ] || {}; type = ( selector ? special.delegateType : special.bindType ) || type; handlers = events[ type ] || []; tmp = tmp[ 2 ] && new RegExp( "(^|\\.)" + namespaces.join( "\\.(?:.*\\.|)" ) + "(\\.|$)" ); // Remove matching events origCount = j = handlers.length; while ( j-- ) { handleObj = handlers[ j ]; if ( ( mappedTypes || origType === handleObj.origType ) && ( !handler || handler.guid === handleObj.guid ) && ( !tmp || tmp.test( handleObj.namespace ) ) && ( !selector || selector === handleObj.selector || selector === "**" && handleObj.selector ) ) { handlers.splice( j, 1 ); if ( handleObj.selector ) { handlers.delegateCount--; } if ( special.remove ) { special.remove.call( elem, handleObj ); } } } // Remove generic event handler if we removed something and no more handlers exist // (avoids potential for endless recursion during removal of special event handlers) if ( origCount && !handlers.length ) { if ( !special.teardown || special.teardown.call( elem, namespaces, elemData.handle ) === false ) { jQuery.removeEvent( elem, type, elemData.handle ); } delete events[ type ]; } } // Remove the expando if it's no longer used if ( jQuery.isEmptyObject( events ) ) { delete elemData.handle; // removeData also checks for emptiness and clears the expando if empty // so use it instead of delete jQuery._removeData( elem, "events" ); } }, trigger: function( event, data, elem, onlyHandlers ) { var handle, ontype, cur, bubbleType, special, tmp, i, eventPath = [ elem || document ], type = hasOwn.call( event, "type" ) ? event.type : event, namespaces = hasOwn.call( event, "namespace" ) ? event.namespace.split( "." ) : []; cur = tmp = elem = elem || document; // Don't do events on text and comment nodes if ( elem.nodeType === 3 || elem.nodeType === 8 ) { return; } // focus/blur morphs to focusin/out; ensure we're not firing them right now if ( rfocusMorph.test( type + jQuery.event.triggered ) ) { return; } if ( type.indexOf( "." ) > -1 ) { // Namespaced trigger; create a regexp to match event type in handle() namespaces = type.split( "." ); type = namespaces.shift(); namespaces.sort(); } ontype = type.indexOf( ":" ) < 0 && "on" + type; // Caller can pass in a jQuery.Event object, Object, or just an event type string event = event[ jQuery.expando ] ? event : new jQuery.Event( type, typeof event === "object" && event ); // Trigger bitmask: & 1 for native handlers; & 2 for jQuery (always true) event.isTrigger = onlyHandlers ? 2 : 3; event.namespace = namespaces.join( "." ); event.rnamespace = event.namespace ? new RegExp( "(^|\\.)" + namespaces.join( "\\.(?:.*\\.|)" ) + "(\\.|$)" ) : null; // Clean up the event in case it is being reused event.result = undefined; if ( !event.target ) { event.target = elem; } // Clone any incoming data and prepend the event, creating the handler arg list data = data == null ? [ event ] : jQuery.makeArray( data, [ event ] ); // Allow special events to draw outside the lines special = jQuery.event.special[ type ] || {}; if ( !onlyHandlers && special.trigger && special.trigger.apply( elem, data ) === false ) { return; } // Determine event propagation path in advance, per W3C events spec (#9951) // Bubble up to document, then to window; watch for a global ownerDocument var (#9724) if ( !onlyHandlers && !special.noBubble && !jQuery.isWindow( elem ) ) { bubbleType = special.delegateType || type; if ( !rfocusMorph.test( bubbleType + type ) ) { cur = cur.parentNode; } for ( ; cur; cur = cur.parentNode ) { eventPath.push( cur ); tmp = cur; } // Only add window if we got to document (e.g., not plain obj or detached DOM) if ( tmp === ( elem.ownerDocument || document ) ) { eventPath.push( tmp.defaultView || tmp.parentWindow || window ); } } // Fire handlers on the event path i = 0; while ( ( cur = eventPath[ i++ ] ) && !event.isPropagationStopped() ) { event.type = i > 1 ? bubbleType : special.bindType || type; // jQuery handler handle = ( jQuery._data( cur, "events" ) || {} )[ event.type ] && jQuery._data( cur, "handle" ); if ( handle ) { handle.apply( cur, data ); } // Native handler handle = ontype && cur[ ontype ]; if ( handle && handle.apply && acceptData( cur ) ) { event.result = handle.apply( cur, data ); if ( event.result === false ) { event.preventDefault(); } } } event.type = type; // If nobody prevented the default action, do it now if ( !onlyHandlers && !event.isDefaultPrevented() ) { if ( ( !special._default || special._default.apply( eventPath.pop(), data ) === false ) && acceptData( elem ) ) { // Call a native DOM method on the target with the same name name as the event. // Can't use an .isFunction() check here because IE6/7 fails that test. // Don't do default actions on window, that's where global variables be (#6170) if ( ontype && elem[ type ] && !jQuery.isWindow( elem ) ) { // Don't re-trigger an onFOO event when we call its FOO() method tmp = elem[ ontype ]; if ( tmp ) { elem[ ontype ] = null; } // Prevent re-triggering of the same event, since we already bubbled it above jQuery.event.triggered = type; try { elem[ type ](); } catch ( e ) { // IE<9 dies on focus/blur to hidden element (#1486,#12518) // only reproducible on winXP IE8 native, not IE9 in IE8 mode } jQuery.event.triggered = undefined; if ( tmp ) { elem[ ontype ] = tmp; } } } } return event.result; }, dispatch: function( event ) { // Make a writable jQuery.Event from the native event object event = jQuery.event.fix( event ); var i, j, ret, matched, handleObj, handlerQueue = [], args = slice.call( arguments ), handlers = ( jQuery._data( this, "events" ) || {} )[ event.type ] || [], special = jQuery.event.special[ event.type ] || {}; // Use the fix-ed jQuery.Event rather than the (read-only) native event args[ 0 ] = event; event.delegateTarget = this; // Call the preDispatch hook for the mapped type, and let it bail if desired if ( special.preDispatch && special.preDispatch.call( this, event ) === false ) { return; } // Determine handlers handlerQueue = jQuery.event.handlers.call( this, event, handlers ); // Run delegates first; they may want to stop propagation beneath us i = 0; while ( ( matched = handlerQueue[ i++ ] ) && !event.isPropagationStopped() ) { event.currentTarget = matched.elem; j = 0; while ( ( handleObj = matched.handlers[ j++ ] ) && !event.isImmediatePropagationStopped() ) { // Triggered event must either 1) have no namespace, or 2) have namespace(s) // a subset or equal to those in the bound event (both can have no namespace). if ( !event.rnamespace || event.rnamespace.test( handleObj.namespace ) ) { event.handleObj = handleObj; event.data = handleObj.data; ret = ( ( jQuery.event.special[ handleObj.origType ] || {} ).handle || handleObj.handler ).apply( matched.elem, args ); if ( ret !== undefined ) { if ( ( event.result = ret ) === false ) { event.preventDefault(); event.stopPropagation(); } } } } } // Call the postDispatch hook for the mapped type if ( special.postDispatch ) { special.postDispatch.call( this, event ); } return event.result; }, handlers: function( event, handlers ) { var i, matches, sel, handleObj, handlerQueue = [], delegateCount = handlers.delegateCount, cur = event.target; // Support (at least): Chrome, IE9 // Find delegate handlers // Black-hole SVG instance trees (#13180) // // Support: Firefox<=42+ // Avoid non-left-click in FF but don't block IE radio events (#3861, gh-2343) if ( delegateCount && cur.nodeType && ( event.type !== "click" || isNaN( event.button ) || event.button < 1 ) ) { /* jshint eqeqeq: false */ for ( ; cur != this; cur = cur.parentNode || this ) { /* jshint eqeqeq: true */ // Don't check non-elements (#13208) // Don't process clicks on disabled elements (#6911, #8165, #11382, #11764) if ( cur.nodeType === 1 && ( cur.disabled !== true || event.type !== "click" ) ) { matches = []; for ( i = 0; i < delegateCount; i++ ) { handleObj = handlers[ i ]; // Don't conflict with Object.prototype properties (#13203) sel = handleObj.selector + " "; if ( matches[ sel ] === undefined ) { matches[ sel ] = handleObj.needsContext ? jQuery( sel, this ).index( cur ) > -1 : jQuery.find( sel, this, null, [ cur ] ).length; } if ( matches[ sel ] ) { matches.push( handleObj ); } } if ( matches.length ) { handlerQueue.push( { elem: cur, handlers: matches } ); } } } } // Add the remaining (directly-bound) handlers if ( delegateCount < handlers.length ) { handlerQueue.push( { elem: this, handlers: handlers.slice( delegateCount ) } ); } return handlerQueue; }, fix: function( event ) { if ( event[ jQuery.expando ] ) { return event; } // Create a writable copy of the event object and normalize some properties var i, prop, copy, type = event.type, originalEvent = event, fixHook = this.fixHooks[ type ]; if ( !fixHook ) { this.fixHooks[ type ] = fixHook = rmouseEvent.test( type ) ? this.mouseHooks : rkeyEvent.test( type ) ? this.keyHooks : {}; } copy = fixHook.props ? this.props.concat( fixHook.props ) : this.props; event = new jQuery.Event( originalEvent ); i = copy.length; while ( i-- ) { prop = copy[ i ]; event[ prop ] = originalEvent[ prop ]; } // Support: IE<9 // Fix target property (#1925) if ( !event.target ) { event.target = originalEvent.srcElement || document; } // Support: Safari 6-8+ // Target should not be a text node (#504, #13143) if ( event.target.nodeType === 3 ) { event.target = event.target.parentNode; } // Support: IE<9 // For mouse/key events, metaKey==false if it's undefined (#3368, #11328) event.metaKey = !!event.metaKey; return fixHook.filter ? fixHook.filter( event, originalEvent ) : event; }, // Includes some event props shared by KeyEvent and MouseEvent props: ( "altKey bubbles cancelable ctrlKey currentTarget detail eventPhase " + "metaKey relatedTarget shiftKey target timeStamp view which" ).split( " " ), fixHooks: {}, keyHooks: { props: "char charCode key keyCode".split( " " ), filter: function( event, original ) { // Add which for key events if ( event.which == null ) { event.which = original.charCode != null ? original.charCode : original.keyCode; } return event; } }, mouseHooks: { props: ( "button buttons clientX clientY fromElement offsetX offsetY " + "pageX pageY screenX screenY toElement" ).split( " " ), filter: function( event, original ) { var body, eventDoc, doc, button = original.button, fromElement = original.fromElement; // Calculate pageX/Y if missing and clientX/Y available if ( event.pageX == null && original.clientX != null ) { eventDoc = event.target.ownerDocument || document; doc = eventDoc.documentElement; body = eventDoc.body; event.pageX = original.clientX + ( doc && doc.scrollLeft || body && body.scrollLeft || 0 ) - ( doc && doc.clientLeft || body && body.clientLeft || 0 ); event.pageY = original.clientY + ( doc && doc.scrollTop || body && body.scrollTop || 0 ) - ( doc && doc.clientTop || body && body.clientTop || 0 ); } // Add relatedTarget, if necessary if ( !event.relatedTarget && fromElement ) { event.relatedTarget = fromElement === event.target ? original.toElement : fromElement; } // Add which for click: 1 === left; 2 === middle; 3 === right // Note: button is not normalized, so don't use it if ( !event.which && button !== undefined ) { event.which = ( button & 1 ? 1 : ( button & 2 ? 3 : ( button & 4 ? 2 : 0 ) ) ); } return event; } }, special: { load: { // Prevent triggered image.load events from bubbling to window.load noBubble: true }, focus: { // Fire native event if possible so blur/focus sequence is correct trigger: function() { if ( this !== safeActiveElement() && this.focus ) { try { this.focus(); return false; } catch ( e ) { // Support: IE<9 // If we error on focus to hidden element (#1486, #12518), // let .trigger() run the handlers } } }, delegateType: "focusin" }, blur: { trigger: function() { if ( this === safeActiveElement() && this.blur ) { this.blur(); return false; } }, delegateType: "focusout" }, click: { // For checkbox, fire native event so checked state will be right trigger: function() { if ( jQuery.nodeName( this, "input" ) && this.type === "checkbox" && this.click ) { this.click(); return false; } }, // For cross-browser consistency, don't fire native .click() on links _default: function( event ) { return jQuery.nodeName( event.target, "a" ); } }, beforeunload: { postDispatch: function( event ) { // Support: Firefox 20+ // Firefox doesn't alert if the returnValue field is not set. if ( event.result !== undefined && event.originalEvent ) { event.originalEvent.returnValue = event.result; } } } }, // Piggyback on a donor event to simulate a different one simulate: function( type, elem, event ) { var e = jQuery.extend( new jQuery.Event(), event, { type: type, isSimulated: true // Previously, `originalEvent: {}` was set here, so stopPropagation call // would not be triggered on donor event, since in our own // jQuery.event.stopPropagation function we had a check for existence of // originalEvent.stopPropagation method, so, consequently it would be a noop. // // Guard for simulated events was moved to jQuery.event.stopPropagation function // since `originalEvent` should point to the original event for the // constancy with other events and for more focused logic } ); jQuery.event.trigger( e, null, elem ); if ( e.isDefaultPrevented() ) { event.preventDefault(); } } }; jQuery.removeEvent = document.removeEventListener ? function( elem, type, handle ) { // This "if" is needed for plain objects if ( elem.removeEventListener ) { elem.removeEventListener( type, handle ); } } : function( elem, type, handle ) { var name = "on" + type; if ( elem.detachEvent ) { // #8545, #7054, preventing memory leaks for custom events in IE6-8 // detachEvent needed property on element, by name of that event, // to properly expose it to GC if ( typeof elem[ name ] === "undefined" ) { elem[ name ] = null; } elem.detachEvent( name, handle ); } }; jQuery.Event = function( src, props ) { // Allow instantiation without the 'new' keyword if ( !( this instanceof jQuery.Event ) ) { return new jQuery.Event( src, props ); } // Event object if ( src && src.type ) { this.originalEvent = src; this.type = src.type; // Events bubbling up the document may have been marked as prevented // by a handler lower down the tree; reflect the correct value. this.isDefaultPrevented = src.defaultPrevented || src.defaultPrevented === undefined && // Support: IE < 9, Android < 4.0 src.returnValue === false ? returnTrue : returnFalse; // Event type } else { this.type = src; } // Put explicitly provided properties onto the event object if ( props ) { jQuery.extend( this, props ); } // Create a timestamp if incoming event doesn't have one this.timeStamp = src && src.timeStamp || jQuery.now(); // Mark it as fixed this[ jQuery.expando ] = true; }; // jQuery.Event is based on DOM3 Events as specified by the ECMAScript Language Binding // http://www.w3.org/TR/2003/WD-DOM-Level-3-Events-20030331/ecma-script-binding.html jQuery.Event.prototype = { constructor: jQuery.Event, isDefaultPrevented: returnFalse, isPropagationStopped: returnFalse, isImmediatePropagationStopped: returnFalse, preventDefault: function() { var e = this.originalEvent; this.isDefaultPrevented = returnTrue; if ( !e ) { return; } // If preventDefault exists, run it on the original event if ( e.preventDefault ) { e.preventDefault(); // Support: IE // Otherwise set the returnValue property of the original event to false } else { e.returnValue = false; } }, stopPropagation: function() { var e = this.originalEvent; this.isPropagationStopped = returnTrue; if ( !e || this.isSimulated ) { return; } // If stopPropagation exists, run it on the original event if ( e.stopPropagation ) { e.stopPropagation(); } // Support: IE // Set the cancelBubble property of the original event to true e.cancelBubble = true; }, stopImmediatePropagation: function() { var e = this.originalEvent; this.isImmediatePropagationStopped = returnTrue; if ( e && e.stopImmediatePropagation ) { e.stopImmediatePropagation(); } this.stopPropagation(); } }; // Create mouseenter/leave events using mouseover/out and event-time checks // so that event delegation works in jQuery. // Do the same for pointerenter/pointerleave and pointerover/pointerout // // Support: Safari 7 only // Safari sends mouseenter too often; see: // https://code.google.com/p/chromium/issues/detail?id=470258 // for the description of the bug (it existed in older Chrome versions as well). jQuery.each( { mouseenter: "mouseover", mouseleave: "mouseout", pointerenter: "pointerover", pointerleave: "pointerout" }, function( orig, fix ) { jQuery.event.special[ orig ] = { delegateType: fix, bindType: fix, handle: function( event ) { var ret, target = this, related = event.relatedTarget, handleObj = event.handleObj; // For mouseenter/leave call the handler if related is outside the target. // NB: No relatedTarget if the mouse left/entered the browser window if ( !related || ( related !== target && !jQuery.contains( target, related ) ) ) { event.type = handleObj.origType; ret = handleObj.handler.apply( this, arguments ); event.type = fix; } return ret; } }; } ); // IE submit delegation if ( !support.submit ) { jQuery.event.special.submit = { setup: function() { // Only need this for delegated form submit events if ( jQuery.nodeName( this, "form" ) ) { return false; } // Lazy-add a submit handler when a descendant form may potentially be submitted jQuery.event.add( this, "click._submit keypress._submit", function( e ) { // Node name check avoids a VML-related crash in IE (#9807) var elem = e.target, form = jQuery.nodeName( elem, "input" ) || jQuery.nodeName( elem, "button" ) ? // Support: IE <=8 // We use jQuery.prop instead of elem.form // to allow fixing the IE8 delegated submit issue (gh-2332) // by 3rd party polyfills/workarounds. jQuery.prop( elem, "form" ) : undefined; if ( form && !jQuery._data( form, "submit" ) ) { jQuery.event.add( form, "submit._submit", function( event ) { event._submitBubble = true; } ); jQuery._data( form, "submit", true ); } } ); // return undefined since we don't need an event listener }, postDispatch: function( event ) { // If form was submitted by the user, bubble the event up the tree if ( event._submitBubble ) { delete event._submitBubble; if ( this.parentNode && !event.isTrigger ) { jQuery.event.simulate( "submit", this.parentNode, event ); } } }, teardown: function() { // Only need this for delegated form submit events if ( jQuery.nodeName( this, "form" ) ) { return false; } // Remove delegated handlers; cleanData eventually reaps submit handlers attached above jQuery.event.remove( this, "._submit" ); } }; } // IE change delegation and checkbox/radio fix if ( !support.change ) { jQuery.event.special.change = { setup: function() { if ( rformElems.test( this.nodeName ) ) { // IE doesn't fire change on a check/radio until blur; trigger it on click // after a propertychange. Eat the blur-change in special.change.handle. // This still fires onchange a second time for check/radio after blur. if ( this.type === "checkbox" || this.type === "radio" ) { jQuery.event.add( this, "propertychange._change", function( event ) { if ( event.originalEvent.propertyName === "checked" ) { this._justChanged = true; } } ); jQuery.event.add( this, "click._change", function( event ) { if ( this._justChanged && !event.isTrigger ) { this._justChanged = false; } // Allow triggered, simulated change events (#11500) jQuery.event.simulate( "change", this, event ); } ); } return false; } // Delegated event; lazy-add a change handler on descendant inputs jQuery.event.add( this, "beforeactivate._change", function( e ) { var elem = e.target; if ( rformElems.test( elem.nodeName ) && !jQuery._data( elem, "change" ) ) { jQuery.event.add( elem, "change._change", function( event ) { if ( this.parentNode && !event.isSimulated && !event.isTrigger ) { jQuery.event.simulate( "change", this.parentNode, event ); } } ); jQuery._data( elem, "change", true ); } } ); }, handle: function( event ) { var elem = event.target; // Swallow native change events from checkbox/radio, we already triggered them above if ( this !== elem || event.isSimulated || event.isTrigger || ( elem.type !== "radio" && elem.type !== "checkbox" ) ) { return event.handleObj.handler.apply( this, arguments ); } }, teardown: function() { jQuery.event.remove( this, "._change" ); return !rformElems.test( this.nodeName ); } }; } // Support: Firefox // Firefox doesn't have focus(in | out) events // Related ticket - https://bugzilla.mozilla.org/show_bug.cgi?id=687787 // // Support: Chrome, Safari // focus(in | out) events fire after focus & blur events, // which is spec violation - http://www.w3.org/TR/DOM-Level-3-Events/#events-focusevent-event-order // Related ticket - https://code.google.com/p/chromium/issues/detail?id=449857 if ( !support.focusin ) { jQuery.each( { focus: "focusin", blur: "focusout" }, function( orig, fix ) { // Attach a single capturing handler on the document while someone wants focusin/focusout var handler = function( event ) { jQuery.event.simulate( fix, event.target, jQuery.event.fix( event ) ); }; jQuery.event.special[ fix ] = { setup: function() { var doc = this.ownerDocument || this, attaches = jQuery._data( doc, fix ); if ( !attaches ) { doc.addEventListener( orig, handler, true ); } jQuery._data( doc, fix, ( attaches || 0 ) + 1 ); }, teardown: function() { var doc = this.ownerDocument || this, attaches = jQuery._data( doc, fix ) - 1; if ( !attaches ) { doc.removeEventListener( orig, handler, true ); jQuery._removeData( doc, fix ); } else { jQuery._data( doc, fix, attaches ); } } }; } ); } jQuery.fn.extend( { on: function( types, selector, data, fn ) { return on( this, types, selector, data, fn ); }, one: function( types, selector, data, fn ) { return on( this, types, selector, data, fn, 1 ); }, off: function( types, selector, fn ) { var handleObj, type; if ( types && types.preventDefault && types.handleObj ) { // ( event ) dispatched jQuery.Event handleObj = types.handleObj; jQuery( types.delegateTarget ).off( handleObj.namespace ? handleObj.origType + "." + handleObj.namespace : handleObj.origType, handleObj.selector, handleObj.handler ); return this; } if ( typeof types === "object" ) { // ( types-object [, selector] ) for ( type in types ) { this.off( type, selector, types[ type ] ); } return this; } if ( selector === false || typeof selector === "function" ) { // ( types [, fn] ) fn = selector; selector = undefined; } if ( fn === false ) { fn = returnFalse; } return this.each( function() { jQuery.event.remove( this, types, fn, selector ); } ); }, trigger: function( type, data ) { return this.each( function() { jQuery.event.trigger( type, data, this ); } ); }, triggerHandler: function( type, data ) { var elem = this[ 0 ]; if ( elem ) { return jQuery.event.trigger( type, data, elem, true ); } } } ); var rinlinejQuery = / jQuery\d+="(?:null|\d+)"/g, rnoshimcache = new RegExp( "<(?:" + nodeNames + ")[\\s/>]", "i" ), rxhtmlTag = /<(?!area|br|col|embed|hr|img|input|link|meta|param)(([\w:-]+)[^>]*)\/>/gi, // Support: IE 10-11, Edge 10240+ // In IE/Edge using regex groups here causes severe slowdowns. // See https://connect.microsoft.com/IE/feedback/details/1736512/ rnoInnerhtml = /\s*$/g, safeFragment = createSafeFragment( document ), fragmentDiv = safeFragment.appendChild( document.createElement( "div" ) ); // Support: IE<8 // Manipulating tables requires a tbody function manipulationTarget( elem, content ) { return jQuery.nodeName( elem, "table" ) && jQuery.nodeName( content.nodeType !== 11 ? content : content.firstChild, "tr" ) ? elem.getElementsByTagName( "tbody" )[ 0 ] || elem.appendChild( elem.ownerDocument.createElement( "tbody" ) ) : elem; } // Replace/restore the type attribute of script elements for safe DOM manipulation function disableScript( elem ) { elem.type = ( jQuery.find.attr( elem, "type" ) !== null ) + "/" + elem.type; return elem; } function restoreScript( elem ) { var match = rscriptTypeMasked.exec( elem.type ); if ( match ) { elem.type = match[ 1 ]; } else { elem.removeAttribute( "type" ); } return elem; } function cloneCopyEvent( src, dest ) { if ( dest.nodeType !== 1 || !jQuery.hasData( src ) ) { return; } var type, i, l, oldData = jQuery._data( src ), curData = jQuery._data( dest, oldData ), events = oldData.events; if ( events ) { delete curData.handle; curData.events = {}; for ( type in events ) { for ( i = 0, l = events[ type ].length; i < l; i++ ) { jQuery.event.add( dest, type, events[ type ][ i ] ); } } } // make the cloned public data object a copy from the original if ( curData.data ) { curData.data = jQuery.extend( {}, curData.data ); } } function fixCloneNodeIssues( src, dest ) { var nodeName, e, data; // We do not need to do anything for non-Elements if ( dest.nodeType !== 1 ) { return; } nodeName = dest.nodeName.toLowerCase(); // IE6-8 copies events bound via attachEvent when using cloneNode. if ( !support.noCloneEvent && dest[ jQuery.expando ] ) { data = jQuery._data( dest ); for ( e in data.events ) { jQuery.removeEvent( dest, e, data.handle ); } // Event data gets referenced instead of copied if the expando gets copied too dest.removeAttribute( jQuery.expando ); } // IE blanks contents when cloning scripts, and tries to evaluate newly-set text if ( nodeName === "script" && dest.text !== src.text ) { disableScript( dest ).text = src.text; restoreScript( dest ); // IE6-10 improperly clones children of object elements using classid. // IE10 throws NoModificationAllowedError if parent is null, #12132. } else if ( nodeName === "object" ) { if ( dest.parentNode ) { dest.outerHTML = src.outerHTML; } // This path appears unavoidable for IE9. When cloning an object // element in IE9, the outerHTML strategy above is not sufficient. // If the src has innerHTML and the destination does not, // copy the src.innerHTML into the dest.innerHTML. #10324 if ( support.html5Clone && ( src.innerHTML && !jQuery.trim( dest.innerHTML ) ) ) { dest.innerHTML = src.innerHTML; } } else if ( nodeName === "input" && rcheckableType.test( src.type ) ) { // IE6-8 fails to persist the checked state of a cloned checkbox // or radio button. Worse, IE6-7 fail to give the cloned element // a checked appearance if the defaultChecked value isn't also set dest.defaultChecked = dest.checked = src.checked; // IE6-7 get confused and end up setting the value of a cloned // checkbox/radio button to an empty string instead of "on" if ( dest.value !== src.value ) { dest.value = src.value; } // IE6-8 fails to return the selected option to the default selected // state when cloning options } else if ( nodeName === "option" ) { dest.defaultSelected = dest.selected = src.defaultSelected; // IE6-8 fails to set the defaultValue to the correct value when // cloning other types of input fields } else if ( nodeName === "input" || nodeName === "textarea" ) { dest.defaultValue = src.defaultValue; } } function domManip( collection, args, callback, ignored ) { // Flatten any nested arrays args = concat.apply( [], args ); var first, node, hasScripts, scripts, doc, fragment, i = 0, l = collection.length, iNoClone = l - 1, value = args[ 0 ], isFunction = jQuery.isFunction( value ); // We can't cloneNode fragments that contain checked, in WebKit if ( isFunction || ( l > 1 && typeof value === "string" && !support.checkClone && rchecked.test( value ) ) ) { return collection.each( function( index ) { var self = collection.eq( index ); if ( isFunction ) { args[ 0 ] = value.call( this, index, self.html() ); } domManip( self, args, callback, ignored ); } ); } if ( l ) { fragment = buildFragment( args, collection[ 0 ].ownerDocument, false, collection, ignored ); first = fragment.firstChild; if ( fragment.childNodes.length === 1 ) { fragment = first; } // Require either new content or an interest in ignored elements to invoke the callback if ( first || ignored ) { scripts = jQuery.map( getAll( fragment, "script" ), disableScript ); hasScripts = scripts.length; // Use the original fragment for the last item // instead of the first because it can end up // being emptied incorrectly in certain situations (#8070). for ( ; i < l; i++ ) { node = fragment; if ( i !== iNoClone ) { node = jQuery.clone( node, true, true ); // Keep references to cloned scripts for later restoration if ( hasScripts ) { // Support: Android<4.1, PhantomJS<2 // push.apply(_, arraylike) throws on ancient WebKit jQuery.merge( scripts, getAll( node, "script" ) ); } } callback.call( collection[ i ], node, i ); } if ( hasScripts ) { doc = scripts[ scripts.length - 1 ].ownerDocument; // Reenable scripts jQuery.map( scripts, restoreScript ); // Evaluate executable scripts on first document insertion for ( i = 0; i < hasScripts; i++ ) { node = scripts[ i ]; if ( rscriptType.test( node.type || "" ) && !jQuery._data( node, "globalEval" ) && jQuery.contains( doc, node ) ) { if ( node.src ) { // Optional AJAX dependency, but won't run scripts if not present if ( jQuery._evalUrl ) { jQuery._evalUrl( node.src ); } } else { jQuery.globalEval( ( node.text || node.textContent || node.innerHTML || "" ) .replace( rcleanScript, "" ) ); } } } } // Fix #11809: Avoid leaking memory fragment = first = null; } } return collection; } function remove( elem, selector, keepData ) { var node, elems = selector ? jQuery.filter( selector, elem ) : elem, i = 0; for ( ; ( node = elems[ i ] ) != null; i++ ) { if ( !keepData && node.nodeType === 1 ) { jQuery.cleanData( getAll( node ) ); } if ( node.parentNode ) { if ( keepData && jQuery.contains( node.ownerDocument, node ) ) { setGlobalEval( getAll( node, "script" ) ); } node.parentNode.removeChild( node ); } } return elem; } jQuery.extend( { htmlPrefilter: function( html ) { return html.replace( rxhtmlTag, "<$1>" ); }, clone: function( elem, dataAndEvents, deepDataAndEvents ) { var destElements, node, clone, i, srcElements, inPage = jQuery.contains( elem.ownerDocument, elem ); if ( support.html5Clone || jQuery.isXMLDoc( elem ) || !rnoshimcache.test( "<" + elem.nodeName + ">" ) ) { clone = elem.cloneNode( true ); // IE<=8 does not properly clone detached, unknown element nodes } else { fragmentDiv.innerHTML = elem.outerHTML; fragmentDiv.removeChild( clone = fragmentDiv.firstChild ); } if ( ( !support.noCloneEvent || !support.noCloneChecked ) && ( elem.nodeType === 1 || elem.nodeType === 11 ) && !jQuery.isXMLDoc( elem ) ) { // We eschew Sizzle here for performance reasons: http://jsperf.com/getall-vs-sizzle/2 destElements = getAll( clone ); srcElements = getAll( elem ); // Fix all IE cloning issues for ( i = 0; ( node = srcElements[ i ] ) != null; ++i ) { // Ensure that the destination node is not null; Fixes #9587 if ( destElements[ i ] ) { fixCloneNodeIssues( node, destElements[ i ] ); } } } // Copy the events from the original to the clone if ( dataAndEvents ) { if ( deepDataAndEvents ) { srcElements = srcElements || getAll( elem ); destElements = destElements || getAll( clone ); for ( i = 0; ( node = srcElements[ i ] ) != null; i++ ) { cloneCopyEvent( node, destElements[ i ] ); } } else { cloneCopyEvent( elem, clone ); } } // Preserve script evaluation history destElements = getAll( clone, "script" ); if ( destElements.length > 0 ) { setGlobalEval( destElements, !inPage && getAll( elem, "script" ) ); } destElements = srcElements = node = null; // Return the cloned set return clone; }, cleanData: function( elems, /* internal */ forceAcceptData ) { var elem, type, id, data, i = 0, internalKey = jQuery.expando, cache = jQuery.cache, attributes = support.attributes, special = jQuery.event.special; for ( ; ( elem = elems[ i ] ) != null; i++ ) { if ( forceAcceptData || acceptData( elem ) ) { id = elem[ internalKey ]; data = id && cache[ id ]; if ( data ) { if ( data.events ) { for ( type in data.events ) { if ( special[ type ] ) { jQuery.event.remove( elem, type ); // This is a shortcut to avoid jQuery.event.remove's overhead } else { jQuery.removeEvent( elem, type, data.handle ); } } } // Remove cache only if it was not already removed by jQuery.event.remove if ( cache[ id ] ) { delete cache[ id ]; // Support: IE<9 // IE does not allow us to delete expando properties from nodes // IE creates expando attributes along with the property // IE does not have a removeAttribute function on Document nodes if ( !attributes && typeof elem.removeAttribute !== "undefined" ) { elem.removeAttribute( internalKey ); // Webkit & Blink performance suffers when deleting properties // from DOM nodes, so set to undefined instead // https://code.google.com/p/chromium/issues/detail?id=378607 } else { elem[ internalKey ] = undefined; } deletedIds.push( id ); } } } } } } ); jQuery.fn.extend( { // Keep domManip exposed until 3.0 (gh-2225) domManip: domManip, detach: function( selector ) { return remove( this, selector, true ); }, remove: function( selector ) { return remove( this, selector ); }, text: function( value ) { return access( this, function( value ) { return value === undefined ? jQuery.text( this ) : this.empty().append( ( this[ 0 ] && this[ 0 ].ownerDocument || document ).createTextNode( value ) ); }, null, value, arguments.length ); }, append: function() { return domManip( this, arguments, function( elem ) { if ( this.nodeType === 1 || this.nodeType === 11 || this.nodeType === 9 ) { var target = manipulationTarget( this, elem ); target.appendChild( elem ); } } ); }, prepend: function() { return domManip( this, arguments, function( elem ) { if ( this.nodeType === 1 || this.nodeType === 11 || this.nodeType === 9 ) { var target = manipulationTarget( this, elem ); target.insertBefore( elem, target.firstChild ); } } ); }, before: function() { return domManip( this, arguments, function( elem ) { if ( this.parentNode ) { this.parentNode.insertBefore( elem, this ); } } ); }, after: function() { return domManip( this, arguments, function( elem ) { if ( this.parentNode ) { this.parentNode.insertBefore( elem, this.nextSibling ); } } ); }, empty: function() { var elem, i = 0; for ( ; ( elem = this[ i ] ) != null; i++ ) { // Remove element nodes and prevent memory leaks if ( elem.nodeType === 1 ) { jQuery.cleanData( getAll( elem, false ) ); } // Remove any remaining nodes while ( elem.firstChild ) { elem.removeChild( elem.firstChild ); } // If this is a select, ensure that it displays empty (#12336) // Support: IE<9 if ( elem.options && jQuery.nodeName( elem, "select" ) ) { elem.options.length = 0; } } return this; }, clone: function( dataAndEvents, deepDataAndEvents ) { dataAndEvents = dataAndEvents == null ? false : dataAndEvents; deepDataAndEvents = deepDataAndEvents == null ? dataAndEvents : deepDataAndEvents; return this.map( function() { return jQuery.clone( this, dataAndEvents, deepDataAndEvents ); } ); }, html: function( value ) { return access( this, function( value ) { var elem = this[ 0 ] || {}, i = 0, l = this.length; if ( value === undefined ) { return elem.nodeType === 1 ? elem.innerHTML.replace( rinlinejQuery, "" ) : undefined; } // See if we can take a shortcut and just use innerHTML if ( typeof value === "string" && !rnoInnerhtml.test( value ) && ( support.htmlSerialize || !rnoshimcache.test( value ) ) && ( support.leadingWhitespace || !rleadingWhitespace.test( value ) ) && !wrapMap[ ( rtagName.exec( value ) || [ "", "" ] )[ 1 ].toLowerCase() ] ) { value = jQuery.htmlPrefilter( value ); try { for ( ; i < l; i++ ) { // Remove element nodes and prevent memory leaks elem = this[ i ] || {}; if ( elem.nodeType === 1 ) { jQuery.cleanData( getAll( elem, false ) ); elem.innerHTML = value; } } elem = 0; // If using innerHTML throws an exception, use the fallback method } catch ( e ) {} } if ( elem ) { this.empty().append( value ); } }, null, value, arguments.length ); }, replaceWith: function() { var ignored = []; // Make the changes, replacing each non-ignored context element with the new content return domManip( this, arguments, function( elem ) { var parent = this.parentNode; if ( jQuery.inArray( this, ignored ) < 0 ) { jQuery.cleanData( getAll( this ) ); if ( parent ) { parent.replaceChild( elem, this ); } } // Force callback invocation }, ignored ); } } ); jQuery.each( { appendTo: "append", prependTo: "prepend", insertBefore: "before", insertAfter: "after", replaceAll: "replaceWith" }, function( name, original ) { jQuery.fn[ name ] = function( selector ) { var elems, i = 0, ret = [], insert = jQuery( selector ), last = insert.length - 1; for ( ; i <= last; i++ ) { elems = i === last ? this : this.clone( true ); jQuery( insert[ i ] )[ original ]( elems ); // Modern browsers can apply jQuery collections as arrays, but oldIE needs a .get() push.apply( ret, elems.get() ); } return this.pushStack( ret ); }; } ); var iframe, elemdisplay = { // Support: Firefox // We have to pre-define these values for FF (#10227) HTML: "block", BODY: "block" }; /** * Retrieve the actual display of a element * @param {String} name nodeName of the element * @param {Object} doc Document object */ // Called only from within defaultDisplay function actualDisplay( name, doc ) { var elem = jQuery( doc.createElement( name ) ).appendTo( doc.body ), display = jQuery.css( elem[ 0 ], "display" ); // We don't have any data stored on the element, // so use "detach" method as fast way to get rid of the element elem.detach(); return display; } /** * Try to determine the default display value of an element * @param {String} nodeName */ function defaultDisplay( nodeName ) { var doc = document, display = elemdisplay[ nodeName ]; if ( !display ) { display = actualDisplay( nodeName, doc ); // If the simple way fails, read from inside an iframe if ( display === "none" || !display ) { // Use the already-created iframe if possible iframe = ( iframe || jQuery( "'; break; case 3: delete config.title; delete config.closeBtn; config.icon === -1 && (config.icon === 0); layer.closeAll('loading'); break; case 4: conType || (config.content = [config.content, 'body']); config.follow = config.content[1]; config.content = config.content[0] + ''; delete config.title; config.tips = typeof config.tips === 'object' ? config.tips : [config.tips, true]; config.tipsMore || layer.closeAll('tips'); break; } //建立容器 that.vessel(conType, function(html, titleHTML, moveElem){ body.append(html[0]); conType ? function(){ (config.type == 2 || config.type == 4) ? function(){ $('body').append(html[1]); }() : function(){ if(!content.parents('.'+doms[0])[0]){ content.data('display', content.css('display')).show().addClass('layui-layer-wrap').wrap(html[1]); $('#'+ doms[0] + times).find('.'+doms[5]).before(titleHTML); } }(); }() : body.append(html[1]); $('#'+ doms.MOVE)[0] || body.append(ready.moveElem = moveElem); that.layero = $('#'+ doms[0] + times); that.shadeo = $('#'+ doms.SHADE + times); config.scrollbar || doms.html.css('overflow', 'hidden').attr('layer-full', times); }).auto(times); //遮罩 that.shadeo.css({ 'background-color': config.shade[1] || '#000' ,'opacity': config.shade[0] || config.shade }); config.type == 2 && layer.ie == 6 && that.layero.find('iframe').attr('src', content[0]); //坐标自适应浏览器窗口尺寸 config.type == 4 ? that.tips() : function(){ that.offset() //首次弹出时,若 css 尚未加载,则等待 css 加载完毕后,重新设定尺寸 parseInt(ready.getStyle(document.getElementById(doms.MOVE), 'z-index')) || function(){ that.layero.css('visibility', 'hidden'); layer.ready(function(){ that.offset(); that.layero.css('visibility', 'visible'); }); }(); }(); //如果是固定定位 if(config.fixed){ win.on('resize', function(){ that.offset(); (/^\d+%$/.test(config.area[0]) || /^\d+%$/.test(config.area[1])) && that.auto(times); config.type == 4 && that.tips(); }); } config.time <= 0 || setTimeout(function(){ layer.close(that.index); }, config.time); that.move().callback(); //为兼容jQuery3.0的css动画影响元素尺寸计算 if(doms.anim[config.anim]){ var animClass = 'layer-anim '+ doms.anim[config.anim]; that.layero.addClass(animClass).one('webkitAnimationEnd mozAnimationEnd MSAnimationEnd oanimationend animationend', function(){ $(this).removeClass(animClass); }); }; //记录关闭动画 if(config.isOutAnim){ that.layero.data('isOutAnim', true); } }; //自适应 Class.pt.auto = function(index){ var that = this, config = that.config, layero = $('#'+ doms[0] + index); if(config.area[0] === '' && config.maxWidth > 0){ //为了修复IE7下一个让人难以理解的bug if(layer.ie && layer.ie < 8 && config.btn){ layero.width(layero.innerWidth()); } layero.outerWidth() > config.maxWidth && layero.width(config.maxWidth); } var area = [layero.innerWidth(), layero.innerHeight()] ,titHeight = layero.find(doms[1]).outerHeight() || 0 ,btnHeight = layero.find('.'+doms[6]).outerHeight() || 0 ,setHeight = function(elem){ elem = layero.find(elem); elem.height(area[1] - titHeight - btnHeight - 2*(parseFloat(elem.css('padding-top'))|0)); }; switch(config.type){ case 2: setHeight('iframe'); break; default: if(config.area[1] === ''){ if(config.maxHeight > 0 && layero.outerHeight() > config.maxHeight){ area[1] = config.maxHeight; setHeight('.'+doms[5]); } else if(config.fixed && area[1] >= win.height()){ area[1] = win.height(); setHeight('.'+doms[5]); } } else { setHeight('.'+doms[5]); } break; }; return that; }; //计算坐标 Class.pt.offset = function(){ var that = this, config = that.config, layero = that.layero; var area = [layero.outerWidth(), layero.outerHeight()]; var type = typeof config.offset === 'object'; that.offsetTop = (win.height() - area[1])/2; that.offsetLeft = (win.width() - area[0])/2; if(type){ that.offsetTop = config.offset[0]; that.offsetLeft = config.offset[1]||that.offsetLeft; } else if(config.offset !== 'auto'){ if(config.offset === 't'){ //上 that.offsetTop = 0; } else if(config.offset === 'r'){ //右 that.offsetLeft = win.width() - area[0]; } else if(config.offset === 'b'){ //下 that.offsetTop = win.height() - area[1]; } else if(config.offset === 'l'){ //左 that.offsetLeft = 0; } else if(config.offset === 'lt'){ //左上角 that.offsetTop = 0; that.offsetLeft = 0; } else if(config.offset === 'lb'){ //左下角 that.offsetTop = win.height() - area[1]; that.offsetLeft = 0; } else if(config.offset === 'rt'){ //右上角 that.offsetTop = 0; that.offsetLeft = win.width() - area[0]; } else if(config.offset === 'rb'){ //右下角 that.offsetTop = win.height() - area[1]; that.offsetLeft = win.width() - area[0]; } else { that.offsetTop = config.offset; } } if(!config.fixed){ that.offsetTop = /%$/.test(that.offsetTop) ? win.height()*parseFloat(that.offsetTop)/100 : parseFloat(that.offsetTop); that.offsetLeft = /%$/.test(that.offsetLeft) ? win.width()*parseFloat(that.offsetLeft)/100 : parseFloat(that.offsetLeft); that.offsetTop += win.scrollTop(); that.offsetLeft += win.scrollLeft(); } if(layero.attr('minLeft')){ that.offsetTop = win.height() - (layero.find(doms[1]).outerHeight() || 0); that.offsetLeft = layero.css('left'); } layero.css({top: that.offsetTop, left: that.offsetLeft}); }; //Tips Class.pt.tips = function(){ var that = this, config = that.config, layero = that.layero; var layArea = [layero.outerWidth(), layero.outerHeight()], follow = $(config.follow); if(!follow[0]) follow = $('body'); var goal = { width: follow.outerWidth(), height: follow.outerHeight(), top: follow.offset().top, left: follow.offset().left }, tipsG = layero.find('.layui-layer-TipsG'); var guide = config.tips[0]; config.tips[1] || tipsG.remove(); goal.autoLeft = function(){ if(goal.left + layArea[0] - win.width() > 0){ goal.tipLeft = goal.left + goal.width - layArea[0]; tipsG.css({right: 12, left: 'auto'}); } else { goal.tipLeft = goal.left; }; }; //辨别tips的方位 goal.where = [function(){ //上 goal.autoLeft(); goal.tipTop = goal.top - layArea[1] - 10; tipsG.removeClass('layui-layer-TipsB').addClass('layui-layer-TipsT').css('border-right-color', config.tips[1]); }, function(){ //右 goal.tipLeft = goal.left + goal.width + 10; goal.tipTop = goal.top; tipsG.removeClass('layui-layer-TipsL').addClass('layui-layer-TipsR').css('border-bottom-color', config.tips[1]); }, function(){ //下 goal.autoLeft(); goal.tipTop = goal.top + goal.height + 10; tipsG.removeClass('layui-layer-TipsT').addClass('layui-layer-TipsB').css('border-right-color', config.tips[1]); }, function(){ //左 goal.tipLeft = goal.left - layArea[0] - 10; goal.tipTop = goal.top; tipsG.removeClass('layui-layer-TipsR').addClass('layui-layer-TipsL').css('border-bottom-color', config.tips[1]); }]; goal.where[guide-1](); /* 8*2为小三角形占据的空间 */ if(guide === 1){ goal.top - (win.scrollTop() + layArea[1] + 8*2) < 0 && goal.where[2](); } else if(guide === 2){ win.width() - (goal.left + goal.width + layArea[0] + 8*2) > 0 || goal.where[3]() } else if(guide === 3){ (goal.top - win.scrollTop() + goal.height + layArea[1] + 8*2) - win.height() > 0 && goal.where[0](); } else if(guide === 4){ layArea[0] + 8*2 - goal.left > 0 && goal.where[1]() } layero.find('.'+doms[5]).css({ 'background-color': config.tips[1], 'padding-right': (config.closeBtn ? '30px' : '') }); layero.css({ left: goal.tipLeft - (config.fixed ? win.scrollLeft() : 0), top: goal.tipTop - (config.fixed ? win.scrollTop() : 0) }); } //拖拽层 Class.pt.move = function(){ var that = this ,config = that.config ,_DOC = $(document) ,layero = that.layero ,moveElem = layero.find(config.move) ,resizeElem = layero.find('.layui-layer-resize') ,dict = {}; if(config.move){ moveElem.css('cursor', 'move'); } moveElem.on('mousedown', function(e){ e.preventDefault(); if(config.move){ dict.moveStart = true; dict.offset = [ e.clientX - parseFloat(layero.css('left')) ,e.clientY - parseFloat(layero.css('top')) ]; ready.moveElem.css('cursor', 'move').show(); } }); resizeElem.on('mousedown', function(e){ e.preventDefault(); dict.resizeStart = true; dict.offset = [e.clientX, e.clientY]; dict.area = [ layero.outerWidth() ,layero.outerHeight() ]; ready.moveElem.css('cursor', 'se-resize').show(); }); _DOC.on('mousemove', function(e){ //拖拽移动 if(dict.moveStart){ var X = e.clientX - dict.offset[0] ,Y = e.clientY - dict.offset[1] ,fixed = layero.css('position') === 'fixed'; e.preventDefault(); dict.stX = fixed ? 0 : win.scrollLeft(); dict.stY = fixed ? 0 : win.scrollTop(); //控制元素不被拖出窗口外 if(!config.moveOut){ var setRig = win.width() - layero.outerWidth() + dict.stX ,setBot = win.height() - layero.outerHeight() + dict.stY; X < dict.stX && (X = dict.stX); X > setRig && (X = setRig); Y < dict.stY && (Y = dict.stY); Y > setBot && (Y = setBot); } layero.css({ left: X ,top: Y }); } //Resize if(config.resize && dict.resizeStart){ var X = e.clientX - dict.offset[0] ,Y = e.clientY - dict.offset[1]; e.preventDefault(); layer.style(that.index, { width: dict.area[0] + X ,height: dict.area[1] + Y }) dict.isResize = true; config.resizing && config.resizing(layero); } }).on('mouseup', function(e){ if(dict.moveStart){ delete dict.moveStart; ready.moveElem.hide(); config.moveEnd && config.moveEnd(layero); } if(dict.resizeStart){ delete dict.resizeStart; ready.moveElem.hide(); } }); return that; }; Class.pt.callback = function(){ var that = this, layero = that.layero, config = that.config; that.openLayer(); if(config.success){ if(config.type == 2){ layero.find('iframe').on('load', function(){ config.success(layero, that.index, that); }); } else { config.success(layero, that.index, that); } } layer.ie == 6 && that.IE6(layero); // 节流函数 //按钮 // 按钮的事件在这里 layero.find('.'+ doms[6]).children('a').on('click', function(){ var index = $(this).index(); if(index === 0){ if(that.yesStatus){ that.yesStatus = false setTimeout(()=>{ that.yesStatus = true },1000) }else{ return } if(config.yes){ config.yes(that.index, layero) } else if(config['btn1']){ config['btn1'](that.index, layero) } else { layer.close(that.index); } } else { var close = config['btn'+(index+1)] && config['btn'+(index+1)](that.index, layero); close === false || layer.close(that.index); } }); //取消 function cancel(){ var close = config.cancel && config.cancel(that.index, layero); close === false || layer.close(that.index); } //右上角关闭回调 layero.find('.'+ doms[7]).on('click', cancel); //点遮罩关闭 if(config.shadeClose){ that.shadeo.on('click', function(){ layer.close(that.index); }); } //最小化 layero.find('.layui-layer-min').on('click', function(){ var min = config.min && config.min(layero, that.index); min === false || layer.min(that.index, config); }); //全屏/还原 layero.find('.layui-layer-max').on('click', function(){ if($(this).hasClass('layui-layer-maxmin')){ layer.restore(that.index); config.restore && config.restore(layero, that.index); } else { layer.full(that.index, config); setTimeout(function(){ config.full && config.full(layero, that.index); }, 100); } }); config.end && (ready.end[that.index] = config.end); }; //for ie6 恢复select ready.reselect = function(){ $.each($('select'), function(index , value){ var sthis = $(this); if(!sthis.parents('.'+doms[0])[0]){ (sthis.attr('layer') == 1 && $('.'+doms[0]).length < 1) && sthis.removeAttr('layer').show(); } sthis = null; }); }; Class.pt.IE6 = function(layero){ //隐藏select $('select').each(function(index , value){ var sthis = $(this); if(!sthis.parents('.'+doms[0])[0]){ sthis.css('display') === 'none' || sthis.attr({'layer' : '1'}).hide(); } sthis = null; }); }; //需依赖原型的对外方法 Class.pt.openLayer = function(){ var that = this; //置顶当前窗口 layer.zIndex = that.config.zIndex; layer.setTop = function(layero){ var setZindex = function(){ layer.zIndex++; layero.css('z-index', layer.zIndex + 1); }; layer.zIndex = parseInt(layero[0].style.zIndex); layero.on('mousedown', setZindex); return layer.zIndex; }; }; //记录宽高坐标,用于还原 ready.record = function(layero){ var area = [ layero.width(), layero.height(), layero.position().top, layero.position().left + parseFloat(layero.css('margin-left')) ]; layero.find('.layui-layer-max').addClass('layui-layer-maxmin'); layero.attr({area: area}); }; ready.rescollbar = function(index){ if(doms.html.attr('layer-full') == index){ if(doms.html[0].style.removeProperty){ doms.html[0].style.removeProperty('overflow'); } else { doms.html[0].style.removeAttribute('overflow'); } doms.html.removeAttr('layer-full'); } }; /** 内置成员 */ window.layer = layer; //获取子iframe的DOM layer.getChildFrame = function(selector, index){ index = index || $('.'+doms[4]).attr('times'); return $('#'+ doms[0] + index).find('iframe').contents().find(selector); }; //得到当前iframe层的索引,子iframe时使用 layer.getFrameIndex = function(name){ return $('#'+ name).parents('.'+doms[4]).attr('times'); }; //iframe层自适应宽高 layer.iframeAuto = function(index){ if(!index) return; var heg = layer.getChildFrame('html', index).outerHeight(); var layero = $('#'+ doms[0] + index); var titHeight = layero.find(doms[1]).outerHeight() || 0; var btnHeight = layero.find('.'+doms[6]).outerHeight() || 0; layero.css({height: heg + titHeight + btnHeight}); layero.find('iframe').css({height: heg}); }; //重置iframe url layer.iframeSrc = function(index, url){ $('#'+ doms[0] + index).find('iframe').attr('src', url); }; //设定层的样式 layer.style = function(index, options, limit){ var layero = $('#'+ doms[0] + index) ,contElem = layero.find('.layui-layer-content') ,type = layero.attr('type') ,titHeight = layero.find(doms[1]).outerHeight() || 0 ,btnHeight = layero.find('.'+doms[6]).outerHeight() || 0 ,minLeft = layero.attr('minLeft'); if(type === ready.type[3] || type === ready.type[4]){ return; } if(!limit){ if(parseFloat(options.width) <= 260){ options.width = 260; }; if(parseFloat(options.height) - titHeight - btnHeight <= 64){ options.height = 64 + titHeight + btnHeight; }; } layero.css(options); btnHeight = layero.find('.'+doms[6]).outerHeight(); if(type === ready.type[2]){ layero.find('iframe').css({ height: parseFloat(options.height) - titHeight - btnHeight }); } else { contElem.css({ height: parseFloat(options.height) - titHeight - btnHeight - parseFloat(contElem.css('padding-top')) - parseFloat(contElem.css('padding-bottom')) }) } }; //最小化 layer.min = function(index, options){ options = options || {}; var layero = $('#'+ doms[0] + index) ,shadeo = $('#'+ doms.SHADE + index) ,titHeight = layero.find(doms[1]).outerHeight() || 0 ,left = layero.attr('minLeft') || (181*ready.minIndex)+'px' ,position = layero.css('position') ,settings = { width: 180 ,height: titHeight ,position: 'fixed' ,overflow: 'hidden' }; //记录宽高坐标,用于还原 ready.record(layero); if(ready.minLeft[0]){ left = ready.minLeft[0]; ready.minLeft.shift(); } //是否堆叠在左下角 if(options.minStack){ settings.left = left; settings.top = win.height() - titHeight; layero.attr('minLeft') || ready.minIndex++; //初次执行,最小化操作索引自增 layero.attr('minLeft', left); } layero.attr('position', position); layer.style(index, settings, true); layero.find('.layui-layer-min').hide(); layero.attr('type') === 'page' && layero.find(doms[4]).hide(); ready.rescollbar(index); //隐藏遮罩 shadeo.hide(); }; //还原 layer.restore = function(index){ var layero = $('#'+ doms[0] + index) ,shadeo = $('#'+ doms.SHADE + index) ,area = layero.attr('area').split(',') ,type = layero.attr('type'); //恢复原来尺寸 layer.style(index, { width: parseFloat(area[0]), height: parseFloat(area[1]), top: parseFloat(area[2]), left: parseFloat(area[3]), position: layero.attr('position'), overflow: 'visible' }, true); layero.find('.layui-layer-max').removeClass('layui-layer-maxmin'); layero.find('.layui-layer-min').show(); layero.attr('type') === 'page' && layero.find(doms[4]).show(); ready.rescollbar(index); //恢复遮罩 shadeo.show(); }; //全屏 layer.full = function(index){ var layero = $('#'+ doms[0] + index), timer; ready.record(layero); if(!doms.html.attr('layer-full')){ doms.html.css('overflow','hidden').attr('layer-full', index); } clearTimeout(timer); timer = setTimeout(function(){ var isfix = layero.css('position') === 'fixed'; layer.style(index, { top: isfix ? 0 : win.scrollTop(), left: isfix ? 0 : win.scrollLeft(), width: win.width(), height: win.height() }, true); layero.find('.layui-layer-min').hide(); }, 100); }; //改变title layer.title = function(name, index){ var title = $('#'+ doms[0] + (index||layer.index)).find(doms[1]); title.html(name); }; //关闭layer总方法 layer.close = function(index, callback){ var layero = $('#'+ doms[0] + index), type = layero.attr('type'), closeAnim = 'layer-anim-close'; if(!layero[0]) return; var WRAP = 'layui-layer-wrap', remove = function(){ if(type === ready.type[1] && layero.attr('conType') === 'object'){ layero.children(':not(.'+ doms[5] +')').remove(); var wrap = layero.find('.'+WRAP); for(var i = 0; i < 2; i++){ wrap.unwrap(); } wrap.css('display', wrap.data('display')).removeClass(WRAP); } else { //低版本IE 回收 iframe if(type === ready.type[2]){ try { var iframe = $('#'+doms[4]+index)[0]; iframe.contentWindow.document.write(''); iframe.contentWindow.close(); layero.find('.'+doms[5])[0].removeChild(iframe); } catch(e){} } layero[0].innerHTML = ''; layero.remove(); } typeof ready.end[index] === 'function' && ready.end[index](); delete ready.end[index]; typeof callback === 'function' && callback(); }; if(layero.data('isOutAnim')){ layero.addClass('layer-anim '+ closeAnim); } $('#layui-layer-moves, #'+ doms.SHADE + index).remove(); layer.ie == 6 && ready.reselect(); ready.rescollbar(index); if(layero.attr('minLeft')){ ready.minIndex--; ready.minLeft.push(layero.attr('minLeft')); } if((layer.ie && layer.ie < 10) || !layero.data('isOutAnim')){ remove() } else { setTimeout(function(){ remove(); }, 200); } }; //关闭所有层 layer.closeAll = function(type, callback){ if(typeof type === 'function'){ callback = type; type = null; }; var domsElem = $('.'+doms[0]); $.each(domsElem, function(_index){ var othis = $(this); var is = type ? (othis.attr('type') === type) : 1; is && layer.close(othis.attr('times'), _index === domsElem.length - 1 ? callback : null); is = null; }); if(domsElem.length === 0) typeof callback === 'function' && callback(); }; /** 拓展模块,layui 开始合并在一起 */ var cache = layer.cache||{}, skin = function(type){ return (cache.skin ? (' ' + cache.skin + ' ' + cache.skin + '-'+type) : ''); }; //仿系统prompt layer.prompt = function(options, yes){ var style = ''; options = options || {}; if(typeof options === 'function') yes = options; if(options.area){ var area = options.area; style = 'style="width: '+ area[0] +'; height: '+ area[1] + ';"'; delete options.area; } var prompt, content = options.formType == 2 ? '' : function(){ return ''; }(); var success = options.success; delete options.success; return layer.open($.extend({ type: 1 ,btn: ['确定','取消'] ,content: content ,skin: 'layui-layer-prompt' + skin('prompt') ,maxWidth: win.width() ,success: function(layero){ prompt = layero.find('.layui-layer-input'); prompt.val(options.value || '').focus(); typeof success === 'function' && success(layero); } ,resize: false ,yes: function(index){ var value = prompt.val(); if(value === ''){ prompt.focus(); } else if(value.length > (options.maxlength||500)) { layer.tips('最多输入'+ (options.maxlength || 500) +'个字数', prompt, {tips: 1}); } else { yes && yes(value, index, prompt); } } }, options)); }; //tab层 layer.tab = function(options){ options = options || {}; var tab = options.tab || {} ,THIS = 'layui-this' ,success = options.success; delete options.success; return layer.open($.extend({ type: 1, skin: 'layui-layer-tab' + skin('tab'), resize: false, title: function(){ var len = tab.length, ii = 1, str = ''; if(len > 0){ str = ''+ tab[0].title +''; for(; ii < len; ii++){ str += ''+ tab[ii].title +''; } } return str; }(), content: '
    '+ function(){ var len = tab.length, ii = 1, str = ''; if(len > 0){ str = '
  • '+ (tab[0].content || 'no content') +'
  • '; for(; ii < len; ii++){ str += '
  • '+ (tab[ii].content || 'no content') +'
  • '; } } return str; }() +'
', success: function(layero){ var btn = layero.find('.layui-layer-title').children(); var main = layero.find('.layui-layer-tabmain').children(); btn.on('mousedown', function(e){ e.stopPropagation ? e.stopPropagation() : e.cancelBubble = true; var othis = $(this), index = othis.index(); othis.addClass(THIS).siblings().removeClass(THIS); main.eq(index).show().siblings().hide(); typeof options.change === 'function' && options.change(index); }); typeof success === 'function' && success(layero); } }, options)); }; //相册层 layer.photos = function(options, loop, key){ var dict = {}; options = options || {}; if(!options.photos) return; //若 photos 并非选择器或 jQuery 对象,则为普通 object var isObject = !(typeof options.photos === 'string' || options.photos instanceof $) ,photos = isObject ? options.photos : {} ,data = photos.data || [] ,start = photos.start || 0; dict.imgIndex = (start|0) + 1; options.img = options.img || 'img'; var success = options.success; delete options.success; //如果 options.photos 不是一个对象 if(!isObject){ //页面直接获取 var parent = $(options.photos), pushData = function(){ data = []; parent.find(options.img).each(function(index){ var othis = $(this); othis.attr('layer-index', index); data.push({ alt: othis.attr('alt'), pid: othis.attr('layer-pid'), src: othis.attr('layer-src') || othis.attr('src'), thumb: othis.attr('src') }); }); }; pushData(); if (data.length === 0) return; loop || parent.on('click', options.img, function(){ pushData(); var othis = $(this), index = othis.attr('layer-index'); layer.photos($.extend(options, { photos: { start: index, data: data, tab: options.tab }, full: options.full }), true); }); //不直接弹出 if(!loop) return; } else if (data.length === 0){ return layer.msg('没有图片'); } //上一张 dict.imgprev = function(key){ dict.imgIndex--; if(dict.imgIndex < 1){ dict.imgIndex = data.length; } dict.tabimg(key); }; //下一张 dict.imgnext = function(key,errorMsg){ dict.imgIndex++; if(dict.imgIndex > data.length){ dict.imgIndex = 1; if (errorMsg) {return}; } dict.tabimg(key) }; //方向键 dict.keyup = function(event){ if(!dict.end){ var code = event.keyCode; event.preventDefault(); if(code === 37){ dict.imgprev(true); } else if(code === 39) { dict.imgnext(true); } else if(code === 27) { layer.close(dict.index); } } } //切换 dict.tabimg = function(key){ if(data.length <= 1) return; photos.start = dict.imgIndex - 1; layer.close(dict.index); return layer.photos(options, true, key); setTimeout(function(){ layer.photos(options, true, key); }, 200); } //一些动作 dict.event = function(){ /* dict.bigimg.hover(function(){ dict.imgsee.show(); }, function(){ dict.imgsee.hide(); }); */ dict.bigimg.find('.layui-layer-imgprev').on('click', function(event){ event.preventDefault(); dict.imgprev(true); }); dict.bigimg.find('.layui-layer-imgnext').on('click', function(event){ event.preventDefault(); dict.imgnext(true); }); $(document).on('keyup', dict.keyup); }; //图片预加载 function loadImage(url, callback, error) { var img = new Image(); img.src = url; if(img.complete){ return callback(img); } img.onload = function(){ img.onload = null; callback(img); }; img.onerror = function(e){ img.onerror = null; error(e); }; }; dict.loadi = layer.load(1, { shade: 'shade' in options ? false : 0.9, scrollbar: false }); loadImage(data[start].src, function(img){ layer.close(dict.loadi); //切换图片时不出现动画 if(key) options.anim = -1; //弹出图片层 dict.index = layer.open($.extend({ type: 1, id: 'layui-layer-photos', area: function(){ var imgarea = [img.width, img.height]; var winarea = [$(window).width() - 100, $(window).height() - 100]; //如果 实际图片的宽或者高比 屏幕大(那么进行缩放) if(!options.full && (imgarea[0]>winarea[0]||imgarea[1]>winarea[1])){ var wh = [imgarea[0]/winarea[0],imgarea[1]/winarea[1]];//取宽度缩放比例、高度缩放比例 if(wh[0] > wh[1]){//取缩放比例最大的进行缩放 imgarea[0] = imgarea[0]/wh[0]; imgarea[1] = imgarea[1]/wh[0]; } else if(wh[0] < wh[1]){ imgarea[0] = imgarea[0]/wh[1]; imgarea[1] = imgarea[1]/wh[1]; } } return [imgarea[0]+'px', imgarea[1]+'px']; }(), title: false, shade: 0.9, shadeClose: true, closeBtn: false, move: '.layui-layer-phimg img', moveType: 1, scrollbar: false, moveOut: true, anim: 5, isOutAnim: false, skin: 'layui-layer-photos' + skin('photos'), content: '
' +''+ (data[start].alt||'') +'' +function(){ if(data.length > 1){ return '
' +'' +'
'+ (data[start].alt || '') +''+ dict.imgIndex +' / '+ data.length +'
' +'
' } return ''; }() +'
', success: function(layero, index){ dict.bigimg = layero.find('.layui-layer-phimg'); dict.imgsee = layero.find('.layui-layer-imgbar'); dict.event(layero); options.tab && options.tab(data[start], layero); typeof success === 'function' && success(layero); }, end: function(){ dict.end = true; $(document).off('keyup', dict.keyup); } }, options)); }, function(){ layer.close(dict.loadi); layer.msg('当前图片地址异常
是否继续查看下一张?', { time: 30000, btn: ['下一张', '不看了'], yes: function(){ data.length > 1 && dict.imgnext(true,true); } }); }); }; //主入口 ready.run = function(_$){ $ = _$; win = $(window); doms.html = $('html'); layer.open = function(deliver){ var o = new Class(deliver); return o.index; }; }; //加载方式 window.layui && layui.define ? ( layer.ready() ,layui.define('jquery', function(exports){ //layui 加载 layer.path = layui.cache.dir; ready.run(layui.$); //暴露模块 window.layer = layer; exports('layer', layer); }) ) : ( (typeof define === 'function' && define.amd) ? define(['jquery'], function(){ //requirejs 加载 ready.run(window.jQuery); return layer; }) : function(){ //普通 script 标签加载 layer.ready(); ready.run(window.jQuery); }() ); }(window); /** * util 工具组件 */ layui.define('jquery', function(exports){ "use strict"; var $ = layui.$ ,hint = layui.hint() //外部接口 ,util = { //固定块 fixbar: function(options){ var ELEM = 'layui-fixbar', TOP_BAR = 'layui-fixbar-top' ,dom = $(document), body = $('body') ,is, timer; options = $.extend({ showHeight: 200 //出现TOP的滚动条高度临界值 }, options); options.bar1 = options.bar1 === true ? '' : options.bar1; options.bar2 = options.bar2 === true ? '' : options.bar2; options.bgcolor = options.bgcolor ? ('background-color:' + options.bgcolor) : ''; var icon = [options.bar1, options.bar2, ''] //图标:信息、问号、TOP ,elem = $(['
    ' ,options.bar1 ? '
  • '+ icon[0] +'
  • ' : '' ,options.bar2 ? '
  • '+ icon[1] +'
  • ' : '' ,'
  • '+ icon[2] +'
  • ' ,'
'].join('')) ,topBar = elem.find('.'+TOP_BAR) ,scroll = function(){ var stop = dom.scrollTop(); if(stop >= (options.showHeight)){ is || (topBar.show(), is = 1); } else { is && (topBar.hide(), is = 0); } }; if($('.'+ ELEM)[0]) return; typeof options.css === 'object' && elem.css(options.css); body.append(elem), scroll(); //bar点击事件 elem.find('li').on('click', function(){ var othis = $(this), type = othis.attr('lay-type'); if(type === 'top'){ $('html,body').animate({ scrollTop : 0 }, 200); } options.click && options.click.call(this, type); }); //Top显示控制 dom.on('scroll', function(){ clearTimeout(timer); timer = setTimeout(function(){ scroll(); }, 100); }); } //倒计时 ,countdown: function(endTime, serverTime, callback){ var that = this ,type = typeof serverTime === 'function' ,end = new Date(endTime).getTime() ,now = new Date((!serverTime || type) ? new Date().getTime() : serverTime).getTime() ,count = end - now ,time = [ Math.floor(count/(1000*60*60*24)) //天 ,Math.floor(count/(1000*60*60)) % 24 //时 ,Math.floor(count/(1000*60)) % 60 //分 ,Math.floor(count/1000) % 60 //秒 ]; if(type) callback = serverTime; var timer = setTimeout(function(){ that.countdown(endTime, now + 1000, callback); }, 1000); callback && callback(count > 0 ? time : [0,0,0,0], serverTime, timer); if(count <= 0) clearTimeout(timer); return timer; } //某个时间在当前时间的多久前 ,timeAgo: function(time, onlyDate){ var that = this ,arr = [[], []] ,stamp = new Date().getTime() - new Date(time).getTime(); //返回具体日期 if(stamp > 1000*60*60*24*31){ stamp = new Date(time); arr[0][0] = that.digit(stamp.getFullYear(), 4); arr[0][1] = that.digit(stamp.getMonth() + 1); arr[0][2] = that.digit(stamp.getDate()); //是否输出时间 if(!onlyDate){ arr[1][0] = that.digit(stamp.getHours()); arr[1][1] = that.digit(stamp.getMinutes()); arr[1][2] = that.digit(stamp.getSeconds()); } return arr[0].join('-') + ' ' + arr[1].join(':'); } //30天以内,返回“多久前” if(stamp >= 1000*60*60*24){ return ((stamp/1000/60/60/24)|0) + '天前'; } else if(stamp >= 1000*60*60){ return ((stamp/1000/60/60)|0) + '小时前'; } else if(stamp >= 1000*60*3){ //3分钟以内为:刚刚 return ((stamp/1000/60)|0) + '分钟前'; } else if(stamp < 0){ return '未来'; } else { return '刚刚'; } } //数字前置补零 ,digit: function(num, length){ var str = ''; num = String(num); length = length || 2; for(var i = num.length; i < length; i++){ str += '0'; } return num < Math.pow(10, length) ? str + (num|0) : num; } //转化为日期格式字符 ,toDateString: function(time, format){ //若 null 或空字符,则返回空字符 if(time === null || time === '') return ''; var that = this ,date = new Date(function(){ if(!time) return; return isNaN(time) ? time : (typeof time === 'string' ? parseInt(time) : time) }() || new Date()) ,ymd = [ that.digit(date.getFullYear(), 4) ,that.digit(date.getMonth() + 1) ,that.digit(date.getDate()) ] ,hms = [ that.digit(date.getHours()) ,that.digit(date.getMinutes()) ,that.digit(date.getSeconds()) ]; if(!date.getDate()) return hint.error('Invalid Msec for "util.toDateString(Msec)"'), ''; format = format || 'yyyy-MM-dd HH:mm:ss'; return format.replace(/yyyy/g, ymd[0]) .replace(/MM/g, ymd[1]) .replace(/dd/g, ymd[2]) .replace(/HH/g, hms[0]) .replace(/mm/g, hms[1]) .replace(/ss/g, hms[2]); } //转义 html ,escape: function(html){ var exp = /[<"'>]|&(?=#[a-zA-Z0-9]+)/g; if(html === undefined || html === null) return ''; html += ''; if(!exp.test(html)) return html; return html.replace(/&(?!#?[a-zA-Z0-9]+;)/g, '&') .replace(//g, '>') .replace(/'/g, ''').replace(/"/g, '"'); } //还原转义的 html ,unescape: function(html){ if(html === undefined || html === null) html = ''; html += ''; return html.replace(/\&/g, '&') .replace(/\</g, '<').replace(/\>/g, '>') .replace(/\'/g, '\'').replace(/\"/g, '"'); } //让指定的元素保持在可视区域 ,toVisibleArea: function(options){ options = $.extend({ margin: 160 //触发动作的边界值 ,duration: 200 //动画持续毫秒数 ,type: 'y' //触发方向,x 水平、y 垂直 }, options); if(!options.scrollElem[0] || !options.thisElem[0]) return; var scrollElem = options.scrollElem //滚动元素 ,thisElem = options.thisElem //目标元素 ,vertical = options.type === 'y' //是否垂直方向 ,SCROLL_NAME = vertical ? 'scrollTop' : 'scrollLeft' //滚动方法 ,OFFSET_NAME = vertical ? 'top' : 'left' //坐标方式 ,scrollValue = scrollElem[SCROLL_NAME]() //当前滚动距离 ,size = scrollElem[vertical ? 'height' : 'width']() //滚动元素的尺寸 ,scrollOffet = scrollElem.offset()[OFFSET_NAME] //滚动元素所处位置 ,thisOffset = thisElem.offset()[OFFSET_NAME] - scrollOffet //目标元素当前的所在位置 ,obj = {}; //边界满足条件 if(thisOffset > size - options.margin || thisOffset < options.margin){ obj[SCROLL_NAME] = thisOffset - size/2 + scrollValue scrollElem.animate(obj, options.duration); } } //批量事件 ,event: function(attr, obj, eventType){ var _body = $('body'); eventType = eventType || 'click'; //记录事件回调集合 obj = util.event[attr] = $.extend(true, util.event[attr], obj) || {}; //清除委托事件 util.event.UTIL_EVENT_CALLBACK = util.event.UTIL_EVENT_CALLBACK || {}; _body.off(eventType, '*['+ attr +']', util.event.UTIL_EVENT_CALLBACK[attr]) //绑定委托事件 util.event.UTIL_EVENT_CALLBACK[attr] = function(){ var othis = $(this) ,key = othis.attr(attr); (typeof obj[key] === 'function') && obj[key].call(this, othis); }; //清除旧事件,绑定新事件 _body.on(eventType, '*['+ attr +']', util.event.UTIL_EVENT_CALLBACK[attr]); return obj; } }; util.on = util.event; // DOM 尺寸变化,该创意来自:http://benalman.com/projects/jquery-resize-plugin/ /* !function(a,b,c){"$:nomunge";function l(){f=b[g](function(){d.each(function(){var b=a(this),c=b.width(),d=b.height(),e=a.data(this,i);(c!==e.w||d!==e.h)&&b.trigger(h,[e.w=c,e.h=d])}),l()},e[j])}var f,d=a([]),e=a.resize=a.extend(a.resize,{}),g="setTimeout",h="resize",i=h+"-special-event",j="delay",k="throttleWindow";e[j]=250,e[k]=!0,a.event.special[h]={setup:function(){if(!e[k]&&this[g])return!1;var b=a(this);d=d.add(b),a.data(this,i,{w:b.width(),h:b.height()}),1===d.length&&l()},teardown:function(){if(!e[k]&&this[g])return!1;var b=a(this);d=d.not(b),b.removeData(i),d.length||clearTimeout(f)},add:function(b){function f(b,e,f){var g=a(this),h=a.data(this,i)||{};h.w=e!==c?e:g.width(),h.h=f!==c?f:g.height(),d.apply(this,arguments)}if(!e[k]&&this[g])return!1;var d;return a.isFunction(b)?(d=b,f):(d=b.handler,b.handler=f,void 0)}}}($,window); */ // 输出接口 exports('util', util); });/** * dropdown * 下拉菜单组件 */ layui.define(['jquery', 'laytpl', 'lay'], function(exports){ "use strict"; var $ = layui.$ ,laytpl = layui.laytpl ,hint = layui.hint() ,device = layui.device() ,clickOrMousedown = (device.mobile ? 'click' : 'mousedown') //模块名 ,MOD_NAME = 'dropdown' ,MOD_INDEX = 'layui_'+ MOD_NAME +'_index' //模块索引名 //外部接口 ,dropdown = { config: {} ,index: layui[MOD_NAME] ? (layui[MOD_NAME].index + 10000) : 0 //设置全局项 ,set: function(options){ var that = this; that.config = $.extend({}, that.config, options); return that; } //事件 ,on: function(events, callback){ return layui.onevent.call(this, MOD_NAME, events, callback); } } //操作当前实例 ,thisModule = function(){ var that = this ,options = that.config ,id = options.id; thisModule.that[id] = that; //记录当前实例对象 return { config: options //重置实例 ,reload: function(options){ that.reload.call(that, options); } } } //字符常量 ,STR_ELEM = 'layui-dropdown', STR_HIDE = 'layui-hide', STR_DISABLED = 'layui-disabled', STR_NONE = 'layui-none' ,STR_ITEM_UP = 'layui-menu-item-up', STR_ITEM_DOWN = 'layui-menu-item-down', STR_MENU_TITLE = 'layui-menu-body-title', STR_ITEM_GROUP = 'layui-menu-item-group', STR_ITEM_PARENT = 'layui-menu-item-parent', STR_ITEM_DIV = 'layui-menu-item-divider', STR_ITEM_CHECKED = 'layui-menu-item-checked', STR_ITEM_CHECKED2 = 'layui-menu-item-checked2', STR_MENU_PANEL = 'layui-menu-body-panel', STR_MENU_PANEL_L = 'layui-menu-body-panel-left' ,STR_GROUP_TITLE = '.'+ STR_ITEM_GROUP + '>.'+ STR_MENU_TITLE //构造器 ,Class = function(options){ var that = this; that.index = ++dropdown.index; that.config = $.extend({}, that.config, dropdown.config, options); that.init(); }; //默认配置 Class.prototype.config = { trigger: 'click' //事件类型 ,content: '' //自定义菜单内容 ,className: '' //自定义样式类名 ,style: '' //设置面板 style 属性 ,show: false //是否初始即显示菜单面板 ,isAllowSpread: true //是否允许菜单组展开收缩 ,isSpreadItem: true //是否初始展开子菜单 ,data: [] //菜单数据结构 ,delay: 300 //延迟关闭的毫秒数,若 trigger 为 hover 时才生效 }; //重载实例 Class.prototype.reload = function(options){ var that = this; that.config = $.extend({}, that.config, options); that.init(true); }; //初始化准备 Class.prototype.init = function(rerender){ var that = this ,options = that.config ,elem = options.elem = $(options.elem); //若 elem 非唯一 if(elem.length > 1){ layui.each(elem, function(){ dropdown.render($.extend({}, options, { elem: this })); }); return that; } //若重复执行 render,则视为 reload 处理 if(!rerender && elem[0] && elem.data(MOD_INDEX)){; var newThat = thisModule.getThis(elem.data(MOD_INDEX)); if(!newThat) return; return newThat.reload(options); }; //初始化 id 参数 options.id = ('id' in options) ? options.id : that.index; if(options.show) that.render(rerender); //初始即显示 that.events(); //事件 }; //渲染 Class.prototype.render = function(rerender){ var that = this ,options = that.config ,elemBody = $('body') //默认菜单内容 ,getDefaultView = function(){ var elemUl = $('
    '); if(options.data.length > 0 ){ eachItemView(elemUl, options.data) } else { elemUl.html('
  • no menu
  • '); } return elemUl; } //遍历菜单项 ,eachItemView = function(views, data){ //var views = []; layui.each(data, function(index, item){ //是否存在子级 var isChild = item.child && item.child.length > 0 ,isSpreadItem = ('isSpreadItem' in item) ? item.isSpreadItem : options.isSpreadItem ,title = item.templet ? laytpl(item.templet).render(item) : (options.templet ? laytpl(options.templet).render(item) : item.title) //初始类型 ,type = function(){ if(isChild){ item.type = item.type || 'parent'; } if(item.type){ return ({ group: 'group' ,parent: 'parent' ,'-': '-' })[item.type] || 'parent'; } return ''; }(); if(type !== '-' && (!item.title && !item.id && !isChild)) return; //列表元素 var viewLi = $(['' //标题区 ,function(){ //是否超文本 var viewText = ('href' in item) ? ( ''+ title +'' ) : title; //是否存在子级 if(isChild){ return '
    '+ viewText + function(){ if(type === 'parent'){ return ''; } else if(type === 'group' && options.isAllowSpread){ return ''; } else { return ''; } }() +'
    ' } return '
    '+ viewText +'
    '; }() ,''].join('')); viewLi.data('item', item); //子级区 if(isChild){ var elemPanel = $('
    ') ,elemUl = $('
      '); if(type === 'parent'){ elemPanel.append(eachItemView(elemUl, item.child)); viewLi.append(elemPanel); } else { viewLi.append(eachItemView(elemUl, item.child)); } } views.append(viewLi); }); return views; } //主模板 ,TPL_MAIN = ['
      ' ,'
      '].join(''); //如果是右键事件,则每次触发事件时,将允许重新渲染 if(options.trigger === 'contextmenu' || lay.isTopElem(options.elem[0])) rerender = true; //判断是否已经打开了下拉菜单面板 if(!rerender && options.elem.data(MOD_INDEX +'_opened')) return; //记录模板对象 that.elemView = $(TPL_MAIN); that.elemView.append(options.content || getDefaultView()); //初始化某些属性 if(options.className) that.elemView.addClass(options.className); if(options.style) that.elemView.attr('style', options.style); //记录当前执行的实例索引 dropdown.thisId = options.id; //插入视图 that.remove(); //移除非当前绑定元素的面板 elemBody.append(that.elemView); options.elem.data(MOD_INDEX +'_opened', true); //坐标定位 that.position(); thisModule.prevElem = that.elemView; //记录当前打开的元素,以便在下次关闭 thisModule.prevElem.data('prevElem', options.elem); //将当前绑定的元素,记录在打开元素的 data 对象中 //阻止全局事件 that.elemView.find('.layui-menu').on(clickOrMousedown, function(e){ layui.stope(e); }); //触发菜单列表事件 that.elemView.find('.layui-menu li').on('click', function(e){ var othis = $(this) ,data = othis.data('item') || {} ,isChild = data.child && data.child.length > 0; if(!isChild && data.type !== '-'){ that.remove(); typeof options.click === 'function' && options.click(data, othis); } }); //触发菜单组展开收缩 that.elemView.find(STR_GROUP_TITLE).on('click', function(e){ var othis = $(this) ,elemGroup = othis.parent() ,data = elemGroup.data('item') || {} if(data.type === 'group' && options.isAllowSpread){ thisModule.spread(elemGroup); } }); //如果是鼠标移入事件,则鼠标移出时自动关闭 if(options.trigger === 'mouseenter'){ that.elemView.on('mouseenter', function(){ clearTimeout(thisModule.timer); }).on('mouseleave', function(){ that.delayRemove(); }); } }; //位置定位 Class.prototype.position = function(obj){ var that = this ,options = that.config; lay.position(options.elem[0], that.elemView[0], { position: options.position ,e: that.e ,clickType: options.trigger === 'contextmenu' ? 'right' : null ,align: options.align || null }); }; //删除视图 Class.prototype.remove = function(){ var that = this ,options = that.config ,elemPrev = thisModule.prevElem; //若存在已打开的面板元素,则移除 if(elemPrev){ elemPrev.data('prevElem') && ( elemPrev.data('prevElem').data(MOD_INDEX +'_opened', false) ); elemPrev.remove(); } }; //延迟删除视图 Class.prototype.delayRemove = function(){ var that = this ,options = that.config; clearTimeout(thisModule.timer); thisModule.timer = setTimeout(function(){ that.remove(); }, options.delay); }; //事件 Class.prototype.events = function(){ var that = this ,options = that.config; //如果传入 hover,则解析为 mouseenter if(options.trigger === 'hover') options.trigger = 'mouseenter'; //解除上一个事件 if(that.prevElem) that.prevElem.off(options.trigger, that.prevElemCallback); //记录被绑定的元素及回调 that.prevElem = options.elem; that.prevElemCallback = function(e){ clearTimeout(thisModule.timer); that.e = e; that.render(); e.preventDefault(); //组件打开完毕的时间 typeof options.ready === 'function' && options.ready(that.elemView, options.elem, that.e.target); }; //触发元素事件 options.elem.on(options.trigger, that.prevElemCallback); //如果是鼠标移入事件 if(options.trigger === 'mouseenter'){ //直行鼠标移出事件 options.elem.on('mouseleave', function(){ that.delayRemove(); }); } }; //记录所有实例 thisModule.that = {}; //记录所有实例对象 //获取当前实例对象 thisModule.getThis = function(id){ var that = thisModule.that[id]; if(!that) hint.error(id ? (MOD_NAME +' instance with ID \''+ id +'\' not found') : 'ID argument required'); return that; }; //设置菜单组展开和收缩状态 thisModule.spread = function(othis){ //菜单组展开和收缩 var elemIcon = othis.children('.'+ STR_MENU_TITLE).find('.layui-icon'); if(othis.hasClass(STR_ITEM_UP)){ othis.removeClass(STR_ITEM_UP).addClass(STR_ITEM_DOWN); elemIcon.removeClass('layui-icon-down').addClass('layui-icon-up'); } else { othis.removeClass(STR_ITEM_DOWN).addClass(STR_ITEM_UP); elemIcon.removeClass('layui-icon-up').addClass('layui-icon-down') } }; //全局事件 ;!function(){ var _WIN = $(window) ,_DOC = $(document); //自适应定位 _WIN.on('resize', function(){ if(!dropdown.thisId) return; var that = thisModule.getThis(dropdown.thisId); if(!that) return; if(!that.elemView[0] || !$('.'+ STR_ELEM)[0]){ return false; } var options = that.config; if(options.trigger === 'contextmenu'){ that.remove(); } else { that.position(); } }); //点击任意处关闭 _DOC.on(clickOrMousedown, function(e){ if(!dropdown.thisId) return; var that = thisModule.getThis(dropdown.thisId) if(!that) return; var options = that.config; //如果触发的是绑定的元素,或者属于绑定元素的子元素,则不关闭 //满足条件:当前绑定的元素不是 body document,或者不是鼠标右键事件 if(!(lay.isTopElem(options.elem[0]) || options.trigger === 'contextmenu')){ if( e.target === options.elem[0] || options.elem.find(e.target)[0] || e.target === that.elemView[0] || (that.elemView && that.elemView.find(e.target)[0]) ) return; } that.remove(); }); //基础菜单的静态元素事件 var ELEM_LI = '.layui-menu:not(.layui-dropdown-menu) li'; _DOC.on('click', ELEM_LI, function(e){ var othis = $(this) ,parent = othis.parents('.layui-menu').eq(0) ,isChild = othis.hasClass(STR_ITEM_GROUP) || othis.hasClass(STR_ITEM_PARENT) ,filter = parent.attr('lay-filter') || parent.attr('id') ,options = lay.options(this); //非触发元素 if(othis.hasClass(STR_ITEM_DIV)) return; //非菜单组 if(!isChild){ //选中 parent.find('.'+ STR_ITEM_CHECKED).removeClass(STR_ITEM_CHECKED); //清除选中样式 parent.find('.'+ STR_ITEM_CHECKED2).removeClass(STR_ITEM_CHECKED2); //清除父级菜单选中样式 othis.addClass(STR_ITEM_CHECKED); //添加选中样式 othis.parents('.'+ STR_ITEM_PARENT).addClass(STR_ITEM_CHECKED2); //添加父级菜单选中样式 //触发事件 layui.event.call(this, MOD_NAME, 'click('+ filter +')', options); } }); //基础菜单的展开收缩事件 _DOC.on('click', (ELEM_LI + STR_GROUP_TITLE), function(e){ var othis = $(this) ,elemGroup = othis.parents('.'+ STR_ITEM_GROUP +':eq(0)') ,options = lay.options(elemGroup[0]); if(('isAllowSpread' in options) ? options.isAllowSpread : true){ thisModule.spread(elemGroup); }; }); //判断子级菜单是否超出屏幕 var ELEM_LI_PAR = '.layui-menu .'+ STR_ITEM_PARENT _DOC.on('mouseenter', ELEM_LI_PAR, function(e){ var othis = $(this) ,elemPanel = othis.find('.'+ STR_MENU_PANEL); if(!elemPanel[0]) return; var rect = elemPanel[0].getBoundingClientRect(); //是否超出右侧屏幕 if(rect.right > _WIN.width()){ elemPanel.addClass(STR_MENU_PANEL_L); //不允许超出左侧屏幕 rect = elemPanel[0].getBoundingClientRect(); if(rect.left < 0){ elemPanel.removeClass(STR_MENU_PANEL_L); } } //是否超出底部屏幕 if(rect.bottom > _WIN.height()){ elemPanel.eq(0).css('margin-top', -(rect.bottom - _WIN.height())); }; }).on('mouseleave', ELEM_LI_PAR, function(e){ var othis = $(this) ,elemPanel = othis.children('.'+ STR_MENU_PANEL); elemPanel.removeClass(STR_MENU_PANEL_L); elemPanel.css('margin-top', 0); }); }(); //重载实例 dropdown.reload = function(id, options){ var that = thisModule.getThis(id); if(!that) return this; that.reload(options); return thisModule.call(that); }; //核心入口 dropdown.render = function(options){ var inst = new Class(options); return thisModule.call(inst); }; exports(MOD_NAME, dropdown); }); /** * slider 滑块组件 */ layui.define('jquery', function(exports){ "use strict"; var $ = layui.$ //外部接口 ,slider = { config: {} ,index: layui.slider ? (layui.slider.index + 10000) : 0 //设置全局项 ,set: function(options){ var that = this; that.config = $.extend({}, that.config, options); return that; } //事件 ,on: function(events, callback){ return layui.onevent.call(this, MOD_NAME, events, callback); } } //操作当前实例 ,thisSlider = function(){ var that = this ,options = that.config; return { setValue: function(value, index,s){ //设置值 options.value = value; return that.slide('set', value, index || 0,s); } ,config: options } } //字符常量 ,MOD_NAME = 'slider', DISABLED = 'layui-disabled', ELEM_VIEW = 'layui-slider', SLIDER_BAR = 'layui-slider-bar', SLIDER_WRAP = 'layui-slider-wrap', SLIDER_WRAP_BTN = 'layui-slider-wrap-btn', SLIDER_TIPS = 'layui-slider-tips', SLIDER_INPUT = 'layui-slider-input', SLIDER_INPUT_TXT = 'layui-slider-input-txt', SLIDER_INPUT_BTN = 'layui-slider-input-btn', ELEM_HOVER = 'layui-slider-hover' //构造器 ,Class = function(options){ var that = this; that.index = ++slider.index; that.config = $.extend({}, that.config, slider.config, options); that.render(); that.anxia = false; }; //默认配置 Class.prototype.config = { type: 'default' //滑块类型,垂直:vertical ,min: 0 //最小值 ,max: 100 //最大值,默认100 ,value: 0 //初始值,默认为0 ,step: 1 //间隔值 ,showstep: false //间隔点开启 ,tips: true //文字提示,开启 ,input: false //输入框,关闭 ,range: false //范围选择,与输入框不能同时开启,默认关闭 ,height: 200 //配合 type:"vertical" 使用,默认200px ,disabled: false //滑块禁用,默认关闭 ,theme: '#009688' //主题颜色 }; //滑块渲染 Class.prototype.render = function(){ var that = this ,options = that.config; //间隔值不能小于 1 if(options.step < 1) options.step = 1; //最大值不能小于最小值 if(options.max < options.min) options.max = options.min + options.step; //判断是否开启双滑块 if(options.range){ options.value = typeof(options.value) == 'object' ? options.value : [options.min, options.value]; var minValue = Math.min(options.value[0], options.value[1]) ,maxValue = Math.max(options.value[0], options.value[1]); options.value[0] = minValue > options.min ? minValue : options.min; options.value[1] = maxValue > options.min ? maxValue : options.min; options.value[0] = options.value[0] > options.max ? options.max : options.value[0]; options.value[1] = options.value[1] > options.max ? options.max : options.value[1]; var scaleFir = Math.floor((options.value[0] - options.min) / (options.max - options.min) * 100) ,scaleSec = Math.floor((options.value[1] - options.min) / (options.max - options.min) * 100) ,scale = scaleSec - scaleFir + '%'; scaleFir = scaleFir + '%'; scaleSec = scaleSec + '%'; } else { //如果初始值是一个数组,则获取数组的最小值 if(typeof options.value == 'object'){ options.value = Math.min.apply(null, options.value); } //初始值不能小于最小值且不能大于最大值 if(options.value < options.min) options.value = options.min; if(options.value > options.max) options.value = options.max; var scale = Math.floor((options.value - options.min) / (options.max - options.min) * 100) + '%'; }; //如果禁用,颜色为统一的灰色 var theme = options.disabled ? '#c2c2c2' : options.theme; //滑块 var temp = '
      '+ (options.tips ? '
      ' : '') + '
      ' + '
      '+ (options.range ? '
      ' : '') +'
      '; var othis = $(options.elem) ,hasRender = othis.next('.' + ELEM_VIEW); //生成替代元素 hasRender[0] && hasRender.remove(); //如果已经渲染,则Rerender that.elemTemp = $(temp); //把数据缓存到滑块上 if(options.range){ that.elemTemp.find('.' + SLIDER_WRAP).eq(0).data('value', options.value[0]); that.elemTemp.find('.' + SLIDER_WRAP).eq(1).data('value', options.value[1]); }else{ that.elemTemp.find('.' + SLIDER_WRAP).data('value', options.value); }; //插入替代元素 othis.html(that.elemTemp); //垂直滑块 if(options.type === 'vertical'){ that.elemTemp.height(options.height + 'px'); }; //显示间断点 if(options.showstep){ var number = (options.max - options.min) / options.step, item = ''; for(var i = 1; i < number + 1; i++) { var step = i * 100 / number; if(step < 100){ item += '
      ' } }; that.elemTemp.append(item); }; //插入输入框 if(options.input && !options.range){ var elemInput = $('
      '); othis.css("position","relative"); othis.append(elemInput); othis.find('.' + SLIDER_INPUT_TXT).children('input').val(options.value); if(options.type === 'vertical'){ elemInput.css({ left: 0 ,top: -48 }); } else { that.elemTemp.css("margin-right", elemInput.outerWidth() + 15); } }; //给未禁止的滑块滑动事件 if(!options.disabled){ that.slide(); }else{ that.elemTemp.addClass(DISABLED); that.elemTemp.find('.' + SLIDER_WRAP_BTN).addClass(DISABLED); }; //划过滑块显示数值 var timer; that.elemTemp.find('.' + SLIDER_WRAP_BTN).on('mouseover', function(){ var sliderWidth = options.type === 'vertical' ? options.height : that.elemTemp[0].offsetWidth ,sliderWrap = that.elemTemp.find('.' + SLIDER_WRAP) ,tipsLeft = options.type === 'vertical' ? (sliderWidth - $(this).parent()[0].offsetTop - sliderWrap.height()) : $(this).parent()[0].offsetLeft ,left = tipsLeft / sliderWidth * 100 ,value = $(this).parent().data('value') ,tipsTxt = options.setTips ? options.setTips(value) : value; that.elemTemp.find('.' + SLIDER_TIPS).html(tipsTxt); clearTimeout(timer); timer = setTimeout(function(){ if(options.type === 'vertical'){ that.elemTemp.find('.' + SLIDER_TIPS).css({ "bottom": left + '%', "margin-bottom": "20px", "display": "inline-block" }); } else { that.elemTemp.find('.' + SLIDER_TIPS).css({ "left": left + '%', "display": "inline-block" }); }; }, 300); }).on('mouseout', function(){ clearTimeout(timer); that.elemTemp.find('.' + SLIDER_TIPS).css("display", "none"); }); }; //滑块滑动 Class.prototype.slide = function(setValue, value, i,s){ var that = this ,options = that.config ,sliderAct = that.elemTemp ,sliderWidth = function(){ return options.type === 'vertical' ? options.height : sliderAct[0].offsetWidth } ,sliderWrap = sliderAct.find('.' + SLIDER_WRAP) ,sliderTxt = sliderAct.next('.' + SLIDER_INPUT) ,inputValue = sliderTxt.children('.' + SLIDER_INPUT_TXT).children('input').val() ,step = 100 / ((options.max - options.min) / Math.ceil(options.step)) ,change = function(offsetValue, index,s){ if(Math.ceil(offsetValue) * step > 100){ offsetValue = Math.ceil(offsetValue) * step }else{ offsetValue = Math.round(offsetValue) * step }; offsetValue = offsetValue > 100 ? 100: offsetValue; sliderWrap.eq(index).css((options.type === 'vertical' ?'bottom':'left'), offsetValue + '%'); var firLeft = valueTo(sliderWrap[0].offsetLeft) ,secLeft = options.range ? valueTo(sliderWrap[1].offsetLeft) : 0; if(options.type === 'vertical'){ sliderAct.find('.' + SLIDER_TIPS).css({"bottom":offsetValue + '%', "margin-bottom":"20px"}); firLeft = valueTo(sliderWidth() - sliderWrap[0].offsetTop - sliderWrap.height()); secLeft = options.range ? valueTo(sliderWidth() - sliderWrap[1].offsetTop - sliderWrap.height()) : 0; }else{ sliderAct.find('.' + SLIDER_TIPS).css("left",offsetValue + '%'); }; firLeft = firLeft > 100 ? 100: firLeft; secLeft = secLeft > 100 ? 100: secLeft; var minLeft = Math.min(firLeft, secLeft) ,wrapWidth = Math.abs(firLeft - secLeft); if(options.type === 'vertical'){ sliderAct.find('.' + SLIDER_BAR).css({"height":wrapWidth + '%', "bottom":minLeft + '%'}); }else{ sliderAct.find('.' + SLIDER_BAR).css({"width":wrapWidth + '%', "left":minLeft + '%'}); }; var selfValue = options.min + Math.round((options.max - options.min) * offsetValue / 100); inputValue = selfValue; sliderTxt.children('.' + SLIDER_INPUT_TXT).children('input').val(inputValue); sliderWrap.eq(index).data('value', selfValue); sliderAct.find('.' + SLIDER_TIPS).html(options.setTips ? options.setTips(selfValue) : selfValue); //如果开启范围选择,则返回数组值 if(options.range){ var arrValue = [ sliderWrap.eq(0).data('value') ,sliderWrap.eq(1).data('value') ]; if(arrValue[0] > arrValue[1]) arrValue.reverse(); //如果前面的圆点超过了后面的圆点值,则调换顺序 } //回调 options.change && options.change(options.range ? arrValue : selfValue,selfValue,s); } ,valueTo = function(value){ var oldLeft = value / sliderWidth() * 100 / step ,left = Math.round(oldLeft) * step; if(value == sliderWidth()){ left = Math.ceil(oldLeft) * step; }; return left; } //拖拽元素 ,elemMove = $(['
      sliderWidth())left = sliderWidth(); var reaLeft = left / sliderWidth() * 100 / step; change(reaLeft, index,2); othis.addClass(ELEM_HOVER); sliderAct.find('.' + SLIDER_TIPS).show(); e.preventDefault(); }; var up = function(){ othis.removeClass(ELEM_HOVER); sliderAct.find('.' + SLIDER_TIPS).hide(); }; createMoveElem(move, up) }); }); //点击滑块 sliderAct.on('click', function(e){ var main = $('.' + SLIDER_WRAP_BTN); if(!main.is(event.target) && main.has(event.target).length === 0 && main.length){ var left = options.type === 'vertical' ? (sliderWidth() - e.clientY + $(this).offset().top):(e.clientX - $(this).offset().left), index; if(left < 0)left = 0; if(left > sliderWidth())left = sliderWidth(); var reaLeft = left / sliderWidth() * 100 / step; if(options.range){ if(options.type === 'vertical'){ index = Math.abs(left - parseInt($(sliderWrap[0]).css('bottom'))) > Math.abs(left - parseInt($(sliderWrap[1]).css('bottom'))) ? 1 : 0; }else{ index = Math.abs(left - sliderWrap[0].offsetLeft) > Math.abs(left - sliderWrap[1].offsetLeft) ? 1 : 0; } }else{ index = 0; }; // console.log(reaLeft,left,step) change(reaLeft, index,true); e.preventDefault(); } }); // 拖动滑块 sliderAct.find('.' + SLIDER_BAR).on("mousemove",function (e){ if(!that.anxia){ return } return var main = $('.' + SLIDER_WRAP_BTN); if(!main.is(event.target) && main.has(event.target).length === 0 && main.length){ var left = options.type === 'vertical' ? (sliderWidth() - e.clientY + $(this).offset().top):(e.clientX - $(this).offset().left), index; if(left < 0)left = 0; if(left > sliderWidth())left = sliderWidth(); var reaLeft = left / sliderWidth() * 100 / step; if(options.range){ if(options.type === 'vertical'){ index = Math.abs(left - parseInt($(sliderWrap[0]).css('bottom'))) > Math.abs(left - parseInt($(sliderWrap[1]).css('bottom'))) ? 1 : 0; }else{ index = Math.abs(left - sliderWrap[0].offsetLeft) > Math.abs(left - sliderWrap[1].offsetLeft) ? 1 : 0; } }else{ index = 0; }; console.log(reaLeft,left,step) change(reaLeft, index); e.preventDefault(); } }) sliderAct.find('.' + SLIDER_BAR).on("mousedown",function (){ that.anxia = true }) sliderAct.find('.' + SLIDER_BAR).on("mouseup",function (){ that.anxia = false }) sliderAct.find('.' + SLIDER_BAR).on("click",function (e){ e.preventDefault(); }) //点击加减输入框 sliderTxt.children('.' + SLIDER_INPUT_BTN).children('i').each(function(index){ $(this).on('click', function(){ inputValue = sliderTxt.children('.' + SLIDER_INPUT_TXT).children('input').val(); if(index == 1){ //减 inputValue = inputValue - options.step < options.min ? options.min : Number(inputValue) - options.step; }else{ inputValue = Number(inputValue) + options.step > options.max ? options.max : Number(inputValue) + options.step; }; var inputScale = (inputValue - options.min) / (options.max - options.min) * 100 / step; change(inputScale, 0); }); }); //获取输入框值 var getInputValue = function(){ var realValue = this.value; realValue = isNaN(realValue) ? 0 : realValue; realValue = realValue < options.min ? options.min : realValue; realValue = realValue > options.max ? options.max : realValue; this.value = realValue; var inputScale = (realValue - options.min) / (options.max - options.min) * 100 / step; change(inputScale, 0); }; sliderTxt.children('.' + SLIDER_INPUT_TXT).children('input').on('keydown', function(e){ if(e.keyCode === 13){ e.preventDefault(); getInputValue.call(this); } }).on('change', getInputValue); }; //事件处理 Class.prototype.events = function(){ var that = this ,options = that.config; }; //核心入口 slider.render = function(options){ var inst = new Class(options); return thisSlider.call(inst); }; exports(MOD_NAME, slider); })/** * colorpicker * 颜色选择组件 */ layui.define(['jquery', 'lay'], function(exports){ "use strict"; var $ = layui.jquery ,lay = layui.lay ,device = layui.device() ,clickOrMousedown = (device.mobile ? 'click' : 'mousedown') //外部接口 ,colorpicker = { config: {} ,index: layui.colorpicker ? (layui.colorpicker.index + 10000) : 0 //设置全局项 ,set: function(options){ var that = this; that.config = $.extend({}, that.config, options); return that; } //事件 ,on: function(events, callback){ return layui.onevent.call(this, 'colorpicker', events, callback); } } //操作当前实例 ,thisColorPicker = function(){ var that = this ,options = that.config; return { config: options } } //字符常量 ,MOD_NAME = 'colorpicker', SHOW = 'layui-show', THIS = 'layui-this', ELEM = 'layui-colorpicker' ,ELEM_MAIN = '.layui-colorpicker-main', ICON_PICKER_DOWN = 'layui-icon-down', ICON_PICKER_CLOSE = 'layui-icon-close' ,PICKER_TRIG_SPAN = 'layui-colorpicker-trigger-span', PICKER_TRIG_I = 'layui-colorpicker-trigger-i', PICKER_SIDE = 'layui-colorpicker-side', PICKER_SIDE_SLIDER = 'layui-colorpicker-side-slider' ,PICKER_BASIS = 'layui-colorpicker-basis', PICKER_ALPHA_BG = 'layui-colorpicker-alpha-bgcolor', PICKER_ALPHA_SLIDER = 'layui-colorpicker-alpha-slider', PICKER_BASIS_CUR = 'layui-colorpicker-basis-cursor', PICKER_INPUT = 'layui-colorpicker-main-input' //RGB转HSB ,RGBToHSB = function(rgb){ var hsb = {h:0, s:0, b:0}; var min = Math.min(rgb.r, rgb.g, rgb.b); var max = Math.max(rgb.r, rgb.g, rgb.b); var delta = max - min; hsb.b = max; hsb.s = max != 0 ? 255*delta/max : 0; if(hsb.s != 0){ if(rgb.r == max){ hsb.h = (rgb.g - rgb.b) / delta; }else if(rgb.g == max){ hsb.h = 2 + (rgb.b - rgb.r) / delta; }else{ hsb.h = 4 + (rgb.r - rgb.g) / delta; } }else{ hsb.h = -1; }; if(max == min){ hsb.h = 0; }; hsb.h *= 60; if(hsb.h < 0) { hsb.h += 360; }; hsb.s *= 100/255; hsb.b *= 100/255; return hsb; } //HEX转HSB ,HEXToHSB = function(hex){ var hex = hex.indexOf('#') > -1 ? hex.substring(1) : hex; if(hex.length == 3){ var num = hex.split(""); hex = num[0]+num[0]+num[1]+num[1]+num[2]+num[2] }; hex = parseInt(hex, 16); var rgb = {r:hex >> 16, g:(hex & 0x00FF00) >> 8, b:(hex & 0x0000FF)}; return RGBToHSB(rgb); } //HSB转RGB ,HSBToRGB = function(hsb){ var rgb = {}; var h = hsb.h; var s = hsb.s*255/100; var b = hsb.b*255/100; if(s == 0){ rgb.r = rgb.g = rgb.b = b; }else{ var t1 = b; var t2 = (255 - s) * b /255; var t3 = (t1 - t2) * (h % 60) /60; if(h == 360) h = 0; if(h < 60) {rgb.r=t1; rgb.b=t2; rgb.g=t2+t3} else if(h < 120) {rgb.g=t1; rgb.b=t2; rgb.r=t1-t3} else if(h < 180) {rgb.g=t1; rgb.r=t2; rgb.b=t2+t3} else if(h < 240) {rgb.b=t1; rgb.r=t2; rgb.g=t1-t3} else if(h < 300) {rgb.b=t1; rgb.g=t2; rgb.r=t2+t3} else if(h < 360) {rgb.r=t1; rgb.g=t2; rgb.b=t1-t3} else {rgb.r=0; rgb.g=0; rgb.b=0} } return {r:Math.round(rgb.r), g:Math.round(rgb.g), b:Math.round(rgb.b)}; } //HSB转HEX ,HSBToHEX = function(hsb){ var rgb = HSBToRGB(hsb); var hex = [ rgb.r.toString(16) ,rgb.g.toString(16) ,rgb.b.toString(16) ]; $.each(hex, function(nr, val){ if(val.length == 1){ hex[nr] = '0' + val; } }); return hex.join(''); } //转化成所需rgb格式 ,RGBSTo = function(rgbs){ var regexp = /[0-9]{1,3}/g; var re = rgbs.match(regexp) || []; return {r:re[0], g:re[1], b:re[2]}; } ,$win = $(window) ,$doc = $(document) //构造器 ,Class = function(options){ var that = this; that.index = ++colorpicker.index; that.config = $.extend({}, that.config, colorpicker.config, options); that.render(); }; //默认配置 Class.prototype.config = { color: '' //默认颜色,默认没有 ,size: null //选择器大小 ,alpha: false //是否开启透明度 ,format: 'hex' //颜色显示/输入格式,可选 rgb,hex ,predefine: false //预定义颜色是否开启 ,colors: [ //默认预定义颜色列表 '#009688', '#5FB878', '#1E9FFF', '#FF5722', '#FFB800', '#01AAED', '#999', '#c00', '#ff8c00','#ffd700' ,'#90ee90', '#00ced1', '#1e90ff', '#c71585', 'rgb(0, 186, 189)', 'rgb(255, 120, 0)', 'rgb(250, 212, 0)', '#393D49', 'rgba(0,0,0,.5)', 'rgba(255, 69, 0, 0.68)', 'rgba(144, 240, 144, 0.5)', 'rgba(31, 147, 255, 0.73)' ] }; //初始颜色选择框 Class.prototype.render = function(){ var that = this ,options = that.config //颜色选择框对象 ,elemColorBox = $(['
      ' ,'' ,'' ,'' ,'' ,'' ,'
      '].join('')) //初始化颜色选择框 var othis = $(options.elem); options.size && elemColorBox.addClass('layui-colorpicker-'+ options.size); //初始化颜色选择框尺寸 //插入颜色选择框 othis.addClass('layui-inline').html( that.elemColorBox = elemColorBox ); //获取背景色值 that.color = that.elemColorBox.find('.'+ PICKER_TRIG_SPAN)[0].style.background; //相关事件 that.events(); }; //渲染颜色选择器 Class.prototype.renderPicker = function(){ var that = this ,options = that.config ,elemColorBox = that.elemColorBox[0] //颜色选择器对象 ,elemPicker = that.elemPicker = $(['
      ' //颜色面板 ,'
      ' ,'
      ' ,'
      ' ,'
      ' ,'
      ' ,'
      ' ,'
      ' ,'
      ' ,'
      ' ,'
      ' //透明度条块 ,'
      ' ,'
      ' ,'
      ' ,'
      ' ,'
      ' //预设颜色列表 ,function(){ if(options.predefine){ var list = ['
      ']; layui.each(options.colors, function(i, v){ list.push(['
      ' ,'
      ' ,'
      '].join('')); }); list.push('
      '); return list.join(''); } else { return ''; } }() //底部表单元素区域 ,'
      ' ,'
      ' ,'' ,'
      ' ,'
      ' ,'' ,'' ,'' ,'
      '].join('')) ,elemColorBoxSpan = that.elemColorBox.find('.' + PICKER_TRIG_SPAN)[0]; //如果当前点击的颜色盒子已经存在选择器,则关闭 if($(ELEM_MAIN)[0] && $(ELEM_MAIN).data('index') == that.index){ that.removePicker(Class.thisElemInd); } else { //插入颜色选择器 that.removePicker(Class.thisElemInd); $('body').append(elemPicker); } Class.thisElemInd = that.index; //记录最新打开的选择器索引 Class.thisColor = elemColorBox.style.background //记录最新打开的选择器颜色选中值 that.position(); that.pickerEvents(); }; //颜色选择器移除 Class.prototype.removePicker = function(index){ var that = this ,options = that.config; $('#layui-colorpicker'+ (index || that.index)).remove(); return that; }; //定位算法 Class.prototype.position = function(){ var that = this ,options = that.config; lay.position(that.bindElem || that.elemColorBox[0], that.elemPicker[0], { position: options.position ,align: 'center' }); return that; }; //颜色选择器赋值 Class.prototype.val = function(){ var that = this ,options = that.config ,elemColorBox = that.elemColorBox.find('.' + PICKER_TRIG_SPAN) ,elemPickerInput = that.elemPicker.find('.' + PICKER_INPUT) ,e = elemColorBox[0] ,bgcolor = e.style.backgroundColor; //判断是否有背景颜色 if(bgcolor){ //转化成hsb格式 var hsb = RGBToHSB(RGBSTo(bgcolor)) ,type = elemColorBox.attr('lay-type'); //同步滑块的位置及颜色选择器的选择 that.select(hsb.h, hsb.s, hsb.b); //如果格式要求为rgb if(type === 'torgb'){ elemPickerInput.find('input').val(bgcolor); }; //如果格式要求为rgba if(type === 'rgba'){ var rgb = RGBSTo(bgcolor); //如果开启透明度而没有设置,则给默认值 if((bgcolor.match(/[0-9]{1,3}/g) || []).length == 3){ elemPickerInput.find('input').val('rgba('+ rgb.r +', '+ rgb.g +', '+ rgb.b +', 1)'); that.elemPicker.find('.'+ PICKER_ALPHA_SLIDER).css("left", 280); } else { elemPickerInput.find('input').val(bgcolor); var left = bgcolor.slice(bgcolor.lastIndexOf(",") + 1, bgcolor.length - 1) * 280; that.elemPicker.find('.'+ PICKER_ALPHA_SLIDER).css("left", left); }; //设置span背景色 that.elemPicker.find('.'+ PICKER_ALPHA_BG)[0].style.background = 'linear-gradient(to right, rgba('+ rgb.r +', '+ rgb.g +', '+ rgb.b +', 0), rgb('+ rgb.r +', '+ rgb.g +', '+ rgb.b +'))'; }; }else{ //如果没有背景颜色则默认到最初始的状态 that.select(0,100,100); elemPickerInput.find('input').val(""); that.elemPicker.find('.'+ PICKER_ALPHA_BG)[0].style.background = ''; that.elemPicker.find('.'+ PICKER_ALPHA_SLIDER).css("left", 280); } }; //颜色选择器滑动 / 点击 Class.prototype.side = function(){ var that = this ,options = that.config ,span = that.elemColorBox.find('.' + PICKER_TRIG_SPAN) ,type = span.attr('lay-type') ,side = that.elemPicker.find('.' + PICKER_SIDE) ,slider = that.elemPicker.find('.' + PICKER_SIDE_SLIDER) ,basis = that.elemPicker.find('.' + PICKER_BASIS) ,choose = that.elemPicker.find('.' + PICKER_BASIS_CUR) ,alphacolor = that.elemPicker.find('.' + PICKER_ALPHA_BG) ,alphaslider = that.elemPicker.find('.' + PICKER_ALPHA_SLIDER) ,_h = slider[0].offsetTop/180*360 ,_b = 100 - (choose[0].offsetTop + 3)/180*100 ,_s = (choose[0].offsetLeft + 3)/260*100 ,_a = Math.round(alphaslider[0].offsetLeft/280*100)/100 ,i = that.elemColorBox.find('.' + PICKER_TRIG_I) ,pre = that.elemPicker.find('.layui-colorpicker-pre').children('div') ,change = function(x,y,z,a){ that.select(x, y, z); var rgb = HSBToRGB({h:x, s:y, b:z}); i.addClass(ICON_PICKER_DOWN).removeClass(ICON_PICKER_CLOSE); span[0].style.background = 'rgb('+ rgb.r +', '+ rgb.g +', '+ rgb.b +')'; if(type === 'torgb'){ that.elemPicker.find('.' + PICKER_INPUT).find('input').val('rgb('+ rgb.r +', '+ rgb.g +', '+ rgb.b +')'); }; if(type === 'rgba'){ var left = 0; left = a * 280; alphaslider.css("left", left); that.elemPicker.find('.' + PICKER_INPUT).find('input').val('rgba('+ rgb.r +', '+ rgb.g +', '+ rgb.b +', '+ a +')'); span[0].style.background = 'rgba('+ rgb.r +', '+ rgb.g +', '+ rgb.b +', '+ a +')'; alphacolor[0].style.background = 'linear-gradient(to right, rgba('+ rgb.r +', '+ rgb.g +', '+ rgb.b +', 0), rgb('+ rgb.r +', '+ rgb.g +', '+ rgb.b +'))' }; //回调更改的颜色 options.change && options.change(that.elemPicker.find('.' + PICKER_INPUT).find('input').val()); } //拖拽元素 ,elemMove = $(['
      '].join('')) ,createMoveElem = function(call){ $('#LAY-colorpicker-moving')[0] || $('body').append(elemMove); elemMove.on('mousemove', call); elemMove.on('mouseup', function(){ elemMove.remove(); }).on('mouseleave', function(){ elemMove.remove(); }); }; //右侧主色选择 slider.on('mousedown', function(e){ var oldtop = this.offsetTop ,oldy = e.clientY; var move = function(e){ var top = oldtop + (e.clientY - oldy) ,maxh = side[0].offsetHeight; if(top < 0)top = 0; if(top > maxh)top = maxh; var h = top/180*360; _h = h; change(h, _s, _b, _a); e.preventDefault(); }; createMoveElem(move); //layui.stope(e); e.preventDefault(); }); side.on('click', function(e){ var top = e.clientY - $(this).offset().top; if(top < 0)top = 0; if(top > this.offsetHeight)top = this.offsetHeight; var h = top/180*360; _h = h; change(h, _s, _b, _a); e.preventDefault(); }); //中间小圆点颜色选择 choose.on('mousedown', function(e){ var oldtop = this.offsetTop ,oldleft = this.offsetLeft ,oldy = e.clientY ,oldx = e.clientX; var move = function(e){ var top = oldtop + (e.clientY - oldy) ,left = oldleft + (e.clientX - oldx) ,maxh = basis[0].offsetHeight - 3 ,maxw = basis[0].offsetWidth - 3; if(top < -3)top = -3; if(top > maxh)top = maxh; if(left < -3)left = -3; if(left > maxw)left = maxw; var s = (left + 3)/260*100 ,b = 100 - (top + 3)/180*100; _b = b; _s = s; change(_h, s, b, _a); e.preventDefault(); }; layui.stope(e); createMoveElem(move); e.preventDefault(); }); basis.on('mousedown', function(e){ var top = e.clientY - $(this).offset().top - 3 + $win.scrollTop() ,left = e.clientX - $(this).offset().left - 3 + $win.scrollLeft() if(top < -3)top = -3; if(top > this.offsetHeight - 3)top = this.offsetHeight - 3; if(left < -3)left = -3; if(left > this.offsetWidth - 3)left = this.offsetWidth - 3; var s = (left + 3)/260*100 ,b = 100 - (top + 3)/180*100; _b = b; _s = s; change(_h, s, b, _a); layui.stope(e); e.preventDefault(); choose.trigger(e, 'mousedown'); }); //底部透明度选择 alphaslider.on('mousedown', function(e){ var oldleft = this.offsetLeft ,oldx = e.clientX; var move = function(e){ var left = oldleft + (e.clientX - oldx) ,maxw = alphacolor[0].offsetWidth; if(left < 0)left = 0; if(left > maxw)left = maxw; var a = Math.round(left /280*100) /100; _a = a; change(_h, _s, _b, a); e.preventDefault(); }; createMoveElem(move); e.preventDefault(); }); alphacolor.on('click', function(e){ var left = e.clientX - $(this).offset().left if(left < 0)left = 0; if(left > this.offsetWidth)left = this.offsetWidth; var a = Math.round(left /280*100) /100; _a = a; change(_h, _s, _b, a); e.preventDefault(); }); //预定义颜色选择 pre.each(function(){ $(this).on('click', function(){ $(this).parent('.layui-colorpicker-pre').addClass('selected').siblings().removeClass('selected'); var color = this.style.backgroundColor ,hsb = RGBToHSB(RGBSTo(color)) ,a = color.slice(color.lastIndexOf(",") + 1, color.length - 1),left; _h = hsb.h; _s = hsb.s; _b = hsb.b; if((color.match(/[0-9]{1,3}/g) || []).length == 3) a = 1; _a = a; left = a * 280; change(hsb.h, hsb.s, hsb.b, a); }) }); }; //颜色选择器hsb转换 Class.prototype.select = function(h, s, b, type){ var that = this ,options = that.config ,hex = HSBToHEX({h:h, s:100, b:100}) ,color = HSBToHEX({h:h, s:s, b:b}) ,sidetop = h/360*180 ,top = 180 - b/100*180 - 3 ,left = s/100*260 - 3; that.elemPicker.find('.' + PICKER_SIDE_SLIDER).css("top", sidetop); //滑块的top that.elemPicker.find('.' + PICKER_BASIS)[0].style.background = '#' + hex; //颜色选择器的背景 //选择器的top left that.elemPicker.find('.' + PICKER_BASIS_CUR).css({ "top": top ,"left": left }); if(type === 'change') return; //选中的颜色 that.elemPicker.find('.' + PICKER_INPUT).find('input').val('#' + color); }; Class.prototype.pickerEvents = function(){ var that = this ,options = that.config ,elemColorBoxSpan = that.elemColorBox.find('.' + PICKER_TRIG_SPAN) //颜色盒子 ,elemPickerInput = that.elemPicker.find('.' + PICKER_INPUT + ' input') //颜色选择器表单 ,pickerEvents = { //清空 clear: function(othis){ elemColorBoxSpan[0].style.background =''; that.elemColorBox.find('.' + PICKER_TRIG_I).removeClass(ICON_PICKER_DOWN).addClass(ICON_PICKER_CLOSE); that.color = ''; options.done && options.done(''); that.removePicker(); } //确认 ,confirm: function(othis, change){ var value = elemPickerInput.val() ,colorValue = value ,hsb = {}; if(value.indexOf(',') > -1){ hsb = RGBToHSB(RGBSTo(value)); that.select(hsb.h, hsb.s, hsb.b); elemColorBoxSpan[0].style.background = (colorValue = '#' + HSBToHEX(hsb)); if((value.match(/[0-9]{1,3}/g) || []).length > 3 && elemColorBoxSpan.attr('lay-type') === 'rgba'){ var left = value.slice(value.lastIndexOf(",") + 1, value.length - 1) * 280; that.elemPicker.find('.' + PICKER_ALPHA_SLIDER).css("left", left); elemColorBoxSpan[0].style.background = value; colorValue = value; }; } else { hsb = HEXToHSB(value); elemColorBoxSpan[0].style.background = (colorValue = '#' + HSBToHEX(hsb)); that.elemColorBox.find('.' + PICKER_TRIG_I).removeClass(ICON_PICKER_CLOSE).addClass(ICON_PICKER_DOWN); }; if(change === 'change'){ that.select(hsb.h, hsb.s, hsb.b, change); options.change && options.change(colorValue); return; } that.color = value; options.done && options.done(value); that.removePicker(); } }; //选择器面板点击事件 that.elemPicker.on('click', '*[colorpicker-events]', function(){ var othis = $(this) ,attrEvent = othis.attr('colorpicker-events'); pickerEvents[attrEvent] && pickerEvents[attrEvent].call(this, othis); }); //输入框事件 elemPickerInput.on('keyup', function(e){ var othis = $(this) pickerEvents.confirm.call(this, othis, e.keyCode === 13 ? null : 'change'); }); } //颜色选择器输入 Class.prototype.events = function(){ var that = this ,options = that.config ,elemColorBoxSpan = that.elemColorBox.find('.' + PICKER_TRIG_SPAN) //弹出颜色选择器 that.elemColorBox.on('click' , function(){ that.renderPicker(); if($(ELEM_MAIN)[0]){ that.val(); that.side(); }; }); if(!options.elem[0] || that.elemColorBox[0].eventHandler) return; //绑定关闭控件事件 $doc.on(clickOrMousedown, function(e){ //如果点击的元素是颜色框 if($(e.target).hasClass(ELEM) || $(e.target).parents('.'+ELEM)[0] ) return; //如果点击的元素是选择器 if($(e.target).hasClass(ELEM_MAIN.replace(/\./g, '')) || $(e.target).parents(ELEM_MAIN)[0] ) return; if(!that.elemPicker) return; if(that.color){ var hsb = RGBToHSB(RGBSTo(that.color)); that.select(hsb.h, hsb.s, hsb.b); } else { that.elemColorBox.find('.' + PICKER_TRIG_I).removeClass(ICON_PICKER_DOWN).addClass(ICON_PICKER_CLOSE); } elemColorBoxSpan[0].style.background = that.color || ''; that.removePicker(); }); //自适应定位 $win.on('resize', function(){ if(!that.elemPicker || !$(ELEM_MAIN)[0]){ return false; } that.position(); }); that.elemColorBox[0].eventHandler = true; }; //核心入口 colorpicker.render = function(options){ var inst = new Class(options); return thisColorPicker.call(inst); }; exports(MOD_NAME, colorpicker); }); /** * element 常用元素操作 * MIT Licensed */ layui.define('jquery', function(exports){ "use strict"; var $ = layui.$ ,hint = layui.hint() ,device = layui.device() ,MOD_NAME = 'element', THIS = 'layui-this', SHOW = 'layui-show' ,Element = function(){ this.config = {}; }; //全局设置 Element.prototype.set = function(options){ var that = this; $.extend(true, that.config, options); return that; }; //表单事件 Element.prototype.on = function(events, callback){ return layui.onevent.call(this, MOD_NAME, events, callback); }; //外部Tab新增 Element.prototype.tabAdd = function(filter, options){ var TITLE = '.layui-tab-title' ,tabElem = $('.layui-tab[lay-filter='+ filter +']') ,titElem = tabElem.children(TITLE) ,barElem = titElem.children('.layui-tab-bar') ,contElem = tabElem.children('.layui-tab-content') ,li = ' 0) layAttr.unshift(''); //向前插,预留空格 return layAttr.join(' '); }() +'>'+ (options.title || 'unnaming') +''; barElem[0] ? barElem.before(li) : titElem.append(li); contElem.append('
      '+ (options.content || '') +'
      '); call.hideTabMore(true); call.tabAuto(); return this; }; //外部Tab删除 Element.prototype.tabDelete = function(filter, layid){ var TITLE = '.layui-tab-title' ,tabElem = $('.layui-tab[lay-filter='+ filter +']') ,titElem = tabElem.children(TITLE) ,liElem = titElem.find('>li[lay-id="'+ layid +'"]'); call.tabDelete(null, liElem); return this; }; //外部Tab切换 Element.prototype.tabChange = function(filter, layid){ var TITLE = '.layui-tab-title' ,tabElem = $('.layui-tab[lay-filter='+ filter +']') ,titElem = tabElem.children(TITLE) ,liElem = titElem.find('>li[lay-id="'+ layid +'"]'); call.tabClick.call(liElem[0], null, null, liElem); return this; }; //自定义Tab选项卡 Element.prototype.tab = function(options){ options = options || {}; dom.on('click', options.headerElem, function(e){ var index = $(this).index(); call.tabClick.call(this, e, index, null, options); }); }; //动态改变进度条 Element.prototype.progress = function(filter, percent){ var ELEM = 'layui-progress' ,elem = $('.'+ ELEM +'[lay-filter='+ filter +']') ,elemBar = elem.find('.'+ ELEM +'-bar') ,text = elemBar.find('.'+ ELEM +'-text'); elemBar.css('width', percent).attr('lay-percent', percent); text.text(percent); return this; }; var NAV_ELEM = '.layui-nav', NAV_ITEM = 'layui-nav-item', NAV_BAR = 'layui-nav-bar' ,NAV_TREE = 'layui-nav-tree', NAV_CHILD = 'layui-nav-child', NAV_CHILD_C = 'layui-nav-child-c' ,NAV_MORE = 'layui-nav-more', NAV_DOWN = 'layui-icon-down', NAV_ANIM = 'layui-anim layui-anim-upbit' //基础事件体 ,call = { //Tab 点击 tabClick: function(e, index, liElem, options){ options = options || {}; var othis = liElem || $(this) ,index = index || othis.parent().children('li').index(othis) ,parents = options.headerElem ? othis.parent() : othis.parents('.layui-tab').eq(0) ,item = options.bodyElem ? $(options.bodyElem) : parents.children('.layui-tab-content').children('.layui-tab-item') ,elemA = othis.find('a') ,isJump = elemA.attr('href') !== 'javascript:;' && elemA.attr('target') === '_blank' //是否存在跳转 ,unselect = typeof othis.attr('lay-unselect') === 'string' //是否禁用选中 ,filter = parents.attr('lay-filter'); //执行切换 if(!(isJump || unselect)){ othis.addClass(THIS).siblings().removeClass(THIS); item.eq(index).addClass(SHOW).siblings().removeClass(SHOW); } layui.event.call(this, MOD_NAME, 'tab('+ filter +')', { elem: parents ,index: index }); } //Tab删除 ,tabDelete: function(e, othis){ var li = othis || $(this).parent(), index = li.index() ,parents = li.parents('.layui-tab').eq(0) ,item = parents.children('.layui-tab-content').children('.layui-tab-item') ,filter = parents.attr('lay-filter'); if(li.hasClass(THIS)){ if(li.next()[0]){ call.tabClick.call(li.next()[0], null, index + 1); } else if(li.prev()[0]){ call.tabClick.call(li.prev()[0], null, index - 1); } } li.remove(); item.eq(index).remove(); setTimeout(function(){ call.tabAuto(); }, 50); layui.event.call(this, MOD_NAME, 'tabDelete('+ filter +')', { elem: parents ,index: index }); } //Tab自适应 ,tabAuto: function(){ var SCROLL = 'layui-tab-scroll', MORE = 'layui-tab-more', BAR = 'layui-tab-bar' ,CLOSE = 'layui-tab-close', that = this; $('.layui-tab').each(function(){ var othis = $(this) ,title = othis.children('.layui-tab-title') ,item = othis.children('.layui-tab-content').children('.layui-tab-item') ,STOPE = 'lay-stope="tabmore"' ,span = $(''); if(that === window && device.ie != 8){ call.hideTabMore(true) } //允许关闭 if(othis.attr('lay-allowClose')){ title.find('li').each(function(){ var li = $(this); if(!li.find('.'+CLOSE)[0]){ var close = $(''); close.on('click', call.tabDelete); li.append(close); } }); } if(typeof othis.attr('lay-unauto') === 'string') return; //响应式 if(title.prop('scrollWidth') > title.outerWidth()+1){ if(title.find('.'+BAR)[0]) return; title.append(span); othis.attr('overflow', ''); span.on('click', function(e){ title[this.title ? 'removeClass' : 'addClass'](MORE); this.title = this.title ? '' : '收缩'; }); } else { title.find('.'+BAR).remove(); othis.removeAttr('overflow'); } }); } //隐藏更多Tab ,hideTabMore: function(e){ var tsbTitle = $('.layui-tab-title'); if(e === true || $(e.target).attr('lay-stope') !== 'tabmore'){ tsbTitle.removeClass('layui-tab-more'); tsbTitle.find('.layui-tab-bar').attr('title',''); } } //点击一级菜单 /* ,clickThis: function(){ var othis = $(this), parents = othis.parents(NAV_ELEM) ,filter = parents.attr('lay-filter') ,elemA = othis.find('a') ,unselect = typeof othis.attr('lay-unselect') === 'string'; if(othis.find('.'+NAV_CHILD)[0]) return; if(!(elemA.attr('href') !== 'javascript:;' && elemA.attr('target') === '_blank') && !unselect){ parents.find('.'+THIS).removeClass(THIS); othis.addClass(THIS); } layui.event.call(this, MOD_NAME, 'nav('+ filter +')', othis); } ) */ //点击菜单 - a标签触发 ,clickThis: function(){ var othis = $(this) ,parents = othis.parents(NAV_ELEM) ,filter = parents.attr('lay-filter') ,parent = othis.parent() ,child = othis.siblings('.'+NAV_CHILD) ,unselect = typeof parent.attr('lay-unselect') === 'string'; //是否禁用选中 if(!(othis.attr('href') !== 'javascript:;' && othis.attr('target') === '_blank') && !unselect){ if(!child[0]){ parents.find('.'+THIS).removeClass(THIS); parent.addClass(THIS); } } //如果是垂直菜单 if(parents.hasClass(NAV_TREE)){ child.removeClass(NAV_ANIM); //如果有子菜单,则展开 if(child[0]){ parent[child.css('display') === 'none' ? 'addClass': 'removeClass'](NAV_ITEM+'ed'); if(parents.attr('lay-shrink') === 'all'){ parent.siblings().removeClass(NAV_ITEM + 'ed'); } } } layui.event.call(this, MOD_NAME, 'nav('+ filter +')', othis); } //点击子菜单选中 /* ,clickChild: function(){ var othis = $(this), parents = othis.parents(NAV_ELEM) ,filter = parents.attr('lay-filter'); parents.find('.'+THIS).removeClass(THIS); othis.addClass(THIS); layui.event.call(this, MOD_NAME, 'nav('+ filter +')', othis); } */ //折叠面板 ,collapse: function(){ var othis = $(this), icon = othis.find('.layui-colla-icon') ,elemCont = othis.siblings('.layui-colla-content') ,parents = othis.parents('.layui-collapse').eq(0) ,filter = parents.attr('lay-filter') ,isNone = elemCont.css('display') === 'none'; //是否手风琴 if(typeof parents.attr('lay-accordion') === 'string'){ var show = parents.children('.layui-colla-item').children('.'+SHOW); show.siblings('.layui-colla-title').children('.layui-colla-icon').html(''); show.removeClass(SHOW); } elemCont[isNone ? 'addClass' : 'removeClass'](SHOW); icon.html(isNone ? '' : ''); layui.event.call(this, MOD_NAME, 'collapse('+ filter +')', { title: othis ,content: elemCont ,show: isNone }); } }; //初始化元素操作 Element.prototype.init = function(type, filter){ var that = this, elemFilter = function(){ return filter ? ('[lay-filter="' + filter +'"]') : ''; }(), items = { //Tab选项卡 tab: function(){ call.tabAuto.call({}); } //导航菜单 ,nav: function(){ var TIME = 200, timer = {}, timerMore = {}, timeEnd = {}, NAV_TITLE = 'layui-nav-title' //滑块跟随 ,follow = function(bar, nav, index){ var othis = $(this), child = othis.find('.'+NAV_CHILD); if(nav.hasClass(NAV_TREE)){ //无子菜单时跟随 if(!child[0]){ var thisA = othis.children('.'+ NAV_TITLE); bar.css({ top: othis.offset().top - nav.offset().top ,height: (thisA[0] ? thisA : othis).outerHeight() ,opacity: 1 }); } } else { child.addClass(NAV_ANIM); //若居中对齐 if(child.hasClass(NAV_CHILD_C)) child.css({ left: -(child.outerWidth() - othis.width())/2 }); //滑块定位 if(child[0]){ //若有子菜单,则滑块消失 bar.css({ left: bar.position().left + bar.width()/2 ,width: 0 ,opacity: 0 }); } else { //bar 跟随 bar.css({ left: othis.position().left + parseFloat(othis.css('marginLeft')) ,top: othis.position().top + othis.height() - bar.height() }); } //渐显滑块并适配宽度 timer[index] = setTimeout(function(){ bar.css({ width: child[0] ? 0 : othis.width() ,opacity: child[0] ? 0 : 1 }); }, device.ie && device.ie < 10 ? 0 : TIME); //显示子菜单 clearTimeout(timeEnd[index]); if(child.css('display') === 'block'){ clearTimeout(timerMore[index]); } timerMore[index] = setTimeout(function(){ child.addClass(SHOW); othis.find('.'+NAV_MORE).addClass(NAV_MORE+'d'); }, 300); } }; //遍历导航 $(NAV_ELEM + elemFilter).each(function(index){ var othis = $(this) ,bar = $('') ,itemElem = othis.find('.'+NAV_ITEM); //hover 滑动效果 if(!othis.find('.'+NAV_BAR)[0]){ othis.append(bar); (othis.hasClass(NAV_TREE) ? itemElem.find('dd,>.'+ NAV_TITLE) : itemElem).on('mouseenter', function(){ follow.call(this, bar, othis, index); }).on('mouseleave', function(){ //鼠标移出 //是否为垂直导航 if(othis.hasClass(NAV_TREE)){ bar.css({ height: 0 ,opacity: 0 }); } else { //隐藏子菜单 clearTimeout(timerMore[index]); timerMore[index] = setTimeout(function(){ othis.find('.'+NAV_CHILD).removeClass(SHOW); othis.find('.'+NAV_MORE).removeClass(NAV_MORE+'d'); }, 300); } }); othis.on('mouseleave', function(){ clearTimeout(timer[index]) timeEnd[index] = setTimeout(function(){ if(!othis.hasClass(NAV_TREE)){ bar.css({ width: 0 ,left: bar.position().left + bar.width()/2 ,opacity: 0 }); } }, TIME); }); } //展开子菜单 itemElem.find('a').each(function(){ var thisA = $(this) ,parent = thisA.parent() ,child = thisA.siblings('.'+NAV_CHILD); //输出小箭头 if(child[0] && !thisA.children('.'+NAV_MORE)[0]){ thisA.append(''); } thisA.off('click', call.clickThis).on('click', call.clickThis); //点击菜单 }); }); } //面包屑 ,breadcrumb: function(){ var ELEM = '.layui-breadcrumb'; $(ELEM + elemFilter).each(function(){ var othis = $(this) ,ATTE_SPR = 'lay-separator' ,separator = othis.attr(ATTE_SPR) || '/' ,aNode = othis.find('a'); if(aNode.next('span['+ ATTE_SPR +']')[0]) return; aNode.each(function(index){ if(index === aNode.length - 1) return; $(this).after(''+ separator +''); }); othis.css('visibility', 'visible'); }); } //进度条 ,progress: function(){ var ELEM = 'layui-progress'; $('.' + ELEM + elemFilter).each(function(){ var othis = $(this) ,elemBar = othis.find('.layui-progress-bar') ,percent = elemBar.attr('lay-percent'); elemBar.css('width', function(){ return /^.+\/.+$/.test(percent) ? (new Function('return '+ percent)() * 100) + '%' : percent; }()); if(othis.attr('lay-showPercent')){ setTimeout(function(){ elemBar.html(''+ percent +''); },350); } }); } //折叠面板 ,collapse: function(){ var ELEM = 'layui-collapse'; $('.' + ELEM + elemFilter).each(function(){ var elemItem = $(this).find('.layui-colla-item') elemItem.each(function(){ var othis = $(this) ,elemTitle = othis.find('.layui-colla-title') ,elemCont = othis.find('.layui-colla-content') ,isNone = elemCont.css('display') === 'none'; //初始状态 elemTitle.find('.layui-colla-icon').remove(); elemTitle.append(''+ (isNone ? '' : '') +''); //点击标题 elemTitle.off('click', call.collapse).on('click', call.collapse); }); }); } }; return items[type] ? items[type]() : layui.each(items, function(index, item){ item(); }); }; Element.prototype.render = Element.prototype.init; var element = new Element(), dom = $(document); $(function(){ element.render(); }); var TITLE = '.layui-tab-title li'; dom.on('click', TITLE, call.tabClick); //Tab切换 dom.on('click', call.hideTabMore); //隐藏展开的Tab $(window).on('resize', call.tabAuto); //自适应 exports(MOD_NAME, element); }); /** * upload * 上传组件 */ layui.define('layer' , function(exports){ "use strict"; var $ = layui.$ ,layer = layui.layer ,hint = layui.hint() ,device = layui.device() //外部接口 ,upload = { config: {} //全局配置项 //设置全局项 ,set: function(options){ var that = this; that.config = $.extend({}, that.config, options); return that; } //事件 ,on: function(events, callback){ return layui.onevent.call(this, MOD_NAME, events, callback); } } //操作当前实例 ,thisUpload = function(){ var that = this; return { upload: function(files){ that.upload.call(that, files); } ,reload: function(options){ that.reload.call(that, options); } ,config: that.config } } //字符常量 ,MOD_NAME = 'upload', ELEM = 'layui-upload', THIS = 'layui-this', SHOW = 'layui-show', HIDE = 'layui-hide', DISABLED = 'layui-disabled' ,ELEM_FILE = 'layui-upload-file', ELEM_FORM = 'layui-upload-form', ELEM_IFRAME = 'layui-upload-iframe', ELEM_CHOOSE = 'layui-upload-choose', ELEM_DRAG = 'layui-upload-drag' //构造器 ,Class = function(options){ var that = this; that.config = $.extend({}, that.config, upload.config, options); that.render(); }; //默认配置 Class.prototype.config = { accept: 'images' //允许上传的文件类型:images/file/video/audio ,exts: '' //允许上传的文件后缀名 ,auto: true //是否选完文件后自动上传 ,bindAction: '' //手动上传触发的元素 ,url: '' //上传地址 ,force: '' //强制规定返回的数据格式,目前只支持是否强制 json ,field: 'file' //文件字段名 ,acceptMime: '' //筛选出的文件类型,默认为所有文件 ,method: 'post' //请求上传的 http 类型 ,data: {} //请求上传的额外参数 ,drag: true //是否允许拖拽上传 ,size: 0 //文件限制大小,默认不限制 ,number: 0 //允许同时上传的文件数,默认不限制 ,multiple: false //是否允许多文件上传,不支持ie8-9 }; //初始渲染 Class.prototype.render = function(options){ var that = this ,options = that.config; options.elem = $(options.elem); options.bindAction = $(options.bindAction); that.file(); that.events(); }; //追加文件域 Class.prototype.file = function(){ var that = this ,options = that.config ,elemFile = that.elemFile = $([ '' ].join('')) ,next = options.elem.next(); if(next.hasClass(ELEM_FILE) || next.hasClass(ELEM_FORM)){ next.remove(); } //包裹ie8/9容器 if(device.ie && device.ie < 10){ options.elem.wrap('
      '); } that.isFile() ? ( that.elemFile = options.elem ,options.field = options.elem[0].name ) : options.elem.after(elemFile); //初始化ie8/9的Form域 if(device.ie && device.ie < 10){ that.initIE(); } }; //ie8-9初始化 Class.prototype.initIE = function(){ var that = this ,options = that.config ,iframe = $('') ,elemForm = $(['
      ' ,''].join('')); //插入iframe $('#'+ ELEM_IFRAME)[0] || $('body').append(iframe); //包裹文件域 if(!options.elem.next().hasClass(ELEM_FORM)){ that.elemFile.wrap(elemForm); //追加额外的参数 options.elem.next('.'+ ELEM_FORM).append(function(){ var arr = []; layui.each(options.data, function(key, value){ value = typeof value === 'function' ? value() : value; arr.push('') }); return arr.join(''); }()); } }; //异常提示 Class.prototype.msg = function(content){ return layer.msg(content, { icon: 2 ,shift: 6 }); }; //判断绑定元素是否为文件域本身 Class.prototype.isFile = function(){ var elem = this.config.elem[0]; if(!elem) return; return elem.tagName.toLocaleLowerCase() === 'input' && elem.type === 'file' } //预读图片信息 Class.prototype.preview = function(callback){ var that = this; if(window.FileReader){ layui.each(that.chooseFiles, function(index, file){ var reader = new FileReader(); reader.readAsDataURL(file); reader.onload = function(){ callback && callback(index, file, this.result); } }); } }; //执行上传 Class.prototype.upload = function(files, type){ var that = this ,options = that.config ,elemFile = that.elemFile[0] //高级浏览器处理方式,支持跨域 ,ajaxSend = function(){ var successful = 0, failed = 0 ,items = files || that.files || that.chooseFiles || elemFile.files ,allDone = function(){ //多文件全部上传完毕的回调 if(options.multiple && successful + failed === that.fileLength){ typeof options.allDone === 'function' && options.allDone({ total: that.fileLength ,successful: successful ,failed: failed }); } }; layui.each(items, function(index, file){ var formData = new FormData(); formData.append(options.field, file); //追加额外的参数 layui.each(options.data, function(key, value){ value = typeof value === 'function' ? value() : value; formData.append(key, value); }); //提交文件 var opts = { url: options.url ,type: 'post' //统一采用 post 上传 ,data: formData ,contentType: false ,processData: false ,dataType: 'json' ,headers: options.headers || {} //成功回调 ,success: function(res){ successful++; done(index, res); allDone(); } //异常回调 ,error: function(e){ failed++; that.msg('Request URL is abnormal: '+ (e.statusText || 'error')); error(index); allDone(); } }; //进度条 if(typeof options.progress === 'function'){ opts.xhr = function(){ var xhr = $.ajaxSettings.xhr(); //上传进度 xhr.upload.addEventListener("progress", function (obj) { if(obj.lengthComputable){ var percent = Math.floor((obj.loaded/obj.total)* 100); //百分比 options.progress(percent, (options.item ? options.item[0] : options.elem[0]) , obj, index); } }); return xhr; } } $.ajax(opts); }); } //低版本 IE 处理方式,不支持跨域 ,iframeSend = function(){ var iframe = $('#'+ ELEM_IFRAME); that.elemFile.parent().submit(); //获取响应信息 clearInterval(Class.timer); Class.timer = setInterval(function() { var res, iframeBody = iframe.contents().find('body'); try { res = iframeBody.text(); } catch(e) { that.msg('Cross-domain requests are not supported'); clearInterval(Class.timer); error(); } if(res){ clearInterval(Class.timer); iframeBody.html(''); done(0, res); } }, 30); } //统一回调 ,done = function(index, res){ that.elemFile.next('.'+ ELEM_CHOOSE).remove(); elemFile.value = ''; if(options.force === 'json'){ if(typeof res !== 'object'){ try { res = JSON.parse(res); } catch(e){ res = {}; return that.msg('Please return JSON data format'); } } } typeof options.done === 'function' && options.done(res, index || 0, function(files){ that.upload(files); }); } //统一网络异常回调 ,error = function(index){ if(options.auto){ elemFile.value = ''; } typeof options.error === 'function' && options.error(index || 0, function(files){ that.upload(files); }); } ,exts = options.exts ,check ,value = function(){ var arr = []; layui.each(files || that.chooseFiles, function(i, item){ arr.push(item.name); }); return arr; }() //回调返回的参数 ,args = { //预览 preview: function(callback){ that.preview(callback); } //上传 ,upload: function(index, file){ var thisFile = {}; thisFile[index] = file; that.upload(thisFile); } //追加文件到队列 ,pushFile: function(){ that.files = that.files || {}; layui.each(that.chooseFiles, function(index, item){ that.files[index] = item; }); return that.files; } //重置文件 ,resetFile: function(index, file, filename){ var newFile = new File([file], filename); that.files = that.files || {}; that.files[index] = newFile; } } //提交上传 ,send = function(){ //上传前的回调 - 如果回调函数明确返回false,则停止上传(#pulls55) if(options.before && (options.before(args) === false)) return; //IE兼容处理 if(device.ie){ return device.ie > 9 ? ajaxSend() : iframeSend(); } ajaxSend(); } //文件类型名称 ,typeName = ({ file: '文件' ,images: '图片' ,video: '视频' ,audio: '音频' })[options.accept] || '文件'; //校验文件格式 value = value.length === 0 ? ((elemFile.value.match(/[^\/\\]+\..+/g)||[]) || '') : value; if(value.length === 0) return; //根据文件类型校验 switch(options.accept){ case 'file': //一般文件 layui.each(value, function(i, item){ if(exts && !RegExp('.\\.('+ exts +')$', 'i').test(escape(item))){ return check = true; } }); break; case 'video': //视频文件 layui.each(value, function(i, item){ if(!RegExp('.\\.('+ (exts || 'avi|mp4|wma|rmvb|rm|flash|3gp|flv') +')$', 'i').test(escape(item))){ return check = true; } }); break; case 'audio': //音频文件 layui.each(value, function(i, item){ if(!RegExp('.\\.('+ (exts || 'mp3|wav|mid') +')$', 'i').test(escape(item))){ return check = true; } }); break; default: //图片文件 layui.each(value, function(i, item){ if(!RegExp('.\\.('+ (exts || 'jpg|png|gif|bmp|jpeg') +')$', 'i').test(escape(item))){ return check = true; } }); break; } //校验失败提示 if(check){ that.msg('选择的'+ typeName +'中包含不支持的格式'); return elemFile.value = ''; } //选择文件的回调 if(type === 'choose' || options.auto){ options.choose && options.choose(args); if(type === 'choose'){ return; } } //检验文件数量 that.fileLength = function(){ var length = 0 ,items = files || that.files || that.chooseFiles || elemFile.files; layui.each(items, function(){ length++; }); return length; }(); if(options.number && that.fileLength > options.number){ return that.msg( '同时最多只能上传: '+ options.number + ' 个文件' +'
      您当前已经选择了: '+ that.fileLength +' 个文件' ); } //检验文件大小 if(options.size > 0 && !(device.ie && device.ie < 10)){ var limitSize; layui.each(that.chooseFiles, function(index, file){ if(file.size > 1024*options.size){ var size = options.size/1024; size = size >= 1 ? (size.toFixed(2) + 'MB') : options.size + 'KB' elemFile.value = ''; limitSize = size; } }); if(limitSize) return that.msg('文件大小不能超过 '+ limitSize); } send(); }; //重置方法 Class.prototype.reload = function(options){ options = options || {}; delete options.elem; delete options.bindAction; var that = this ,options = that.config = $.extend({}, that.config, upload.config, options) ,next = options.elem.next(); //更新文件域相关属性 next.attr({ name: options.name ,accept: options.acceptMime ,multiple: options.multiple }); }; //事件处理 Class.prototype.events = function(){ var that = this ,options = that.config //设置当前选择的文件队列 ,setChooseFile = function(files){ that.chooseFiles = {}; layui.each(files, function(i, item){ var time = new Date().getTime(); that.chooseFiles[time + '-' + i] = item; }); } //设置选择的文本 ,setChooseText = function(files, filename){ var elemFile = that.elemFile ,item = options.item ? options.item : options.elem ,value = files.length > 1 ? files.length + '个文件' : ((files[0] || {}).name || (elemFile[0].value.match(/[^\/\\]+\..+/g)||[]) || ''); if(elemFile.next().hasClass(ELEM_CHOOSE)){ elemFile.next().remove(); } that.upload(null, 'choose'); if(that.isFile() || options.choose) return; elemFile.after(''+ value +''); }; //点击上传容器 options.elem.off('upload.start').on('upload.start', function(){ var othis = $(this), data = othis.attr('lay-data'); if(data){ try{ data = new Function('return '+ data)(); that.config = $.extend({}, options, data); } catch(e){ hint.error('Upload element property lay-data configuration item has a syntax error: ' + data) } } that.config.item = othis; that.elemFile[0].click(); }); //拖拽上传 if(!(device.ie && device.ie < 10)){ options.elem.off('upload.over').on('upload.over', function(){ var othis = $(this) othis.attr('lay-over', ''); }) .off('upload.leave').on('upload.leave', function(){ var othis = $(this) othis.removeAttr('lay-over'); }) .off('upload.drop').on('upload.drop', function(e, param){ var othis = $(this), files = param.originalEvent.dataTransfer.files || []; othis.removeAttr('lay-over'); setChooseFile(files); options.auto ? that.upload() : setChooseText(files); //是否自动触发上传 }); } //文件选择 that.elemFile.off('upload.change').on('upload.change', function(){ var files = this.files || []; setChooseFile(files); options.auto ? that.upload() : setChooseText(files); //是否自动触发上传 }); //手动触发上传 options.bindAction.off('upload.action').on('upload.action', function(){ that.upload(); }); //防止事件重复绑定 if(options.elem.data('haveEvents')) return; that.elemFile.on('change', function(){ $(this).trigger('upload.change'); }); options.elem.on('click', function(){ if(that.isFile()) return; $(this).trigger('upload.start'); }); if(options.drag){ options.elem.on('dragover', function(e){ e.preventDefault(); $(this).trigger('upload.over'); }).on('dragleave', function(e){ $(this).trigger('upload.leave'); }).on('drop', function(e){ e.preventDefault(); $(this).trigger('upload.drop', e); }); } options.bindAction.on('click', function(){ $(this).trigger('upload.action'); }); options.elem.data('haveEvents', true); }; //核心入口 upload.render = function(options){ var inst = new Class(options); return thisUpload.call(inst); }; exports(MOD_NAME, upload); }); /** * form 表单组件 * MIT Licensed */ layui.define('layer', function(exports){ "use strict"; var $ = layui.$ ,layer = layui.layer ,hint = layui.hint() ,device = layui.device() ,MOD_NAME = 'form', ELEM = '.layui-form', THIS = 'layui-this' ,SHOW = 'layui-show', HIDE = 'layui-hide', DISABLED = 'layui-disabled' ,Form = function(){ this.config = { verify: { required: [ /[\S]+/ ,'必填项不能为空' ] ,phone: [ /^1\d{10}$/ ,'请输入正确的手机号' ] ,email: [ /^([a-zA-Z0-9_\.\-])+\@(([a-zA-Z0-9\-])+\.)+([a-zA-Z0-9]{2,4})+$/ ,'邮箱格式不正确' ] ,url: [ /^(#|(http(s?)):\/\/|\/\/)[^\s]+\.[^\s]+$/ ,'链接格式不正确' ] ,number: function(value){ if(!value || isNaN(value)) return '只能填写数字' } ,date: [ /^(\d{4})[-\/](\d{1}|0\d{1}|1[0-2])([-\/](\d{1}|0\d{1}|[1-2][0-9]|3[0-1]))*$/ ,'日期格式不正确' ] ,identity: [ /(^\d{15}$)|(^\d{17}(x|X|\d)$)/ ,'请输入正确的身份证号' ] } ,autocomplete: null //全局 autocomplete 状态。null 表示不干预 }; }; //全局设置 Form.prototype.set = function(options){ var that = this; $.extend(true, that.config, options); return that; }; //验证规则设定 Form.prototype.verify = function(settings){ var that = this; $.extend(true, that.config.verify, settings); return that; }; //获取指定表单对象 Form.prototype.getFormElem = function(filter){ return $(ELEM + function(){ return filter ? ('[lay-filter="' + filter +'"]') : ''; }()); }; //表单事件 Form.prototype.on = function(events, callback){ return layui.onevent.call(this, MOD_NAME, events, callback); }; //赋值/取值 Form.prototype.val = function(filter, object){ var that = this ,formElem = that.getFormElem(filter); //遍历 formElem.each(function(index, item){ var itemForm = $(this); //赋值 layui.each(object, function(key, value){ var itemElem = itemForm.find('[name="'+ key +'"]') ,type; //如果对应的表单不存在,则不执行 if(!itemElem[0]) return; type = itemElem[0].type; //如果为复选框 if(type === 'checkbox'){ itemElem[0].checked = value; } else if(type === 'radio') { //如果为单选框 itemElem.each(function(){ if(this.value == value ){ this.checked = true } }); } else { //其它类型的表单 itemElem.val(value); } }); }); form.render(null, filter); //返回值 return that.getValue(filter); }; //取值 Form.prototype.getValue = function(filter, itemForm){ itemForm = itemForm || this.getFormElem(filter); var nameIndex = {} //数组 name 索引 ,field = {} ,fieldElem = itemForm.find('input,select,textarea') //获取所有表单域 layui.each(fieldElem, function(_, item){ var othis = $(this) ,init_name; //初始 name item.name = (item.name || '').replace(/^\s*|\s*&/, ''); if(!item.name) return; //用于支持数组 name if(/^.*\[\]$/.test(item.name)){ var key = item.name.match(/^(.*)\[\]$/g)[0]; nameIndex[key] = nameIndex[key] | 0; init_name = item.name.replace(/^(.*)\[\]$/, '$1['+ (nameIndex[key]++) +']'); } if(/^checkbox|radio$/.test(item.type) && !item.checked) return; //复选框和单选框未选中,不记录字段 field[init_name || item.name] = item.value; }); return field; }; //表单控件渲染 Form.prototype.render = function(type, filter){ var that = this ,options = that.config ,elemForm = $(ELEM + function(){ return filter ? ('[lay-filter="' + filter +'"]') : ''; }()) ,items = { //输入框 input: function(elem){ var inputs = elem || elemForm.find('input,textarea'); //初始化全局的 autocomplete options.autocomplete && inputs.attr('autocomplete', options.autocomplete); } //下拉选择框 ,select: function(elem){ var TIPS = '请选择', CLASS = 'layui-form-select', TITLE = 'layui-select-title' ,NONE = 'layui-select-none', initValue = '', thatInput ,selects = elem || elemForm.find('select') //隐藏 select ,hide = function(e, clear){ if(!$(e.target).parent().hasClass(TITLE) || clear){ $('.'+CLASS).removeClass(CLASS+'ed ' + CLASS+'up'); thatInput && initValue && thatInput.val(initValue); } thatInput = null; } //各种事件 ,events = function(reElem, disabled, isSearch){ var select = $(this) ,title = reElem.find('.' + TITLE) ,input = title.find('input') ,dl = reElem.find('dl') ,dds = dl.children('dd') ,dts = dl.children('dt') // select分组dt元素 ,index = this.selectedIndex //当前选中的索引 ,nearElem; //select 组件当前选中的附近元素,用于辅助快捷键功能 if(disabled) return; // 搜索项 var laySearch = select.attr('lay-search'); //展开下拉 var showDown = function(){ var top = reElem.offset().top + reElem.outerHeight() + 5 - $win.scrollTop() ,dlHeight = dl.outerHeight(); index = select[0].selectedIndex; //获取最新的 selectedIndex reElem.addClass(CLASS+'ed'); dds.removeClass(HIDE); dts.removeClass(HIDE); nearElem = null; //初始选中样式 dds.eq(index).addClass(THIS).siblings().removeClass(THIS); //上下定位识别 if(top + dlHeight > $win.height() && top >= dlHeight){ reElem.addClass(CLASS + 'up'); } followScroll(); } //隐藏下拉 ,hideDown = function(choose){ reElem.removeClass(CLASS+'ed ' + CLASS+'up'); input.blur(); nearElem = null; if(choose) return; notOption(input.val(), function(none){ var selectedIndex = select[0].selectedIndex; //未查询到相关值 if(none){ initValue = $(select[0].options[selectedIndex]).html(); //重新获得初始选中值 //如果是第一项,且文本值等于 placeholder,则清空初始值 if(selectedIndex === 0 && initValue === input.attr('placeholder')){ initValue = ''; }; //如果有选中值,则将输入框纠正为该值。否则清空输入框 input.val(initValue || ''); } }); } //定位下拉滚动条 ,followScroll = function(){ var thisDd = dl.children('dd.'+ THIS); if(!thisDd[0]) return; var posTop = thisDd.position().top ,dlHeight = dl.height() ,ddHeight = thisDd.height(); //若选中元素在滚动条不可见底部 if(posTop > dlHeight){ dl.scrollTop(posTop + dl.scrollTop() - dlHeight + ddHeight - 5); } //若选择玄素在滚动条不可见顶部 if(posTop < 0){ dl.scrollTop(posTop + dl.scrollTop() - 5); } }; //点击标题区域 title.on('click', function(e){ reElem.hasClass(CLASS+'ed') ? ( hideDown() ) : ( hide(e, true), showDown() ); dl.find('.'+NONE).remove(); }); //点击箭头获取焦点 title.find('.layui-edge').on('click', function(){ input.focus(); }); //select 中 input 键盘事件 input.on('keyup', function(e){ //键盘松开 var keyCode = e.keyCode; //Tab键展开 if(keyCode === 9){ showDown(); } }).on('keydown', function(e){ //键盘按下 var keyCode = e.keyCode; //Tab键隐藏 if(keyCode === 9){ hideDown(); } //标注 dd 的选中状态 var setThisDd = function(prevNext, thisElem1){ var nearDd, cacheNearElem e.preventDefault(); //得到当前队列元素 var thisElem = function(){ var thisDd = dl.children('dd.'+ THIS); //如果是搜索状态,且按 Down 键,且当前可视 dd 元素在选中元素之前, //则将当前可视 dd 元素的上一个元素作为虚拟的当前选中元素,以保证递归不中断 if(dl.children('dd.'+ HIDE)[0] && prevNext === 'next'){ var showDd = dl.children('dd:not(.'+ HIDE +',.'+ DISABLED +')') ,firstIndex = showDd.eq(0).index(); if(firstIndex >=0 && firstIndex < thisDd.index() && !showDd.hasClass(THIS)){ return showDd.eq(0).prev()[0] ? showDd.eq(0).prev() : dl.children(':last'); } } if(thisElem1 && thisElem1[0]){ return thisElem1; } if(nearElem && nearElem[0]){ return nearElem; } return thisDd; //return dds.eq(index); }(); cacheNearElem = thisElem[prevNext](); //当前元素的附近元素 nearDd = thisElem[prevNext]('dd:not(.'+ HIDE +')'); //当前可视元素的 dd 元素 //如果附近的元素不存在,则停止执行,并清空 nearElem if(!cacheNearElem[0]) return nearElem = null; //记录附近的元素,让其成为下一个当前元素 nearElem = thisElem[prevNext](); //如果附近不是 dd ,或者附近的 dd 元素是禁用状态,则进入递归查找 if((!nearDd[0] || nearDd.hasClass(DISABLED)) && nearElem[0]){ return setThisDd(prevNext, nearElem); } nearDd.addClass(THIS).siblings().removeClass(THIS); //标注样式 followScroll(); //定位滚动条 }; if(keyCode === 38) setThisDd('prev'); //Up 键 if(keyCode === 40) setThisDd('next'); //Down 键 //Enter 键 if(keyCode === 13){ e.preventDefault(); dl.children('dd.'+THIS).trigger('click'); } }); // 检测值是否不属于 select 项 var notOption = function(value, callback, origin){ var num = 0; layui.each(dds, function(){ var othis = $(this); var text = othis.text(); // 是否区分大小写 if(laySearch !== 'exact'){ text = text.toLowerCase(); value = value.toLowerCase(); } // 匹配 var not = text.indexOf(value) === -1; if(value === '' || (origin === 'blur') ? value !== text : not) num++; origin === 'keyup' && othis[not ? 'addClass' : 'removeClass'](HIDE); }); // 处理select分组元素 origin === 'keyup' && layui.each(dts, function(){ var othis = $(this) ,thisDds = othis.nextUntil('dt').filter('dd') // 当前分组下的dd元素 ,allHide = thisDds.length == thisDds.filter('.' + HIDE).length; // 当前分组下所有dd元素都隐藏了 othis[allHide ? 'addClass' : 'removeClass'](HIDE); }); var none = num === dds.length; return callback(none), none; }; //搜索匹配 var search = function(e){ var value = this.value, keyCode = e.keyCode; if(keyCode === 9 || keyCode === 13 || keyCode === 37 || keyCode === 38 || keyCode === 39 || keyCode === 40 ){ return false; } notOption(value, function(none){ if(none){ dl.find('.'+NONE)[0] || dl.append('

      无匹配项

      '); } else { dl.find('.'+NONE).remove(); } }, 'keyup'); if(value === ''){ dl.find('.'+NONE).remove(); } followScroll(); //定位滚动条 }; if(isSearch){ input.on('keyup', search).on('blur', function(e){ var selectedIndex = select[0].selectedIndex; thatInput = input; //当前的 select 中的 input 元素 initValue = $(select[0].options[selectedIndex]).html(); //重新获得初始选中值 //如果是第一项,且文本值等于 placeholder,则清空初始值 if(selectedIndex === 0 && initValue === input.attr('placeholder')){ initValue = ''; }; setTimeout(function(){ notOption(input.val(), function(none){ initValue || input.val(''); //none && !initValue }, 'blur'); }, 200); }); } //选择 dds.on('click', function(){ var othis = $(this), value = othis.attr('lay-value'); var filter = select.attr('lay-filter'); //获取过滤器 if(othis.hasClass(DISABLED)) return false; if(othis.hasClass('layui-select-tips')){ input.val(''); } else { input.val(othis.text()); othis.addClass(THIS); } othis.siblings().removeClass(THIS); select.val(value).removeClass('layui-form-danger') layui.event.call(this, MOD_NAME, 'select('+ filter +')', { elem: select[0] ,value: value ,othis: reElem }); hideDown(true); return false; }); dds.on('mousedown',(events)=>{ events.stopPropagation() }); dds.on('mouseup',(events)=>{ events.stopPropagation() }); reElem.find('dl>dt').on('click', function(e){ return false; }); $(document).off('click', hide).on('click', hide); //点击其它元素关闭 select } selects.each(function(index, select){ var othis = $(this) ,hasRender = othis.next('.'+CLASS) ,disabled = this.disabled ,value = select.value ,selected = $(select.options[select.selectedIndex]) //获取当前选中项 ,optionsFirst = select.options[0]; if(typeof othis.attr('lay-ignore') === 'string') return othis.show(); var isSearch = typeof othis.attr('lay-search') === 'string' ,placeholder = optionsFirst ? ( optionsFirst.value ? TIPS : (optionsFirst.innerHTML || TIPS) ) : TIPS; //替代元素 var reElem = $(['
      ' ,'
      ' ,('') //禁用状态 ,'
      ' ,'
      ' ,function(options){ var arr = []; layui.each(options, function(index, item){ if(index === 0 && !item.value){ arr.push('
      '+ $.trim(item.innerHTML || TIPS) +'
      '); } else if(item.tagName.toLowerCase() === 'optgroup'){ arr.push('
      '+ item.label +'
      '); } else { arr.push('
      '+ $.trim(item.innerHTML) +'
      '); } }); arr.length === 0 && arr.push('
      没有选项
      '); return arr.join(''); }(othis.find('*')) +'
      ' ,'
      '].join('')); hasRender[0] && hasRender.remove(); //如果已经渲染,则Rerender othis.after(reElem); events.call(this, reElem, disabled, isSearch); }); } //复选框/开关 ,checkbox: function(elem){ var CLASS = { checkbox: ['layui-form-checkbox', 'layui-form-checked', 'checkbox'] ,_switch: ['layui-form-switch', 'layui-form-onswitch', 'switch'] } ,checks = elem || elemForm.find('input[type=checkbox]') ,events = function(reElem, RE_CLASS){ var check = $(this); //勾选 reElem.on('click', function(){ var filter = check.attr('lay-filter') //获取过滤器 ,text = (check.attr('lay-text')||'').split('|'); if(check[0].disabled) return; check[0].checked ? ( check[0].checked = false ,reElem.removeClass(RE_CLASS[1]).find('em').text(text[1]) ) : ( check[0].checked = true ,reElem.addClass(RE_CLASS[1]).find('em').text(text[0]) ); layui.event.call(check[0], MOD_NAME, RE_CLASS[2]+'('+ filter +')', { elem: check[0] ,value: check[0].value ,othis: reElem }); }); } checks.each(function(index, check){ var othis = $(this), skin = othis.attr('lay-skin') ,text = (othis.attr('lay-text') || '').split('|'), disabled = this.disabled; if(skin === 'switch') skin = '_'+skin; var RE_CLASS = CLASS[skin] || CLASS.checkbox; if(typeof othis.attr('lay-ignore') === 'string') return othis.show(); //替代元素 var hasRender = othis.next('.' + RE_CLASS[0]) ,reElem = $(['
      ' ,function(){ //不同风格的内容 var title = check.title.replace(/\s/g, '') ,type = { //复选框 checkbox: [ (title ? (''+ check.title +'') : '') ,'' ].join('') //开关 ,_switch: ''+ ((check.checked ? text[0] : text[1]) || '') +'' }; return type[skin] || type['checkbox']; }() ,'
      '].join('')); hasRender[0] && hasRender.remove(); //如果已经渲染,则Rerender othis.after(reElem); events.call(this, reElem, RE_CLASS); }); } //单选框 ,radio: function(elem){ var CLASS = 'layui-form-radio', ICON = ['', ''] ,radios = elem || elemForm.find('input[type=radio]') ,events = function(reElem){ var radio = $(this), ANIM = 'layui-anim-scaleSpring'; reElem.on('click', function(){ var name = radio[0].name, forms = radio.parents(ELEM); var filter = radio.attr('lay-filter'); //获取过滤器 var sameRadio = forms.find('input[name='+ name.replace(/(\.|#|\[|\])/g, '\\$1') +']'); //找到相同name的兄弟 if(radio[0].disabled) return; layui.each(sameRadio, function(){ var next = $(this).next('.'+CLASS); this.checked = false; next.removeClass(CLASS+'ed'); next.find('.layui-icon').removeClass(ANIM).html(ICON[1]); }); radio[0].checked = true; reElem.addClass(CLASS+'ed'); reElem.find('.layui-icon').addClass(ANIM).html(ICON[0]); layui.event.call(radio[0], MOD_NAME, 'radio('+ filter +')', { elem: radio[0] ,value: radio[0].value ,othis: reElem }); }); }; radios.each(function(index, radio){ var othis = $(this), hasRender = othis.next('.' + CLASS), disabled = this.disabled; if(typeof othis.attr('lay-ignore') === 'string') return othis.show(); hasRender[0] && hasRender.remove(); //如果已经渲染,则Rerender //替代元素 var reElem = $(['
      ' //禁用状态 ,''+ ICON[radio.checked ? 0 : 1] +'' ,'
      '+ function(){ var title = radio.title || ''; if(typeof othis.next().attr('lay-radio') === 'string'){ title = othis.next().html(); //othis.next().remove(); } return title }() +'
      ' ,'
      '].join('')); othis.after(reElem); events.call(this, reElem); }); } }; if (layui.type(type) === 'object') { // jquery 对象 type.each(function (index, item) { var elem = $(item); if (!elem.closest(ELEM).length) { // 如果不是存在layui-form中的直接跳过 return; } if (item.tagName === 'SELECT') { items['select'](elem); } else if (item.tagName === 'INPUT') { var itemType = item.type; if (itemType === 'checkbox' || itemType === 'radio') { items[itemType](elem); } else { items['input'](elem); } } }); } else { type ? ( items[type] ? items[type]() : hint.error('不支持的 "'+ type + '" 表单渲染') ) : layui.each(items, function(index, item){ item(); }); } return that; }; // elem 即要验证的区域表单选择器 - return true or false Form.prototype.validate = function(elem){ var stop = null; //验证不通过状态 var verify = form.config.verify; //验证规则 var DANGER = 'layui-form-danger'; //警示样式 elem = $(elem); // 节点不存在可视为 true if(!elem[0]) return !0; // 若节点不存在特定属性,则查找容器内有待验证的子节点 if(!elem.attr('lay-verify')){ elem = elem.find('*[lay-verify]'); } //开始校验 layui.each(elem, function(_, item){ var othis = $(this); var verifyStr = othis.attr('lay-verify') || ''; var vers = verifyStr.split('|'); var verType = othis.attr('lay-verType'); //提示方式 var value = othis.val(); othis.removeClass(DANGER); //移除警示样式 //遍历元素绑定的验证规则 layui.each(vers, function(_, thisVer){ var isTrue //是否命中校验 ,errorText = '' //错误提示文本 ,isFn = typeof verify[thisVer] === 'function'; //匹配验证规则 if(verify[thisVer]){ var isTrue = isFn ? errorText = verify[thisVer](value, item) : !verify[thisVer][0].test(value) //是否属于美化替换后的表单元素 ,isForm2Elem = item.tagName.toLowerCase() === 'select' || /^checkbox|radio$/.test(item.type); errorText = errorText || verify[thisVer][1]; if(thisVer === 'required'){ errorText = othis.attr('lay-reqText') || errorText; } //如果是必填项或者非空命中校验,则阻止提交,弹出提示 if(isTrue){ //提示层风格 if(verType === 'tips'){ layer.tips(errorText, function(){ if(typeof othis.attr('lay-ignore') !== 'string'){ if(isForm2Elem){ return othis.next(); } } return othis; }(), {tips: 1}); } else if(verType === 'alert') { layer.alert(errorText, {title: '提示', shadeClose: true}); } //如果返回的为字符或数字,则自动弹出默认提示框;否则由 verify 方法中处理提示 else if(/\bstring|number\b/.test(typeof errorText)){ layer.msg(errorText, {icon: 5, shift: 6}); } setTimeout(function(){ (isForm2Elem ? othis.next().find('input') : item).focus(); }, 7); /* // 非移动设备自动定位焦点 if(!device.mobile){ setTimeout(function(){ (isForm2Elem ? othis.next().find('input') : item).focus(); }, 7); } else { // 移动设备定位 $dom.scrollTop(function(){ try { return (isForm2Elem ? othis.next() : othis).focus().offset().top - 15 } catch(e){ return 0; } }()); } */ othis.addClass(DANGER); return stop = true; } } }); if(stop) return stop; }); return !stop; } // 提交表单并校验 var submit = Form.prototype.submit = function(filter, callback){ var field = {}; //字段集合 var button = $(this); //当前触发的按钮 // 表单域 lay-filter 属性值 var layFilter = typeof filter === 'string' ? filter : button.attr('lay-filter'); // 当前所在表单域 var elem = this.getFormElem ? this.getFormElem(layFilter) : button.parents(ELEM).eq(0); // 获取需要校验的元素 var verifyElem = elem.find('*[lay-verify]'); //开始校验 if(!form.validate(verifyElem)) return false; //获取当前表单值 field = form.getValue(null, elem); //返回的参数 var params = { elem: this.getFormElem ? (window.event && window.event.target) : this //触发事件的对象 ,form: this.getFormElem ? elem[0] : button.parents('form')[0] //当前所在的 form 元素,如果存在的话 ,field: field //当前表单数据 }; //回调 typeof callback === 'function' && callback(params); //事件 return layui.event.call(this, MOD_NAME, 'submit('+ layFilter +')', params); }; //自动完成渲染 var form = new Form() ,$dom = $(document), $win = $(window); $(function(){ form.render(); }); //表单reset重置渲染 $dom.on('reset', ELEM, function(){ var filter = $(this).attr('lay-filter'); setTimeout(function(){ form.render(null, filter); }, 50); }); //表单提交事件 $dom.on('submit', ELEM, submit) .on('click', '*[lay-submit]', submit); exports(MOD_NAME, form); }); /** * layui.table * 表格组件 */ layui.define(['laytpl', 'laypage', 'layer', 'form', 'util'], function(exports){ "use strict"; var $ = layui.$; var laytpl = layui.laytpl; var laypage = layui.laypage; var layer = layui.layer; var form = layui.form; var util = layui.util; var hint = layui.hint(); var device = layui.device(); //外部接口 var table = { config: { checkName: 'LAY_CHECKED' //是否选中状态的字段名 ,indexName: 'LAY_TABLE_INDEX' //初始下标索引名,用于恢复排序 ,disabledName: 'LAY_DISABLED' } //全局配置项 ,cache: {} //数据缓存 ,allData:[] // 全部数据 ,index: layui.table ? (layui.table.index + 10000) : 0 //设置全局项 ,set: function(options){ var that = this; that.config = $.extend({}, that.config, options); return that; } //事件 ,on: function(events, callback){ return layui.onevent.call(this, MOD_NAME, events, callback); } } //操作当前实例 ,thisTable = function(){ var that = this ,options = that.config ,id = options.id || options.index; if(id){ thisTable.that[id] = that; //记录当前实例对象 thisTable.config[id] = options; //记录当前实例配置项 } return { config: options ,reload: function(options, deep){ that.reload.call(that, options, deep); } ,reloadData: function(options, deep){ table.reloadData(id, options, deep); } ,setColsWidth: function(){ that.setColsWidth.call(that); } ,resize: function(){ //重置表格尺寸/结构 that.resize.call(that); }, getData: function(){ // return JSON.parse(JSON.stringify(that.config.data)) return that.config.data }, mergeData:function(id,data,index){ table.mergeData(id,data,index) }, // 设置列宽调整后的回调 onColumnsWidth: function(fun){ that.config.onColumnsWidth = fun; } } } //获取当前实例配置项 ,getThisTableConfig = function(id){ var config = thisTable.config[id]; if(!config) hint.error(id ? ('The table instance with ID \''+ id +'\' not found') : 'ID argument required'); return config || null; } //解析自定义模板数据 ,parseTempData = function(obj){ obj = obj || {}; var options = this.config || {} ,item3 = obj.item3 //表头数据 ,content = obj.content; //原始内容 //是否编码 HTML if(options.escape) content = util.escape(content); //获取模板 var templet = obj.text && item3.exportTemplet || (item3.templet || item3.toolbar); //获取模板内容 if(templet){ content = typeof templet === 'function' ? templet.call(item3, obj.tplData, obj.obj) : laytpl($(templet).html() || String(content)).render(obj.tplData); } //是否只返回文本 return obj.text ? $('
      '+ content +'
      ').text() : content; } //字符常量 ,MOD_NAME = 'table', ELEM = '.layui-table', THIS = 'layui-this', SHOW = 'layui-show', HIDE = 'layui-hide', HIDE_V = 'layui-hide-v', DISABLED = 'layui-disabled', NONE = 'layui-none' ,ELEM_VIEW = 'layui-table-view', ELEM_TOOL = '.layui-table-tool', ELEM_BOX = '.layui-table-box', ELEM_INIT = '.layui-table-init', ELEM_HEADER = '.layui-table-header', ELEM_BODY = '.layui-table-body', ELEM_MAIN = '.layui-table-main', ELEM_FIXED = '.layui-table-fixed', ELEM_FIXL = '.layui-table-fixed-l', ELEM_FIXR = '.layui-table-fixed-r', ELEM_TOTAL = '.layui-table-total', ELEM_PAGE = '.layui-table-page', ELEM_SORT = '.layui-table-sort', ELEM_EDIT = 'layui-table-edit', ELEM_HOVER = 'layui-table-hover' //thead区域模板 ,TPL_HEADER = function(options){ var rowCols = '{{#if(item2.colspan){}} colspan="{{=item2.colspan}}"{{#} if(item2.rowspan){}} rowspan="{{=item2.rowspan}}"{{#}}}'; options = options || {}; return ['
      ' ,'' ,'{{# layui.each(d.data.cols, function(i1, item1){ }}' ,'' ,'{{# layui.each(item1, function(i2, item2){ }}' ,'{{# if(item2.fixed && item2.fixed !== "right"){ left = true; } }}' ,'{{# if(item2.fixed === "right"){ right = true; } }}' ,function(){ if(options.fixed && options.fixed !== 'right'){ return '{{# if(item2.fixed && item2.fixed !== "right"){ }}'; } if(options.fixed === 'right'){ return '{{# if(item2.fixed === "right"){ }}'; } return ''; }() ,'{{# var isSort = !(item2.colGroup) && item2.sort; }}' ,'' ,(options.fixed ? '{{# }; }}' : '') ,'{{# }); }}' ,'' ,'{{# }); }}' ,'' ,'
      ' ,'
      ' ,'{{# if(item2.type === "checkbox"){ }}' //复选框 ,'' ,'{{# } else { }}' ,'{{-item2.title||""}}' ,'{{# if(isSort){ }}' ,'' ,'{{# } }}' ,'{{# } }}' ,'
      ' ,'
      '].join(''); } // tbody 区域模板 ,TPL_BODY = ['' ,'' ,'
      '].join('') //主模板 ,TPL_MAIN = [ ,'{{# if(d.data.toolbar){ }}' ,'
      ' ,'
      ' ,'
      ' ,'
      ' ,'{{# } }}' ,'
      ' ,'{{# if(d.data.loading){ }}' ,'
      ' ,'' ,'
      ' ,'{{# } }}' ,'{{# var left, right; }}' ,'
      ' ,TPL_HEADER() ,'
      ' ,'
      ' ,TPL_BODY ,'
      ' ,'{{# if(left){ }}' ,'
      ' ,'
      ' ,TPL_HEADER({fixed: true}) ,'
      ' ,'
      ' ,TPL_BODY ,'
      ' ,'
      ' ,'{{# }; }}' ,'{{# if(right){ }}' ,'
      ' ,'
      ' ,TPL_HEADER({fixed: 'right'}) ,'
      ' ,'
      ' ,'
      ' ,TPL_BODY ,'
      ' ,'
      ' ,'{{# }; }}' ,'
      ' ,'{{# if(d.data.totalRow){ }}' ,'
      ' ,'' ,'' , '
      ' ,'
      ' ,'{{# } }}' ,'{{# if(d.data.page || d.data.pagebar){ }}' ,'
      ' ,'
      ' ,'
      ' ,'{{# } }}' ,'' ].join('') ,_WIN = $(window) ,_DOC = $(document) //构造器 ,Class = function(options){ var that = this; that.reanderTime = new Date().getTime() that.index = ++table.index; that.config = $.extend({}, that.config, table.config, options); that.render(); }; //初始默认配置 Class.prototype.config = { limit: 10 //每页显示的数量 ,loading: true //请求数据时,是否显示 loading ,escape: true // 是否开启 HTML 编码功能,即转义 html 原文 ,cellMinWidth: 60 //所有单元格默认最小宽度 ,editTrigger: 'click' //单元格编辑的事件触发方式 ,defaultToolbar: ['filter', 'exports', 'print'] //工具栏右侧图标 ,autoSort: true //是否前端自动排序。如果否,则需自主排序(通常为服务端处理好排序) ,text: { none: '无数据' } }; //表格渲染 Class.prototype.render = function(type){ var that = this ,options = that.config; options.elem = $(options.elem); options.where = options.where || {}; options.id = options.id || options.elem.attr('id') || that.index; //请求参数的自定义格式 options.request = $.extend({ pageName: 'page' ,limitName: 'limit' }, options.request) //响应数据的自定义格式 options.response = $.extend({ statusName: 'code' //规定数据状态的字段名称 ,statusCode: 0 //规定成功的状态码 ,msgName: 'msg' //规定状态信息的字段名称 ,dataName: 'data' //规定数据总数的字段名称 ,totalRowName: 'totalRow' //规定数据统计的字段名称 ,countName: 'count' }, options.response); //如果 page 传入 laypage 对象 if(typeof options.page === 'object'){ options.limit = options.page.limit || options.limit; options.limits = options.page.limits || options.limits; that.page = options.page.curr = options.page.curr || 1; delete options.page.elem; delete options.page.jump; } if(!options.elem[0]) return that; // 仅重载数据 if(type === 'reloadData'){ return that.pullData(that.page); //请求数据 } //高度铺满:full-差距值 if(options.height && /^full-\d+$/.test(options.height)){ that.fullHeightGap = options.height.split('-')[1]; options.height = _WIN.height() - that.fullHeightGap; } //初始化一些参数 that.setInit(); //开始插入替代元素 var othis = options.elem ,hasRender = othis.next('.' + ELEM_VIEW) //主容器 ,reElem = that.elem = $('
      '); reElem.addClass(function(){ var arr = [ELEM_VIEW, ELEM_VIEW +'-'+ that.index]; if(options.className) arr.push(options.className); return arr.join(' '); }()).attr({ 'lay-filter': 'LAY-TABLE-FORM-DF-'+ that.index ,'lay-id': options.id ,'style': function(){ var arr = []; if(options.width) arr.push('width:'+ options.width + 'px;'); if(options.height) arr.push('height:'+ options.height + 'px;'); return arr.join('') }() }).html(laytpl(TPL_MAIN).render({ data: options ,index: that.index //索引 })); options.index = that.index; that.key = options.id || options.index; table.allData[that.key] = options.data //生成替代元素 hasRender[0] && hasRender.remove(); //如果已经渲染,则Rerender othis.after(reElem); //各级容器 that.layTool = reElem.find(ELEM_TOOL); that.layBorderBox = reElem; that.layBox = reElem.find(ELEM_BOX); that.layHeader = reElem.find(ELEM_HEADER); that.layMain = reElem.find(ELEM_MAIN); that.layBody = reElem.find(ELEM_BODY); that.layFixed = reElem.find(ELEM_FIXED); that.layFixLeft = reElem.find(ELEM_FIXL); that.layFixRight = reElem.find(ELEM_FIXR); that.layTotal = reElem.find(ELEM_TOTAL); that.layPage = reElem.find(ELEM_PAGE); // 初始化头部工具栏 that.renderToolbar(); // 初始化底部分页栏 that.renderPagebar(); // 让表格平铺 that.fullSize(); // 如果多级表头,则填补表头高度 if(options.cols.length > 1){ // 补全高度 var th = that.layFixed.find(ELEM_HEADER).find('th'); th.height(that.layHeader.height() - 1 - parseFloat(th.css('padding-top')) - parseFloat(th.css('padding-bottom'))); } that.pullData(that.page); //请求数据 that.events(); //事件 }; //根据列类型,定制化参数 Class.prototype.initOpts = function(item){ var that = this ,options = that.config ,initWidth = { checkbox: 50 ,radio: 50 ,space: 15 ,numbers: 40 }; //让 type 参数兼容旧版本 if(item.checkbox) item.type = "checkbox"; if(item.space) item.type = "space"; if(!item.type) item.type = "normal"; if(item.type !== "normal"){ item.unresize = true; item.width = item.width || initWidth[item.type]; } }; //初始化一些参数 Class.prototype.setInit = function(type){ var that = this ,options = that.config; options.clientWidth = options.width || function(){ //获取容器宽度 //如果父元素宽度为0(一般为隐藏元素),则继续查找上层元素,直到找到真实宽度为止 var getWidth = function(parent){ var width, isNone; parent = parent || options.elem.parent() width = parent.width(); try { isNone = parent.css('display') === 'none'; } catch(e){} if(parent[0] && (!width || isNone)) return getWidth(parent.parent()); return width; }; return getWidth(); }(); if(type === 'width') return options.clientWidth; // 初始化 css 参数 if(options.css && options.css.indexOf(ELEM_VIEW) === -1){ var css = options.css.split('}'); layui.each(css, function(index, value){ if(value){ css[index] = '.'+ ELEM_VIEW + '-'+ that.index + ' ' + value; } }); options.css = css.join('}'); } // 封装对col的配置处理 var initChildCols = function (i1, item1, i2, item2) { //如果列参数为空,则移除 if (!item2) { item1.splice(i2, 1); return; } item2.key = i1 + '-' + i2; item2.hide = item2.hide || false; item2.colspan = item2.colspan || 1; item2.rowspan = item2.rowspan || 1; //根据列类型,定制化参数 that.initOpts(item2); //设置列的父列索引 //如果是组合列,则捕获对应的子列 var indexChild = i1 + (parseInt(item2.rowspan) || 1); if (indexChild < options.cols.length) { // 只要不是最后一层都会有子列 item2.colGroup = true; var childIndex = 0; layui.each(options.cols[indexChild], function (i22, item22) { //如果子列已经被标注为{HAS_PARENT},或者子列累计 colspan 数等于父列定义的 colspan,则跳出当前子列循环 if (item22.HAS_PARENT || (childIndex >= 1 && childIndex == (item2.colspan || 1))) return; item22.HAS_PARENT = true; item22.parentKey = i1 + '-' + i2; childIndex = childIndex + parseInt(item22.colspan > 1 ? item22.colspan : 1); initChildCols(indexChild, options.cols[indexChild], i22, item22); }); } else { item2.colGroup = false; } }; //初始化列参数 layui.each(options.cols, function(i1, item1){ if (i1) return true; layui.each(item1, function(i2, item2){ initChildCols(i1, item1, i2, item2); }); }); }; //初始工具栏 Class.prototype.renderToolbar = function(){ var that = this ,options = that.config //添加工具栏左侧模板 var leftDefaultTemp = [ '
      ' ,'
      ' ,'
      ' ].join('') ,elemToolTemp = that.layTool.find('.layui-table-tool-temp'); if(options.toolbar === 'default'){ elemToolTemp.html(leftDefaultTemp); } else if(typeof options.toolbar === 'string'){ var toolbarHtml = $(options.toolbar).html() || ''; toolbarHtml && elemToolTemp.html( laytpl(toolbarHtml).render(options) ); } //添加工具栏右侧面板 var layout = { filter: { title: '筛选列' ,layEvent: 'LAYTABLE_COLS' ,icon: 'layui-icon-cols' } ,exports: { title: '导出' ,layEvent: 'LAYTABLE_EXPORT' ,icon: 'layui-icon-export' } ,print: { title: '打印' ,layEvent: 'LAYTABLE_PRINT' ,icon: 'layui-icon-print' } }, iconElem = []; if(typeof options.defaultToolbar === 'object'){ layui.each(options.defaultToolbar, function(i, item){ var thisItem = typeof item === 'string' ? layout[item] : item; if(thisItem){ iconElem.push('
      ' +'' +'
      '); } }); } that.layTool.find('.layui-table-tool-self').html(iconElem.join('')); }; // 分页栏 Class.prototype.renderPagebar = function(){ var that = this ,options = that.config ,layPagebar = that.layPagebar = $('
      ') //开启分页栏自定义模板 if(options.pagebar){ var pagebarHtml = $(options.pagebar).html() || ''; pagebarHtml && layPagebar.append(laytpl(pagebarHtml).render(options)); that.layPage.append(layPagebar); } }; //同步表头父列的相关值 Class.prototype.setParentCol = function(hide, parentKey){ var that = this ,options = that.config ,parentTh = that.layHeader.find('th[data-key="'+ options.index +'-'+ parentKey +'"]') //获取父列元素 ,parentColspan = parseInt(parentTh.attr('colspan')) || 0; if(parentTh[0]){ var arrParentKey = parentKey.split('-') ,getThisCol = options.cols[arrParentKey[0]][arrParentKey[1]]; hide ? parentColspan-- : parentColspan++; parentTh.attr('colspan', parentColspan); parentTh[parentColspan < 1 ? 'addClass' : 'removeClass'](HIDE); getThisCol.colspan = parentColspan; //同步 colspan 参数 getThisCol.hide = parentColspan < 1; //同步 hide 参数 //递归,继续往上查询是否有父列 var nextParentKey = parentTh.data('parentkey'); nextParentKey && that.setParentCol(hide, nextParentKey); } }; //多级表头补丁 Class.prototype.setColsPatch = function(){ var that = this ,options = that.config //同步表头父列的相关值 layui.each(options.cols, function(i1, item1){ layui.each(item1, function(i2, item2){ if(item2.hide){ that.setParentCol(item2.hide, item2.parentKey); } }); }); }; //动态分配列宽 Class.prototype.setColsWidth = function(){ var that = this ,options = that.config ,colNums = 0 //列个数 ,autoColNums = 0 //自动列宽的列个数 ,autoWidth = 0 //自动列分配的宽度 ,countWidth = 0 //所有列总宽度和 ,cntrWidth = that.setInit('width'); //统计列个数 that.eachCols(function(i, item){ item.hide || colNums++; }); //减去边框差和滚动条宽 cntrWidth = cntrWidth - function(){ return (options.skin === 'line' || options.skin === 'nob') ? 2 : colNums + 1; }() - that.getScrollWidth(that.layMain[0]) - 1; //计算自动分配的宽度 var getAutoWidth = function(back){ //遍历所有列 layui.each(options.cols, function(i1, item1){ layui.each(item1, function(i2, item2){ var width = 0 ,minWidth = item2.minWidth || options.cellMinWidth; //最小宽度 if(!item2){ item1.splice(i2, 1); return; } if(item2.colGroup || item2.hide) return; if(!back){ width = item2.width || 0; if(/\d+%$/.test(width)){ //列宽为百分比 width = Math.floor((parseFloat(width) / 100) * cntrWidth); width < minWidth && (width = minWidth); } else if(!width){ //列宽未填写 item2.width = width = 0; autoColNums++; } } else if(autoWidth && autoWidth < minWidth){ autoColNums--; width = minWidth; } if(item2.hide) width = 0; countWidth = countWidth + width; }); }); //如果未填充满,则将剩余宽度平分 (cntrWidth > countWidth && autoColNums) && ( autoWidth = (cntrWidth - countWidth) / autoColNums ); } getAutoWidth(); getAutoWidth(true); //重新检测分配的宽度是否低于最小列宽 //记录自动列数 that.autoColNums = autoColNums; //设置列宽 that.eachCols(function(i3, item3){ var minWidth = item3.minWidth || options.cellMinWidth; if(item3.colGroup || item3.hide) return; //给位分配宽的列平均分配宽 if(item3.width === 0){ that.getCssRule(options.index +'-'+ item3.key, function(item){ item.style.width = Math.floor(autoWidth >= minWidth ? autoWidth : minWidth) + 'px'; }); } //给设定百分比的列分配列宽 else if(/\d+%$/.test(item3.width)){ that.getCssRule(options.index +'-'+ item3.key, function(item){ item.style.width = Math.floor((parseFloat(item3.width) / 100) * cntrWidth) + 'px'; }); } }); //填补 Math.floor 造成的数差 var patchNums = that.layMain.width() - that.getScrollWidth(that.layMain[0]) - that.layMain.children('table').outerWidth(); if(that.autoColNums && patchNums >= -colNums && patchNums <= colNums){ var getEndTh = function(th){ var field; th = th || that.layHeader.eq(0).find('thead th:last-child') field = th.data('field'); if(!field && th.prev()[0]){ return getEndTh(th.prev()) } return th } ,th = getEndTh() ,key = th.data('key'); that.getCssRule(key, function(item){ var width = item.style.width || th.outerWidth(); item.style.width = (parseFloat(width) + patchNums) + 'px'; //二次校验,如果仍然出现横向滚动条(通常是 1px 的误差导致) if(that.layMain.height() - that.layMain.prop('clientHeight') > 0){ item.style.width = (parseFloat(item.style.width) - 1) + 'px'; } }); } that.loading(!0); }; //重置表格尺寸/结构 Class.prototype.resize = function(){ var that = this; that.fullSize(); //让表格铺满 that.setColsWidth(); //自适应列宽 that.scrollPatch(); //滚动条补丁 }; //表格重载 Class.prototype.reload = function(options, deep, type){ var that = this; options = options || {}; delete that.haveInit; //防止数组深度合并 layui.each(options, function(key, item){ if(layui.type(item) === 'array') delete that.config[key]; }); //对参数进行深度或浅扩展 that.config = $.extend(deep, {}, that.config, options); table.allData[that.key] = that.config.data //执行渲染 that.render(type); }; //异常提示 Class.prototype.errorView = function(html){ var that = this ,elemNone = that.layMain.find('.'+ NONE) ,layNone = $('
      '+ (html || 'Error') +'
      '); if(elemNone[0]){ that.layNone.remove(); elemNone.remove(); } that.layFixed.addClass(HIDE); that.layMain.find('tbody').html(''); that.layMain.append(that.layNone = layNone); // 异常情况下对page和total的内容处理 that.layPage && that.layPage.addClass(HIDE_V).find('>div').html(''); that.layTotal && that.layTotal.addClass(HIDE_V).find('tbody').html(''); table.cache[that.key] = []; //格式化缓存数据 }; // 初始页码 Class.prototype.page = 1; //获得数据 Class.prototype.pullData = function(curr){ var that = this ,options = that.config ,request = options.request ,response = options.response ,sort = function(){ if(typeof options.initSort === 'object'){ that.sort(options.initSort.field, options.initSort.type); } }; that.startTime = new Date().getTime(); //渲染开始时间 if(options.url){ //Ajax请求 var params = {}; params[request.pageName] = curr; params[request.limitName] = options.limit; //参数 var data = $.extend(params, options.where); if(options.contentType && options.contentType.indexOf("application/json") == 0){ //提交 json 格式 data = JSON.stringify(data); } that.loading(); $.ajax({ type: options.method || 'get' ,url: options.url ,contentType: options.contentType ,data: data ,dataType: 'json' ,headers: options.headers || {} ,success: function(res){ //如果有数据解析的回调,则获得其返回的数据 if(typeof options.parseData === 'function'){ res = options.parseData(res) || res; } //检查数据格式是否符合规范 if(res[response.statusName] != response.statusCode){ that.renderForm(); that.errorView( res[response.msgName] || ('返回的数据不符合规范,正确的成功状态码应为:"'+ response.statusName +'": '+ response.statusCode) ); } else { that.renderData(res, curr, res[response.countName]), sort(); options.time = (new Date().getTime() - that.startTime) + ' ms'; //耗时(接口请求+视图渲染) } that.setColsWidth(); typeof options.done === 'function' && options.done(res, curr, res[response.countName]); } ,error: function(e, msg){ that.errorView('请求异常,错误提示:'+ msg); that.renderForm(); that.setColsWidth(); typeof options.error === 'function' && options.error(e, msg); } }); } else if(layui.type(options.data) === 'array'){ //已知数据 var res = {} ,startLimit = curr*options.limit - options.limit res[response.dataName] = options.data.concat().splice(startLimit, options.limit); res[response.countName] = options.data.length; //记录合计行数据 if(typeof options.totalRow === 'object'){ res[response.totalRowName] = $.extend({}, options.totalRow); } that.renderData(res, curr, res[response.countName]), sort(); that.setColsWidth(); typeof options.done === 'function' && options.done(res, curr, res[response.countName]); } }; //遍历表头 Class.prototype.eachCols = function(callback){ var that = this; table.eachCols(null, callback, that.config.cols); return that; }; //数据渲染 Class.prototype.renderData = function(res, curr, count, sort){ var that = this ,options = that.config ,data = res[options.response.dataName] || [] //列表数据 ,totalRowData = res[options.response.totalRowName] //合计行数据 ,trs = [] ,trs_fixed = [] ,trs_fixed_r = [] //渲染视图 ,render = function(){ //后续性能提升的重点 var thisCheckedRowIndex; if(!sort && that.sortKey){ return that.sort(that.sortKey.field, that.sortKey.sort, true); } layui.each(data, function(i1, item1){ var tds = [], tds_fixed = [], tds_fixed_r = [] ,numbers = i1 + options.limit*(curr - 1) + 1; //序号 //若数据项为空数组,则不往下执行(因为删除数据时,会将原有数据设置为 []) if(layui.type(item1) === 'array' && item1.length === 0) return; //记录下标索引,用于恢复排序 if(!sort){ item1[table.config.indexName] = i1; } //遍历表头 that.eachCols(function(i3, item3){ var field = item3.field || i3 ,key = options.index + '-' + item3.key ,content = item1[field]; if(content === undefined || content === null) content = ''; if(item3.colGroup) return; //td内容 var td = ['' ,'
      ' + function(){ var tplData = $.extend(true, { LAY_INDEX: numbers ,LAY_COL: item3 }, item1) ,checkName = table.config.checkName ,disabledName = table.config.disabledName; //渲染不同风格的列 switch(item3.type){ case 'checkbox': // 复选 return ''; break; case 'radio': // 单选 if(tplData[checkName]){ thisCheckedRowIndex = i1; } return ''; break; case 'numbers': return numbers; break; }; //解析工具列模板 if(item3.toolbar){ return laytpl($(item3.toolbar).html()||'').render(tplData); } return parseTempData.call(that, { item3: item3 ,content: content ,tplData: tplData }); }() ,'
      '].join(''); tds.push(td); if(item3.fixed && item3.fixed !== 'right') tds_fixed.push(td); if(item3.fixed === 'right') tds_fixed_r.push(td); }); trs.push(''+ tds.join('') + ''); trs_fixed.push(''+ tds_fixed.join('') + ''); trs_fixed_r.push(''+ tds_fixed_r.join('') + ''); }); // 容器的滚动条位置复位 that.layBody.scrollTop(0); if(options.resetScrollbar){ that.layBody.scrollLeft(0); } that.layMain.find('.'+ NONE).remove(); that.layMain.find('tbody').html(trs.join('')); that.layFixLeft.find('tbody').html(trs_fixed.join('')); that.layFixRight.find('tbody').html(trs_fixed_r.join('')); that.renderForm(); typeof thisCheckedRowIndex === 'number' && that.setThisRowChecked(thisCheckedRowIndex); that.syncCheckAll(); //滚动条补丁 that.haveInit ? that.scrollPatch() : setTimeout(function(){ that.scrollPatch(); }, 50); that.haveInit = true; layer.close(that.tipsIndex); //同步表头父列的相关值 options.HAS_SET_COLS_PATCH || that.setColsPatch(); options.HAS_SET_COLS_PATCH = true; }; table.cache[that.key] = data; //记录数据 //显示隐藏分页栏 //that.layPage[(count == 0 || (data.length === 0 && curr == 1)) ? 'addClass' : 'removeClass'](HIDE); //显示隐藏合计栏 that.layTotal[data.length == 0 ? 'addClass' : 'removeClass'](HIDE_V); //显示隐藏分页栏 if(!options.pagebar){ that.layPage[ (count == 0 || (data.length === 0 && curr == 1)) ? 'addClass' : 'removeClass' ](HIDE_V); } //如果无数据 if(data.length === 0){ that.renderForm(); return that.errorView(options.text.none); } else { that.layFixed.removeClass(HIDE); } //如果执行初始排序 if(sort){ return render(); } //正常初始化数据渲染 render(); //渲染数据 // 传data 合计当前页 传 全部data 合计全部页 that.renderTotal(that.config.data, totalRowData); //数据合计 that.layTotal && that.layTotal.removeClass(HIDE); //同步分页状态 if(options.page){ options.page = $.extend({ elem: 'layui-table-page' + options.index ,count: count ,limit: options.limit ,limits: options.limits || [10,20,30,40,50,60,70,80,90] ,groups: 3 ,layout: ['prev', 'page', 'next', 'skip', 'count', 'limit'] ,prev: '' ,next: '' ,jump: function(obj, first){ if(!first){ //分页本身并非需要做以下更新,下面参数的同步,主要是因为其它处理统一用到了它们 //而并非用的是 options.page 中的参数(以确保分页未开启的情况仍能正常使用) that.page = obj.curr; //更新页码 options.limit = obj.limit; //更新每页条数 that.pullData(obj.curr); } } }, options.page); options.page.count = count; //更新总条数 laypage.render(options.page); } }; //数据合计行 Class.prototype.renderTotal = function(data, totalRowData){ var that = this ,options = that.config ,totalNums = {}; if(!options.totalRow) return; layui.each(data, function(i1, item1){ //若数据项为空数组,则不往下执行(因为删除数据时,会将原有数据设置为 []) if(layui.type(item1) === 'array' && item1.length === 0) return; that.eachCols(function(i3, item3){ var field = item3.field || i3 ,content = item1[field]; if(item3.totalRow){ totalNums[field] = (totalNums[field] || 0) + (parseFloat(content) || 0); } }); }); that.dataTotal = {}; var tds = []; that.eachCols(function(i3, item3){ var field = item3.field || i3; //td 内容 var content = function(){ var text = item3.totalRowText || '' ,decimals = 'totalRowDecimals' in item3 ? item3.totalRowDecimals : 2 ,thisTotalNum = parseFloat(totalNums[field]).toFixed(decimals) ,tplData = {} ,getContent; tplData[field] = thisTotalNum; //获取自动计算的合并内容 getContent = item3.totalRow ? (parseTempData.call(that, { item3: item3 ,content: thisTotalNum ,tplData: tplData }) || text) : text; //如果直接传入了合计行数据,则不输出自动计算的结果 return totalRowData ? (totalRowData[item3.field] || getContent) : getContent; }() ,td = ['' ,'
      ' + function(){ var totalRow = item3.totalRow || options.totalRow; //如果 totalRow 参数为字符类型,则解析为自定义模版 if(typeof totalRow === 'string'){ return laytpl(totalRow).render($.extend({ TOTAL_NUMS: totalNums[field] }, item3)); } return content; }() ,'
      '].join(''); item3.field && (that.dataTotal[field] = content); tds.push(td); }); that.layTotal.find('tbody').html('' + tds.join('') + ''); }; //找到对应的列元素 Class.prototype.getColElem = function(parent, key){ var that = this ,options = that.config; return parent.eq(0).find('.laytable-cell-'+ (options.index + '-' + key) + ':eq(0)'); }; //渲染表单 Class.prototype.renderForm = function(type){ var that = this ,options = that.config ,filter = that.elem.attr('lay-filter'); form.render(type, filter); }; //标记当前行选中状态 Class.prototype.setThisRowChecked = function(index){ var that = this ,options = that.config ,ELEM_CLICK = 'layui-table-click' ,tr = that.layBody.find('tr[data-index="'+ index +'"]'); tr.addClass(ELEM_CLICK).siblings('tr').removeClass(ELEM_CLICK); }; //数据排序 Class.prototype.sort = function(th, type, pull, formEvent){ var that = this ,field ,res = {} ,options = that.config ,filter = options.elem.attr('lay-filter') ,data = table.cache[that.key], thisData; //字段匹配 if(typeof th === 'string'){ field = th; that.layHeader.find('th').each(function(i, item){ var othis = $(this) ,_field = othis.data('field'); if(_field === th){ th = othis; field = _field; return false; } }); } try { var field = field || th.data('field') ,key = th.data('key'); //如果欲执行的排序已在状态中,则不执行渲染 if(that.sortKey && !pull){ if(field === that.sortKey.field && type === that.sortKey.sort){ return; } } var elemSort = that.layHeader.find('th .laytable-cell-'+ key).find(ELEM_SORT); that.layHeader.find('th').find(ELEM_SORT).removeAttr('lay-sort'); //清除其它标题排序状态 elemSort.attr('lay-sort', type || null); that.layFixed.find('th') } catch(e){ hint.error('Table modules: sort field \''+ field +'\' not matched'); } //记录排序索引和类型 that.sortKey = { field: field ,sort: type }; //默认为前端自动排序。如果否,则需自主排序(通常为服务端处理好排序) if(options.autoSort){ if(type === 'asc'){ //升序 thisData = layui.thissort(data, field); } else if(type === 'desc'){ //降序 thisData = layui.thissort(data, field, true); } else { //清除排序 thisData = layui.thissort(data, table.config.indexName); delete that.sortKey; } } res[options.response.dataName] = thisData || data; that.renderData(res, that.page, that.count, true); // table.cache[that.key] = thisData if(formEvent){ options.initSort = { field: field ,type: type }; layui.event.call(th, MOD_NAME, 'sort('+ filter +')', options.initSort); } // if(this) this.config.afterSort && this.config.afterSort() }; //请求loading Class.prototype.loading = function(hide){ var that = this ,options = that.config; if(options.loading){ if(hide){ that.layInit && that.layInit.remove(); delete that.layInit; that.layBox.find(ELEM_INIT).remove(); } else { that.layInit = $(['
      ' ,'' ,'
      '].join('')); that.layBox.append(that.layInit); } } }; //同步选中值状态 Class.prototype.setCheckData = function(index, checked){ var that = this ,options = that.config ,thisData = table.cache[that.key]; if(!thisData[index]) return; if(layui.type(thisData[index]) === 'array') return; thisData[index][options.checkName] = checked; }; // 同步全选按钮状态 Class.prototype.syncCheckAll = function(){ var that = this ,options = that.config ,checkAllElem = that.layHeader.find('input[name="layTableCheckbox"]') ,syncColsCheck = function(checked){ that.eachCols(function(i, item){ if(item.type === 'checkbox'){ item[options.checkName] = checked; } }); return checked; }; if(!checkAllElem[0]) return; if(table.checkStatus(that.key).isAll){ if(!checkAllElem[0].checked){ checkAllElem.prop('checked', true); that.renderForm('checkbox'); } syncColsCheck(true); } else { if(checkAllElem[0].checked){ checkAllElem.prop('checked', false); that.renderForm('checkbox'); } syncColsCheck(false); } }; //获取cssRule Class.prototype.getCssRule = function(key, callback){ var that = this ,style = that.elem.find('style')[0] ,sheet = style.sheet || style.styleSheet || {} ,rules = sheet.cssRules || sheet.rules; layui.each(rules, function(i, item){ if(item.selectorText === ('.laytable-cell-'+ key)){ return callback(item), true; } }); }; //让表格铺满 Class.prototype.fullSize = function(){ var that = this ,options = that.config ,height = options.height ,bodyHeight; if(that.fullHeightGap){ height = _WIN.height() - that.fullHeightGap; if(height < 135) height = 135; that.elem.css('height', height); } if(!height) return; //减去列头区域的高度 bodyHeight = parseFloat(height) - (that.layHeader.outerHeight() || 38); //此处的数字常量是为了防止容器处在隐藏区域无法获得高度的问题,暂时只对默认尺寸的表格做支持。 //减去工具栏的高度 if(options.toolbar){ bodyHeight -= (that.layTool.outerHeight() || 50); } //减去统计朗的高度 if(options.totalRow){ bodyHeight -= (that.layTotal.outerHeight() || 40); } //减去分页栏的高度 if(options.page){ bodyHeight -= (that.layPage.outerHeight() || 41); } // 减去筛选插件高度 if(this.layBorderBox.find(".soul-bottom-contion")[0]){ bodyHeight -= (this.layBorderBox.find(".soul-bottom-contion")[0].offsetHeight || 31); } let h = bodyHeight - 2 - parseFloat(that.layMain.css('height')); // that.layBody.css("height", parseFloat(that.layBody.css("height")) + h); // that.layBorderBox.css("height", parseFloat(that.layBorderBox.css("height")) + h); that.layMain.css('height', bodyHeight - 2); }; //获取滚动条宽度 Class.prototype.getScrollWidth = function(elem){ var width = 0; if(elem){ width = elem.offsetWidth - elem.clientWidth; } else { elem = document.createElement('div'); elem.style.width = '100px'; elem.style.height = '100px'; elem.style.overflowY = 'scroll'; document.body.appendChild(elem); width = elem.offsetWidth - elem.clientWidth; document.body.removeChild(elem); } return width; }; //滚动条补丁 Class.prototype.scrollPatch = function(){ var that = this ,layMainTable = that.layMain.children('table') ,scollWidth = that.layMain.width() - that.layMain.prop('clientWidth') //纵向滚动条宽度 ,scollHeight = that.layMain.height() - that.layMain.prop('clientHeight') //横向滚动条高度 ,getScrollWidth = that.getScrollWidth(that.layMain[0]) //获取主容器滚动条宽度,如果有的话 ,outWidth = layMainTable.outerWidth() - that.layMain.width() //表格内容器的超出宽度 //添加补丁 ,addPatch = function(elem){ if(scollWidth && scollHeight){ elem = elem.eq(0); if(!elem.find('.layui-table-patch')[0]){ var patchElem = $('
      '); //补丁元素 patchElem.find('div').css({ width: scollWidth }); elem.find('tr').append(patchElem); } } else { elem.find('.layui-table-patch').remove(); } } addPatch(that.layHeader); addPatch(that.layTotal); //固定列区域高度 var mainHeight = that.layMain.height() ,fixHeight = mainHeight - scollHeight; that.layFixed.find(ELEM_BODY).css('height', layMainTable.height() >= fixHeight ? fixHeight : 'auto'); //表格宽度小于容器宽度时,隐藏固定列 that.layFixRight[outWidth > 0 ? 'removeClass' : 'addClass'](HIDE); //操作栏 that.layFixRight.css('right', scollWidth - 1); }; //事件处理 Class.prototype.events = function(){ var that = this ,options = that.config ,_BODY = $('body') ,dict = {} ,th = that.layHeader.find('th') ,resizing ,ELEM_CELL = '.layui-table-cell' ,filter = options.elem.attr('lay-filter'); //工具栏操作事件 that.layTool.on('click', '*[lay-event]', function(e){ var othis = $(this) ,events = othis.attr('lay-event') ,openPanel = function(sets){ var list = $(sets.list) ,panel = $(''); panel.html(list); //限制最大高度 if(options.height){ panel.css('max-height', options.height - (that.layTool.outerHeight() || 50)); } //插入元素 othis.find('.layui-table-tool-panel')[0] || othis.append(panel); that.renderForm(); panel.on('click', function(e){ layui.stope(e); }); sets.done && sets.done(panel, list) }; layui.stope(e); _DOC.trigger('table.tool.panel.remove'); layer.close(that.tipsIndex); switch(events){ case 'LAYTABLE_COLS': //筛选列 openPanel({ list: function(){ var lis = []; that.eachCols(function(i, item){ if(item.field && item.type == 'normal'){ lis.push('
    • '); } }); return lis.join(''); }() ,done: function(){ form.on('checkbox(LAY_TABLE_TOOL_COLS)', function(obj){ var othis = $(obj.elem) ,checked = this.checked ,key = othis.data('key') ,parentKey = othis.data('parentkey'); layui.each(options.cols, function(i1, item1){ layui.each(item1, function(i2, item2){ if(i1+ '-'+ i2 === key){ var hide = item2.hide; //同步勾选列的 hide 值和隐藏样式 item2.hide = !checked; that.elem.find('*[data-key="'+ options.index +'-'+ key +'"]') [checked ? 'removeClass' : 'addClass'](HIDE); //根据列的显示隐藏,同步多级表头的父级相关属性值 if(hide != item2.hide){ that.setParentCol(!checked, parentKey); } //重新适配尺寸 that.resize(); } }); }); }); } }); break; case 'LAYTABLE_EXPORT': //导出 if(device.ie){ layer.tips('导出功能不支持 IE,请用 Chrome 等高级浏览器导出', this, { tips: 3 }) } else { openPanel({ list: function(){ return [ '
    • 导出 csv 格式文件
    • ' ,'
    • 导出 xls 格式文件
    • ' ].join('') }() ,done: function(panel, list){ list.on('click', function(){ var type = $(this).data('type') table.exportFile.call(that, options.id, null, type); }); } }); } break; case 'LAYTABLE_PRINT': //打印 var printWin = window.open('about:blank', '_blank') ,style = [''].join('') ,html = $(that.layHeader.html()); //输出表头 html.append(that.layMain.find('table').html()); //输出表体 html.append(that.layTotal.find('table').html()) //输出合计行 html.find('th.layui-table-patch').remove(); //移除补丁 html.find('.layui-table-col-special').remove(); //移除特殊列 printWin.document.write(style + html.prop('outerHTML')); printWin.document.close(); printWin.print(); printWin.close(); break; } layui.event.call(this, MOD_NAME, 'toolbar('+ filter +')', $.extend({ event: events ,config: options },{})); }); //分页栏操作事件 that.layPagebar.on('click', '*[lay-event]', function(e){ var othis = $(this) ,events = othis.attr('lay-event'); layui.event.call(this, MOD_NAME, 'pagebar('+ filter +')', $.extend({ event: events ,config: options },{})); }); //拖拽调整宽度 th.on('mousemove', function(e){ var othis = $(this) ,oLeft = othis.offset().left ,pLeft = e.clientX - oLeft; if(othis.data('unresize') || dict.resizeStart){ return; } dict.allowResize = othis.width() - pLeft <= 10; //是否处于拖拽允许区域 _BODY.css('cursor', (dict.allowResize ? 'col-resize' : '')); }).on('mouseleave', function(){ var othis = $(this); if(dict.resizeStart) return; _BODY.css('cursor', ''); }).on('mousedown', function(e){ var othis = $(this); if(dict.allowResize){ var key = othis.data('key'); e.preventDefault(); dict.resizeStart = true; //开始拖拽 dict.offset = [e.clientX, e.clientY]; //记录初始坐标 that.getCssRule(key, function(item){ var width = item.style.width || othis.outerWidth(); dict.rule = item; dict.ruleWidth = parseFloat(width); dict.minWidth = othis.data('minwidth') || options.cellMinWidth; dict.target = othis[0] }); } }); //拖拽中 _DOC.on('mousemove', function(e){ if(dict.resizeStart){ e.preventDefault(); if(dict.rule){ var setWidth = dict.ruleWidth + e.clientX - dict.offset[0]; if(setWidth < dict.minWidth) setWidth = dict.minWidth; dict.rule.style.width = setWidth + 'px'; layer.close(that.tipsIndex); } resizing = 1 } }).on('mouseup', function(e){ if(dict.resizeStart){ // 处理宽度 for(let j of that.config.cols){ for(let i of j){ if(i.field == dict.target.dataset.field){ i.width = dict.target.clientWidth } } } that.config.onColumnsWidth && that.config.onColumnsWidth(that.config.cols) dict = {}; _BODY.css('cursor', ''); that.scrollPatch(); } if(resizing === 2){ resizing = null; } }); //排序 th.on('click', function(e){ var othis = $(this) ,elemSort = othis.find(ELEM_SORT) ,nowType = elemSort.attr('lay-sort') ,type; if(!elemSort[0] || resizing === 1) return resizing = 2; if(nowType === 'asc'){ type = 'desc'; } else if(nowType === 'desc'){ type = null; } else { type = 'asc'; } that.sort(othis, type, null, true); }).find(ELEM_SORT+' .layui-edge ').on('click', function(e){ var othis = $(this) ,index = othis.index() ,field = othis.parents('th').eq(0).data('field') layui.stope(e); if(index === 0){ that.sort(field, 'asc', null, true); } else { that.sort(field, 'desc', null, true); } }); //数据行中的事件返回的公共对象成员 var commonMember = that.commonMember = function(sets){ var othis = $(this) ,index = othis.parents('tr').eq(0).data('index') ,tr = that.layBody.find('tr[data-index="'+ index +'"]') ,data = table.cache[that.key] || []; data = data[index] || {}; return $.extend({ tr: tr //行元素 ,data: table.clearCacheKey(data) //当前行数据 ,del: function(){ //删除行数据 table.cache[that.key][index] = []; tr.remove(); that.scrollPatch(); } ,update: function(fields){ //修改行数据 fields = fields || {}; layui.each(fields, function(key, value){ var td = tr.children('td[data-field="'+ key +'"]') ,cell = td.children(ELEM_CELL); //获取当前修改的列 //更新缓存中的数据 if(key in data) data[key] = value; that.eachCols(function(i, item3){ //更新相应列视图 if(item3.field == key){ cell.html(parseTempData.call(that, { item3: item3 ,content: value ,tplData: data })); td.data('content', value); item3.templet && that.renderForm(); } else if(item3.templet || item3.toolbar){ //更新所有其他列的模板 var thisTd = tr.children('td[data-field="'+ (item3.field || i) +'"]') ,content = data[item3.field]; thisTd.children(ELEM_CELL).html(parseTempData.call(that, { item3: item3 ,content: content ,tplData: data })); thisTd.data('content', content); that.renderForm(); } }); }); } }, sets); }; //复选框选择 that.elem.on('click', 'input[name="layTableCheckbox"]+', function(){ //替代元素的 click 事件 var checkbox = $(this).prev() ,childs = that.layBody.find('input[name="layTableCheckbox"]') ,index = checkbox.parents('tr').eq(0).data('index') ,checked = checkbox[0].checked ,isAll = checkbox.attr('lay-filter') === 'layTableAllChoose'; if(checkbox[0].disabled) return; //全选 if(isAll){ childs.each(function(i, item){ item.checked = checked; that.setCheckData(i, checked); }); that.syncCheckAll(); that.renderForm('checkbox'); } else { that.setCheckData(index, checked); that.syncCheckAll(); } // 事件 layui.event.call( checkbox[0], MOD_NAME, 'checkbox('+ filter +')', commonMember.call(checkbox[0], { checked: checked, type: isAll ? 'all' : 'one' }) ); }); //单选框选择 that.elem.on('click', 'input[lay-type="layTableRadio"]+', function(){ var radio = $(this).prev() ,checked = radio[0].checked ,thisData = table.cache[that.key] ,index = radio.parents('tr').eq(0).data('index'); //重置数据单选属性 layui.each(thisData, function(i, item){ if(index === i){ item[options.checkName] = true; } else { delete item[options.checkName]; } }); that.setThisRowChecked(index); layui.event.call(this, MOD_NAME, 'radio('+ filter +')', commonMember.call(this, { checked: checked })); }); // 行事件 that.layBody.on('mouseenter', 'tr', function(){ //鼠标移入行 var othis = $(this) ,index = othis.index(); if(othis.data('off')) return; //不触发事件 that.layBody.find('tr:eq('+ index +')').addClass(ELEM_HOVER) }).on('mouseleave', 'tr', function(){ //鼠标移出行 var othis = $(this) ,index = othis.index(); if(othis.data('off')) return; //不触发事件 that.layBody.find('tr:eq('+ index +')').removeClass(ELEM_HOVER) }).on('click', 'tr', function(){ //单击行 setRowEvent.call(this, 'row'); }).on('dblclick', 'tr', function(){ //双击行 setRowEvent.call(this, 'rowDouble'); }); //创建行单击、双击事件 var setRowEvent = function(eventType){ var othis = $(this); if(othis.data('off')) return; //不触发事件 layui.event.call(this, MOD_NAME, eventType + '('+ filter +')' ,commonMember.call(othis.children('td')[0]) ); }; // 单元格编辑 that.layBody.on('change', '.'+ELEM_EDIT, function(){ var othis = $(this) ,value = this.value ,field = othis.parent().data('field') ,index = othis.parents('tr').eq(0).data('index') ,data = table.cache[that.key][index]; data[field] = value; //更新缓存中的值 layui.event.call(this, MOD_NAME, 'edit('+ filter +')', commonMember.call(this, { value: value ,field: field })); }).on('blur', '.'+ELEM_EDIT, function(){ var item3 ,othis = $(this) ,thisElem = this ,field = othis.parent().data('field') ,index = othis.parents('tr').eq(0).data('index') ,data = table.cache[that.key][index]; that.eachCols(function(i, item){ if(item.field == field && item.templet){ item3 = item; } }); othis.siblings(ELEM_CELL).html(function(value){ return parseTempData.call(that, { item3: item3 || {} ,content: value ,tplData: data }); }(thisElem.value)); othis.parent().data('content', thisElem.value); othis.remove(); }); // 单元格事件 that.layBody.on(options.editTrigger, 'td', function(e){ var othis = $(this) ,field = othis.data('field') ,editType = othis.data('edit') ,elemCell = othis.children(ELEM_CELL); if(othis.data('off')) return; //不触发事件 //显示编辑表单 if(editType){ var input = $(function(){ var inputElem = ''; if(editType === 'textarea') { inputElem = ''; } return inputElem; }()); input[0].value = othis.data('content') || elemCell.text(); othis.find('.'+ELEM_EDIT)[0] || othis.append(input); input.focus(); layui.stope(e); return; } }).on('mouseenter', 'td', function(){ gridExpand.call(this) }).on('mouseleave', 'td', function(){ gridExpand.call(this, 'hide'); }); //单元格展开图标 var ELEM_GRID = 'layui-table-grid', ELEM_GRID_DOWN = 'layui-table-grid-down', ELEM_GRID_PANEL = 'layui-table-grid-panel' ,gridExpand = function(hide){ var othis = $(this) ,elemCell = othis.children(ELEM_CELL); if(othis.data('off')) return; //不触发事件 if(hide){ othis.find('.layui-table-grid-down').remove(); } else if(( elemCell.prop('scrollWidth') > elemCell.outerWidth() || elemCell.find("br").length > 0 ) && !options.lineStyle){ if(elemCell.find('.'+ ELEM_GRID_DOWN)[0]) return; othis.append('
      '); } }; //单元格展开事件 that.layBody.on('click', '.'+ ELEM_GRID_DOWN, function(e){ var othis = $(this) ,td = othis.parent() ,elemCell = td.children(ELEM_CELL); that.tipsIndex = layer.tips([ '
      ' ,elemCell.html() ,'
      ' ,'' ].join(''), elemCell[0], { tips: [3, ''] ,time: -1 ,anim: -1 ,maxWidth: (device.ios || device.android) ? 300 : that.elem.width()/2 ,isOutAnim: false ,skin: 'layui-table-tips' ,success: function(layero, index){ layero.find('.layui-table-tips-c').on('click', function(){ layer.close(index); }); } }); layui.stope(e); }); // 行工具条操作事件 var toolFn = function(type){ var othis = $(this); var index = othis.parents('tr').eq(0).data('index'); layui.event.call( this, MOD_NAME, (type || 'tool') + '('+ filter +')', commonMember.call(this, { event: othis.attr('lay-event') }) ); that.setThisRowChecked(index); }; // 行工具条单击事件 that.layBody.on('click', '*[lay-event]', function(){ toolFn.call(this); return false; }).on('dblclick', '*[lay-event]', function(){ //行工具条双击事件 toolFn.call(this, 'toolDouble'); return false; }); //同步滚动条 that.layMain.on('scroll', function(){ var othis = $(this) ,scrollLeft = othis.scrollLeft() ,scrollTop = othis.scrollTop(); that.layHeader.scrollLeft(scrollLeft); that.layTotal.scrollLeft(scrollLeft); that.layFixed.find(ELEM_BODY).scrollTop(scrollTop); layer.close(that.tipsIndex); }); //自适应 _WIN.on('resize', function(){ that.resize(); }); }; //一次性事件 ;(function(){ //全局点击 _DOC.on('click', function(){ _DOC.trigger('table.remove.tool.panel'); }); //工具面板移除事件 _DOC.on('table.remove.tool.panel', function(){ $('.layui-table-tool-panel').remove(); }); })(); //初始化 table.init = function(filter, settings){ settings = settings || {}; var that = this ,inst = null ,elemTable = filter ? $('table[lay-filter="'+ filter +'"]') : $(ELEM + '[lay-data]') ,errorTips = 'Table element property lay-data configuration item has a syntax error: '; //遍历数据表格 elemTable.each(function(){ var othis = $(this), tableData = othis.attr('lay-data'); try { tableData = new Function('return '+ tableData)(); } catch(e) { hint.error(errorTips + tableData, 'error') } var cols = [], options = $.extend({ elem: this ,cols: [] ,data: [] ,skin: othis.attr('lay-skin') //风格 ,size: othis.attr('lay-size') //尺寸 ,even: typeof othis.attr('lay-even') === 'string' //偶数行背景 }, table.config, settings, tableData); filter && othis.hide(); //获取表头数据 othis.find('thead>tr').each(function(i){ options.cols[i] = []; $(this).children().each(function(ii){ var th = $(this), itemData = th.attr('lay-data'); try{ itemData = new Function('return '+ itemData)(); } catch(e){ return hint.error(errorTips + itemData) } var row = $.extend({ title: th.text() ,colspan: th.attr('colspan') || 1 //列单元格 ,rowspan: th.attr('rowspan') || 1 //行单元格 }, itemData); if(row.colspan < 2) cols.push(row); options.cols[i].push(row); }); }); //获取表体数据 othis.find('tbody>tr').each(function(i1){ var tr = $(this), row = {}; //如果定义了字段名 tr.children('td').each(function(i2, item2){ var td = $(this) ,field = td.data('field'); if(field){ return row[field] = td.html(); } }); //如果未定义字段名 layui.each(cols, function(i3, item3){ var td = tr.children('td').eq(i3); row[item3.field] = td.html(); }); options.data[i1] = row; }); //执行渲染 table.render(options); }); return that; }; //记录所有实例 thisTable.that = {}; //记录所有实例对象 thisTable.config = {}; //记录所有实例配置项 var eachChildCols = function (index, cols, i1, item2) { //如果是组合列,则捕获对应的子列 if (item2.colGroup) { var childIndex = 0; index++; item2.CHILD_COLS = []; // 找到它的子列所在cols的下标 var i2 = i1 + (parseInt(item2.rowspan) || 1); layui.each(cols[i2], function (i22, item22) { //如果子列已经被标注为{PARENT_COL_INDEX},或者子列累计 colspan 数等于父列定义的 colspan,则跳出当前子列循环 if (item22.PARENT_COL_INDEX || (childIndex >= 1 && childIndex == (item2.colspan || 1))) return; item22.PARENT_COL_INDEX = index; item2.CHILD_COLS.push(item22); childIndex = childIndex + (item22.hide ? 0 : parseInt(item22.colspan > 1 ? item22.colspan : 1)); eachChildCols(index, cols, i2, item22); }); } }; // 遍历表头 table.eachCols = function(id, callback, cols){ var config = thisTable.config[id] || {} ,arrs = [], index = 0; cols = $.extend(true, [], cols || config.cols); //重新整理表头结构 layui.each(cols, function(i1, item1){ if (i1) return true; // 只需遍历第一层 layui.each(item1, function(i2, item2){ eachChildCols(index, cols, i1, item2); if(item2.PARENT_COL_INDEX) return; //如果是子列,则不进行追加,因为已经存储在父列中 arrs.push(item2) }); }); //重新遍历列,如果有子列,则进入递归 var eachArrs = function(obj){ layui.each(obj || arrs, function(i, item){ if(item.CHILD_COLS) return eachArrs(item.CHILD_COLS); typeof callback === 'function' && callback(i, item); }); }; eachArrs(); }; // 表格选中状态 table.checkStatus = function(id){ var nums = 0 ,invalidNum = 0 ,arr = [] ,data = table.cache[id] || []; //计算全选个数 layui.each(data, function(i, item){ if(layui.type(item) === 'array'){ invalidNum++; //无效数据,或已删除的 return; } if(item[table.config.checkName]){ nums++; if(!item[table.config.disabledName]){ arr.push(table.clearCacheKey(item)); } } }); return { data: arr //选中的数据 ,isAll: data.length ? (nums === (data.length - invalidNum)) : false //是否全选 }; }; // 获取表格当前页的所有行数据 table.getData = function(id){ var arr = [] ,data = table.cache[id] || []; layui.each(data, function(i, item){ if(layui.type(item) === 'array'){ return; }; arr.push(table.clearCacheKey(item)); }); return arr; }; // 表格导出 table.exportFile = function(id, data, options){ data = data || table.clearCacheKey(table.cache[id]); options = typeof options === 'object' ? options : function(){ var obj = {}; options && (obj.type = options); return obj; }(); var type = options.type || 'csv'; var thatTable = thisTable.that[id]; var config = thisTable.config[id] || {}; var textType = ({ csv: 'text/csv' ,xls: 'application/vnd.ms-excel' })[type]; var alink = document.createElement("a"); if(device.ie) return hint.error('IE_NOT_SUPPORT_EXPORTS'); alink.href = 'data:'+ textType +';charset=utf-8,\ufeff'+ encodeURIComponent(function(){ var dataTitle = [] ,dataMain = [] ,dataTotal = [] ,fieldsIsHide = {}; //表头和表体 layui.each(data, function(i1, item1){ var vals = []; if(typeof id === 'object'){ //如果 id 参数直接为表头数据 layui.each(id, function(i, item){ i1 == 0 && dataTitle.push(item || ''); }); layui.each(table.clearCacheKey(item1), function(i2, item2){ vals.push('"'+ (item2 || '') +'"'); }); } else { table.eachCols(id, function(i3, item3){ if(item3.field && item3.type == 'normal'){ //不导出隐藏列 if(item3.hide){ if(i1 == 0) fieldsIsHide[item3.field] = true; //记录隐藏列 return; } var content = item1[item3.field] ,td = thatTable.layBody.find('tr[data-index="'+ i1 +'"]>td'); if(content === undefined || content === null) content = ''; i1 == 0 && dataTitle.push(item3.title || ''); vals.push('"'+ parseTempData.call(thatTable, { item3: item3 ,content: content ,tplData: item1 ,text: 'text' ,obj: thatTable.commonMember.call(td.eq(0), { td: function(field){ return td.filter('[data-field="'+ field +'"]'); } }) }) + '"'); } }); } dataMain.push(vals.join(',')); }); //表合计 thatTable && layui.each(thatTable.dataTotal, function(key, value){ fieldsIsHide[key] || dataTotal.push(value); }); return dataTitle.join(',') + '\r\n' + dataMain.join('\r\n') + '\r\n' + dataTotal.join(','); }()); alink.download = (options.title || config.title || 'table_'+ (config.index || '')) + '.' + type; document.body.appendChild(alink); alink.click(); document.body.removeChild(alink); }; // 重置表格尺寸结构 table.resize = function(id){ //如果指定表格唯一 id,则只执行该 id 对应的表格实例 if(id){ var config = getThisTableConfig(id); //获取当前实例配置项 if(!config) return; thisTable.that[id].resize(); } else { //否则重置所有表格实例尺寸 layui.each(thisTable.that, function(){ this.resize(); }); } }; // 重载 table.reload = function(id, options, deep, type){ var config = getThisTableConfig(id); //获取当前实例配置项 if(!config) return; var that = thisTable.that[id]; that.reload(options, deep, type); return thisTable.call(that); }; // 仅重载数据 table.reloadData = function(){ var args = $.extend([], arguments); args[3] = 'reloadData'; // 过滤与数据无关的参数 var dataParams = new RegExp('^('+ [ 'data', 'url', 'where', 'page', 'limit', 'request', 'response', 'parseData' ].join('|') + ')$'); layui.each(args[1], function (key, value) { if(!dataParams.test(key)){ delete args[1][key]; } }); return table.reload.apply(null, args); }; // 仅仅合并数据 table.mergeData = function(id,data,index){ var config = getThisTableConfig(id); //获取当前实例配置项 if(!config) return; var that = thisTable.that[id]; let arr = [] for(let i in data){ if(table.cache[that.key][i]){ arr.push({...table.cache[that.key][i],...data[i]}) } } let tr = $(that.layMain).find(`tr[data-index=${index}]`) layui.each(data[index], function(key, value){ var td = tr.children('td[data-field="'+ key +'"]') ,cell = td.children('.layui-table-cell'); //获取当前修改的列 let d = data[index] //更新缓存中的数据 that.eachCols(function(i, item3){ //更新相应列视图 if(item3.field == key){ cell.html(parseTempData.call(that, { item3: item3 ,content: value ,tplData: d })); td.data('content', value); } else if(item3.templet || item3.toolbar){ //更新所有其他列的模板 var thisTd = tr.children('td[data-field="'+ (item3.field || i) +'"]') ,content = d[item3.field]; thisTd.children('.layui-table-cell').html(parseTempData.call(that, { item3: item3 ,content: content ,tplData: d })); thisTd.data('content', content); } }); }); table.cache[that.key] = arr config.data = arr } // 核心入口 table.render = function(options){ var inst = new Class(options); return thisTable.call(inst); }; // 清除临时 Key table.clearCacheKey = function(data){ data = $.extend({}, data); delete data[table.config.checkName]; delete data[table.config.indexName]; delete data[table.config.disabledName]; return data; }; // 自动完成渲染 $(function(){ table.init(); }); exports(MOD_NAME, table); }); /** * tree 树组件 */ layui.define('form', function(exports){ "use strict"; var $ = layui.$ ,form = layui.form ,layer = layui.layer //模块名 ,MOD_NAME = 'tree' //外部接口 ,tree = { config: {} ,index: layui[MOD_NAME] ? (layui[MOD_NAME].index + 10000) : 0 //设置全局项 ,set: function(options){ var that = this; that.config = $.extend({}, that.config, options); return that; } //事件 ,on: function(events, callback){ return layui.onevent.call(this, MOD_NAME, events, callback); } } //操作当前实例 ,thisModule = function(){ var that = this ,options = that.config ,id = options.id || that.index; thisModule.that[id] = that; //记录当前实例对象 thisModule.config[id] = options; //记录当前实例配置项 return { config: options //重置实例 ,reload: function(options){ that.reload.call(that, options); } ,getChecked: function(){ return that.getChecked.call(that); } ,setChecked: function(id){//设置值 return that.setChecked.call(that, id); } } } //获取当前实例配置项 ,getThisModuleConfig = function(id){ var config = thisModule.config[id]; if(!config) hint.error('The ID option was not found in the '+ MOD_NAME +' instance'); return config || null; } //字符常量 ,SHOW = 'layui-show', HIDE = 'layui-hide', NONE = 'layui-none', DISABLED = 'layui-disabled' ,ELEM_VIEW = 'layui-tree', ELEM_SET = 'layui-tree-set', ICON_CLICK = 'layui-tree-iconClick' ,ICON_ADD = 'layui-icon-addition', ICON_SUB = 'layui-icon-subtraction', ELEM_ENTRY = 'layui-tree-entry', ELEM_MAIN = 'layui-tree-main', ELEM_TEXT = 'layui-tree-txt', ELEM_PACK = 'layui-tree-pack', ELEM_SPREAD = 'layui-tree-spread' ,ELEM_LINE_SHORT = 'layui-tree-setLineShort', ELEM_SHOW = 'layui-tree-showLine', ELEM_EXTEND = 'layui-tree-lineExtend' //构造器 ,Class = function(options){ var that = this; that.index = ++tree.index; that.config = $.extend({}, that.config, tree.config, options); that.render(); }; //默认配置 Class.prototype.config = { data: [] //数据 ,showCheckbox: false //是否显示复选框 ,showLine: true //是否开启连接线 ,accordion: false //是否开启手风琴模式 ,onlyIconControl: false //是否仅允许节点左侧图标控制展开收缩 ,isJump: false //是否允许点击节点时弹出新窗口跳转 ,edit: false //是否开启节点的操作图标 ,text: { defaultNodeName: '未命名' //节点默认名称 ,none: '无数据' //数据为空时的文本提示 } }; //重载实例 Class.prototype.reload = function(options){ var that = this; layui.each(options, function(key, item){ if(layui.type(item) === 'array') delete that.config[key]; }); that.config = $.extend(true, {}, that.config, options); that.render(); }; //主体渲染 Class.prototype.render = function(){ var that = this ,options = that.config; that.checkids = []; var temp = $('
      '); that.tree(temp); var othis = options.elem = $(options.elem); if(!othis[0]) return; //索引 that.key = options.id || that.index; //插入组件结构 that.elem = temp; that.elemNone = $('
      '+ options.text.none +'
      '); othis.html(that.elem); if(that.elem.find('.layui-tree-set').length == 0){ return that.elem.append(that.elemNone); }; //复选框渲染 if(options.showCheckbox){ that.renderForm('checkbox'); }; that.elem.find('.layui-tree-set').each(function(){ var othis = $(this); //最外层 if(!othis.parent('.layui-tree-pack')[0]){ othis.addClass('layui-tree-setHide'); }; //没有下一个节点 上一层父级有延伸线 if(!othis.next()[0] && othis.parents('.layui-tree-pack').eq(1).hasClass('layui-tree-lineExtend')){ othis.addClass(ELEM_LINE_SHORT); }; //没有下一个节点 外层最后一个 if(!othis.next()[0] && !othis.parents('.layui-tree-set').eq(0).next()[0]){ othis.addClass(ELEM_LINE_SHORT); }; }); that.events(); }; //渲染表单 Class.prototype.renderForm = function(type){ form.render(type, 'LAY-tree-'+ this.index); }; //节点解析 Class.prototype.tree = function(elem, children){ var that = this ,options = that.config ,data = children || options.data; //遍历数据 layui.each(data, function(index, item){ var hasChild = item.children && item.children.length > 0 ,packDiv = $('
      ') ,entryDiv = $(['
      ' ,'
      ' ,'
      ' //箭头 ,function(){ if(options.showLine){ if(hasChild){ return ''; }else{ return ''; }; }else{ return ''; }; }() //复选框 ,function(){ return options.showCheckbox ? '' : ''; }() //节点 ,function(){ if(options.isJump && item.href){ return ''+ (item.title || item.label || options.text.defaultNodeName) +''; }else{ return ''+ (item.title || item.label || options.text.defaultNodeName) +''; } }() ,'
      ' //节点操作图标 ,function(){ if(!options.edit) return ''; var editIcon = { add: '' ,update: '' ,del: '' }, arr = ['
      ']; if(options.edit === true){ options.edit = ['update', 'del'] } if(typeof options.edit === 'object'){ layui.each(options.edit, function(i, val){ arr.push(editIcon[val] || '') }); return arr.join('') + '
      '; } }() ,'
      '].join('')); //如果有子节点,则递归继续生成树 if(hasChild){ entryDiv.append(packDiv); that.tree(packDiv, item.children); }; elem.append(entryDiv); //若有前置节点,前置节点加连接线 if(entryDiv.prev('.'+ELEM_SET)[0]){ entryDiv.prev().children('.layui-tree-pack').addClass('layui-tree-showLine'); }; //若无子节点,则父节点加延伸线 if(!hasChild){ entryDiv.parent('.layui-tree-pack').addClass('layui-tree-lineExtend'); }; //展开节点操作 that.spread(entryDiv, item); //选择框 if(options.showCheckbox){ item.checked && that.checkids.push(item.id); that.checkClick(entryDiv, item); } //操作节点 options.edit && that.operate(entryDiv, item); }); }; //展开节点 Class.prototype.spread = function(elem, item){ var that = this ,options = that.config ,entry = elem.children('.'+ELEM_ENTRY) ,elemMain = entry.children('.'+ ELEM_MAIN) ,elemIcon = entry.find('.'+ ICON_CLICK) ,elemText = entry.find('.'+ ELEM_TEXT) ,touchOpen = options.onlyIconControl ? elemIcon : elemMain //判断展开通过节点还是箭头图标 ,state = ''; //展开收缩 touchOpen.on('click', function(e){ var packCont = elem.children('.'+ELEM_PACK) ,iconClick = touchOpen.children('.layui-icon')[0] ? touchOpen.children('.layui-icon') : touchOpen.find('.layui-tree-icon').children('.layui-icon'); //若没有子节点 if(!packCont[0]){ state = 'normal'; }else{ if(elem.hasClass(ELEM_SPREAD)){ elem.removeClass(ELEM_SPREAD); packCont.slideUp(200); iconClick.removeClass(ICON_SUB).addClass(ICON_ADD); }else{ elem.addClass(ELEM_SPREAD); packCont.slideDown(200); iconClick.addClass(ICON_SUB).removeClass(ICON_ADD); //是否手风琴 if(options.accordion){ var sibls = elem.siblings('.'+ELEM_SET); sibls.removeClass(ELEM_SPREAD); sibls.children('.'+ELEM_PACK).slideUp(200); sibls.find('.layui-tree-icon').children('.layui-icon').removeClass(ICON_SUB).addClass(ICON_ADD); }; }; }; }); //点击回调 elemText.on('click', function(){ var othis = $(this); //判断是否禁用状态 if(othis.hasClass(DISABLED)) return; //判断展开收缩状态 if(elem.hasClass(ELEM_SPREAD)){ state = options.onlyIconControl ? 'open' : 'close'; } else { state = options.onlyIconControl ? 'close' : 'open'; } //点击产生的回调 options.click && options.click({ elem: elem ,state: state ,data: item }); }); }; //计算复选框选中状态 Class.prototype.setCheckbox = function(elem, item, elemCheckbox){ var that = this ,options = that.config ,checked = elemCheckbox.prop('checked'); if(elemCheckbox.prop('disabled')) return; //同步子节点选中状态 if(typeof item.children === 'object' || elem.find('.'+ELEM_PACK)[0]){ var childs = elem.find('.'+ ELEM_PACK).find('input[same="layuiTreeCheck"]'); childs.each(function(){ if(this.disabled) return; //不可点击则跳过 this.checked = checked; }); }; //同步父节点选中状态 var setParentsChecked = function(thisNodeElem){ //若无父节点,则终止递归 if(!thisNodeElem.parents('.'+ ELEM_SET)[0]) return; var state ,parentPack = thisNodeElem.parent('.'+ ELEM_PACK) ,parentNodeElem = parentPack.parent() ,parentCheckbox = parentPack.prev().find('input[same="layuiTreeCheck"]'); //如果子节点有任意一条选中,则父节点为选中状态 if(checked){ parentCheckbox.prop('checked', checked); } else { //如果当前节点取消选中,则根据计算“兄弟和子孙”节点选中状态,来同步父节点选中状态 parentPack.find('input[same="layuiTreeCheck"]').each(function(){ if(this.checked){ state = true; } }); //如果兄弟子孙节点全部未选中,则父节点也应为非选中状态 state || parentCheckbox.prop('checked', false); } //向父节点递归 setParentsChecked(parentNodeElem); }; setParentsChecked(elem); that.renderForm('checkbox'); }; //复选框选择 Class.prototype.checkClick = function(elem, item){ var that = this ,options = that.config ,entry = elem.children('.'+ ELEM_ENTRY) ,elemMain = entry.children('.'+ ELEM_MAIN); //点击复选框 elemMain.on('click', 'input[same="layuiTreeCheck"]+', function(e){ layui.stope(e); //阻止点击节点事件 var elemCheckbox = $(this).prev() ,checked = elemCheckbox.prop('checked'); if(elemCheckbox.prop('disabled')) return; that.setCheckbox(elem, item, elemCheckbox); //复选框点击产生的回调 options.oncheck && options.oncheck({ elem: elem ,checked: checked ,data: item }); }); }; //节点操作 Class.prototype.operate = function(elem, item){ var that = this ,options = that.config ,entry = elem.children('.'+ ELEM_ENTRY) ,elemMain = entry.children('.'+ ELEM_MAIN); entry.children('.layui-tree-btnGroup').on('click', '.layui-icon', function(e){ layui.stope(e); //阻止节点操作 var type = $(this).data("type") ,packCont = elem.children('.'+ELEM_PACK) ,returnObj = { data: item ,type: type ,elem:elem }; //增加 if(type == 'add'){ //若节点本身无子节点 if(!packCont[0]){ //若开启连接线,更改图标样式 if(options.showLine){ elemMain.find('.'+ICON_CLICK).addClass('layui-tree-icon'); elemMain.find('.'+ICON_CLICK).children('.layui-icon').addClass(ICON_ADD).removeClass('layui-icon-file'); //若未开启连接线,显示箭头 }else{ elemMain.find('.layui-tree-iconArrow').removeClass(HIDE); }; //节点添加子节点容器 elem.append('
      '); }; //新增节点 var key = options.operate && options.operate(returnObj) ,obj = {}; obj.title = options.text.defaultNodeName; obj.id = key; that.tree(elem.children('.'+ELEM_PACK), [obj]); //放在新增后面,因为要对元素进行操作 if(options.showLine){ //节点本身无子节点 if(!packCont[0]){ //遍历兄弟节点,判断兄弟节点是否有子节点 var siblings = elem.siblings('.'+ELEM_SET), num = 1 ,parentPack = elem.parent('.'+ELEM_PACK); layui.each(siblings, function(index, i){ if(!$(i).children('.'+ELEM_PACK)[0]){ num = 0; }; }); //若兄弟节点都有子节点 if(num == 1){ //兄弟节点添加连接线 siblings.children('.'+ELEM_PACK).addClass(ELEM_SHOW); siblings.children('.'+ELEM_PACK).children('.'+ELEM_SET).removeClass(ELEM_LINE_SHORT); elem.children('.'+ELEM_PACK).addClass(ELEM_SHOW); //父级移除延伸线 parentPack.removeClass(ELEM_EXTEND); //同层节点最后一个更改线的状态 parentPack.children('.'+ELEM_SET).last().children('.'+ELEM_PACK).children('.'+ELEM_SET).last().addClass(ELEM_LINE_SHORT); }else{ elem.children('.'+ELEM_PACK).children('.'+ELEM_SET).addClass(ELEM_LINE_SHORT); }; }else{ //添加延伸线 if(!packCont.hasClass(ELEM_EXTEND)){ packCont.addClass(ELEM_EXTEND); }; //子节点添加延伸线 elem.find('.'+ELEM_PACK).each(function(){ $(this).children('.'+ELEM_SET).last().addClass(ELEM_LINE_SHORT); }); //如果前一个节点有延伸线 if(packCont.children('.'+ELEM_SET).last().prev().hasClass(ELEM_LINE_SHORT)){ packCont.children('.'+ELEM_SET).last().prev().removeClass(ELEM_LINE_SHORT); }else{ //若之前的没有,说明处于连接状态 packCont.children('.'+ELEM_SET).last().removeClass(ELEM_LINE_SHORT); }; //若是最外层,要始终保持相连的状态 if(!elem.parent('.'+ELEM_PACK)[0] && elem.next()[0]){ packCont.children('.'+ELEM_SET).last().removeClass(ELEM_LINE_SHORT); }; }; }; if(!options.showCheckbox) return; //若开启复选框,同步新增节点状态 if(elemMain.find('input[same="layuiTreeCheck"]')[0].checked){ var packLast = elem.children('.'+ELEM_PACK).children('.'+ELEM_SET).last(); packLast.find('input[same="layuiTreeCheck"]')[0].checked = true; }; that.renderForm('checkbox'); //修改 }else if(type == 'update'){ var text = elemMain.children('.'+ ELEM_TEXT).html(); elemMain.children('.'+ ELEM_TEXT).html(''); //添加输入框,覆盖在文字上方 elemMain.append(''); //获取焦点 elemMain.children('.layui-tree-editInput').val(text).focus(); //嵌入文字移除输入框 var getVal = function(input){ var textNew = input.val().trim(); textNew = textNew ? textNew : options.text.defaultNodeName; input.remove(); elemMain.children('.'+ ELEM_TEXT).html(textNew); //同步数据 returnObj.data.title = textNew; //节点修改的回调 options.operate && options.operate(returnObj); }; //失去焦点 elemMain.children('.layui-tree-editInput').blur(function(){ getVal($(this)); }); //回车 elemMain.children('.layui-tree-editInput').on('keydown', function(e){ if(e.keyCode === 13){ e.preventDefault(); getVal($(this)); }; }); //删除 } else { layer.confirm('确认删除该节点 "'+ (item.title || '') +'" 吗?', function(index){ options.operate && options.operate(returnObj); //节点删除的回调 returnObj.status = 'remove'; //标注节点删除 layer.close(index); //若删除最后一个,显示空数据提示 if(!elem.prev('.'+ELEM_SET)[0] && !elem.next('.'+ELEM_SET)[0] && !elem.parent('.'+ELEM_PACK)[0]){ elem.remove(); that.elem.append(that.elemNone); return; }; //若有兄弟节点 if(elem.siblings('.'+ELEM_SET).children('.'+ELEM_ENTRY)[0]){ //若开启复选框 if(options.showCheckbox){ //若开启复选框,进行下步操作 var elemDel = function(elem){ //若无父结点,则不执行 if(!elem.parents('.'+ELEM_SET)[0]) return; var siblingTree = elem.siblings('.'+ELEM_SET).children('.'+ELEM_ENTRY) ,parentTree = elem.parent('.'+ELEM_PACK).prev() ,checkState = parentTree.find('input[same="layuiTreeCheck"]')[0] ,state = 1, num = 0; //若父节点未勾选 if(checkState.checked == false){ //遍历兄弟节点 siblingTree.each(function(i, item1){ var input = $(item1).find('input[same="layuiTreeCheck"]')[0] if(input.checked == false && !input.disabled){ state = 0; }; //判断是否全为不可勾选框 if(!input.disabled){ num = 1; }; }); //若有可勾选选择框并且已勾选 if(state == 1 && num == 1){ //勾选父节点 checkState.checked = true; that.renderForm('checkbox'); //向上遍历祖先节点 elemDel(parentTree.parent('.'+ELEM_SET)); }; }; }; elemDel(elem); }; //若开启连接线 if(options.showLine){ //遍历兄弟节点,判断兄弟节点是否有子节点 var siblings = elem.siblings('.'+ELEM_SET), num = 1 ,parentPack = elem.parent('.'+ELEM_PACK); layui.each(siblings, function(index, i){ if(!$(i).children('.'+ELEM_PACK)[0]){ num = 0; }; }); //若兄弟节点都有子节点 if(num == 1){ //若节点本身无子节点 if(!packCont[0]){ //父级去除延伸线,因为此时子节点里没有空节点 parentPack.removeClass(ELEM_EXTEND); siblings.children('.'+ELEM_PACK).addClass(ELEM_SHOW); siblings.children('.'+ELEM_PACK).children('.'+ELEM_SET).removeClass(ELEM_LINE_SHORT); }; //若为最后一个节点 if(!elem.next()[0]){ elem.prev().children('.'+ELEM_PACK).children('.'+ELEM_SET).last().addClass(ELEM_LINE_SHORT); }else{ parentPack.children('.'+ELEM_SET).last().children('.'+ELEM_PACK).children('.'+ELEM_SET).last().addClass(ELEM_LINE_SHORT); }; //若为最外层最后一个节点,去除前一个结点的连接线 if(!elem.next()[0] && !elem.parents('.'+ELEM_SET)[1] && !elem.parents('.'+ELEM_SET).eq(0).next()[0]){ elem.prev('.'+ELEM_SET).addClass(ELEM_LINE_SHORT); }; }else{ //若为最后一个节点且有延伸线 if(!elem.next()[0] && elem.hasClass(ELEM_LINE_SHORT)){ elem.prev().addClass(ELEM_LINE_SHORT); }; }; }; }else{ //若无兄弟节点 var prevDiv = elem.parent('.'+ELEM_PACK).prev(); //若开启了连接线 if(options.showLine){ prevDiv.find('.'+ICON_CLICK).removeClass('layui-tree-icon'); prevDiv.find('.'+ICON_CLICK).children('.layui-icon').removeClass(ICON_SUB).addClass('layui-icon-file'); //父节点所在层添加延伸线 var pare = prevDiv.parents('.'+ELEM_PACK).eq(0); pare.addClass(ELEM_EXTEND); //兄弟节点最后子节点添加延伸线 pare.children('.'+ELEM_SET).each(function(){ $(this).children('.'+ELEM_PACK).children('.'+ELEM_SET).last().addClass(ELEM_LINE_SHORT); }); }else{ //父节点隐藏箭头 prevDiv.find('.layui-tree-iconArrow').addClass(HIDE); }; //移除展开属性 elem.parents('.'+ELEM_SET).eq(0).removeClass(ELEM_SPREAD); //移除节点容器 elem.parent('.'+ELEM_PACK).remove(); }; elem.remove(); }); }; }); }; //部分事件 Class.prototype.events = function(){ var that = this ,options = that.config ,checkWarp = that.elem.find('.layui-tree-checkedFirst'); //初始选中 that.setChecked(that.checkids); //搜索 that.elem.find('.layui-tree-search').on('keyup', function(){ var input = $(this) ,val = input.val() ,pack = input.nextAll() ,arr = []; //遍历所有的值 pack.find('.'+ ELEM_TEXT).each(function(){ var entry = $(this).parents('.'+ELEM_ENTRY); //若值匹配,加一个类以作标识 if($(this).html().indexOf(val) != -1){ arr.push($(this).parent()); var select = function(div){ div.addClass('layui-tree-searchShow'); //向上父节点渲染 if(div.parent('.'+ELEM_PACK)[0]){ select(div.parent('.'+ELEM_PACK).parent('.'+ELEM_SET)); }; }; select(entry.parent('.'+ELEM_SET)); }; }); //根据标志剔除 pack.find('.'+ELEM_ENTRY).each(function(){ var parent = $(this).parent('.'+ELEM_SET); if(!parent.hasClass('layui-tree-searchShow')){ parent.addClass(HIDE); }; }); if(pack.find('.layui-tree-searchShow').length == 0){ that.elem.append(that.elemNone); }; //节点过滤的回调 options.onsearch && options.onsearch({ elem: arr }); }); //还原搜索初始状态 that.elem.find('.layui-tree-search').on('keydown', function(){ $(this).nextAll().find('.'+ELEM_ENTRY).each(function(){ var parent = $(this).parent('.'+ELEM_SET); parent.removeClass('layui-tree-searchShow '+ HIDE); }); if($('.layui-tree-emptyText')[0]) $('.layui-tree-emptyText').remove(); }); }; //得到选中节点 Class.prototype.getChecked = function(){ var that = this ,options = that.config ,checkId = [] ,checkData = []; //遍历节点找到选中索引 that.elem.find('.layui-form-checked').each(function(){ checkId.push($(this).prev()[0].value); }); //遍历节点 var eachNodes = function(data, checkNode){ layui.each(data, function(index, item){ layui.each(checkId, function(index2, item2){ if(item.id == item2){ var cloneItem = $.extend({}, item); delete cloneItem.children; checkNode.push(cloneItem); if(item.children){ cloneItem.children = []; eachNodes(item.children, cloneItem.children); } return true } }); }); }; eachNodes($.extend({}, options.data), checkData); return checkData; }; //设置选中节点 Class.prototype.setChecked = function(checkedId){ var that = this ,options = that.config; //初始选中 that.elem.find('.'+ELEM_SET).each(function(i, item){ var thisId = $(this).data('id') ,input = $(item).children('.'+ELEM_ENTRY).find('input[same="layuiTreeCheck"]') ,reInput = input.next(); //若返回数字 if(typeof checkedId === 'number'){ if(thisId == checkedId){ if(!input[0].checked){ reInput.click(); }; return false; }; } //若返回数组 else if(typeof checkedId === 'object'){ layui.each(checkedId, function(index, value){ if(value == thisId && !input[0].checked){ reInput.click(); return true; } }); }; }); }; //记录所有实例 thisModule.that = {}; //记录所有实例对象 thisModule.config = {}; //记录所有实例配置项 //重载实例 tree.reload = function(id, options){ var that = thisModule.that[id]; that.reload(options); return thisModule.call(that); }; //获得选中的节点数据 tree.getChecked = function(id){ var that = thisModule.that[id]; return that.getChecked(); }; //设置选中节点 tree.setChecked = function(id, checkedId){ var that = thisModule.that[id]; return that.setChecked(checkedId); }; //核心入口 tree.render = function(options){ var inst = new Class(options); return thisModule.call(inst); }; exports(MOD_NAME, tree); })/** * transfer 穿梭框组件 */ layui.define(['laytpl', 'form'], function(exports){ "use strict"; var $ = layui.$ ,laytpl = layui.laytpl ,form = layui.form //模块名 ,MOD_NAME = 'transfer' //外部接口 ,transfer = { config: {} ,index: layui[MOD_NAME] ? (layui[MOD_NAME].index + 10000) : 0 //设置全局项 ,set: function(options){ var that = this; that.config = $.extend({}, that.config, options); return that; } //事件 ,on: function(events, callback){ return layui.onevent.call(this, MOD_NAME, events, callback); } } //操作当前实例 ,thisModule = function(){ var that = this ,options = that.config ,id = options.id || that.index; thisModule.that[id] = that; //记录当前实例对象 thisModule.config[id] = options; //记录当前实例配置项 return { config: options //重置实例 ,reload: function(options){ that.reload.call(that, options); } //获取右侧数据 ,getData: function(){ return that.getData.call(that); } } } //获取当前实例配置项 ,getThisModuleConfig = function(id){ var config = thisModule.config[id]; if(!config) hint.error('The ID option was not found in the '+ MOD_NAME +' instance'); return config || null; } //字符常量 ,ELEM = 'layui-transfer', HIDE = 'layui-hide', DISABLED = 'layui-btn-disabled', NONE = 'layui-none' ,ELEM_BOX = 'layui-transfer-box', ELEM_HEADER = 'layui-transfer-header', ELEM_SEARCH = 'layui-transfer-search', ELEM_ACTIVE = 'layui-transfer-active', ELEM_DATA = 'layui-transfer-data' //穿梭框模板 ,TPL_BOX = function(obj){ obj = obj || {}; return ['
      ' ,'
      ' ,'' ,'
      ' ,'{{# if(d.data.showSearch){ }}' ,'' ,'{{# } }}' ,'
        ' ,'
        '].join(''); } //主模板 ,TPL_MAIN = function(option){ return ['
        ' ,TPL_BOX({ index: 0 ,checkAllName: 'layTransferLeftCheckAll', disAll: option.disAll }) ,'
        ' ,'' ,'' ,'
        ' ,TPL_BOX({ index: 1 ,checkAllName: 'layTransferRightCheckAll' }) ,'
        '].join('')} //构造器 ,Class = function(options){ var that = this; that.index = ++transfer.index; that.config = $.extend({}, that.config, transfer.config, options); that.render(); }; //默认配置 Class.prototype.config = { title: ['列表一', '列表二'] ,width: 200 ,height: 360 ,data: [] //数据源 ,value: [] //选中的数据 ,showSearch: false //是否开启搜索 ,id: '' //唯一索引,默认自增 index ,text: { none: '无数据' ,searchNone: '无匹配数据' } }; //重载实例 Class.prototype.reload = function(options){ var that = this; that.config = $.extend({}, that.config, options); that.render(); }; //渲染 Class.prototype.render = function(){ var that = this ,options = that.config; //解析模板 var thisElem = that.elem = $(laytpl(TPL_MAIN(options)).render({ data: options ,index: that.index //索引 })); var othis = options.elem = $(options.elem); if(!othis[0]) return; //初始化属性 options.data = options.data || []; options.value = options.value || []; //索引 that.key = options.id || that.index; //插入组件结构 othis.html(that.elem); //各级容器 that.layBox = that.elem.find('.'+ ELEM_BOX) that.layHeader = that.elem.find('.'+ ELEM_HEADER) that.laySearch = that.elem.find('.'+ ELEM_SEARCH) that.layData = thisElem.find('.'+ ELEM_DATA); that.layBtn = thisElem.find('.'+ ELEM_ACTIVE + ' .layui-btn'); //初始化尺寸 that.layBox.css({ width: options.width ,height: options.height }); that.layData.css({ height: function(){ var height = options.height - that.layHeader.outerHeight(); if(options.showSearch){ height -= that.laySearch.outerHeight(); } return height - 2; }() }); that.renderData(); //渲染数据 that.events(); //事件 }; //渲染数据 Class.prototype.renderData = function(){ var that = this ,options = that.config; //左右穿梭框差异数据 var arr = [{ checkName: 'layTransferLeftCheck' ,views: [] }, { checkName: 'layTransferRightCheck' ,views: [] }]; //解析格式 that.parseData(function(item){ //标注为 selected 的为右边的数据 var _index = item.selected ? 1 : 0 ,listElem = ['
      • ' ,'' ,'
      • '].join(''); arr[_index].views.push(listElem); delete item.selected; }); that.layData.eq(0).html(arr[0].views.join('')); that.layData.eq(1).html(arr[1].views.join('')); that.renderCheckBtn(); } //渲染表单 Class.prototype.renderForm = function(type){ form.render(type, 'LAY-transfer-'+ this.index); }; //同步复选框和按钮状态 Class.prototype.renderCheckBtn = function(obj){ var that = this ,options = that.config; obj = obj || {}; that.layBox.each(function(_index){ var othis = $(this) ,thisDataElem = othis.find('.'+ ELEM_DATA) ,allElemCheckbox = othis.find('.'+ ELEM_HEADER).find('input[type="checkbox"]') ,listElemCheckbox = thisDataElem.find('input[type="checkbox"]'); //同步复选框和按钮状态 var nums = 0 ,haveChecked = false; listElemCheckbox.each(function(){ var isHide = $(this).data('hide'); if(this.checked || this.disabled || isHide){ nums++; } if(this.checked && !isHide){ haveChecked = true; } }); allElemCheckbox.prop('checked', haveChecked && nums === listElemCheckbox.length); //全选复选框状态 that.layBtn.eq(_index)[haveChecked ? 'removeClass' : 'addClass'](DISABLED); //对应的按钮状态 //无数据视图 if(!obj.stopNone){ var isNone = thisDataElem.children('li:not(.'+ HIDE +')').length that.noneView(thisDataElem, isNone ? '' : options.text.none); } }); that.renderForm('checkbox'); }; //无数据视图 Class.prototype.noneView = function(thisDataElem, text){ var createNoneElem = $('

        '+ (text || '') +'

        '); if(thisDataElem.find('.'+ NONE)[0]){ thisDataElem.find('.'+ NONE).remove(); } text.replace(/\s/g, '') && thisDataElem.append(createNoneElem); }; //同步 value 属性值 Class.prototype.setValue = function(){ var that = this ,options = that.config ,arr = []; that.layBox.eq(1).find('.'+ ELEM_DATA +' input[type="checkbox"]').each(function(){ var isHide = $(this).data('hide'); isHide || arr.push(this.value); }); options.value = arr; return that; }; //解析数据 Class.prototype.parseData = function(callback){ var that = this ,options = that.config ,newData = []; layui.each(options.data, function(index, item){ //解析格式 item = (typeof options.parseData === 'function' ? options.parseData(item) : item) || item; newData.push(item = $.extend({}, item)) layui.each(options.value, function(index2, item2){ if(item2 == item.value){ item.selected = true; } }); callback && callback(item); }); options.data = newData; return that; }; //获得右侧面板数据 Class.prototype.getData = function(value){ var that = this ,options = that.config ,selectedData = []; that.setValue(); layui.each(value || options.value, function(index, item){ layui.each(options.data, function(index2, item2){ delete item2.selected; if(item == item2.value){ selectedData.push(item2); }; }); }); return selectedData; }; //执行穿梭 Class.prototype.transfer = function (_index, elem) { var that = this ,options = that.config ,thisBoxElem = that.layBox.eq(_index) ,arr = [] if (!elem) { //通过按钮触发找到选中的进行移动 thisBoxElem.each(function(_index){ var othis = $(this) ,thisDataElem = othis.find('.'+ ELEM_DATA); thisDataElem.children('li').each(function(){ var thisList = $(this) ,thisElemCheckbox = thisList.find('input[type="checkbox"]') ,isHide = thisElemCheckbox.data('hide'); if(thisElemCheckbox[0].checked && !isHide){ thisElemCheckbox[0].checked = false; thisBoxElem.siblings('.'+ ELEM_BOX).find('.'+ ELEM_DATA).append(thisList.clone()); thisList.remove(); //记录当前穿梭的数据 arr.push(thisElemCheckbox[0].value); } that.setValue(); }); }); } else { //双击单条记录移动 var thisList = elem ,thisElemCheckbox = thisList.find('input[type="checkbox"]') thisElemCheckbox[0].checked = false; thisBoxElem.siblings('.'+ ELEM_BOX).find('.'+ ELEM_DATA).append(thisList.clone()); thisList.remove(); //记录当前穿梭的数据 arr.push(thisElemCheckbox[0].value); that.setValue(); } that.renderCheckBtn(); //穿梭时,如果另外一个框正在搜索,则触发匹配 var siblingInput = thisBoxElem.siblings('.'+ ELEM_BOX).find('.'+ ELEM_SEARCH +' input') siblingInput.val() === '' || siblingInput.trigger('keyup'); //穿梭时的回调 options.onchange && options.onchange(that.getData(arr), _index); } //事件 Class.prototype.events = function(){ var that = this ,options = that.config; //左右复选框 that.elem.on('click', 'input[lay-filter="layTransferCheckbox"]+', function(){ var thisElemCheckbox = $(this).prev() ,checked = thisElemCheckbox[0].checked ,thisDataElem = thisElemCheckbox.parents('.'+ ELEM_BOX).eq(0).find('.'+ ELEM_DATA); if(thisElemCheckbox[0].disabled) return; //判断是否全选 if(thisElemCheckbox.attr('lay-type') === 'all'){ thisDataElem.find('input[type="checkbox"]').each(function(){ if(this.disabled) return; this.checked = checked; }); } setTimeout(function () { that.renderCheckBtn({stopNone: true}); }, 0) }); // 双击穿梭 that.elem.on('dblclick', '.' + ELEM_DATA + '>li', function(event){ var elemThis = $(this) ,thisElemCheckbox = elemThis.children('input[type="checkbox"]') ,thisDataElem = elemThis.parent() ,thisBoxElem = thisDataElem.parent() if(thisElemCheckbox[0].disabled) return; that.transfer(thisBoxElem.data('index'), elemThis); }) // 穿梭按钮事件 that.layBtn.on('click', function(){ var othis = $(this) ,_index = othis.data('index') if(othis.hasClass(DISABLED)) return; that.transfer(_index); }); //搜索 that.laySearch.find('input').on('keyup', function(){ var value = this.value ,thisDataElem = $(this).parents('.'+ ELEM_SEARCH).eq(0).siblings('.'+ ELEM_DATA) ,thisListElem = thisDataElem.children('li'); thisListElem.each(function(){ var thisList = $(this) ,thisElemCheckbox = thisList.find('input[type="checkbox"]') ,isMatch = thisElemCheckbox[0].title.indexOf(value) !== -1; thisList[isMatch ? 'removeClass': 'addClass'](HIDE); thisElemCheckbox.data('hide', isMatch ? false : true); }); that.renderCheckBtn(); //无匹配数据视图 var isNone = thisListElem.length === thisDataElem.children('li.'+ HIDE).length; that.noneView(thisDataElem, isNone ? options.text.searchNone : ''); }); }; //记录所有实例 thisModule.that = {}; //记录所有实例对象 thisModule.config = {}; //记录所有实例配置项 //重载实例 transfer.reload = function(id, options){ var that = thisModule.that[id]; that.reload(options); return thisModule.call(that); }; //获得选中的数据(右侧面板) transfer.getData = function(id){ var that = thisModule.that[id]; return that.getData(); }; //核心入口 transfer.render = function(options){ var inst = new Class(options); return thisModule.call(inst); }; exports(MOD_NAME, transfer); }); /** * carousel 轮播模块 * MIT Licensed */ layui.define('jquery', function(exports){ "use strict"; var $ = layui.$ ,hint = layui.hint() ,device = layui.device() //外部接口 ,carousel = { config: {} //全局配置项 //设置全局项 ,set: function(options){ var that = this; that.config = $.extend({}, that.config, options); return that; } //事件 ,on: function(events, callback){ return layui.onevent.call(this, MOD_NAME, events, callback); } } //字符常量 ,MOD_NAME = 'carousel', ELEM = '.layui-carousel', THIS = 'layui-this', SHOW = 'layui-show', HIDE = 'layui-hide', DISABLED = 'layui-disabled' ,ELEM_ITEM = '>*[carousel-item]>*', ELEM_LEFT = 'layui-carousel-left', ELEM_RIGHT = 'layui-carousel-right', ELEM_PREV = 'layui-carousel-prev', ELEM_NEXT = 'layui-carousel-next', ELEM_ARROW = 'layui-carousel-arrow', ELEM_IND = 'layui-carousel-ind' //构造器 ,Class = function(options){ var that = this; that.config = $.extend({}, that.config, carousel.config, options); that.render(); }; //默认配置 Class.prototype.config = { width: '600px' ,height: '280px' ,full: false //是否全屏 ,arrow: 'hover' //切换箭头默认显示状态:hover/always/none ,indicator: 'inside' //指示器位置:inside/outside/none ,autoplay: true //是否自动切换 ,interval: 3000 //自动切换的时间间隔,不能低于800ms ,anim: '' //动画类型:default/updown/fade ,trigger: 'click' //指示器的触发方式:click/hover ,index: 0 //初始开始的索引 }; //轮播渲染 Class.prototype.render = function(){ var that = this ,options = that.config; options.elem = $(options.elem); if(!options.elem[0]) return; that.elemItem = options.elem.find(ELEM_ITEM); if(options.index < 0) options.index = 0; if(options.index >= that.elemItem.length) options.index = that.elemItem.length - 1; if(options.interval < 800) options.interval = 800; //是否全屏模式 if(options.full){ options.elem.css({ position: 'fixed' ,width: '100%' ,height: '100%' ,zIndex: 9999 }); } else { options.elem.css({ width: options.width ,height: options.height }); } options.elem.attr('lay-anim', options.anim); //初始焦点状态 that.elemItem.eq(options.index).addClass(THIS); //指示器等动作 if(that.elemItem.length <= 1) return; that.indicator(); that.arrow(); that.autoplay(); that.events(); }; //重置轮播 Class.prototype.reload = function(options){ var that = this; clearInterval(that.timer); that.config = $.extend({}, that.config, options); that.render(); }; //获取上一个等待条目的索引 Class.prototype.prevIndex = function(){ var that = this ,options = that.config; var prevIndex = options.index - 1; if(prevIndex < 0){ prevIndex = that.elemItem.length - 1; } return prevIndex; }; //获取下一个等待条目的索引 Class.prototype.nextIndex = function(){ var that = this ,options = that.config; var nextIndex = options.index + 1; if(nextIndex >= that.elemItem.length){ nextIndex = 0; } return nextIndex; }; //索引递增 Class.prototype.addIndex = function(num){ var that = this ,options = that.config; num = num || 1; options.index = options.index + num; //index不能超过轮播总数量 if(options.index >= that.elemItem.length){ options.index = 0; } }; //索引递减 Class.prototype.subIndex = function(num){ var that = this ,options = that.config; num = num || 1; options.index = options.index - num; //index不能超过轮播总数量 if(options.index < 0){ options.index = that.elemItem.length - 1; } }; //自动轮播 Class.prototype.autoplay = function(){ var that = this ,options = that.config; if(!options.autoplay) return; clearInterval(that.timer); that.timer = setInterval(function(){ that.slide(); }, options.interval); }; //箭头 Class.prototype.arrow = function(){ var that = this ,options = that.config; //模板 var tplArrow = $([ '' ,'' ].join('')); //预设基础属性 options.elem.attr('lay-arrow', options.arrow); //避免重复插入 if(options.elem.find('.'+ELEM_ARROW)[0]){ options.elem.find('.'+ELEM_ARROW).remove(); }; options.elem.append(tplArrow); //事件 tplArrow.on('click', function(){ var othis = $(this) ,type = othis.attr('lay-type') that.slide(type); }); }; //指示器 Class.prototype.indicator = function(){ var that = this ,options = that.config; //模板 var tplInd = that.elemInd = $(['
          ' ,function(){ var li = []; layui.each(that.elemItem, function(index){ li.push(''); }); return li.join(''); }() ,'
        '].join('')); //预设基础属性 options.elem.attr('lay-indicator', options.indicator); //避免重复插入 if(options.elem.find('.'+ELEM_IND)[0]){ options.elem.find('.'+ELEM_IND).remove(); }; options.elem.append(tplInd); if(options.anim === 'updown'){ tplInd.css('margin-top', -(tplInd.height()/2)); } //事件 tplInd.find('li').on(options.trigger === 'hover' ? 'mouseover' : options.trigger, function(){ var othis = $(this) ,index = othis.index(); if(index > options.index){ that.slide('add', index - options.index); } else if(index < options.index){ that.slide('sub', options.index - index); } }); }; //滑动切换 Class.prototype.slide = function(type, num){ var that = this ,elemItem = that.elemItem ,options = that.config ,thisIndex = options.index ,filter = options.elem.attr('lay-filter'); if(that.haveSlide) return; //滑动方向 if(type === 'sub'){ that.subIndex(num); elemItem.eq(options.index).addClass(ELEM_PREV); setTimeout(function(){ elemItem.eq(thisIndex).addClass(ELEM_RIGHT); elemItem.eq(options.index).addClass(ELEM_RIGHT); }, 50); } else { //默认递增滑 that.addIndex(num); elemItem.eq(options.index).addClass(ELEM_NEXT); setTimeout(function(){ elemItem.eq(thisIndex).addClass(ELEM_LEFT); elemItem.eq(options.index).addClass(ELEM_LEFT); }, 50); }; //移除过度类 setTimeout(function(){ elemItem.removeClass(THIS + ' ' + ELEM_PREV + ' ' + ELEM_NEXT + ' ' + ELEM_LEFT + ' ' + ELEM_RIGHT); elemItem.eq(options.index).addClass(THIS); that.haveSlide = false; //解锁 }, 300); //指示器焦点 that.elemInd.find('li').eq(options.index).addClass(THIS) .siblings().removeClass(THIS); that.haveSlide = true; // 回调返回的参数 var params = { index: options.index ,prevIndex: thisIndex ,item: elemItem.eq(options.index) }; typeof options.change === 'function' && options.change(params); layui.event.call(this, MOD_NAME, 'change('+ filter +')', params); }; //事件处理 Class.prototype.events = function(){ var that = this ,options = that.config; if(options.elem.data('haveEvents')) return; //移入移出容器 options.elem.on('mouseenter', function(){ if (that.config.autoplay === 'always') return; clearInterval(that.timer); }).on('mouseleave', function(){ if (that.config.autoplay === 'always') return; that.autoplay(); }); options.elem.data('haveEvents', true); }; //核心入口 carousel.render = function(options){ var inst = new Class(options); return inst; }; exports(MOD_NAME, carousel); }); /** * rate 评分评星组件 */ layui.define('jquery',function(exports){ "use strict"; var $ = layui.jquery //外部接口 ,rate = { config: {} ,index: layui.rate ? (layui.rate.index + 10000) : 0 //设置全局项 ,set: function(options){ var that = this; that.config = $.extend({}, that.config, options); return that; } //事件 ,on: function(events, callback){ return layui.onevent.call(this, MOD_NAME, events, callback); } } //操作当前实例 ,thisRate = function(){ var that = this ,options = that.config; return { setvalue: function(value){ that.setvalue.call(that, value); } ,config: options } } //字符常量 ,MOD_NAME = 'rate',ELEM_VIEW = 'layui-rate', ICON_RATE = 'layui-icon-rate', ICON_RATE_SOLID = 'layui-icon-rate-solid', ICON_RATE_HALF = 'layui-icon-rate-half' ,ICON_SOLID_HALF = 'layui-icon-rate-solid layui-icon-rate-half', ICON_SOLID_RATE = 'layui-icon-rate-solid layui-icon-rate', ICON_HALF_RATE = 'layui-icon-rate layui-icon-rate-half' //构造器 ,Class = function(options){ var that = this; that.index = ++rate.index; that.config = $.extend({}, that.config, rate.config, options); that.render(); }; //默认配置 Class.prototype.config = { length: 5 //初始长度 ,text: false //是否显示评分等级 ,readonly: false //是否只读 ,half: false //是否可以半星 ,value: 0 //星星选中个数 ,theme: '' }; //评分渲染 Class.prototype.render = function(){ var that = this ,options = that.config ,style = options.theme ? ('style="color: '+ options.theme + ';"') : ''; options.elem = $(options.elem); //最大值不能大于总长度 if(options.value > options.length){ options.value = options.length; } //如果没有选择半星的属性,却给了小数的数值,统一向上或向下取整 if(parseInt(options.value) !== options.value){ if(!options.half){ options.value = (Math.ceil(options.value) - options.value) < 0.5 ? Math.ceil(options.value): Math.floor(options.value) } } //组件模板 var temp = '' + (options.text ? (''+ options.value + '星') : '') + ''; //开始插入替代元素 var othis = options.elem ,hasRender = othis.next('.' + ELEM_VIEW); //生成替代元素 hasRender[0] && hasRender.remove(); //如果已经渲染,则Rerender that.elemTemp = $(temp); options.span = that.elemTemp.next('span'); options.setText && options.setText(options.value); othis.html(that.elemTemp); othis.addClass("layui-inline"); //如果不是只读,那么进行触控事件 if(!options.readonly) that.action(); }; //评分重置 Class.prototype.setvalue = function(value){ var that = this ,options = that.config ; options.value = value ; that.render(); }; //li触控事件 Class.prototype.action = function(){ var that = this ,options = that.config ,_ul = that.elemTemp ,wide = _ul.find("i").width(); _ul.children("li").each(function(index){ var ind = index + 1 ,othis = $(this); //点击 othis.on('click', function(e){ //将当前点击li的索引值赋给value options.value = ind; if(options.half){ //获取鼠标在li上的位置 var x = e.pageX - $(this).offset().left; if(x <= wide / 2){ options.value = options.value - 0.5; } } if(options.text) _ul.next("span").text(options.value + "星"); options.choose && options.choose(options.value); options.setText && options.setText(options.value); }); //移入 othis.on('mousemove', function(e){ _ul.find("i").each(function(){ $(this).addClass(ICON_RATE).removeClass(ICON_SOLID_HALF) }); _ul.find("i:lt(" + ind + ")").each(function(){ $(this).addClass(ICON_RATE_SOLID).removeClass(ICON_HALF_RATE) }); // 如果设置可选半星,那么判断鼠标相对li的位置 if(options.half){ var x = e.pageX - $(this).offset().left; if(x <= wide / 2){ othis.children("i").addClass(ICON_RATE_HALF).removeClass(ICON_RATE_SOLID) } } }) //移出 othis.on('mouseleave', function(){ _ul.find("i").each(function(){ $(this).addClass(ICON_RATE).removeClass(ICON_SOLID_HALF) }); _ul.find("i:lt(" + Math.floor(options.value) + ")").each(function(){ $(this).addClass(ICON_RATE_SOLID).removeClass(ICON_HALF_RATE) }); //如果设置可选半星,根据分数判断是否有半星 if(options.half){ if(parseInt(options.value) !== options.value){ _ul.children("li:eq(" + Math.floor(options.value) + ")").children("i").addClass(ICON_RATE_HALF).removeClass(ICON_SOLID_RATE) } } }) }) }; //事件处理 Class.prototype.events = function(){ var that = this ,options = that.config; }; //核心入口 rate.render = function(options){ var inst = new Class(options); return thisRate.call(inst); }; exports(MOD_NAME, rate); })/** * flow 流加载组件 */ layui.define('jquery', function(exports){ "use strict"; var $ = layui.$, Flow = function(options){} ,ELEM_MORE = 'layui-flow-more' ,ELEM_LOAD = ''; //主方法 Flow.prototype.load = function(options){ var that = this, page = 0, lock, isOver, lazyimg, timer; options = options || {}; var elem = $(options.elem); if(!elem[0]) return; var scrollElem = $(options.scrollElem || document); //滚动条所在元素 var mb = options.mb || 50; //与底部的临界距离 var isAuto = 'isAuto' in options ? options.isAuto : true; //是否自动滚动加载 var end = options.end || '没有更多了'; //“末页”显示文案 //滚动条所在元素是否为document var notDocment = options.scrollElem && options.scrollElem !== document; //加载更多 var ELEM_TEXT = '加载更多' ,more = $(''); if(!elem.find('.layui-flow-more')[0]){ elem.append(more); } //加载下一个元素 var next = function(html, over){ html = $(html); more.before(html); over = over == 0 ? true : null; over ? more.html(end) : more.find('a').html(ELEM_TEXT); isOver = over; lock = null; lazyimg && lazyimg(); }; //触发请求 var done = function(){ lock = true; more.find('a').html(ELEM_LOAD); typeof options.done === 'function' && options.done(++page, next); }; done(); //不自动滚动加载 more.find('a').on('click', function(){ var othis = $(this); if(isOver) return; lock || done(); }); //如果允许图片懒加载 if(options.isLazyimg){ var lazyimg = that.lazyimg({ elem: options.elem + ' img' ,scrollElem: options.scrollElem }); } if(!isAuto) return that; scrollElem.on('scroll', function(){ var othis = $(this), top = othis.scrollTop(); if(timer) clearTimeout(timer); if(isOver || !elem.width()) return; //如果已经结束,或者元素处于隐藏状态,则不执行滚动加载 timer = setTimeout(function(){ //计算滚动所在容器的可视高度 var height = notDocment ? othis.height() : $(window).height(); //计算滚动所在容器的实际高度 var scrollHeight = notDocment ? othis.prop('scrollHeight') : document.documentElement.scrollHeight; //临界点 if(scrollHeight - top - height <= mb){ lock || done(); } }, 100); }); return that; }; //图片懒加载 Flow.prototype.lazyimg = function(options){ var that = this, index = 0, haveScroll; options = options || {}; var scrollElem = $(options.scrollElem || document); //滚动条所在元素 var elem = options.elem || 'img'; //滚动条所在元素是否为document var notDocment = options.scrollElem && options.scrollElem !== document; //显示图片 var show = function(item, height){ var start = scrollElem.scrollTop(), end = start + height; var elemTop = notDocment ? function(){ return item.offset().top - scrollElem.offset().top + start; }() : item.offset().top; /* 始终只加载在当前屏范围内的图片 */ if(elemTop >= start && elemTop <= end){ if(item.attr('lay-src')){ var src = item.attr('lay-src'); layui.img(src, function(){ var next = that.lazyimg.elem.eq(index); item.attr('src', src).removeAttr('lay-src'); /* 当前图片加载就绪后,检测下一个图片是否在当前屏 */ next[0] && render(next); index++; }, function(){ var next = that.lazyimg.elem.eq(index); item.removeAttr('lay-src'); }); } } }, render = function(othis, scroll){ //计算滚动所在容器的可视高度 var height = notDocment ? (scroll||scrollElem).height() : $(window).height(); var start = scrollElem.scrollTop(), end = start + height; that.lazyimg.elem = $(elem); if(othis){ show(othis, height); } else { //计算未加载过的图片 for(var i = 0; i < that.lazyimg.elem.length; i++){ var item = that.lazyimg.elem.eq(i), elemTop = notDocment ? function(){ return item.offset().top - scrollElem.offset().top + start; }() : item.offset().top; show(item, height); index = i; //如果图片的top坐标,超出了当前屏,则终止后续图片的遍历 if(elemTop > end) break; } } }; render(); if(!haveScroll){ var timer; scrollElem.on('scroll', function(){ var othis = $(this); if(timer) clearTimeout(timer) timer = setTimeout(function(){ render(null, othis); }, 50); }); haveScroll = true; } return render; }; //暴露接口 exports('flow', new Flow()); }); /** * layedit 富文本编辑器 */ layui.define(['layer', 'form'], function(exports){ "use strict"; var $ = layui.$ ,layer = layui.layer ,form = layui.form ,hint = layui.hint() ,device = layui.device() ,MOD_NAME = 'layedit', THIS = 'layui-this', SHOW = 'layui-show', ABLED = 'layui-disabled' ,Edit = function(){ var that = this; that.index = 0; //全局配置 that.config = { //默认工具bar tool: [ 'strong', 'italic', 'underline', 'del' ,'|' ,'left', 'center', 'right' ,'|' ,'link', 'unlink' ] ,hideTool: [] ,height: 280 //默认高 }; }; //全局设置 Edit.prototype.set = function(options){ var that = this; $.extend(true, that.config, options); return that; }; //事件 Edit.prototype.on = function(events, callback){ return layui.onevent(MOD_NAME, events, callback); }; //建立编辑器 Edit.prototype.build = function(id, settings){ settings = settings || {}; var that = this ,config = that.config ,ELEM = 'layui-layedit', textArea = $(typeof(id)=='string'?'#'+id:id) ,name = 'LAY_layedit_'+ (++that.index) ,haveBuild = textArea.next('.'+ELEM) ,set = $.extend({}, config, settings) ,tool = function(){ var node = [], hideTools = {}; layui.each(set.hideTool, function(_, item){ hideTools[item] = true; }); layui.each(set.tool, function(_, item){ if(tools[item] && !hideTools[item]){ node.push(tools[item]); } }); return node.join(''); }() ,editor = $(['
        ' ,'
        '+ tool +'
        ' ,'
        ' ,'' ,'
        ' ,'
        '].join('')) //编辑器不兼容ie8以下 if(device.ie && device.ie < 8){ return textArea.removeClass('layui-hide').addClass(SHOW); } haveBuild[0] && (haveBuild.remove()); setIframe.call(that, editor, textArea[0], set) textArea.addClass('layui-hide').after(editor); return that.index; }; //获得编辑器中内容 Edit.prototype.getContent = function(index){ var iframeWin = getWin(index); if(!iframeWin[0]) return; return toLower(iframeWin[0].document.body.innerHTML); }; //获得编辑器中纯文本内容 Edit.prototype.getText = function(index){ var iframeWin = getWin(index); if(!iframeWin[0]) return; return $(iframeWin[0].document.body).text(); }; /** * 设置编辑器内容 * @param {[type]} index 编辑器索引 * @param {[type]} content 要设置的内容 * @param {[type]} flag 是否追加模式 */ Edit.prototype.setContent = function(index, content, flag){ var iframeWin = getWin(index); if(!iframeWin[0]) return; if(flag){ $(iframeWin[0].document.body).append(content) }else{ $(iframeWin[0].document.body).html(content) }; layedit.sync(index) }; //将编辑器内容同步到textarea(一般用于异步提交时) Edit.prototype.sync = function(index){ var iframeWin = getWin(index); if(!iframeWin[0]) return; var textarea = $('#'+iframeWin[1].attr('textarea')); textarea.val(toLower(iframeWin[0].document.body.innerHTML)); }; //获取编辑器选中内容 Edit.prototype.getSelection = function(index){ var iframeWin = getWin(index); if(!iframeWin[0]) return; var range = Range(iframeWin[0].document); return document.selection ? range.text : range.toString(); }; //iframe初始化 var setIframe = function(editor, textArea, set){ var that = this, iframe = editor.find('iframe'); iframe.css({ height: set.height }).on('load', function(){ var conts = iframe.contents() ,iframeWin = iframe.prop('contentWindow') ,head = conts.find('head') ,style = $([''].join('')) ,body = conts.find('body'); head.append(style); body.attr('contenteditable', 'true').css({ 'min-height': set.height }).html(textArea.value||''); hotkey.apply(that, [iframeWin, iframe, textArea, set]); //快捷键处理 toolActive.call(that, iframeWin, editor, set); //触发工具 }); } //获得iframe窗口对象 ,getWin = function(index){ var iframe = $('#LAY_layedit_'+ index) ,iframeWin = iframe.prop('contentWindow'); return [iframeWin, iframe]; } //IE8下将标签处理成小写 ,toLower = function(html){ if(device.ie == 8){ html = html.replace(/<.+>/g, function(str){ return str.toLowerCase(); }); } return html; } //快捷键处理 ,hotkey = function(iframeWin, iframe, textArea, set){ var iframeDOM = iframeWin.document, body = $(iframeDOM.body); body.on('keydown', function(e){ var keycode = e.keyCode; //处理回车 if(keycode === 13){ var range = Range(iframeDOM); var container = getContainer(range) ,parentNode = container.parentNode; if(parentNode.tagName.toLowerCase() === 'pre'){ if(e.shiftKey) return layer.msg('请暂时用shift+enter'); return false; } iframeDOM.execCommand('formatBlock', false, '

        '); } }); //给textarea同步内容 $(textArea).parents('form').on('submit', function(){ var html = body.html(); //IE8下将标签处理成小写 if(device.ie == 8){ html = html.replace(/<.+>/g, function(str){ return str.toLowerCase(); }); } textArea.value = html; }); //处理粘贴 body.on('paste', function(e){ iframeDOM.execCommand('formatBlock', false, '

        '); setTimeout(function(){ filter.call(iframeWin, body); textArea.value = body.html(); }, 100); }); } //标签过滤 ,filter = function(body){ var iframeWin = this ,iframeDOM = iframeWin.document; //清除影响版面的css属性 body.find('*[style]').each(function(){ var textAlign = this.style.textAlign; this.removeAttribute('style'); $(this).css({ 'text-align': textAlign || '' }) }); //修饰表格 body.find('table').addClass('layui-table'); //移除不安全的标签 body.find('script,link').remove(); } //Range对象兼容性处理 ,Range = function(iframeDOM){ return iframeDOM.selection ? iframeDOM.selection.createRange() : iframeDOM.getSelection().getRangeAt(0); } //当前Range对象的endContainer兼容性处理 ,getContainer = function(range){ return range.endContainer || range.parentElement().childNodes[0] } //在选区插入内联元素 ,insertInline = function(tagName, attr, range){ var iframeDOM = this.document ,elem = document.createElement(tagName) for(var key in attr){ elem.setAttribute(key, attr[key]); } elem.removeAttribute('text'); if(iframeDOM.selection){ //IE var text = range.text || attr.text; if(tagName === 'a' && !text) return; if(text){ elem.innerHTML = text; } range.pasteHTML($(elem).prop('outerHTML')); range.select(); } else { //非IE var text = range.toString() || attr.text; if(tagName === 'a' && !text) return; if(text){ elem.innerHTML = text; } range.deleteContents(); range.insertNode(elem); } } //工具选中 ,toolCheck = function(tools, othis){ var iframeDOM = this.document ,CHECK = 'layedit-tool-active' ,container = getContainer(Range(iframeDOM)) ,item = function(type){ return tools.find('.layedit-tool-'+type) } if(othis){ othis[othis.hasClass(CHECK) ? 'removeClass' : 'addClass'](CHECK); } tools.find('>i').removeClass(CHECK); item('unlink').addClass(ABLED); $(container).parents().each(function(){ var tagName = this.tagName.toLowerCase() ,textAlign = this.style.textAlign; //文字 if(tagName === 'b' || tagName === 'strong'){ item('b').addClass(CHECK) } if(tagName === 'i' || tagName === 'em'){ item('i').addClass(CHECK) } if(tagName === 'u'){ item('u').addClass(CHECK) } if(tagName === 'strike'){ item('d').addClass(CHECK) } //对齐 if(tagName === 'p'){ if(textAlign === 'center'){ item('center').addClass(CHECK); } else if(textAlign === 'right'){ item('right').addClass(CHECK); } else { item('left').addClass(CHECK); } } //超链接 if(tagName === 'a'){ item('link').addClass(CHECK); item('unlink').removeClass(ABLED); } }); } //触发工具 ,toolActive = function(iframeWin, editor, set){ var iframeDOM = iframeWin.document ,body = $(iframeDOM.body) ,toolEvent = { //超链接 link: function(range){ var container = getContainer(range) ,parentNode = $(container).parent(); link.call(body, { href: parentNode.attr('href') ,target: parentNode.attr('target') }, function(field){ var parent = parentNode[0]; if(parent.tagName === 'A'){ parent.href = field.url; } else { insertInline.call(iframeWin, 'a', { target: field.target ,href: field.url ,text: field.url }, range); } }); } //清除超链接 ,unlink: function(range){ iframeDOM.execCommand('unlink'); } //插入代码 ,code: function(range){ code.call(body, function(pre){ insertInline.call(iframeWin, 'pre', { text: pre.code ,'lay-lang': pre.lang }, range); }); } //帮助 ,help: function(){ layer.open({ type: 2 ,title: '帮助' ,area: ['600px', '380px'] ,shadeClose: true ,shade: 0.1 ,skin: 'layui-layer-msg' ,content: ['', 'no'] }); } } ,tools = editor.find('.layui-layedit-tool') ,click = function(){ var othis = $(this) ,events = othis.attr('layedit-event') ,command = othis.attr('lay-command'); if(othis.hasClass(ABLED)) return; body.focus(); var range = Range(iframeDOM) ,container = range.commonAncestorContainer if(command){ iframeDOM.execCommand(command); if(/justifyLeft|justifyCenter|justifyRight/.test(command)){ iframeDOM.execCommand('formatBlock', false, '

        '); } setTimeout(function(){ body.focus(); }, 10); } else { toolEvent[events] && toolEvent[events].call(this, range); } toolCheck.call(iframeWin, tools, othis); } ,isClick = /image/ tools.find('>i').on('mousedown', function(){ var othis = $(this) ,events = othis.attr('layedit-event'); if(isClick.test(events)) return; click.call(this) }).on('click', function(){ var othis = $(this) ,events = othis.attr('layedit-event'); if(!isClick.test(events)) return; click.call(this) }); //触发内容区域 body.on('click', function(){ toolCheck.call(iframeWin, tools); }); } //超链接面板 ,link = function(options, callback){ var body = this, index = layer.open({ type: 1 ,id: 'LAY_layedit_link' ,area: '350px' ,shade: 0.05 ,shadeClose: true ,moveType: 1 ,title: '超链接' ,skin: 'layui-layer-msg' ,content: ['

        '].join('') ,success: function(layero, index){ var eventFilter = 'submit(layedit-link-yes)'; form.render('radio'); layero.find('.layui-btn-primary').on('click', function(){ layer.close(index); body.focus(); }); form.on(eventFilter, function(data){ layer.close(link.index); callback && callback(data.field); }); } }); link.index = index; } //插入代码面板 ,code = function(callback){ var body = this, index = layer.open({ type: 1 ,id: 'LAY_layedit_code' ,area: '550px' ,shade: 0.05 ,shadeClose: true ,moveType: 1 ,title: '插入代码' ,skin: 'layui-layer-msg' ,content: [''].join('') ,success: function(layero, index){ var eventFilter = 'submit(layedit-code-yes)'; form.render('select'); layero.find('.layui-btn-primary').on('click', function(){ layer.close(index); body.focus(); }); form.on(eventFilter, function(data){ layer.close(code.index); callback && callback(data.field); }); } }); code.index = index; } //全部工具 ,tools = { html: '' ,strong: '' ,italic: '' ,underline: '' ,del: '' ,'|': '' ,left: '' ,center: '' ,right: '' ,link: '' ,unlink: '' ,face: '' ,image: '' ,code: '' ,help: '' } ,edit = new Edit(); exports(MOD_NAME, edit); }); /** * code * 代码区简易修饰 */ layui.define(['util'], function(exports){ "use strict"; var $ = layui.$; var util = layui.util; exports('code', function(options){ var elems = []; var trim = function(str){ return $.trim(str).replace(/^\n|\n$/, ''); } options = options || {}; options.elem = $(options.elem||'.layui-code'); options.lang = 'lang' in options ? options.lang : 'code'; options.elem.each(function(){ elems.push(this); }); layui.each(elems.reverse(), function(index, item){ var othis = $(item); var html = trim(othis.html()); // 转义 HTML 标签 if(othis.attr('lay-encode') || options.encode){ html = util.escape(html); } othis.html('
        1. ' + html.replace(/[\r\t\n]+/g, '
        2. ') + '
        ') if(!othis.find('>.layui-code-h3')[0]){ othis.prepend('

        '+ (othis.attr('lay-title')||options.title||'</>') + ''+ (othis.attr('lay-lang')||options.lang||'') +'' + '

        '); } var ol = othis.find('>.layui-code-ol'); othis.addClass('layui-box layui-code-view'); //识别皮肤 if(othis.attr('lay-skin') || options.skin){ othis.addClass('layui-code-' +(othis.attr('lay-skin') || options.skin)); } //按行数适配左边距 if((ol.find('li').length/100|0) > 0){ ol.css('margin-left', (ol.find('li').length/100|0) + 'px'); } //设置最大高度 if(othis.attr('lay-height') || options.height){ ol.css('max-height', othis.attr('lay-height') || options.height); } }); }); }).addcss('modules/code.css?v=2', 'skincodecss');