HEX
Server: nginx/1.28.1
System: Linux 10-41-63-61 6.8.0-31-generic #31-Ubuntu SMP PREEMPT_DYNAMIC Sat Apr 20 00:40:06 UTC 2024 x86_64
User: www (1001)
PHP: 7.4.33
Disabled: passthru,exec,system,putenv,chroot,chgrp,chown,shell_exec,popen,proc_open,pcntl_exec,ini_alter,ini_restore,dl,openlog,syslog,readlink,symlink,popepassthru,pcntl_alarm,pcntl_fork,pcntl_waitpid,pcntl_wait,pcntl_wifexited,pcntl_wifstopped,pcntl_wifsignaled,pcntl_wifcontinued,pcntl_wexitstatus,pcntl_wtermsig,pcntl_wstopsig,pcntl_signal,pcntl_signal_dispatch,pcntl_get_last_error,pcntl_strerror,pcntl_sigprocmask,pcntl_sigwaitinfo,pcntl_sigtimedwait,pcntl_exec,pcntl_getpriority,pcntl_setpriority,imap_open,apache_setenv
Upload Files
File: /www/wwwroot/fuwufei.xxlht.com/layui/modules/transfer.js
/**
 
 @Name:transfer 穿梭框组件
 @License:MIT

 */

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);
});