You can not select more than 25 topics Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.

438 lines
12 KiB

This file contains ambiguous Unicode characters!

This file contains ambiguous Unicode characters that may be confused with others in your current locale. If your use case is intentional and legitimate, you can safely ignore this warning. Use the Escape button to highlight these characters.

/**
@Nametransfer 穿梭框组件
@LicenseMIT
*/
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 ['<div class="layui-transfer-box" data-index="'+ obj.index +'">'
,'<div class="layui-transfer-header">'
,'<input type="checkbox" name="'+ obj.checkAllName +'" lay-filter="layTransferCheckbox" lay-type="all" lay-skin="primary" title="{{ d.data.title['+ obj.index +'] || \'list'+ (obj.index + 1) +'\' }}">'
,'</div>'
,'{{# if(d.data.showSearch){ }}'
,'<div class="layui-transfer-search">'
,'<i class="layui-icon layui-icon-search"></i>'
,'<input type="input" class="layui-input" placeholder="关键词搜索">'
,'</div>'
,'{{# } }}'
,'<ul class="layui-transfer-data"></ul>'
,'</div>'].join('');
}
//主模板
,TPL_MAIN = ['<div class="layui-transfer layui-form layui-border-box" lay-filter="LAY-transfer-{{ d.index }}">'
,TPL_BOX({
index: 0
,checkAllName: 'layTransferLeftCheckAll'
})
,'<div class="layui-transfer-active">'
,'<button type="button" class="layui-btn layui-btn-sm layui-btn-primary layui-btn-disabled" data-index="0">'
,'<i class="layui-icon layui-icon-next"></i>'
,'</button>'
,'<button type="button" class="layui-btn layui-btn-sm layui-btn-primary layui-btn-disabled" data-index="1">'
,'<i class="layui-icon layui-icon-prev"></i>'
,'</button>'
,'</div>'
,TPL_BOX({
index: 1
,checkAllName: 'layTransferRightCheckAll'
})
,'</div>'].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).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(){
return options.height - that.layHeader.outerHeight() - that.laySearch.outerHeight() - 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 = ['<li>'
,'<input type="checkbox" name="'+ arr[_index].checkName +'" lay-skin="primary" lay-filter="layTransferCheckbox" title="'+ item.title +'"'+ (item.disabled ? ' disabled' : '') + (item.checked ? ' checked' : '') +' value="'+ item.value +'">'
,'</li>'].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 = $('<p class="layui-none">'+ (text || '') +'</p>');
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.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;
});
}
that.renderCheckBtn({stopNone: true});
});
//按钮事件
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.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);
});