diff --git a/src/layui.js b/src/layui.js index f21ef1c5..24d6307b 100644 --- a/src/layui.js +++ b/src/layui.js @@ -232,6 +232,21 @@ return that; }; + Layui.prototype.unuse = 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); diff --git a/src/modules/form.js b/src/modules/form.js index 72cbaf8d..7ff98e86 100644 --- a/src/modules/form.js +++ b/src/modules/form.js @@ -145,19 +145,19 @@ layui.define('layer', function(exports){ }()) ,items = { //输入框 - input: function(){ - var inputs = elemForm.find('input,textarea'); - + input: function(elem){ + var inputs = elem || elemForm.find('input,textarea'); + //初始化全局的 autocomplete options.autocomplete && inputs.attr('autocomplete', options.autocomplete); } //下拉选择框 - ,select: function(){ + ,select: function(elem){ var TIPS = '请选择', CLASS = 'layui-form-select', TITLE = 'layui-select-title' ,NONE = 'layui-select-none', initValue = '', thatInput - ,selects = elemForm.find('select') - + ,selects = elem || elemForm.find('select') + //隐藏 select ,hide = function(e, clear){ if(!$(e.target).parent().hasClass(TITLE) || clear){ @@ -489,13 +489,13 @@ layui.define('layer', function(exports){ } //复选框/开关 - ,checkbox: function(){ + ,checkbox: function(elem){ var CLASS = { checkbox: ['layui-form-checkbox', 'layui-form-checked', 'checkbox'] ,_switch: ['layui-form-switch', 'layui-form-onswitch', 'switch'] } - ,checks = elemForm.find('input[type=checkbox]') - + ,checks = elem || elemForm.find('input[type=checkbox]') + ,events = function(reElem, RE_CLASS){ var check = $(this); @@ -561,10 +561,10 @@ layui.define('layer', function(exports){ } //单选框 - ,radio: function(){ + ,radio: function(elem){ var CLASS = 'layui-form-radio', ICON = ['', ''] - ,radios = elemForm.find('input[type=radio]') - + ,radios = elem || elemForm.find('input[type=radio]') + ,events = function(reElem){ var radio = $(this), ANIM = 'layui-anim-scaleSpring'; @@ -620,34 +620,58 @@ layui.define('layer', function(exports){ }); } }; - type ? ( - items[type] ? items[type]() : hint.error('不支持的 "'+ type + '" 表单渲染') - ) : layui.each(items, function(index, item){ - item(); - }); + if (layui._typeof(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; }; - - //表单提交校验 - var submit = function(){ + + // verifyElem: 要验证的节点或者范围 返回:验证通过返回true,否则返回false + Form.prototype.doVerify = function(verifyElem){ var stop = null //验证不通过状态 - ,verify = form.config.verify //验证规则 - ,DANGER = 'layui-form-danger' //警示样式 - ,field = {} //字段集合 - ,button = $(this) //当前触发的按钮 - ,elem = button.parents(ELEM).eq(0) //当前所在表单域 - ,verifyElem = elem.find('*[lay-verify]') //获取需要校验的元素 - ,formElem = button.parents('form')[0] //获取当前所在的 form 元素,如果存在的话 - ,filter = button.attr('lay-filter'); //获取过滤器 - - + ,verify = form.config.verify //验证规则 + ,DANGER = 'layui-form-danger' //警示样式 + + if (layui.type(verifyElem) !== 'object') { // 不符合要求的格式直接判通过 + hint.error('doVerify: 参数错误'); + return true; + } + if (!verifyElem.attr('lay-verify')) { + // 验证某个容器内的节点 + verifyElem = verifyElem.find('*[lay-verify]'); + } + //开始校验 layui.each(verifyElem, function(_, item){ var othis = $(this) - ,vers = othis.attr('lay-verify').split('|') - ,verType = othis.attr('lay-verType') //提示方式 - ,value = othis.val(); - + ,verifyStr = othis.attr('lay-verify') || '' + ,vers = verifyStr.split('|') + ,verType = othis.attr('lay-verType') //提示方式 + ,value = othis.val(); + othis.removeClass(DANGER); //移除警示样式 //遍历元素绑定的验证规则 @@ -696,7 +720,7 @@ layui.define('layer', function(exports){ } else { //移动设备定位 $dom.scrollTop(function(){ try { - return (isForm2Elem ? othis.next() : othis).offset().top - 15 + return (isForm2Elem ? othis.next() : othis).focus().offset().top - 15 } catch(e){ return 0; } @@ -710,9 +734,22 @@ layui.define('layer', function(exports){ }); if(stop) return stop; }); - - if(stop) return false; - + + return !stop; + } + + //表单提交校验 + var submit = function(){ + var field = {} //字段集合 + ,button = $(this) //当前触发的按钮 + ,elem = button.parents(ELEM).eq(0) //当前所在表单域 + ,verifyElem = elem.find('*[lay-verify]') //获取需要校验的元素 + ,formElem = button.parents('form')[0] //获取当前所在的 form 元素,如果存在的话 + ,filter = button.attr('lay-filter'); //获取过滤器 + + //开始校验 + if(!form.doVerify(verifyElem)) return false; + //获取当前表单值 field = form.getValue(null, elem); diff --git a/src/modules/laydate.js b/src/modules/laydate.js index 51f11d07..28b1ed8a 100644 --- a/src/modules/laydate.js +++ b/src/modules/laydate.js @@ -25,7 +25,9 @@ //外部调用 ,laydate = { v: '5.3.1' //layDate 版本号 - ,config: {} //全局配置项 + ,config: { + weekStart: 0, // 默认周日一周的开始 + } //全局配置项 ,index: (window.laydate && window.laydate.v) ? 100000 : 0 ,path: GLOBAL.laydate_dir || ready.getPath @@ -213,7 +215,16 @@ //将日期格式转化成数组 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 = ''; @@ -415,7 +426,7 @@ lay.each(new Array(7), function(j){ if(i === 0){ var th = lay.elem('th'); - th.innerHTML = lang.weeks[j]; + th.innerHTML = lang.weeks[(j + options.weekStart) % 7]; theadTr.appendChild(th); } tr.insertCell(j); @@ -845,8 +856,8 @@ //计算当前月第一天的星期 thisDate.setFullYear(dateTime.year, dateTime.month, 1); - startWeek = thisDate.getDay(); - + startWeek = (thisDate.getDay() + (7 - options.weekStart)) % 7; + prevMaxDate = laydate.getEndDate(dateTime.month || 12, dateTime.year); //计算上个月的最后一天 thisMaxDate = laydate.getEndDate(dateTime.month + 1, dateTime.year); //计算当前月的最后一天 diff --git a/src/modules/table.js b/src/modules/table.js index d8d616f9..f2fdee79 100644 --- a/src/modules/table.js +++ b/src/modules/table.js @@ -53,6 +53,9 @@ layui.define(['laytpl', 'laypage', 'layer', 'form', 'util'], function(exports){ ,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); } @@ -251,6 +254,7 @@ layui.define(['laytpl', 'laypage', 'layer', 'form', 'util'], function(exports){ ,loading: true //请求数据时,是否显示 loading ,escape: true // 是否开启 HTML 编码功能,即转义 html 原文 ,cellMinWidth: 60 //所有单元格默认最小宽度 + ,editTrigger: 'click' //单元格编辑的触发方式 ,defaultToolbar: ['filter', 'exports', 'print'] //工具栏右侧图标 ,autoSort: true //是否前端自动排序。如果否,则需自主排序(通常为服务端处理好排序) ,text: { @@ -394,39 +398,47 @@ layui.define(['laytpl', 'laypage', 'layer', 'form', 'util'], function(exports){ if(type === 'width') return options.clientWidth; + // 封装对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){ - item2.colspan = item2.colspan || 1; - item2.rowspan = item2.rowspan || 1; - - //如果列参数为空,则移除 - if(!item2){ - item1.splice(i2, 1); - return; - } - - item2.key = i1 + '-' + i2; - item2.hide = item2.hide || false; - - //设置列的父列索引 - //如果是组合列,则捕获对应的子列 - if(item2.colGroup || item2.colspan > 1){ - var childIndex = 0; - layui.each(options.cols[i1 + item2.rowspan], function(i22, item22){ - //如果子列已经被标注为{HAS_PARENT},或者子列累计 colspan 数等于父列定义的 colspan,则跳出当前子列循环 - if(item22.HAS_PARENT || (childIndex >= 1 && childIndex == item2.colspan)) return; - - item22.HAS_PARENT = true; - item22.parentKey = i1 + '-' + i2; - - childIndex = childIndex + parseInt(item22.colspan > 1 ? item22.colspan : 1); - }); - item2.colGroup = true; //标注是组合列 - } - - //根据列类型,定制化参数 - that.initOpts(item2); + initChildCols(i1, item1, i2, item2); }); }); @@ -686,7 +698,11 @@ layui.define(['laytpl', 'laypage', 'layer', 'form', 'util'], function(exports){ that.layMain.find('tbody').html(''); that.layMain.append(that.layNone = layNone); - + + // 异常情况下对page和total的内容处理 + that.layPage && that.layPage.addClass(HIDE).find('>div').html(''); + that.layTotal && that.layTotal.addClass(HIDE).find('tbody').html(''); + table.cache[that.key] = []; //格式化缓存数据 }; @@ -933,6 +949,7 @@ layui.define(['laytpl', 'laypage', 'layer', 'form', 'util'], function(exports){ //正常初始化数据渲染 render(); //渲染数据 that.renderTotal(data, totalRowData); //数据合计 + that.layTotal && that.layTotal.removeClass(HIDE); //同步分页状态 if(options.page){ @@ -1694,7 +1711,7 @@ layui.define(['laytpl', 'laypage', 'layer', 'form', 'util'], function(exports){ }); //单元格单击事件 - that.layBody.on('click', 'td', function(e){ + that.layBody.on(options.editTrigger, 'td', function(e){ var othis = $(this) ,field = othis.data('field') ,editType = othis.data('edit') @@ -1895,7 +1912,27 @@ layui.define(['laytpl', 'laypage', 'layer', 'form', 'util'], function(exports){ //记录所有实例 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 + parseInt(item22.colspan > 1 ? item22.colspan : 1); + eachChildCols(index, cols, i2, item22); + }); + } + }; + //遍历表头 table.eachCols = function(id, callback, cols){ var config = thisTable.config[id] || {} @@ -1905,25 +1942,9 @@ layui.define(['laytpl', 'laypage', 'layer', 'form', 'util'], function(exports){ //重新整理表头结构 layui.each(cols, function(i1, item1){ + if (i1) return true; // 只需遍历第一层 layui.each(item1, function(i2, item2){ - - //如果是组合列,则捕获对应的子列 - if(item2.colGroup){ - var childIndex = 0; - index++ - item2.CHILD_COLS = []; - - layui.each(cols[i1 + item2.rowspan], function(i22, item22){ - //如果子列已经被标注为{PARENT_COL_INDEX},或者子列累计 colspan 数等于父列定义的 colspan,则跳出当前子列循环 - if(item22.PARENT_COL_INDEX || (childIndex >= 1 && childIndex == item2.colspan)) return; - - item22.PARENT_COL_INDEX = index; - - item2.CHILD_COLS.push(item22); - childIndex = childIndex + parseInt(item22.colspan > 1 ? item22.colspan : 1); - }); - } - + eachChildCols(index, cols, i1, item2); if(item2.PARENT_COL_INDEX) return; //如果是子列,则不进行追加,因为已经存储在父列中 arrs.push(item2) }); @@ -1978,8 +1999,6 @@ layui.define(['laytpl', 'laypage', 'layer', 'form', 'util'], function(exports){ //表格导出 table.exportFile = function(id, data, type){ - var that = this; - data = data || table.clearCacheKey(table.cache[id]); type = type || 'csv'; @@ -2019,8 +2038,8 @@ layui.define(['laytpl', 'laypage', 'layer', 'form', 'util'], function(exports){ } var content = item1[item3.field] - ,td = that.layBody.find('tr[data-index="'+ i1 +'"]>td'); - + ,td = thatTable.layBody.find('tr[data-index="'+ i1 +'"]>td'); + if(content === undefined || content === null) content = ''; i1 == 0 && dataTitle.push(item3.title || ''); @@ -2042,14 +2061,14 @@ layui.define(['laytpl', 'laypage', 'layer', 'form', 'util'], function(exports){ }); //表合计 - layui.each(that.dataTotal, function(key, value){ + 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 = (config.title || 'table_'+ (config.index || '')) + '.' + type; + + alink.download = (config.title || 'table_'+ (config.index || new Date().getTime())) + '.' + type; document.body.appendChild(alink); alink.click(); document.body.removeChild(alink); @@ -2081,7 +2100,52 @@ layui.define(['laytpl', 'laypage', 'layer', 'form', 'util'], function(exports){ return thisTable.call(that); }; - + + //需要重新render的参数名单 + var dataParams = ['data', 'url', 'where', 'page', 'request', 'response', 'parseData']; + var dataParamsRegExp = new RegExp('^(' + dataParams.join('|') + ')$') + //重载数据 options只允许跟数据请求相关的配置信息 + table.reloadData = function(id, options, deep){ + var config = getThisTableConfig(id); //获取当前实例配置项 + if (!config) return; + + var that = thisTable.that[id]; + options = options || {}; + + if (options.page !== undefined && !!options.page !== !!config.page) { + // 如果是否分页发生了改变 + hint.error('reloadData不允许对是否分页进行切换(从不分页到分页的切换,反之亦然),如果需要请使用reload重载'); + delete options.page; + } + //过滤options只留下跟数据请求相关的参数 + layui.each(options, function (_key, _value) { + if (!dataParamsRegExp.test(_key)) { + delete options[_key]; + } + }); + if (options.page !== undefined) { // 针对page组件的特殊处理 + if (typeof options.page === 'object') { + options.page.curr && (that.page = options.page.curr); + delete options.elem; + delete options.jump; + } else if (options.page) { + options.page = {}; + } + $.extend(true, that.config, {page: options.page}); + delete options.page; + } + + if (options.data && options.data.constructor === Array) delete that.config.data; + deep ? $.extend(true, that.config, options) : $.extend(that.config, options); + if (!that.config.page) { + that.page = 1; + } + that.loading(); + that.pullData(that.page); + return thisTable.call(that); + } + + //核心入口 table.render = function(options){ var inst = new Class(options); diff --git a/src/modules/transfer.js b/src/modules/transfer.js index fd1b68cf..51e8782b 100644 --- a/src/modules/transfer.js +++ b/src/modules/transfer.js @@ -322,7 +322,62 @@ layui.define(['laytpl', 'form'], function(exports){ }); 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 @@ -343,48 +398,31 @@ layui.define(['laytpl', 'form'], function(exports){ this.checked = checked; }); } - - that.renderCheckBtn({stopNone: true}); + + 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') - ,thisBoxElem = that.layBox.eq(_index) - ,arr = []; if(othis.hasClass(DISABLED)) return; - - that.layBox.eq(_index).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(); - }); - }); - - 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); + + that.transfer(_index); }); //搜索