init
This commit is contained in:
32
public/frontend/layui-main/src/modules/all.js
Executable file
32
public/frontend/layui-main/src/modules/all.js
Executable file
@@ -0,0 +1,32 @@
|
||||
/**
|
||||
* 用于加载所有内置模块
|
||||
* MIT Licensed
|
||||
*/
|
||||
|
||||
layui.define(function(){
|
||||
var mods = []
|
||||
var builtin = layui.cache.builtin;
|
||||
|
||||
layui.each(builtin, function(modName){
|
||||
(modName === 'all' || modName === 'layui.all') || mods.push(modName);
|
||||
});
|
||||
layui.cache.startTime = new Date().getTime();
|
||||
|
||||
return mods;
|
||||
}(), function(exports){
|
||||
"use strict";
|
||||
|
||||
var MOD_NAME = 'all';
|
||||
|
||||
// 外部接口
|
||||
var all = {
|
||||
config: {},
|
||||
time: function(){
|
||||
var time = new Date().getTime() - layui.cache.startTime;
|
||||
delete layui.cache.startTime;
|
||||
return time;
|
||||
}()
|
||||
};
|
||||
|
||||
exports(MOD_NAME, all);
|
||||
});
|
||||
353
public/frontend/layui-main/src/modules/carousel.js
Executable file
353
public/frontend/layui-main/src/modules/carousel.js
Executable file
@@ -0,0 +1,353 @@
|
||||
/**
|
||||
* carousel 轮播模块
|
||||
* MIT Licensed
|
||||
*/
|
||||
|
||||
layui.define(['jquery', 'lay'], function(exports){
|
||||
"use strict";
|
||||
|
||||
var $ = layui.$;
|
||||
var lay = layui.lay;
|
||||
|
||||
var hint = layui.hint();
|
||||
var device = layui.device();
|
||||
|
||||
// 外部接口
|
||||
var 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);
|
||||
}
|
||||
};
|
||||
|
||||
// 字符常量
|
||||
var MOD_NAME = 'carousel';
|
||||
var ELEM = '.layui-carousel';
|
||||
var THIS = 'layui-this';
|
||||
var SHOW = 'layui-show';
|
||||
var HIDE = 'layui-hide';
|
||||
var DISABLED = 'layui-disabled'
|
||||
|
||||
var ELEM_ITEM = '>*[carousel-item]>*';
|
||||
var ELEM_LEFT = 'layui-carousel-left';
|
||||
var ELEM_RIGHT = 'layui-carousel-right';
|
||||
var ELEM_PREV = 'layui-carousel-prev';
|
||||
var ELEM_NEXT = 'layui-carousel-next';
|
||||
var ELEM_ARROW = 'layui-carousel-arrow';
|
||||
var ELEM_IND = 'layui-carousel-ind';
|
||||
|
||||
// 构造器
|
||||
var 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;
|
||||
var options = that.config;
|
||||
|
||||
// 若 elem 非唯一,则拆分为多个实例
|
||||
var elem = $(options.elem);
|
||||
if(elem.length > 1){
|
||||
layui.each(elem, function(){
|
||||
carousel.render($.extend({}, options, {
|
||||
elem: this
|
||||
}));
|
||||
});
|
||||
return that;
|
||||
}
|
||||
|
||||
// 合并 lay-options 属性上的配置信息
|
||||
$.extend(options, lay.options(elem[0]));
|
||||
|
||||
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;
|
||||
var 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;
|
||||
var 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;
|
||||
var 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;
|
||||
var 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;
|
||||
var 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;
|
||||
var options = that.config;
|
||||
|
||||
// 模板
|
||||
var tplArrow = $([
|
||||
'<button class="layui-icon '+ ELEM_ARROW +'" lay-type="sub">'+ (options.anim === 'updown' ? '' : '') +'</button>',
|
||||
'<button class="layui-icon '+ ELEM_ARROW +'" lay-type="add">'+ (options.anim === 'updown' ? '' : '') +'</button>'
|
||||
].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);
|
||||
var type = othis.attr('lay-type')
|
||||
that.slide(type);
|
||||
});
|
||||
};
|
||||
|
||||
// 跳转到特定下标
|
||||
Class.prototype.goto = function(index){
|
||||
var that = this;
|
||||
var options = that.config;
|
||||
|
||||
if(index > options.index){
|
||||
that.slide('add', index - options.index);
|
||||
} else if(index < options.index){
|
||||
that.slide('sub', options.index - index);
|
||||
}
|
||||
}
|
||||
|
||||
// 指示器
|
||||
Class.prototype.indicator = function(){
|
||||
var that = this;
|
||||
var options = that.config;
|
||||
|
||||
// 模板
|
||||
var tplInd = that.elemInd = $(['<div class="'+ ELEM_IND +'"><ul>',
|
||||
function(){
|
||||
var li = [];
|
||||
layui.each(that.elemItem, function(index){
|
||||
li.push('<li'+ (options.index === index ? ' class="layui-this"' : '') +'></li>');
|
||||
});
|
||||
return li.join('');
|
||||
}(),
|
||||
'</ul></div>'].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(){
|
||||
that.goto($(this).index());
|
||||
});
|
||||
};
|
||||
|
||||
// 滑动切换
|
||||
Class.prototype.slide = function(type, num){
|
||||
var that = this;
|
||||
var elemItem = that.elemItem;
|
||||
var options = that.config;
|
||||
var thisIndex = options.index;
|
||||
var 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;
|
||||
var 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){
|
||||
return new Class(options);
|
||||
};
|
||||
|
||||
exports(MOD_NAME, carousel);
|
||||
});
|
||||
|
||||
|
||||
602
public/frontend/layui-main/src/modules/code.js
Executable file
602
public/frontend/layui-main/src/modules/code.js
Executable file
@@ -0,0 +1,602 @@
|
||||
/**
|
||||
* code
|
||||
* Code 预览组件
|
||||
*/
|
||||
|
||||
layui.define(['lay', 'util', 'element', 'form'], function(exports){
|
||||
"use strict";
|
||||
|
||||
var $ = layui.$;
|
||||
var util = layui.util;
|
||||
var element = layui.element;
|
||||
var form = layui.form;
|
||||
var layer = layui.layer;
|
||||
var hint = layui.hint();
|
||||
|
||||
// 常量
|
||||
var CONST = {
|
||||
ELEM_VIEW: 'layui-code-view',
|
||||
ELEM_TAB: 'layui-tab',
|
||||
ELEM_HEADER: 'layui-code-header',
|
||||
ELEM_FULL: 'layui-code-full',
|
||||
ELEM_PREVIEW: 'layui-code-preview',
|
||||
ELEM_ITEM: 'layui-code-item',
|
||||
ELEM_SHOW: 'layui-show',
|
||||
ELEM_LINE: 'layui-code-line',
|
||||
ELEM_LINE_NUM: 'layui-code-line-number',
|
||||
ELEM_LN_MODE: 'layui-code-ln-mode',
|
||||
CDDE_DATA_CODE: 'LayuiCodeDataCode',
|
||||
CDDE_DATA_CLASS: 'LayuiCodeDataClass',
|
||||
LINE_RAW_WIDTH: 45, // 行号初始宽度,需与 css 保持一致
|
||||
};
|
||||
|
||||
// 默认参数项
|
||||
var config = {
|
||||
elem: '', // 元素选择器
|
||||
about: '', // 代码栏右上角信息
|
||||
ln: true, // 代码区域是否显示行号
|
||||
header: false, // 是否显示代码栏头部区域
|
||||
encode: true, // 是否对 code 进行编码(若开启预览,则强制开启)
|
||||
copy: true, // 是否开启代码区域复制功能图标
|
||||
// 默认文本
|
||||
text: {
|
||||
code: util.escape('</>'),
|
||||
preview: 'Preview',
|
||||
},
|
||||
wordWrap: true, // 是否自动换行
|
||||
lang: 'text', // 指定语言类型
|
||||
highlighter: false, // 是否开启语法高亮,'hljs','prism','shiki'
|
||||
langMarker: false, // 代码区域是否显示语言类型标记
|
||||
};
|
||||
|
||||
// 初始索引
|
||||
var codeIndex = layui.code ? (layui.code.index + 10000) : 0;
|
||||
|
||||
// 去除尾部空格
|
||||
var trimEnd = function(str){
|
||||
return String(str).replace(/\s+$/, '');
|
||||
}
|
||||
// 保留首行缩进
|
||||
var trim = function(str){
|
||||
return trimEnd(str).replace(/^\n|\n$/, '');
|
||||
};
|
||||
|
||||
// export api
|
||||
exports('code', function(options, mode){
|
||||
options = $.extend(true, {}, config, options);
|
||||
|
||||
// 返回对象
|
||||
var ret = {
|
||||
config: options,
|
||||
reload: function(opts) { // 重载
|
||||
layui.code(this.updateOptions(opts));
|
||||
},
|
||||
updateOptions: function(opts) { // 更新属性(选项)
|
||||
opts = opts || {};
|
||||
delete opts.elem;
|
||||
return $.extend(true, options, opts);
|
||||
},
|
||||
reloadCode: function(opts) { // 仅重载 code
|
||||
layui.code(this.updateOptions(opts), 'reloadCode');
|
||||
}
|
||||
};
|
||||
|
||||
// 若 elem 非唯一
|
||||
var elem = $(options.elem);
|
||||
if(elem.length > 1){
|
||||
// 是否正向渲染
|
||||
layui.each(options.obverse ? elem : elem.get().reverse(), function(){
|
||||
layui.code($.extend({}, options, {
|
||||
elem: this
|
||||
}), mode);
|
||||
});
|
||||
return ret;
|
||||
}
|
||||
|
||||
// 目标元素是否存在
|
||||
var othis = options.elem = $(options.elem);
|
||||
if(!othis[0]) return ret;
|
||||
|
||||
// 合并属性上的参数,并兼容旧版本属性写法 lay-*
|
||||
$.extend(true, options, lay.options(othis[0]), function(obj){
|
||||
var attrs = ['title', 'height', 'encode', 'skin', 'about'];
|
||||
layui.each(attrs, function(i, attr){
|
||||
var value = othis.attr('lay-'+ attr);
|
||||
if(typeof value === 'string'){
|
||||
obj[attr] = value;
|
||||
}
|
||||
})
|
||||
return obj;
|
||||
}({}));
|
||||
|
||||
// codeRender 需要关闭编码
|
||||
// 未使用 codeRender 时若开启了预览,则强制开启编码
|
||||
options.encode = (options.encode || options.preview) && !options.codeRender;
|
||||
|
||||
// 最终显示的代码
|
||||
var finalCode;
|
||||
|
||||
// 获得初始 code
|
||||
var rawCode = othis.data(CONST.CDDE_DATA_CODE) || function(){
|
||||
var arr = [];
|
||||
var textarea = othis.children('textarea');
|
||||
|
||||
// 若内容放置在 textarea 中
|
||||
textarea.each(function(){
|
||||
arr.push(trim(this.value));
|
||||
});
|
||||
|
||||
// 内容直接放置在元素外层
|
||||
if(arr.length === 0){
|
||||
arr.push(trim(othis.html()));
|
||||
}
|
||||
|
||||
return arr;
|
||||
}();
|
||||
|
||||
// 记录初始 code
|
||||
othis.data(CONST.CDDE_DATA_CODE, rawCode);
|
||||
|
||||
// 创建 code 行结构
|
||||
var createCode = function(html) {
|
||||
// codeRender
|
||||
if(typeof options.codeRender === 'function') {
|
||||
html = options.codeRender(String(html), options);
|
||||
}
|
||||
|
||||
// code 行
|
||||
var lines = String(html).split(/\r?\n/g);
|
||||
|
||||
// 包裹 code 行结构
|
||||
html = $.map(lines, function(line, num) {
|
||||
return [
|
||||
'<div class="'+ CONST.ELEM_LINE +'">',
|
||||
(
|
||||
options.ln ? [
|
||||
'<div class="'+ CONST.ELEM_LINE_NUM +'">',
|
||||
(util.digit(num + 1) + '.'),
|
||||
'</div>',
|
||||
].join('') : ''
|
||||
),
|
||||
'<div class="layui-code-line-content">',
|
||||
(line || ' '),
|
||||
'</div>',
|
||||
'</div>'
|
||||
].join('');
|
||||
});
|
||||
|
||||
return {
|
||||
lines: lines,
|
||||
html: html
|
||||
};
|
||||
};
|
||||
|
||||
// 仅重载 code
|
||||
if (mode === 'reloadCode') {
|
||||
(function(html) {
|
||||
var rst = createCode(html);
|
||||
othis.children('.layui-code-wrap').html(rst.html);
|
||||
})(rawCode.join(''))
|
||||
return ret;
|
||||
}
|
||||
|
||||
// 自增索引
|
||||
var index = layui.code.index = ++codeIndex;
|
||||
othis.attr('lay-code-index', index);
|
||||
|
||||
// 初始化 className
|
||||
var hasDataClass = CONST.CDDE_DATA_CLASS in othis.data();
|
||||
if (hasDataClass) {
|
||||
othis.attr('class', othis.data(CONST.CDDE_DATA_CLASS) || '');
|
||||
}
|
||||
|
||||
// 记录初始 className
|
||||
if (!hasDataClass) {
|
||||
othis.data(CONST.CDDE_DATA_CLASS, othis.attr('class'));
|
||||
}
|
||||
|
||||
// code
|
||||
var html = finalCode = rawCode.join('');
|
||||
|
||||
// 外部重新解析 code
|
||||
if(typeof options.codeParse === 'function'){
|
||||
html = finalCode = options.codeParse(html);
|
||||
}
|
||||
|
||||
// 工具栏
|
||||
var tools = {
|
||||
copy: {
|
||||
className: 'file-b',
|
||||
title: ['复制代码'],
|
||||
event: function(obj){
|
||||
var code = util.unescape(finalCode);
|
||||
|
||||
// 写入剪切板
|
||||
lay.clipboard.writeText({
|
||||
text: code,
|
||||
done: function() {
|
||||
layer.msg('已复制', {icon: 1});
|
||||
},
|
||||
error: function() {
|
||||
layer.msg('复制失败', {icon: 2});
|
||||
}
|
||||
});
|
||||
|
||||
typeof options.onCopy === 'function' && options.onCopy(code);
|
||||
}
|
||||
}
|
||||
};
|
||||
|
||||
// 移除包裹结构
|
||||
var unwrap = (function fn() {
|
||||
var elemViewHas = othis.parent('.' + CONST.ELEM_PREVIEW);
|
||||
var elemTabHas = elemViewHas.children('.'+ CONST.ELEM_TAB);
|
||||
var elemPreviewViewHas = elemViewHas.children('.' + CONST.ELEM_ITEM +'-preview');
|
||||
|
||||
// 移除旧结构
|
||||
elemTabHas.remove(); // 移除 tab
|
||||
elemPreviewViewHas.remove(); // 移除预览区域
|
||||
if (elemViewHas[0]) othis.unwrap(); // 移除外层容器
|
||||
|
||||
return fn;
|
||||
})();
|
||||
|
||||
// 是否开启预览
|
||||
if(options.preview){
|
||||
var FILTER_VALUE = 'LAY-CODE-DF-'+ index;
|
||||
var layout = options.layout || ['code', 'preview'];
|
||||
var isIframePreview = options.preview === 'iframe';
|
||||
|
||||
// 追加 Tab 组件
|
||||
var elemView = $('<div class="'+ CONST.ELEM_PREVIEW +'">');
|
||||
var elemTabView = $('<div class="layui-tab layui-tab-brief">');
|
||||
var elemHeaderView = $('<div class="layui-tab-title">');
|
||||
var elemPreviewView = $('<div class="'+ [
|
||||
CONST.ELEM_ITEM,
|
||||
CONST.ELEM_ITEM +'-preview',
|
||||
'layui-border'
|
||||
].join(' ') +'">');
|
||||
var elemToolbar = $('<div class="layui-code-tools"></div>');
|
||||
|
||||
|
||||
if(options.id) elemView.attr('id', options.id);
|
||||
elemView.addClass(options.className);
|
||||
elemTabView.attr('lay-filter', FILTER_VALUE);
|
||||
|
||||
// 标签头
|
||||
layui.each(layout, function(i, v){
|
||||
var li = $('<li lay-id="'+ v +'">');
|
||||
if(i === 0) li.addClass('layui-this');
|
||||
li.html(options.text[v]);
|
||||
elemHeaderView.append(li);
|
||||
});
|
||||
|
||||
// 工具栏
|
||||
$.extend(tools, {
|
||||
'full': {
|
||||
className: 'screen-full',
|
||||
title: ['最大化显示', '还原显示'],
|
||||
event: function(obj){
|
||||
var el = obj.elem;
|
||||
var elemView = el.closest('.'+ CONST.ELEM_PREVIEW);
|
||||
var classNameFull = 'layui-icon-'+ this.className;
|
||||
var classNameRestore = 'layui-icon-screen-restore';
|
||||
var title = this.title;
|
||||
var html = $('html,body');
|
||||
var ELEM_SCROLLBAR_HIDE = 'layui-scrollbar-hide';
|
||||
|
||||
if(el.hasClass(classNameFull)){
|
||||
elemView.addClass(CONST.ELEM_FULL);
|
||||
el.removeClass(classNameFull).addClass(classNameRestore);
|
||||
el.attr('title', title[1]);
|
||||
html.addClass(ELEM_SCROLLBAR_HIDE);
|
||||
} else {
|
||||
elemView.removeClass(CONST.ELEM_FULL);
|
||||
el.removeClass(classNameRestore).addClass(classNameFull);
|
||||
el.attr('title', title[0]);
|
||||
html.removeClass(ELEM_SCROLLBAR_HIDE);
|
||||
}
|
||||
}
|
||||
},
|
||||
'window': {
|
||||
className: 'release',
|
||||
title: ['在新窗口预览'],
|
||||
event: function(obj){
|
||||
util.openWin({
|
||||
content: finalCode
|
||||
});
|
||||
}
|
||||
}
|
||||
});
|
||||
|
||||
// copy
|
||||
if(options.copy){
|
||||
if(layui.type(options.tools) === 'array'){
|
||||
// 若 copy 未存在于 tools 中,则追加到最前
|
||||
if(options.tools.indexOf('copy') === -1){
|
||||
options.tools.unshift('copy');
|
||||
}
|
||||
} else {
|
||||
options.tools = ['copy'];
|
||||
}
|
||||
}
|
||||
|
||||
// 工具栏事件
|
||||
elemToolbar.on('click', '>i', function(){
|
||||
var oi = $(this);
|
||||
var type = oi.data('type');
|
||||
var parameters = {
|
||||
elem: oi,
|
||||
type: type,
|
||||
options: options, // 当前属性选项
|
||||
rawCode: rawCode.join(''), // 原始 code
|
||||
finalCode: util.unescape(finalCode) // 最终 code
|
||||
};
|
||||
|
||||
// 内部 tools event
|
||||
tools[type] && typeof tools[type].event === 'function' && tools[type].event(parameters);
|
||||
|
||||
// 外部 tools event
|
||||
typeof options.toolsEvent === 'function' && options.toolsEvent(parameters);
|
||||
});
|
||||
|
||||
// 增加工具栏
|
||||
if (options.addTools) {
|
||||
options.tools = [].concat(options.tools || [], options.addTools);
|
||||
}
|
||||
|
||||
// 渲染工具栏
|
||||
layui.each(options.tools, function(i, v){
|
||||
var viso = typeof v === 'object'; // 若为 object 值,则可自定义更多属性
|
||||
var tool = viso ? v : (
|
||||
tools[v] || {
|
||||
className: v,
|
||||
title: [v]
|
||||
}
|
||||
);
|
||||
|
||||
var className = tool.className || tool.type;
|
||||
var title = tool.title || [''];
|
||||
var type = viso ? ( tool.type || className ) : v;
|
||||
|
||||
if (!type) return;
|
||||
|
||||
// 若非内置 tool,则合并到 tools 中
|
||||
if (!tools[type]) {
|
||||
var obj = {};
|
||||
obj[type] = tool;
|
||||
$.extend(tools, obj);
|
||||
}
|
||||
|
||||
elemToolbar.append(
|
||||
'<i class="layui-icon layui-icon-'+ className +'" data-type="'+ type +'" title="'+ title[0] +'"></i>'
|
||||
);
|
||||
});
|
||||
|
||||
othis.addClass(CONST.ELEM_ITEM).wrap(elemView); // 包裹外层容器
|
||||
elemTabView.append(elemHeaderView); // 追加标签头
|
||||
options.tools && elemTabView.append(elemToolbar); // 追加工具栏
|
||||
othis.before(elemTabView); // 追加标签结构
|
||||
|
||||
// 追加预览
|
||||
if(isIframePreview){
|
||||
elemPreviewView.html('<iframe allowtransparency="true" frameborder="0"></iframe>');
|
||||
}
|
||||
|
||||
// 执行预览
|
||||
var run = function(thisItemBody){
|
||||
var iframe = thisItemBody.children('iframe')[0];
|
||||
if(isIframePreview && iframe){
|
||||
iframe.srcdoc = finalCode;
|
||||
} else {
|
||||
thisItemBody.html(rawCode.join(''));
|
||||
}
|
||||
// 回调的返回参数
|
||||
var params = {
|
||||
container: thisItemBody,
|
||||
render: function(){
|
||||
form.render(thisItemBody.find('.layui-form'));
|
||||
element.render();
|
||||
}
|
||||
};
|
||||
|
||||
// 当前实例预览完毕后的回调
|
||||
setTimeout(function(){
|
||||
typeof options.done === 'function' && options.done(params);
|
||||
},3);
|
||||
};
|
||||
|
||||
if(layout[0] === 'preview'){
|
||||
elemPreviewView.addClass(CONST.ELEM_SHOW);
|
||||
othis.before(elemPreviewView);
|
||||
run(elemPreviewView);
|
||||
} else {
|
||||
othis.addClass(CONST.ELEM_SHOW).after(elemPreviewView);
|
||||
}
|
||||
|
||||
// 内容项初始化样式
|
||||
options.previewStyle = [options.style, options.previewStyle].join('');
|
||||
elemPreviewView.attr('style', options.previewStyle);
|
||||
|
||||
// tab change
|
||||
element.on('tab('+ FILTER_VALUE +')', function(data){
|
||||
var $this = $(this);
|
||||
var thisElem = $(data.elem).closest('.'+ CONST.ELEM_PREVIEW);
|
||||
var elemItemBody = thisElem.find('.'+ CONST.ELEM_ITEM);
|
||||
var thisItemBody = elemItemBody.eq(data.index);
|
||||
|
||||
elemItemBody.removeClass(CONST.ELEM_SHOW);
|
||||
thisItemBody.addClass(CONST.ELEM_SHOW);
|
||||
|
||||
if($this.attr('lay-id') === 'preview'){
|
||||
run(thisItemBody);
|
||||
}
|
||||
|
||||
setCodeLayout();
|
||||
});
|
||||
}
|
||||
|
||||
// 创建 code 容器
|
||||
var codeElem = $('<code class="layui-code-wrap"></code>'); // 此处的闭合标签是为了兼容 IE8
|
||||
|
||||
// 添加主容器 className
|
||||
othis.addClass(function(arr) {
|
||||
if (!options.wordWrap) arr.push('layui-code-nowrap');
|
||||
return arr.join(' ')
|
||||
}(['layui-code-view layui-border-box']));
|
||||
|
||||
// code 主题风格
|
||||
var theme = options.theme || options.skin;
|
||||
if (theme) {
|
||||
othis.removeClass('layui-code-theme-dark layui-code-theme-light');
|
||||
othis.addClass('layui-code-theme-'+ theme);
|
||||
}
|
||||
|
||||
// 添加高亮必要的 className
|
||||
if (options.highlighter) {
|
||||
othis.addClass([
|
||||
options.highlighter,
|
||||
'language-' + options.lang,
|
||||
'layui-code-hl'
|
||||
].join(' '));
|
||||
}
|
||||
|
||||
// 转义 HTML 标签
|
||||
if(options.encode) html = util.escape(html); // 编码
|
||||
|
||||
var createCodeRst = createCode(html);
|
||||
var lines = createCodeRst.lines;
|
||||
|
||||
// 插入 code
|
||||
othis.html(codeElem.html(createCodeRst.html));
|
||||
|
||||
// 插入行号边栏
|
||||
if (options.ln) {
|
||||
othis.append('<div class="layui-code-ln-side"></div>');
|
||||
}
|
||||
|
||||
// 兼容旧版本 height 属性
|
||||
if (options.height) {
|
||||
codeElem.css('max-height', options.height);
|
||||
}
|
||||
|
||||
// code 区域样式
|
||||
options.codeStyle = [options.style, options.codeStyle].join('');
|
||||
if (options.codeStyle) {
|
||||
codeElem.attr('style', function(i, val) {
|
||||
return (val || '') + options.codeStyle;
|
||||
});
|
||||
}
|
||||
|
||||
// 动态设置样式
|
||||
var cssRules = [
|
||||
{
|
||||
selector: '>.layui-code-wrap>.layui-code-line{}',
|
||||
setValue: function(item, value) {
|
||||
item.style['padding-left'] = value + 'px';
|
||||
}
|
||||
},
|
||||
{
|
||||
selector: '>.layui-code-wrap>.layui-code-line>.layui-code-line-number{}',
|
||||
setValue: function(item, value) {
|
||||
item.style.width = value + 'px';
|
||||
}
|
||||
},
|
||||
{
|
||||
selector: '>.layui-code-ln-side{}',
|
||||
setValue: function(item, value) {
|
||||
item.style.width = value + 'px';
|
||||
}
|
||||
}
|
||||
];
|
||||
|
||||
// 生成初始 style 元素
|
||||
var styleElem = lay.style({
|
||||
target: othis[0],
|
||||
id: 'DF-code-'+ index,
|
||||
text: $.map($.map(cssRules, function(val){
|
||||
return val.selector;
|
||||
}), function(val, i) {
|
||||
return ['.layui-code-view[lay-code-index="'+ index + '"]', val].join(' ');
|
||||
}).join('')
|
||||
})
|
||||
|
||||
// 动态设置 code 布局
|
||||
var setCodeLayout = (function fn() {
|
||||
if (options.ln) {
|
||||
var multiLine = Math.floor(lines.length / 100);
|
||||
var lineElem = codeElem.children('.'+ CONST.ELEM_LINE);
|
||||
var width = lineElem.last().children('.'+ CONST.ELEM_LINE_NUM).outerWidth();
|
||||
|
||||
othis.addClass(CONST.ELEM_LN_MODE);
|
||||
|
||||
// 若超出 100 行
|
||||
if (multiLine && width > CONST.LINE_RAW_WIDTH) {
|
||||
lay.getStyleRules(styleElem, function(item, i) {
|
||||
try {
|
||||
cssRules[i].setValue(item, width);
|
||||
} catch(e) { }
|
||||
});
|
||||
}
|
||||
}
|
||||
|
||||
return fn;
|
||||
})();
|
||||
|
||||
// 创建 code header
|
||||
if (options.header) {
|
||||
var headerElem = $('<div class="'+ CONST.ELEM_HEADER +'"></div>');
|
||||
headerElem.html(options.title || options.text.code);
|
||||
othis.prepend(headerElem);
|
||||
}
|
||||
|
||||
// 创建 code 区域固定条
|
||||
var elemFixbar = $('<div class="layui-code-fixbar"></div>');
|
||||
|
||||
// 若开启复制,且未开启预览,则单独生成复制图标
|
||||
if(options.copy && !options.preview){
|
||||
var copyElem = $(['<span class="layui-code-copy">',
|
||||
'<i class="layui-icon layui-icon-file-b" title="复制"></i>',
|
||||
'</span>'].join(''));
|
||||
|
||||
// 点击复制
|
||||
copyElem.on('click', function(){
|
||||
tools.copy.event();
|
||||
});
|
||||
|
||||
elemFixbar.append(copyElem);
|
||||
}
|
||||
|
||||
// 创建 language marker
|
||||
if (options.langMarker) {
|
||||
elemFixbar.append('<span class="layui-code-lang-marker">' + options.lang + '</span>');
|
||||
}
|
||||
|
||||
// 创建 about 自定义内容
|
||||
if (options.about) {
|
||||
elemFixbar.append(options.about);
|
||||
}
|
||||
|
||||
// 生成 code fixbar
|
||||
othis.append(elemFixbar);
|
||||
|
||||
// code 渲染完毕后的回调
|
||||
if (!options.preview) {
|
||||
setTimeout(function(){
|
||||
typeof options.done === 'function' && options.done({});
|
||||
},3);
|
||||
}
|
||||
|
||||
// 所有实例渲染完毕后的回调
|
||||
if(options.elem.length === index + 1){
|
||||
typeof options.allDone === 'function' && options.allDone();
|
||||
}
|
||||
|
||||
return ret;
|
||||
});
|
||||
});
|
||||
|
||||
// 若为源码版,则自动加载该组件依赖的 css 文件
|
||||
if(!layui['layui.all']){
|
||||
layui.addcss('modules/code.css?v=6', 'skincodecss');
|
||||
}
|
||||
747
public/frontend/layui-main/src/modules/colorpicker.js
Executable file
747
public/frontend/layui-main/src/modules/colorpicker.js
Executable file
@@ -0,0 +1,747 @@
|
||||
/**
|
||||
* colorpicker
|
||||
* 颜色选择组件
|
||||
*/
|
||||
|
||||
layui.define(['jquery', 'lay'], function(exports){
|
||||
"use strict";
|
||||
|
||||
var $ = layui.$;
|
||||
var lay = layui.lay;
|
||||
var hint = layui.hint();
|
||||
var device = layui.device();
|
||||
var clickOrMousedown = (device.mobile ? 'click' : 'mousedown');
|
||||
|
||||
//外部接口
|
||||
var 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);
|
||||
}
|
||||
};
|
||||
|
||||
// 操作当前实例
|
||||
var thisModule = function(){
|
||||
var that = this;
|
||||
var options = that.config;
|
||||
var id = options.id;
|
||||
|
||||
thisModule.that[id] = that; // 记录当前实例对象
|
||||
|
||||
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){ // 因 rgb 中返回的数字为 string 类型
|
||||
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){
|
||||
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: [ //默认预定义颜色列表
|
||||
'#16baaa', '#16b777', '#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;
|
||||
var options = that.config;
|
||||
|
||||
// 若 elem 非唯一,则拆分为多个实例
|
||||
var elem = $(options.elem);
|
||||
if(elem.length > 1){
|
||||
layui.each(elem, function(){
|
||||
colorpicker.render($.extend({}, options, {
|
||||
elem: this
|
||||
}));
|
||||
});
|
||||
return that;
|
||||
}
|
||||
|
||||
// 合并 lay-options 属性上的配置信息
|
||||
$.extend(options, lay.options(elem[0]));
|
||||
|
||||
//颜色选择框对象
|
||||
var elemColorBox = $(['<div class="layui-unselect layui-colorpicker">'
|
||||
,'<span '+ (options.format == 'rgb' && options.alpha
|
||||
? 'class="layui-colorpicker-trigger-bgcolor"'
|
||||
: '') +'>'
|
||||
,'<span class="layui-colorpicker-trigger-span" '
|
||||
,'lay-type="'+ (options.format == 'rgb' ? (options.alpha ? 'rgba' : 'torgb') : '') +'" '
|
||||
,'style="'+ function(){
|
||||
var bgstr = '';
|
||||
if(options.color){
|
||||
bgstr = options.color;
|
||||
|
||||
if((options.color.match(/[0-9]{1,3}/g) || []).length > 3){ //需要优化
|
||||
if(!(options.alpha && options.format == 'rgb')){
|
||||
bgstr = '#' + HSBToHEX(RGBToHSB(RGBSTo(options.color)))
|
||||
}
|
||||
}
|
||||
|
||||
return 'background: '+ bgstr;
|
||||
}
|
||||
|
||||
return bgstr;
|
||||
}() +'">'
|
||||
,'<i class="layui-icon layui-colorpicker-trigger-i '+ (options.color
|
||||
? ICON_PICKER_DOWN
|
||||
: ICON_PICKER_CLOSE) +'"></i>'
|
||||
,'</span>'
|
||||
,'</span>'
|
||||
,'</div>'].join(''))
|
||||
|
||||
//初始化颜色选择框
|
||||
elem = options.elem = $(options.elem);
|
||||
options.size && elemColorBox.addClass('layui-colorpicker-'+ options.size); //初始化颜色选择框尺寸
|
||||
|
||||
// 插入颜色选择框
|
||||
elem.addClass('layui-inline').html(
|
||||
that.elemColorBox = elemColorBox
|
||||
);
|
||||
|
||||
// 初始化 id 属性 - 优先取 options > 元素 id > 自增索引
|
||||
options.id = 'id' in options ? options.id : (
|
||||
elem.attr('id') || that.index
|
||||
);
|
||||
|
||||
// 获取背景色值
|
||||
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 = $(['<div id="layui-colorpicker'+ that.index +'" data-index="'+ that.index +'" class="layui-anim layui-anim-downbit layui-colorpicker-main">'
|
||||
//颜色面板
|
||||
,'<div class="layui-colorpicker-main-wrapper">'
|
||||
,'<div class="layui-colorpicker-basis">'
|
||||
,'<div class="layui-colorpicker-basis-white"></div>'
|
||||
,'<div class="layui-colorpicker-basis-black"></div>'
|
||||
,'<div class="layui-colorpicker-basis-cursor"></div>'
|
||||
,'</div>'
|
||||
,'<div class="layui-colorpicker-side">'
|
||||
,'<div class="layui-colorpicker-side-slider"></div>'
|
||||
,'</div>'
|
||||
,'</div>'
|
||||
|
||||
//透明度条块
|
||||
,'<div class="layui-colorpicker-main-alpha '+ (options.alpha ? SHOW : '') +'">'
|
||||
,'<div class="layui-colorpicker-alpha-bgcolor">'
|
||||
,'<div class="layui-colorpicker-alpha-slider"></div>'
|
||||
,'</div>'
|
||||
,'</div>'
|
||||
|
||||
//预设颜色列表
|
||||
,function(){
|
||||
if(options.predefine){
|
||||
var list = ['<div class="layui-colorpicker-main-pre">'];
|
||||
layui.each(options.colors, function(i, v){
|
||||
list.push(['<div class="layui-colorpicker-pre'+ ((v.match(/[0-9]{1,3}/g) || []).length > 3
|
||||
? ' layui-colorpicker-pre-isalpha'
|
||||
: '') +'">'
|
||||
,'<div style="background:'+ v +'"></div>'
|
||||
,'</div>'].join(''));
|
||||
});
|
||||
list.push('</div>');
|
||||
return list.join('');
|
||||
} else {
|
||||
return '';
|
||||
}
|
||||
}()
|
||||
|
||||
//底部表单元素区域
|
||||
,'<div class="layui-colorpicker-main-input">'
|
||||
,'<div class="layui-inline">'
|
||||
,'<input type="text" class="layui-input">'
|
||||
,'</div>'
|
||||
,'<div class="layui-btn-container">'
|
||||
,'<button class="layui-btn layui-btn-primary layui-btn-sm" colorpicker-events="clear">清空</button>'
|
||||
,'<button class="layui-btn layui-btn-sm" colorpicker-events="confirm">确定</button>'
|
||||
,'</div'
|
||||
,'</div>'
|
||||
,'</div>'].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);
|
||||
}
|
||||
|
||||
// 记录当前执行的实例索引
|
||||
colorpicker.thisId = options.id;
|
||||
|
||||
Class.thisElemInd = that.index; //记录最新打开的选择器索引
|
||||
Class.thisColor = elemColorBox.style.background //记录最新打开的选择器颜色选中值
|
||||
|
||||
that.position();
|
||||
that.pickerEvents();
|
||||
};
|
||||
|
||||
//颜色选择器移除
|
||||
Class.prototype.removePicker = function(index){
|
||||
var that = this;
|
||||
var options = that.config;
|
||||
var elem = $('#layui-colorpicker'+ (index || that.index));
|
||||
|
||||
if(elem[0]){
|
||||
elem.remove();
|
||||
delete colorpicker.thisId;
|
||||
|
||||
// 面板关闭后的回调
|
||||
typeof options.close === 'function' && options.close(that.color);
|
||||
}
|
||||
|
||||
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);
|
||||
} else if(type === 'rgba'){ // 若格式要求为 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 {
|
||||
elemPickerInput.find('input').val('#'+ HSBToHEX(hsb));
|
||||
}
|
||||
} 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});
|
||||
var color = HSBToHEX({h:x, s:y, b:z});
|
||||
var elemInput = that.elemPicker.find('.' + PICKER_INPUT).find('input');
|
||||
|
||||
i.addClass(ICON_PICKER_DOWN).removeClass(ICON_PICKER_CLOSE);
|
||||
span[0].style.background = 'rgb('+ rgb.r +', '+ rgb.g +', '+ rgb.b +')';
|
||||
|
||||
if(type === 'torgb'){
|
||||
elemInput.val('rgb('+ rgb.r +', '+ rgb.g +', '+ rgb.b +')');
|
||||
} else if(type === 'rgba'){
|
||||
var left = a * 280;
|
||||
alphaslider.css("left", left);
|
||||
elemInput.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 +'))'
|
||||
} else {
|
||||
elemInput.val('#'+ color);
|
||||
}
|
||||
|
||||
//回调更改的颜色
|
||||
options.change && options.change(that.elemPicker.find('.' + PICKER_INPUT).find('input').val());
|
||||
}
|
||||
|
||||
//拖拽元素
|
||||
,elemMove = $(['<div class="layui-auxiliar-moving" id="LAY-colorpicker-moving"></div>'].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 + $win.scrollTop();
|
||||
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;
|
||||
var options = that.config;
|
||||
var hex = HSBToHEX({h:h, s:100, b:100});
|
||||
var color = HSBToHEX({h:h, s:s, b:b});
|
||||
var sidetop = h/360*180;
|
||||
var top = 180 - b/100*180 - 3;
|
||||
var 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
|
||||
,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;
|
||||
var options = that.config;
|
||||
|
||||
// 弹出颜色选择器
|
||||
that.elemColorBox.on('click' , function(){
|
||||
that.renderPicker();
|
||||
if($(ELEM_MAIN)[0]){
|
||||
that.val();
|
||||
that.side();
|
||||
}
|
||||
});
|
||||
};
|
||||
|
||||
//全局事件
|
||||
(function(){
|
||||
//绑定关闭控件事件
|
||||
$doc.on(clickOrMousedown, function(e){
|
||||
if(!colorpicker.thisId) return;
|
||||
var that = thisModule.getThis(colorpicker.thisId);
|
||||
if(!that) return;
|
||||
|
||||
var options = that.config;
|
||||
var elemColorBoxSpan = that.elemColorBox.find('.' + PICKER_TRIG_SPAN);
|
||||
|
||||
//如果点击的元素是颜色框
|
||||
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 || '';
|
||||
|
||||
// 取消选择的回调
|
||||
typeof options.cancel === 'function' && options.cancel(that.color);
|
||||
|
||||
// 移除面板
|
||||
that.removePicker();
|
||||
});
|
||||
|
||||
//自适应定位
|
||||
$win.on('resize', function(){
|
||||
if(!colorpicker.thisId) return;
|
||||
var that = thisModule.getThis(colorpicker.thisId);
|
||||
if(!that) return;
|
||||
|
||||
if(!that.elemPicker || !$(ELEM_MAIN)[0]){
|
||||
return false;
|
||||
}
|
||||
that.position();
|
||||
});
|
||||
})();
|
||||
|
||||
// 记录所有实例
|
||||
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;
|
||||
};
|
||||
|
||||
//核心入口
|
||||
colorpicker.render = function(options){
|
||||
var inst = new Class(options);
|
||||
return thisModule.call(inst);
|
||||
};
|
||||
|
||||
exports(MOD_NAME, colorpicker);
|
||||
});
|
||||
622
public/frontend/layui-main/src/modules/dropdown.js
Executable file
622
public/frontend/layui-main/src/modules/dropdown.js
Executable file
@@ -0,0 +1,622 @@
|
||||
/**
|
||||
* dropdown
|
||||
* 下拉菜单组件
|
||||
*/
|
||||
|
||||
layui.define(['jquery', 'laytpl', 'lay', 'util'], function(exports){
|
||||
"use strict";
|
||||
|
||||
var $ = layui.$;
|
||||
var laytpl = layui.laytpl;
|
||||
var util = layui.util;
|
||||
var hint = layui.hint();
|
||||
var device = layui.device();
|
||||
var clickOrMousedown = (device.mobile ? 'touchstart' : 'mousedown');
|
||||
|
||||
// 模块名
|
||||
var MOD_NAME = 'dropdown';
|
||||
var MOD_INDEX = 'layui_'+ MOD_NAME +'_index'; // 模块索引名
|
||||
|
||||
// 外部接口
|
||||
var dropdown = {
|
||||
config: {
|
||||
customName: { // 自定义 data 字段名
|
||||
id: 'id',
|
||||
title: 'title',
|
||||
children: 'child'
|
||||
}
|
||||
},
|
||||
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);
|
||||
}
|
||||
};
|
||||
|
||||
// 操作当前实例
|
||||
var thisModule = function(){
|
||||
var that = this;
|
||||
var options = that.config;
|
||||
var id = options.id;
|
||||
|
||||
thisModule.that[id] = that; // 记录当前实例对象
|
||||
|
||||
return {
|
||||
config: options,
|
||||
// 重置实例
|
||||
reload: function(options){
|
||||
that.reload.call(that, options);
|
||||
},
|
||||
reloadData: function(options){
|
||||
dropdown.reloadData(id, options);
|
||||
},
|
||||
close: function () {
|
||||
that.remove()
|
||||
}
|
||||
}
|
||||
};
|
||||
|
||||
// 字符常量
|
||||
var STR_ELEM = 'layui-dropdown';
|
||||
var STR_HIDE = 'layui-hide';
|
||||
var STR_DISABLED = 'layui-disabled';
|
||||
var STR_NONE = 'layui-none';
|
||||
var STR_ITEM_UP = 'layui-menu-item-up';
|
||||
var STR_ITEM_DOWN = 'layui-menu-item-down';
|
||||
var STR_MENU_TITLE = 'layui-menu-body-title';
|
||||
var STR_ITEM_GROUP = 'layui-menu-item-group';
|
||||
var STR_ITEM_PARENT = 'layui-menu-item-parent';
|
||||
var STR_ITEM_DIV = 'layui-menu-item-divider';
|
||||
var STR_ITEM_CHECKED = 'layui-menu-item-checked';
|
||||
var STR_ITEM_CHECKED2 = 'layui-menu-item-checked2';
|
||||
var STR_MENU_PANEL = 'layui-menu-body-panel';
|
||||
var STR_MENU_PANEL_L = 'layui-menu-body-panel-left';
|
||||
var STR_ELEM_SHADE = 'layui-dropdown-shade';
|
||||
|
||||
var STR_GROUP_TITLE = '.'+ STR_ITEM_GROUP + '>.'+ STR_MENU_TITLE;
|
||||
|
||||
// 构造器
|
||||
var 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 时才生效
|
||||
shade: 0 // 遮罩
|
||||
};
|
||||
|
||||
// 重载实例
|
||||
Class.prototype.reload = function(options, type){
|
||||
var that = this;
|
||||
that.config = $.extend({}, that.config, options);
|
||||
that.init(true, type);
|
||||
};
|
||||
|
||||
// 初始化准备
|
||||
Class.prototype.init = function(rerender, type){
|
||||
var that = this;
|
||||
var options = that.config;
|
||||
|
||||
// 若 elem 非唯一
|
||||
var elem = $(options.elem);
|
||||
if(elem.length > 1){
|
||||
layui.each(elem, function(){
|
||||
dropdown.render($.extend({}, options, {
|
||||
elem: this
|
||||
}));
|
||||
});
|
||||
return that;
|
||||
}
|
||||
|
||||
// 合并 lay-options 属性上的配置信息
|
||||
$.extend(options, lay.options(elem[0]));
|
||||
|
||||
// 若重复执行 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, type);
|
||||
}
|
||||
|
||||
options.elem = $(options.elem);
|
||||
|
||||
// 初始化 id 属性 - 优先取 options > 元素 id > 自增索引
|
||||
options.id = 'id' in options ? options.id : (
|
||||
elem.attr('id') || that.index
|
||||
);
|
||||
|
||||
// 初始化自定义字段名
|
||||
options.customName = $.extend({}, dropdown.config.customName, options.customName);
|
||||
|
||||
if(options.show || (type === 'reloadData' && that.elemView && $('body').find(that.elemView.get(0)).length)) that.render(rerender, type); //初始即显示或者面板弹出之后执行了刷新数据
|
||||
that.events(); // 事件
|
||||
};
|
||||
|
||||
// 渲染
|
||||
Class.prototype.render = function(rerender, type){
|
||||
var that = this;
|
||||
var options = that.config;
|
||||
var customName = options.customName;
|
||||
var elemBody = $('body');
|
||||
|
||||
// 默认菜单内容
|
||||
var getDefaultView = function(){
|
||||
var elemUl = $('<ul class="layui-menu layui-dropdown-menu"></ul>');
|
||||
if(options.data.length > 0 ){
|
||||
eachItemView(elemUl, options.data)
|
||||
} else {
|
||||
elemUl.html('<li class="layui-menu-item-none">No data</li>');
|
||||
}
|
||||
return elemUl;
|
||||
};
|
||||
|
||||
// 遍历菜单项
|
||||
var eachItemView = function(views, data){
|
||||
// var views = [];
|
||||
|
||||
layui.each(data, function(index, item){
|
||||
// 是否存在子级
|
||||
var isChild = item[customName.children] && item[customName.children].length > 0;
|
||||
var isSpreadItem = ('isSpreadItem' in item) ? item.isSpreadItem : options.isSpreadItem
|
||||
var title = function(title){
|
||||
var templet = item.templet || options.templet;
|
||||
if(templet){
|
||||
title = typeof templet === 'function'
|
||||
? templet(item)
|
||||
: laytpl(templet).render(item);
|
||||
}
|
||||
return title;
|
||||
}(util.escape(item[customName.title]));
|
||||
|
||||
// 初始类型
|
||||
var type = function(){
|
||||
if(isChild){
|
||||
item.type = item.type || 'parent';
|
||||
}
|
||||
if(item.type){
|
||||
return ({
|
||||
group: 'group'
|
||||
,parent: 'parent'
|
||||
,'-': '-'
|
||||
})[item.type] || 'parent';
|
||||
}
|
||||
return '';
|
||||
}();
|
||||
|
||||
if(type !== '-' && (!item[customName.title] && !item[customName.id] && !isChild)) return;
|
||||
|
||||
//列表元素
|
||||
var viewLi = $(['<li'+ function(){
|
||||
var className = {
|
||||
group: 'layui-menu-item-group'+ (
|
||||
options.isAllowSpread ? (
|
||||
isSpreadItem ? ' layui-menu-item-down' : ' layui-menu-item-up'
|
||||
) : ''
|
||||
)
|
||||
,parent: STR_ITEM_PARENT
|
||||
,'-': 'layui-menu-item-divider'
|
||||
};
|
||||
if(isChild || type){
|
||||
return ' class="'+ className[type] +'"';
|
||||
}
|
||||
return item.disabled ? ' class="'+ STR_DISABLED +'"' : '';
|
||||
}() +'>'
|
||||
|
||||
//标题区
|
||||
,function(){
|
||||
//是否超文本
|
||||
var viewText = ('href' in item) ? (
|
||||
'<a href="'+ item.href +'" target="'+ (item.target || '_self') +'">'+ title +'</a>'
|
||||
) : title;
|
||||
|
||||
//是否存在子级
|
||||
if(isChild){
|
||||
return '<div class="'+ STR_MENU_TITLE +'">'+ viewText + function(){
|
||||
if(type === 'parent'){
|
||||
return '<i class="layui-icon layui-icon-right"></i>';
|
||||
} else if(type === 'group' && options.isAllowSpread){
|
||||
return '<i class="layui-icon layui-icon-'+ (isSpreadItem ? 'up' : 'down') +'"></i>';
|
||||
} else {
|
||||
return '';
|
||||
}
|
||||
}() +'</div>'
|
||||
|
||||
}
|
||||
return '<div class="'+ STR_MENU_TITLE +'">'+ viewText +'</div>';
|
||||
}()
|
||||
,'</li>'].join(''));
|
||||
|
||||
viewLi.data('item', item);
|
||||
|
||||
//子级区
|
||||
if(isChild){
|
||||
var elemPanel = $('<div class="layui-panel layui-menu-body-panel"></div>');
|
||||
var elemUl = $('<ul></ul>');
|
||||
|
||||
if(type === 'parent'){
|
||||
elemPanel.append(eachItemView(elemUl, item[customName.children]));
|
||||
viewLi.append(elemPanel);
|
||||
} else {
|
||||
viewLi.append(eachItemView(elemUl, item[customName.children]));
|
||||
}
|
||||
}
|
||||
|
||||
views.append(viewLi);
|
||||
});
|
||||
return views;
|
||||
};
|
||||
|
||||
// 主模板
|
||||
var TPL_MAIN = ['<div class="layui-dropdown layui-border-box layui-panel layui-anim layui-anim-downbit" lay-id="' + options.id + '">'
|
||||
,'</div>'].join('');
|
||||
|
||||
// 如果是右键事件,则每次触发事件时,将允许重新渲染
|
||||
if(options.trigger === 'contextmenu' || lay.isTopElem(options.elem[0])) rerender = true;
|
||||
|
||||
// 判断是否已经打开了下拉菜单面板
|
||||
if(!rerender && options.elem.data(MOD_INDEX +'_opened')) return;
|
||||
|
||||
// 记录模板对象
|
||||
that.elemView = $('.' + STR_ELEM + '[lay-id="' + options.id + '"]');
|
||||
if (type === 'reloadData' && that.elemView.length) {
|
||||
that.elemView.html(options.content || getDefaultView());
|
||||
} else {
|
||||
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);
|
||||
|
||||
// 遮罩
|
||||
var shade = options.shade ? ('<div class="'+ STR_ELEM_SHADE +'" style="'+ ('z-index:'+ (that.elemView.css('z-index')-1) +'; background-color: ' + (options.shade[1] || '#000') + '; opacity: ' + (options.shade[0] || options.shade)) +'"></div>') : '';
|
||||
that.elemView.before(shade);
|
||||
|
||||
// 如果是鼠标移入事件,则鼠标移出时自动关闭
|
||||
if(options.trigger === 'mouseenter'){
|
||||
that.elemView.on('mouseenter', function(){
|
||||
clearTimeout(thisModule.timer);
|
||||
}).on('mouseleave', function(){
|
||||
that.delayRemove();
|
||||
});
|
||||
}
|
||||
}
|
||||
|
||||
// 坐标定位
|
||||
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);
|
||||
var data = othis.data('item') || {};
|
||||
var isChild = data[customName.children] && data[customName.children].length > 0;
|
||||
var isClickAllScope = options.clickScope === 'all'; // 是否所有父子菜单均触发点击事件
|
||||
|
||||
if(data.disabled) return; // 菜单项禁用状态
|
||||
|
||||
// 普通菜单项点击后的回调及关闭面板
|
||||
if((!isChild || isClickAllScope) && data.type !== '-'){
|
||||
var ret = typeof options.click === 'function'
|
||||
? options.click(data, othis)
|
||||
: null;
|
||||
|
||||
ret === false || (isChild || that.remove());
|
||||
layui.stope(e);
|
||||
}
|
||||
});
|
||||
|
||||
// 触发菜单组展开收缩
|
||||
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);
|
||||
}
|
||||
});
|
||||
|
||||
// 组件打开完毕的事件
|
||||
typeof options.ready === 'function' && options.ready(
|
||||
that.elemView,
|
||||
options.elem
|
||||
);
|
||||
};
|
||||
|
||||
// 位置定位
|
||||
Class.prototype.position = function(obj){
|
||||
var that = this;
|
||||
var 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;
|
||||
var options = that.config;
|
||||
var elemPrev = thisModule.prevElem;
|
||||
|
||||
// 若存在已打开的面板元素,则移除
|
||||
if(elemPrev){
|
||||
elemPrev.data('prevElem') && (
|
||||
elemPrev.data('prevElem').data(MOD_INDEX +'_opened', false)
|
||||
);
|
||||
elemPrev.remove();
|
||||
}
|
||||
lay('.' + STR_ELEM_SHADE).remove();
|
||||
};
|
||||
|
||||
// 延迟删除视图
|
||||
Class.prototype.delayRemove = function(){
|
||||
var that = this;
|
||||
var options = that.config;
|
||||
clearTimeout(thisModule.timer);
|
||||
|
||||
thisModule.timer = setTimeout(function(){
|
||||
that.remove();
|
||||
}, options.delay);
|
||||
};
|
||||
|
||||
// 事件
|
||||
Class.prototype.events = function(){
|
||||
var that = this;
|
||||
var 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();
|
||||
};
|
||||
|
||||
// 触发元素事件
|
||||
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 needSpread = othis.hasClass(STR_ITEM_UP);
|
||||
var elemIcon = othis.children('.'+ STR_MENU_TITLE).find('.layui-icon-' + (needSpread ? 'down' : 'up'));
|
||||
if(needSpread){
|
||||
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);
|
||||
var _DOC = $(document);
|
||||
|
||||
// 自适应定位
|
||||
_WIN.on('resize', function(){
|
||||
if(!dropdown.thisId) return;
|
||||
var that = thisModule.getThis(dropdown.thisId);
|
||||
if(!that) return;
|
||||
|
||||
if((that.elemView && !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] ||
|
||||
(that.elemView && 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);
|
||||
var parent = othis.parents('.layui-menu').eq(0);
|
||||
var isChild = othis.hasClass(STR_ITEM_GROUP) || othis.hasClass(STR_ITEM_PARENT);
|
||||
var filter = parent.attr('lay-filter') || parent.attr('id');
|
||||
var 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); // 添加父级菜单选中样式
|
||||
|
||||
options.title = options.title || $.trim(othis.children('.'+ STR_MENU_TITLE).text());
|
||||
|
||||
// 触发事件
|
||||
layui.event.call(this, MOD_NAME, 'click('+ filter +')', options);
|
||||
}
|
||||
});
|
||||
|
||||
// 基础菜单的展开收缩事件
|
||||
_DOC.on('click', (ELEM_LI + STR_GROUP_TITLE), function(e){
|
||||
var othis = $(this);
|
||||
var elemGroup = othis.parents('.'+ STR_ITEM_GROUP +':eq(0)');
|
||||
var 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);
|
||||
var 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() + 5));
|
||||
}
|
||||
}).on('mouseleave', ELEM_LI_PAR, function(e){
|
||||
var othis = $(this)
|
||||
var elemPanel = othis.children('.'+ STR_MENU_PANEL);
|
||||
|
||||
elemPanel.removeClass(STR_MENU_PANEL_L);
|
||||
elemPanel.css('margin-top', 0);
|
||||
});
|
||||
|
||||
})();
|
||||
|
||||
// 关闭面板
|
||||
dropdown.close = function(id){
|
||||
var that = thisModule.getThis(id);
|
||||
if(!that) return this;
|
||||
|
||||
that.remove();
|
||||
return thisModule.call(that);
|
||||
};
|
||||
|
||||
// 重载实例
|
||||
dropdown.reload = function(id, options, type){
|
||||
var that = thisModule.getThis(id);
|
||||
if(!that) return this;
|
||||
|
||||
that.reload(options, type);
|
||||
return thisModule.call(that);
|
||||
};
|
||||
|
||||
// 仅重载数据
|
||||
dropdown.reloadData = function(){
|
||||
var args = $.extend([], arguments);
|
||||
args[2] = 'reloadData';
|
||||
|
||||
// 重载时,与数据相关的参数
|
||||
var dataParams = new RegExp('^('+ [
|
||||
'data', 'templet', 'content'
|
||||
].join('|') + ')$');
|
||||
|
||||
// 过滤与数据无关的参数
|
||||
layui.each(args[1], function (key, value) {
|
||||
if(!dataParams.test(key)){
|
||||
delete args[1][key];
|
||||
}
|
||||
});
|
||||
|
||||
return dropdown.reload.apply(null, args);
|
||||
};
|
||||
|
||||
// 核心入口
|
||||
dropdown.render = function(options){
|
||||
var inst = new Class(options);
|
||||
return thisModule.call(inst);
|
||||
};
|
||||
|
||||
exports(MOD_NAME, dropdown);
|
||||
});
|
||||
557
public/frontend/layui-main/src/modules/element.js
Executable file
557
public/frontend/layui-main/src/modules/element.js
Executable file
@@ -0,0 +1,557 @@
|
||||
/**
|
||||
* element
|
||||
* 常用元素操作组件
|
||||
*/
|
||||
|
||||
layui.define('jquery', function(exports){
|
||||
'use strict';
|
||||
|
||||
var $ = layui.$;
|
||||
var hint = layui.hint();
|
||||
var device = layui.device();
|
||||
|
||||
var MOD_NAME = 'element';
|
||||
var THIS = 'layui-this';
|
||||
var SHOW = 'layui-show';
|
||||
var TITLE = '.layui-tab-title';
|
||||
|
||||
var 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 tabElem = $('.layui-tab[lay-filter='+ filter +']');
|
||||
var titElem = tabElem.children(TITLE);
|
||||
var barElem = titElem.children('.layui-tab-bar');
|
||||
var contElem = tabElem.children('.layui-tab-content');
|
||||
var li = '<li'+ function(){
|
||||
var layAttr = [];
|
||||
layui.each(options, function(key, value){
|
||||
if(/^(title|content)$/.test(key)) return;
|
||||
layAttr.push('lay-'+ key +'="'+ value +'"');
|
||||
});
|
||||
if(layAttr.length > 0) layAttr.unshift(''); //向前插,预留空格
|
||||
return layAttr.join(' ');
|
||||
}() +'>'+ (options.title || 'unnaming') +'</li>';
|
||||
|
||||
barElem[0] ? barElem.before(li) : titElem.append(li);
|
||||
contElem.append('<div class="layui-tab-item">'+ (options.content || '') +'</div>');
|
||||
// call.hideTabMore(true);
|
||||
// 是否添加即切换
|
||||
options.change && this.tabChange(filter, options.id);
|
||||
titElem.data('LAY_TAB_CHANGE', options.change);
|
||||
call.tabAuto(options.change ? 'change' : null);
|
||||
return this;
|
||||
};
|
||||
|
||||
// 外部 Tab 删除
|
||||
Element.prototype.tabDelete = function(filter, layid){
|
||||
var tabElem = $('.layui-tab[lay-filter='+ filter +']');
|
||||
var titElem = tabElem.children(TITLE);
|
||||
var liElem = titElem.find('>li[lay-id="'+ layid +'"]');
|
||||
call.tabDelete(null, liElem);
|
||||
return this;
|
||||
};
|
||||
|
||||
// 外部 Tab 切换
|
||||
Element.prototype.tabChange = function(filter, layid){
|
||||
var tabElem = $('.layui-tab[lay-filter='+ filter +']');
|
||||
var titElem = tabElem.children(TITLE);
|
||||
var liElem = titElem.find('>li[lay-id="'+ layid +'"]');
|
||||
|
||||
call.tabClick.call(liElem[0], {
|
||||
liElem: 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, {
|
||||
index: index,
|
||||
options: options
|
||||
});
|
||||
});
|
||||
};
|
||||
|
||||
|
||||
// 动态改变进度条
|
||||
Element.prototype.progress = function(filter, percent){
|
||||
var ELEM = 'layui-progress';
|
||||
var elem = $('.'+ ELEM +'[lay-filter='+ filter +']');
|
||||
var elemBar = elem.find('.'+ ELEM +'-bar');
|
||||
var text = elemBar.find('.'+ ELEM +'-text');
|
||||
|
||||
elemBar.css('width', function(){
|
||||
return /^.+\/.+$/.test(percent)
|
||||
? (new Function('return '+ percent)() * 100) + '%'
|
||||
: percent;
|
||||
}).attr('lay-percent', percent);
|
||||
text.text(percent);
|
||||
return this;
|
||||
};
|
||||
|
||||
var NAV_ELEM = '.layui-nav';
|
||||
var NAV_ITEM = 'layui-nav-item';
|
||||
var NAV_BAR = 'layui-nav-bar';
|
||||
var NAV_TREE = 'layui-nav-tree';
|
||||
var NAV_CHILD = 'layui-nav-child';
|
||||
var NAV_CHILD_C = 'layui-nav-child-c';
|
||||
var NAV_MORE = 'layui-nav-more';
|
||||
var NAV_DOWN = 'layui-icon-down';
|
||||
var NAV_ANIM = 'layui-anim layui-anim-upbit';
|
||||
|
||||
// 基础事件体
|
||||
var call = {
|
||||
// Tab 点击
|
||||
tabClick: function(obj){
|
||||
obj = obj || {};
|
||||
var options = obj.options || {};
|
||||
var othis = obj.liElem || $(this);
|
||||
var parents = options.headerElem
|
||||
? othis.parent()
|
||||
: othis.parents('.layui-tab').eq(0);
|
||||
var item = options.bodyElem
|
||||
? $(options.bodyElem)
|
||||
: parents.children('.layui-tab-content').children('.layui-tab-item');
|
||||
var elemA = othis.find('a');
|
||||
var isJump = elemA.attr('href') !== 'javascript:;' && elemA.attr('target') === '_blank'; // 是否存在跳转
|
||||
var unselect = typeof othis.attr('lay-unselect') === 'string'; // 是否禁用选中
|
||||
var filter = parents.attr('lay-filter');
|
||||
|
||||
// 下标
|
||||
var index = 'index' in obj
|
||||
? obj.index
|
||||
: othis.parent().children('li').index(othis);
|
||||
|
||||
// 执行切换
|
||||
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();
|
||||
var index = li.parent().children('li').index(li);
|
||||
var tabElem = li.closest('.layui-tab');
|
||||
var item = tabElem.children('.layui-tab-content').children('.layui-tab-item');
|
||||
var filter = tabElem.attr('lay-filter');
|
||||
|
||||
if(li.hasClass(THIS)){
|
||||
if (li.next()[0] && li.next().is('li')){
|
||||
call.tabClick.call(li.next()[0], {
|
||||
index: index + 1
|
||||
});
|
||||
} else if (li.prev()[0] && li.prev().is('li')){
|
||||
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: tabElem,
|
||||
index: index
|
||||
});
|
||||
}
|
||||
|
||||
// Tab 自适应
|
||||
,tabAuto: function(spread){
|
||||
var SCROLL = 'layui-tab-scroll';
|
||||
var MORE = 'layui-tab-more';
|
||||
var BAR = 'layui-tab-bar';
|
||||
var CLOSE = 'layui-tab-close';
|
||||
var that = this;
|
||||
|
||||
$('.layui-tab').each(function(){
|
||||
var othis = $(this);
|
||||
var title = othis.children('.layui-tab-title');
|
||||
var item = othis.children('.layui-tab-content').children('.layui-tab-item');
|
||||
var STOPE = 'lay-stope="tabmore"';
|
||||
var span = $('<span class="layui-unselect layui-tab-bar" '+ STOPE +'><i '+ STOPE +' class="layui-icon"></i></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 = $('<i class="layui-icon layui-icon-close layui-unselect '+ CLOSE +'"></i>');
|
||||
close.on('click', call.tabDelete);
|
||||
li.append(close);
|
||||
}
|
||||
});
|
||||
}
|
||||
|
||||
if(typeof othis.attr('lay-unauto') === 'string') return;
|
||||
|
||||
// 响应式
|
||||
if(
|
||||
title.prop('scrollWidth') > title.outerWidth() + 1 || (
|
||||
title.find('li').length && title.height() > function(height){
|
||||
return height + height/2;
|
||||
}(title.find('li').eq(0).height())
|
||||
)
|
||||
){
|
||||
// 若执行是来自于切换,则自动展开
|
||||
(
|
||||
spread === 'change' && title.data('LAY_TAB_CHANGE')
|
||||
) && title.addClass(MORE);
|
||||
|
||||
if(title.find('.'+BAR)[0]) return;
|
||||
title.append(span);
|
||||
othis.attr('overflow', '');
|
||||
|
||||
// 展开图标事件
|
||||
span.on('click', function(e){
|
||||
var isSpread = title.hasClass(MORE);
|
||||
title[isSpread ? 'removeClass' : 'addClass'](MORE);
|
||||
});
|
||||
} 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 = $('<span class="'+ NAV_BAR +'"></span>')
|
||||
,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('<i class="layui-icon '+ NAV_DOWN +' '+ NAV_MORE +'"></i>');
|
||||
}
|
||||
|
||||
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('<span '+ ATTE_SPR +'>'+ separator +'</span>');
|
||||
});
|
||||
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('<span class="'+ ELEM +'-text">'+ percent +'</span>');
|
||||
},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('<i class="layui-icon layui-colla-icon">'+ (isNone ? '' : '') +'</i>');
|
||||
|
||||
//点击标题
|
||||
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();
|
||||
var dom = $(document);
|
||||
|
||||
$(function(){
|
||||
element.render();
|
||||
});
|
||||
|
||||
dom.on('click', '.layui-tab-title li', call.tabClick); // Tab 切换
|
||||
// dom.on('click', call.hideTabMore); // 隐藏展开的 Tab
|
||||
$(window).on('resize', call.tabAuto); // 自适应
|
||||
|
||||
exports(MOD_NAME, element);
|
||||
});
|
||||
|
||||
176
public/frontend/layui-main/src/modules/flow.js
Executable file
176
public/frontend/layui-main/src/modules/flow.js
Executable file
@@ -0,0 +1,176 @@
|
||||
/**
|
||||
* flow 流加载组件
|
||||
*/
|
||||
|
||||
|
||||
layui.define('jquery', function(exports){
|
||||
"use strict";
|
||||
|
||||
var $ = layui.$, Flow = function(options){}
|
||||
,ELEM_MORE = 'layui-flow-more'
|
||||
,ELEM_LOAD = '<i class="layui-anim layui-anim-rotate layui-anim-loop layui-icon "></i>';
|
||||
|
||||
//主方法
|
||||
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 notDocument = options.scrollElem && options.scrollElem !== document;
|
||||
|
||||
//加载更多
|
||||
var ELEM_TEXT = '<cite>加载更多</cite>'
|
||||
,more = $('<div class="layui-flow-more"><a href="javascript:;">'+ ELEM_TEXT +'</a></div>');
|
||||
|
||||
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){
|
||||
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 = notDocument ? othis.height() : $(window).height();
|
||||
|
||||
//计算滚动所在容器的实际高度
|
||||
var scrollHeight = notDocument
|
||||
? 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 notDocument = options.scrollElem && options.scrollElem !== document;
|
||||
|
||||
//显示图片
|
||||
var show = function(item, height){
|
||||
var start = scrollElem.scrollTop(), end = start + height;
|
||||
var elemTop = notDocument ? 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 = notDocument ? (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 = notDocument ? 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());
|
||||
});
|
||||
1066
public/frontend/layui-main/src/modules/form.js
Executable file
1066
public/frontend/layui-main/src/modules/form.js
Executable file
File diff suppressed because it is too large
Load Diff
10981
public/frontend/layui-main/src/modules/jquery.js
vendored
Executable file
10981
public/frontend/layui-main/src/modules/jquery.js
vendored
Executable file
File diff suppressed because it is too large
Load Diff
541
public/frontend/layui-main/src/modules/lay.js
Executable file
541
public/frontend/layui-main/src/modules/lay.js
Executable file
@@ -0,0 +1,541 @@
|
||||
|
||||
/** lay 基础模块 | MIT Licensed */
|
||||
|
||||
;!function(window){ // gulp build: lay-header
|
||||
"use strict";
|
||||
|
||||
var MOD_NAME = 'lay'; // 模块名
|
||||
var document = window.document;
|
||||
|
||||
// 元素查找
|
||||
var lay = function(selector){
|
||||
return new Class(selector);
|
||||
};
|
||||
|
||||
// 构造器
|
||||
var Class = function(selector){
|
||||
var that = this;
|
||||
var elem = typeof selector === 'object' ? function(){
|
||||
// 仅适配简单元素对象
|
||||
return layui.isArray(selector) ? selector : [selector];
|
||||
}() : (
|
||||
this.selector = selector,
|
||||
document.querySelectorAll(selector || null)
|
||||
);
|
||||
|
||||
lay.each(elem, function(index, item){
|
||||
that.push(elem[index]);
|
||||
});
|
||||
};
|
||||
|
||||
/*
|
||||
* API 兼容
|
||||
*/
|
||||
Array.prototype.indexOf = Array.prototype.indexOf || function(searchElement, fromIndex) {
|
||||
var rst = -1;
|
||||
fromIndex = fromIndex || 0;
|
||||
layui.each(this, function(index, val){
|
||||
if (searchElement === val && index >= fromIndex) {
|
||||
rst = index;
|
||||
return !0;
|
||||
}
|
||||
});
|
||||
return rst;
|
||||
};
|
||||
|
||||
/*
|
||||
lay 对象操作
|
||||
*/
|
||||
|
||||
Class.fn = Class.prototype = [];
|
||||
Class.fn.constructor = Class;
|
||||
|
||||
// 普通对象深度扩展
|
||||
lay.extend = function(){
|
||||
var ai = 1;
|
||||
var length;
|
||||
var args = arguments;
|
||||
var 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];
|
||||
};
|
||||
|
||||
// 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);
|
||||
};
|
||||
|
||||
// 获取 style rules
|
||||
lay.getStyleRules = function(style, callback) {
|
||||
if (!style) return;
|
||||
|
||||
var sheet = style.sheet || style.styleSheet || {};
|
||||
var rules = sheet.cssRules || sheet.rules;
|
||||
|
||||
if (typeof callback === 'function') {
|
||||
layui.each(rules, function(i, item){
|
||||
if (callback(item, i)) return true;
|
||||
});
|
||||
}
|
||||
|
||||
return rules;
|
||||
};
|
||||
|
||||
// 创建 style 样式
|
||||
lay.style = function(options){
|
||||
options = options || {};
|
||||
|
||||
var style = lay.elem('style');
|
||||
var styleText = options.text || '';
|
||||
var target = options.target;
|
||||
|
||||
if (!styleText) return;
|
||||
|
||||
// 添加样式
|
||||
if ('styleSheet' in style) {
|
||||
style.setAttribute('type', 'text/css');
|
||||
style.styleSheet.cssText = styleText;
|
||||
} else {
|
||||
style.innerHTML = styleText;
|
||||
}
|
||||
|
||||
// ID
|
||||
style.id = 'LAY-STYLE-'+ (options.id || function(index) {
|
||||
lay.style.index++;
|
||||
return 'DF-'+ index;
|
||||
}(lay.style.index || 0));
|
||||
|
||||
// 是否向目标容器中追加 style 元素
|
||||
if (target) {
|
||||
var styleElem = lay(target).find('#'+ style.id);
|
||||
styleElem[0] && styleElem.remove();
|
||||
lay(target).append(style);
|
||||
}
|
||||
|
||||
return style;
|
||||
};
|
||||
|
||||
// 元素定位
|
||||
lay.position = function(target, elem, opts){
|
||||
if(!elem) return;
|
||||
opts = opts || {};
|
||||
|
||||
// 如果绑定的是 document 或 body 元素,则直接获取鼠标坐标
|
||||
if(target === document || target === lay('body')[0]){
|
||||
opts.clickType = 'right';
|
||||
}
|
||||
|
||||
// 绑定绑定元素的坐标
|
||||
var rect = opts.clickType === 'right' ? function(){
|
||||
var e = opts.e || window.event || {};
|
||||
return {
|
||||
left: e.clientX,
|
||||
top: e.clientY,
|
||||
right: e.clientX,
|
||||
bottom: e.clientY
|
||||
}
|
||||
}() : target.getBoundingClientRect();
|
||||
var elemWidth = elem.offsetWidth; // 控件的宽度
|
||||
var elemHeight = elem.offsetHeight; // 控件的高度
|
||||
|
||||
// 滚动条高度
|
||||
var scrollArea = function(type){
|
||||
type = type ? 'scrollLeft' : 'scrollTop';
|
||||
return document.body[type] | document.documentElement[type];
|
||||
};
|
||||
|
||||
// 窗口宽高
|
||||
var winArea = function(type){
|
||||
return document.documentElement[type ? 'clientWidth' : 'clientHeight']
|
||||
};
|
||||
var margin = 'margin' in opts ? opts.margin : 5;
|
||||
var left = rect.left;
|
||||
var top = rect.bottom;
|
||||
|
||||
// 相对元素居中
|
||||
if(opts.align === 'center'){
|
||||
left = left - (elemWidth - target.offsetWidth) / 2;
|
||||
} else if(opts.align === 'right'){
|
||||
left = left - elemWidth + target.offsetWidth;
|
||||
}
|
||||
|
||||
// 判断右侧是否超出边界
|
||||
if(left + elemWidth + margin > winArea('width')){
|
||||
left = winArea('width') - elemWidth - margin; // 如果超出右侧,则将面板向右靠齐
|
||||
}
|
||||
// 左侧是否超出边界
|
||||
if(left < margin) left = margin;
|
||||
|
||||
|
||||
// 判断底部和顶部是否超出边界
|
||||
if(rect.bottom + elemHeight + margin > winArea()){ // 底部超出边界
|
||||
// 优先判断顶部是否有足够区域显示完全,且底部不能超出边界
|
||||
if(rect.top > elemHeight + margin && rect.top <= winArea() ){
|
||||
top = rect.top - elemHeight - margin*2; // 顶部有足够的区域显示
|
||||
} else if(!opts.allowBottomOut){ // 顶部没有足够区域显示时,是否允许底部溢出
|
||||
top = winArea() - elemHeight - margin*2; // 面板向底部靠齐
|
||||
if(top < 0) top = 0; // 如果面板底部靠齐时,又溢出窗口顶部,则只能将顶部靠齐
|
||||
}
|
||||
}
|
||||
/*
|
||||
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 = opts.position;
|
||||
if(position) elem.style.position = position;
|
||||
|
||||
// 设置坐标
|
||||
elem.style.left = left + (position === 'fixed' ? 0 : scrollArea(1)) + 'px';
|
||||
elem.style.top = top + (position === 'fixed' ? 0 : scrollArea()) + 'px';
|
||||
|
||||
// 防止页面无滚动条时,又因为弹出面板而出现滚动条导致的坐标计算偏差
|
||||
if(!lay.hasScrollbar()){
|
||||
var rect1 = elem.getBoundingClientRect();
|
||||
// 如果弹出面板的溢出窗口底部,则表示将出现滚动条,此时需要重新计算坐标
|
||||
if(!opts.SYSTEM_RELOAD && (rect1.bottom + margin) > winArea()){
|
||||
opts.SYSTEM_RELOAD = true;
|
||||
setTimeout(function(){
|
||||
lay.position(target, elem, opts);
|
||||
}, 50);
|
||||
}
|
||||
}
|
||||
};
|
||||
|
||||
// 获取元素上的属性配置项
|
||||
lay.options = function(elem, opts){
|
||||
opts = typeof opts === 'object' ? opts : {attr: opts};
|
||||
|
||||
if(elem === document) return {};
|
||||
|
||||
var othis = lay(elem);
|
||||
var attrName = opts.attr || 'lay-options';
|
||||
var attrValue = othis.attr(attrName);
|
||||
|
||||
try {
|
||||
return new Function('return '+ (attrValue || '{}'))();
|
||||
} catch(ev) {
|
||||
layui.hint().error(opts.errorText || [
|
||||
attrName + '="'+ attrValue + '"',
|
||||
'\n parseerror: '+ ev
|
||||
].join('\n'), '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.clipboard = {
|
||||
// 写入文本
|
||||
writeText: function(options) {
|
||||
var text = String(options.text);
|
||||
|
||||
try {
|
||||
navigator.clipboard.writeText(text).then(
|
||||
options.done
|
||||
)['catch'](options.error);
|
||||
} catch(e) {
|
||||
var elem = document.createElement('textarea');
|
||||
|
||||
elem.value = text;
|
||||
elem.style.position = 'fixed';
|
||||
elem.style.opacity = '0';
|
||||
elem.style.top = '0px';
|
||||
elem.style.left = '0px';
|
||||
|
||||
document.body.appendChild(elem);
|
||||
elem.select();
|
||||
|
||||
try {
|
||||
document.execCommand('copy');
|
||||
typeof options.done === 'function' && options.done();
|
||||
} catch(err) {
|
||||
typeof options.error === 'function' && options.error(err);
|
||||
} finally {
|
||||
elem.remove ? elem.remove() : document.body.removeChild(elem);
|
||||
}
|
||||
}
|
||||
}
|
||||
};
|
||||
|
||||
|
||||
/*
|
||||
* lay 元素操作
|
||||
*/
|
||||
|
||||
|
||||
// 追加字符
|
||||
Class.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$/, '');
|
||||
};
|
||||
|
||||
// 移除值
|
||||
Class.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$/, '');
|
||||
};
|
||||
|
||||
// 查找子元素
|
||||
Class.fn.find = function(selector){
|
||||
var that = this;
|
||||
var elem = [];
|
||||
var isObject = typeof selector === 'object';
|
||||
|
||||
this.each(function(i, item){
|
||||
var children = isObject && item.contains(selector)
|
||||
? selector
|
||||
: item.querySelectorAll(selector || null);
|
||||
|
||||
lay.each(children, function(index, child){
|
||||
elem.push(child);
|
||||
});
|
||||
});
|
||||
|
||||
return lay(elem);
|
||||
};
|
||||
|
||||
// 元素遍历
|
||||
Class.fn.each = function(fn){
|
||||
return lay.each.call(this, this, fn);
|
||||
};
|
||||
|
||||
// 添加 className
|
||||
Class.fn.addClass = function(className, type){
|
||||
return this.each(function(index, item){
|
||||
item.className = Class[type ? 'removeStr' : 'addStr'](item.className, className)
|
||||
});
|
||||
};
|
||||
|
||||
// 移除 className
|
||||
Class.fn.removeClass = function(className){
|
||||
return this.addClass(className, true);
|
||||
};
|
||||
|
||||
// 是否包含 css 类
|
||||
Class.fn.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
|
||||
Class.fn.css = function(key, value){
|
||||
var that = this;
|
||||
var 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);
|
||||
});
|
||||
};
|
||||
|
||||
// 添加或获取宽度
|
||||
Class.fn.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);
|
||||
});
|
||||
};
|
||||
|
||||
// 添加或获取高度
|
||||
Class.fn.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);
|
||||
});
|
||||
};
|
||||
|
||||
// 添加或获取属性
|
||||
Class.fn.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);
|
||||
});
|
||||
};
|
||||
|
||||
// 移除属性
|
||||
Class.fn.removeAttr = function(key){
|
||||
return this.each(function(index, item){
|
||||
item.removeAttribute(key);
|
||||
});
|
||||
};
|
||||
|
||||
// 设置或获取 HTML 内容
|
||||
Class.fn.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;
|
||||
});
|
||||
};
|
||||
|
||||
// 设置或获取值
|
||||
Class.fn.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;
|
||||
});
|
||||
};
|
||||
|
||||
// 追加内容
|
||||
Class.fn.append = function(elem){
|
||||
return this.each(function(index, item){
|
||||
typeof elem === 'object'
|
||||
? item.appendChild(elem)
|
||||
: item.innerHTML = item.innerHTML + elem;
|
||||
});
|
||||
};
|
||||
|
||||
// 移除内容
|
||||
Class.fn.remove = function(elem){
|
||||
return this.each(function(index, item){
|
||||
elem ? item.removeChild(elem) : item.parentNode.removeChild(item);
|
||||
});
|
||||
};
|
||||
|
||||
// 事件绑定
|
||||
Class.fn.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);
|
||||
});
|
||||
};
|
||||
|
||||
// 解除事件
|
||||
Class.fn.off = function(eventName, fn){
|
||||
return this.each(function(index, item){
|
||||
item.detachEvent
|
||||
? item.detachEvent('on'+ eventName, fn)
|
||||
: item.removeEventListener(eventName, fn, false);
|
||||
});
|
||||
};
|
||||
|
||||
// export
|
||||
window.lay = lay;
|
||||
|
||||
// 输出为 layui 模块
|
||||
if(window.layui && layui.define){
|
||||
layui.define(function(exports){
|
||||
exports(MOD_NAME, lay);
|
||||
});
|
||||
}
|
||||
|
||||
}(window, window.document); // gulp build: lay-footer
|
||||
2333
public/frontend/layui-main/src/modules/laydate.js
Executable file
2333
public/frontend/layui-main/src/modules/laydate.js
Executable file
File diff suppressed because it is too large
Load Diff
1750
public/frontend/layui-main/src/modules/layer.js
Executable file
1750
public/frontend/layui-main/src/modules/layer.js
Executable file
File diff suppressed because it is too large
Load Diff
314
public/frontend/layui-main/src/modules/laypage.js
Executable file
314
public/frontend/layui-main/src/modules/laypage.js
Executable file
@@ -0,0 +1,314 @@
|
||||
/**
|
||||
* 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
|
||||
? '<a class="layui-laypage-prev'+ (config.curr == 1 ? (' ' + DISABLED) : '') +'" data-page="'+ (config.curr - 1) +'">'+ config.prev +'</a>'
|
||||
: '';
|
||||
}()
|
||||
|
||||
//页码
|
||||
,page: function(){
|
||||
var pager = [];
|
||||
|
||||
//数据量为0时,不输出页码
|
||||
if(config.count < 1){
|
||||
return '';
|
||||
}
|
||||
|
||||
//首页
|
||||
if(index > 1 && config.first !== false && groups !== 0){
|
||||
pager.push('<a class="layui-laypage-first" data-page="1" title="首页">'+ (config.first || 1) +'</a>');
|
||||
}
|
||||
|
||||
//计算当前页码组的起始页
|
||||
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('<span class="layui-laypage-spr">…</span>')
|
||||
}
|
||||
|
||||
//输出连续页码
|
||||
for(; start <= end; start++){
|
||||
if(start === config.curr){
|
||||
//当前页
|
||||
pager.push('<span class="layui-laypage-curr"><em class="layui-laypage-em" '+ (/^#/.test(config.theme) ? 'style="background-color:'+ config.theme +';"' : '') +'></em><em>'+ start +'</em></span>');
|
||||
} else {
|
||||
pager.push('<a data-page="'+ start +'">'+ start +'</a>');
|
||||
}
|
||||
}
|
||||
|
||||
//输出输出右分隔符 & 末页
|
||||
if(config.pages > groups && config.pages > end && config.last !== false){
|
||||
if(end + 1 < config.pages){
|
||||
pager.push('<span class="layui-laypage-spr">…</span>');
|
||||
}
|
||||
if(groups !== 0){
|
||||
pager.push('<a class="layui-laypage-last" title="尾页" data-page="'+ config.pages +'">'+ (config.last || config.pages) +'</a>');
|
||||
}
|
||||
}
|
||||
|
||||
return pager.join('');
|
||||
}()
|
||||
|
||||
//下一页
|
||||
,next: function(){
|
||||
return config.next
|
||||
? '<a class="layui-laypage-next'+ (config.curr == config.pages ? (' ' + DISABLED) : '') +'" data-page="'+ (config.curr + 1) +'">'+ config.next +'</a>'
|
||||
: '';
|
||||
}()
|
||||
|
||||
//数据总数
|
||||
,count: '<span class="layui-laypage-count">共 '+ config.count +' 条</span>'
|
||||
|
||||
//每页条数
|
||||
,limit: function(){
|
||||
var options = ['<span class="layui-laypage-limits"><select lay-ignore>'];
|
||||
layui.each(config.limits, function(index, item){
|
||||
options.push(
|
||||
'<option value="'+ item +'"'
|
||||
+(item === config.limit ? 'selected' : '')
|
||||
+'>'+ item +' 条/页</option>'
|
||||
);
|
||||
});
|
||||
return options.join('') +'</select></span>';
|
||||
}()
|
||||
|
||||
//刷新当前页
|
||||
,refresh: ['<a data-page="'+ config.curr +'" class="layui-laypage-refresh">'
|
||||
,'<i class="layui-icon layui-icon-refresh"></i>'
|
||||
,'</a>'].join('')
|
||||
|
||||
//跳页区域
|
||||
,skip: function(){
|
||||
return ['<span class="layui-laypage-skip">到第'
|
||||
,'<input type="text" min="1" value="'+ config.curr +'" class="layui-input">'
|
||||
,'页<button type="button" class="layui-laypage-btn">确定</button>'
|
||||
,'</span>'].join('');
|
||||
}()
|
||||
};
|
||||
|
||||
return ['<div class="layui-box layui-laypage layui-laypage-'+ (config.theme ? (
|
||||
/^#/.test(config.theme) ? 'molv' : config.theme
|
||||
) : 'default') +'" id="layui-laypage-'+ config.index +'">'
|
||||
,function(){
|
||||
var plate = [];
|
||||
layui.each(config.layout, function(index, item){
|
||||
if(views[item]){
|
||||
plate.push(views[item])
|
||||
}
|
||||
});
|
||||
return plate.join('');
|
||||
}()
|
||||
,'</div>'].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);
|
||||
});
|
||||
158
public/frontend/layui-main/src/modules/laytpl.js
Executable file
158
public/frontend/layui-main/src/modules/laytpl.js
Executable file
@@ -0,0 +1,158 @@
|
||||
/**
|
||||
* laytpl 轻量模板引擎
|
||||
*/
|
||||
|
||||
layui.define(function(exports){
|
||||
"use strict";
|
||||
|
||||
// 默认属性
|
||||
var config = {
|
||||
open: '{{', // 标签符前缀
|
||||
close: '}}' // 标签符后缀
|
||||
};
|
||||
|
||||
// 模板工具
|
||||
var tool = {
|
||||
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, ''').replace(/"/g, '"');
|
||||
}
|
||||
};
|
||||
|
||||
// 内部方法
|
||||
var inner = {
|
||||
exp: function(str){
|
||||
return new RegExp(str, 'g');
|
||||
},
|
||||
// 错误提示
|
||||
error: function(e, source){
|
||||
var error = 'Laytpl Error: ';
|
||||
typeof console === 'object' && console.error(error + e + '\n'+ (source || ''));
|
||||
return error + e;
|
||||
}
|
||||
};
|
||||
|
||||
// constructor
|
||||
var Class = function(template, options){
|
||||
var that = this;
|
||||
that.config = that.config || {};
|
||||
that.template = template;
|
||||
|
||||
// 简单属性合并
|
||||
var extend = function(obj){
|
||||
for(var i in obj){
|
||||
that.config[i] = obj[i];
|
||||
}
|
||||
};
|
||||
|
||||
extend(config);
|
||||
extend(options);
|
||||
};
|
||||
|
||||
// 标签正则
|
||||
Class.prototype.tagExp = function(type, _, __){
|
||||
var options = this.config;
|
||||
var types = [
|
||||
'#([\\s\\S])+?', // js 语句
|
||||
'([^{#}])*?' // 普通字段
|
||||
][type || 0];
|
||||
|
||||
return inner.exp((_||'') + options.open + types + options.close + (__||''));
|
||||
};
|
||||
|
||||
// 模版解析
|
||||
Class.prototype.parse = function(template, data){
|
||||
var that = this;
|
||||
var options = that.config;
|
||||
var source = template;
|
||||
var jss = inner.exp('^'+ options.open +'#', '');
|
||||
var jsse = inner.exp(options.close +'$', '');
|
||||
|
||||
// 模板必须为 string 类型
|
||||
if(typeof template !== 'string') return template;
|
||||
|
||||
// 正则解析
|
||||
template = template.replace(/\s+|\r|\t|\n/g, ' ')
|
||||
.replace(inner.exp(options.open +'#'), options.open +'# ')
|
||||
.replace(inner.exp(options.close +'}'), '} '+ options.close).replace(/\\/g, '\\\\')
|
||||
|
||||
// 不匹配指定区域的内容
|
||||
.replace(inner.exp(options.open + '!(.+?)!' + options.close), function(str){
|
||||
str = str.replace(inner.exp('^'+ options.open + '!'), '')
|
||||
.replace(inner.exp('!'+ options.close), '')
|
||||
.replace(inner.exp(options.open + '|' + options.close), function(tag){
|
||||
return tag.replace(/(.)/g, '\\$1')
|
||||
});
|
||||
return str
|
||||
})
|
||||
|
||||
// 匹配 JS 语法
|
||||
.replace(/(?="|')/g, '\\').replace(that.tagExp(), function(str){
|
||||
str = str.replace(jss, '').replace(jsse, '');
|
||||
return '";' + str.replace(/\\(.)/g, '$1') + ';view+="';
|
||||
})
|
||||
|
||||
// 匹配普通输出语句
|
||||
.replace(that.tagExp(1), function(str){
|
||||
var start = '"+laytpl.escape(';
|
||||
if(str.replace(/\s/g, '') === options.open + options.close){
|
||||
return '';
|
||||
}
|
||||
str = str.replace(inner.exp(options.open + '|' + options.close), '');
|
||||
if(/^=/.test(str)){
|
||||
str = str.replace(/^=/, '');
|
||||
} else if(/^-/.test(str)){
|
||||
str = str.replace(/^-/, '');
|
||||
start = '"+(';
|
||||
}
|
||||
return start + str.replace(/\\(.)/g, '$1') + ')+"';
|
||||
});
|
||||
|
||||
template = '"use strict";var view = "' + template + '";return view;';
|
||||
|
||||
try {
|
||||
that.cache = template = new Function('d, laytpl', template);
|
||||
return template(data, tool);
|
||||
} catch(e) {
|
||||
delete that.cache;
|
||||
return inner.error(e, source);
|
||||
}
|
||||
};
|
||||
|
||||
// 数据渲染
|
||||
Class.prototype.render = function(data, callback){
|
||||
data = data || {};
|
||||
|
||||
var that = this;
|
||||
var result = that.cache ? that.cache(data, tool) : that.parse(that.template, data);
|
||||
|
||||
// 返回渲染结果
|
||||
typeof callback === 'function' && callback(result);
|
||||
return result;
|
||||
};
|
||||
|
||||
// 创建实例
|
||||
var laytpl = function(template, options){
|
||||
return new Class(template, options);
|
||||
};
|
||||
|
||||
// 配置全局属性
|
||||
laytpl.config = function(options){
|
||||
options = options || {};
|
||||
for(var i in options){
|
||||
config[i] = options[i];
|
||||
}
|
||||
};
|
||||
|
||||
laytpl.v = '2.0.0';
|
||||
|
||||
// export
|
||||
exports('laytpl', laytpl);
|
||||
});
|
||||
11
public/frontend/layui-main/src/modules/layui.all.js
Executable file
11
public/frontend/layui-main/src/modules/layui.all.js
Executable file
@@ -0,0 +1,11 @@
|
||||
/**
|
||||
* 用于打包聚合版,该文件不会存在于构建后的目录
|
||||
*/
|
||||
|
||||
layui.define(function(exports){
|
||||
var cache = layui.cache;
|
||||
layui.config({
|
||||
dir: cache.dir.replace(/lay\/dest\/$/, '')
|
||||
});
|
||||
exports('layui.all', layui.v);
|
||||
});
|
||||
27
public/frontend/layui-main/src/modules/mobile.js
Executable file
27
public/frontend/layui-main/src/modules/mobile.js
Executable file
@@ -0,0 +1,27 @@
|
||||
/**
|
||||
* layui 移动模块入口
|
||||
* 构建后则为移动模块集合
|
||||
*/
|
||||
|
||||
|
||||
if(!layui['layui.mobile']){
|
||||
layui.config({
|
||||
base: layui.cache.dir + 'lay/modules/mobile/'
|
||||
}).extend({
|
||||
'layer-mobile': 'layer-mobile'
|
||||
,'zepto': 'zepto'
|
||||
,'upload-mobile': 'upload-mobile'
|
||||
,'layim-mobile': 'layim-mobile'
|
||||
});
|
||||
}
|
||||
|
||||
layui.define([
|
||||
'layer-mobile'
|
||||
,'zepto'
|
||||
,'layim-mobile'
|
||||
], function(exports){
|
||||
exports('mobile', {
|
||||
layer: layui['layer-mobile'] //弹层
|
||||
,layim: layui['layim-mobile'] //WebIM
|
||||
});
|
||||
});
|
||||
230
public/frontend/layui-main/src/modules/rate.js
Executable file
230
public/frontend/layui-main/src/modules/rate.js
Executable file
@@ -0,0 +1,230 @@
|
||||
/**
|
||||
* rate 评分评星组件
|
||||
*/
|
||||
|
||||
layui.define(['jquery', 'lay'],function(exports){
|
||||
"use strict";
|
||||
|
||||
var $ = layui.jquery;
|
||||
var lay = layui.lay;
|
||||
|
||||
// 外部接口
|
||||
var 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);
|
||||
}
|
||||
}
|
||||
|
||||
// 操作当前实例
|
||||
var thisRate = function () {
|
||||
var that = this;
|
||||
var options = that.config;
|
||||
|
||||
return {
|
||||
setvalue: function (value) {
|
||||
that.setvalue.call(that, value);
|
||||
},
|
||||
config: options
|
||||
}
|
||||
};
|
||||
|
||||
//字符常量
|
||||
var MOD_NAME = 'rate';
|
||||
var ELEM_VIEW = 'layui-rate';
|
||||
var ICON_RATE = 'layui-icon-rate';
|
||||
var ICON_RATE_SOLID = 'layui-icon-rate-solid';
|
||||
var ICON_RATE_HALF = 'layui-icon-rate-half';
|
||||
var ICON_SOLID_HALF = 'layui-icon-rate-solid layui-icon-rate-half';
|
||||
var ICON_SOLID_RATE = 'layui-icon-rate-solid layui-icon-rate';
|
||||
var ICON_HALF_RATE = 'layui-icon-rate layui-icon-rate-half';
|
||||
|
||||
//构造器
|
||||
var 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;
|
||||
var options = that.config;
|
||||
|
||||
// 若 elem 非唯一,则拆分为多个实例
|
||||
var elem = $(options.elem);
|
||||
if(elem.length > 1){
|
||||
layui.each(elem, function(){
|
||||
rate.render($.extend({}, options, {
|
||||
elem: this
|
||||
}));
|
||||
});
|
||||
return that;
|
||||
}
|
||||
|
||||
// 合并 lay-options 属性上的配置信息
|
||||
$.extend(options, lay.options(elem[0]));
|
||||
|
||||
// 自定义主题
|
||||
var 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 = '<ul class="layui-rate" '+ (options.readonly ? 'readonly' : '') +'>';
|
||||
for(var i = 1;i <= options.length;i++){
|
||||
var item = '<li class="layui-inline"><i class="layui-icon '
|
||||
+ (i>Math.floor(options.value)?ICON_RATE:ICON_RATE_SOLID)
|
||||
+ '" '+ style +'></i></li>';
|
||||
|
||||
if(options.half&&parseInt(options.value) !== options.value&&i == Math.ceil(options.value)){
|
||||
temp = temp + '<li><i class="layui-icon layui-icon-rate-half" '+ style +'></i></li>';
|
||||
}else{
|
||||
temp = temp +item;
|
||||
}
|
||||
}
|
||||
temp += '</ul>' + (options.text ? ('<span class="layui-inline">'+ options.value + '星') : '') + '</span>';
|
||||
|
||||
//开始插入替代元素
|
||||
var othis = options.elem;
|
||||
var 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;
|
||||
var options = that.config;
|
||||
|
||||
options.value = value ;
|
||||
that.render();
|
||||
};
|
||||
|
||||
//li触控事件
|
||||
Class.prototype.action = function(){
|
||||
var that = this;
|
||||
var options = that.config;
|
||||
var _ul = that.elemTemp;
|
||||
var wide = _ul.find("i").width();
|
||||
|
||||
_ul.children("li").each(function(index){
|
||||
var ind = index + 1;
|
||||
var 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;
|
||||
//var options = that.config;
|
||||
};
|
||||
|
||||
//核心入口
|
||||
rate.render = function(options){
|
||||
var inst = new Class(options);
|
||||
return thisRate.call(inst);
|
||||
};
|
||||
|
||||
exports(MOD_NAME, rate);
|
||||
})
|
||||
431
public/frontend/layui-main/src/modules/slider.js
Executable file
431
public/frontend/layui-main/src/modules/slider.js
Executable file
@@ -0,0 +1,431 @@
|
||||
/**
|
||||
* slider 滑块组件
|
||||
*/
|
||||
|
||||
layui.define(['jquery', 'lay'], function(exports){
|
||||
'use strict';
|
||||
|
||||
var $ = layui.$;
|
||||
var lay = layui.lay;
|
||||
|
||||
// 外部接口
|
||||
var 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);
|
||||
}
|
||||
};
|
||||
|
||||
// 操作当前实例
|
||||
var thisSlider = function(){
|
||||
var that = this
|
||||
,options = that.config;
|
||||
|
||||
return {
|
||||
setValue: function(value, index){ // 设置值
|
||||
value = value > options.max ? options.max : value;
|
||||
value = value < options.min ? options.min : value;
|
||||
options.value = value;
|
||||
return that.slide('set', value, index || 0);
|
||||
}
|
||||
,config: options
|
||||
}
|
||||
};
|
||||
|
||||
// 字符常量
|
||||
var MOD_NAME = 'slider';
|
||||
var DISABLED = 'layui-disabled';
|
||||
var ELEM_VIEW = 'layui-slider';
|
||||
var SLIDER_BAR = 'layui-slider-bar';
|
||||
var SLIDER_WRAP = 'layui-slider-wrap';
|
||||
var SLIDER_WRAP_BTN = 'layui-slider-wrap-btn';
|
||||
var SLIDER_TIPS = 'layui-slider-tips';
|
||||
var SLIDER_INPUT = 'layui-slider-input';
|
||||
var SLIDER_INPUT_TXT = 'layui-slider-input-txt';
|
||||
var SLIDER_INPUT_BTN = 'layui-slider-input-btn';
|
||||
var ELEM_HOVER = 'layui-slider-hover';
|
||||
|
||||
// 构造器
|
||||
var Class = function(options){
|
||||
var that = this;
|
||||
that.index = ++slider.index;
|
||||
that.config = $.extend({}, that.config, slider.config, options);
|
||||
that.render();
|
||||
};
|
||||
|
||||
// 默认配置
|
||||
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: '#16baaa' //主题颜色
|
||||
};
|
||||
|
||||
//滑块渲染
|
||||
Class.prototype.render = function(){
|
||||
var that = this;
|
||||
var options = that.config;
|
||||
|
||||
// 若 elem 非唯一,则拆分为多个实例
|
||||
var elem = $(options.elem);
|
||||
if(elem.length > 1){
|
||||
layui.each(elem, function(){
|
||||
slider.render($.extend({}, options, {
|
||||
elem: this
|
||||
}));
|
||||
});
|
||||
return that;
|
||||
}
|
||||
|
||||
// 合并 lay-options 属性上的配置信息
|
||||
$.extend(options, lay.options(elem[0]));
|
||||
|
||||
//间隔值不能小于 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 = '<div class="layui-slider '+ (options.type === 'vertical' ? 'layui-slider-vertical' : '') +'">'+ (options.tips ? '<div class="'+ SLIDER_TIPS +'"></div>' : '') +
|
||||
'<div class="layui-slider-bar" style="background:'+ theme +'; '+ (options.type === 'vertical' ? 'height' : 'width') +':'+ scale +';'+ (options.type === 'vertical' ? 'bottom' : 'left') +':'+ (scaleFir || 0) +';"></div><div class="layui-slider-wrap" style="'+ (options.type === 'vertical' ? 'bottom' : 'left') +':'+ (scaleFir || scale) +';">' +
|
||||
'<div class="layui-slider-wrap-btn" style="border: 2px solid '+ theme +';"></div></div>'+ (options.range ? '<div class="layui-slider-wrap" style="'+ (options.type === 'vertical' ? 'bottom' : 'left') +':'+ scaleSec +';"><div class="layui-slider-wrap-btn" style="border: 2px solid '+ theme +';"></div></div>' : '') +'</div>';
|
||||
|
||||
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 += '<div class="layui-slider-step" style="'+ (options.type === 'vertical' ? 'bottom' : 'left') +':'+ step +'%"></div>'
|
||||
}
|
||||
};
|
||||
that.elemTemp.append(item);
|
||||
};
|
||||
|
||||
//插入输入框
|
||||
if(options.input && !options.range){
|
||||
var elemInput = $('<div class="layui-slider-input"><div class="layui-slider-input-txt"><input type="text" class="layui-input"></div><div class="layui-slider-input-btn"><i class="layui-icon layui-icon-up"></i><i class="layui-icon layui-icon-down"></i></div></div>');
|
||||
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){
|
||||
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, from){
|
||||
if(Math.ceil(offsetValue) * step > 100){
|
||||
offsetValue = Math.ceil(offsetValue) * step
|
||||
}else{
|
||||
offsetValue = Math.round(offsetValue) * step
|
||||
};
|
||||
offsetValue = offsetValue > 100 ? 100: offsetValue;
|
||||
offsetValue = offsetValue < 0 ? 0: 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(); //如果前面的圆点超过了后面的圆点值,则调换顺序
|
||||
}
|
||||
|
||||
that.value = options.range ? arrValue : selfValue; // 最新值
|
||||
options.change && options.change(that.value); // change 回调
|
||||
|
||||
// 值完成选中的事件
|
||||
if(from === 'done') options.done && options.done(that.value);
|
||||
}
|
||||
,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 = $(['<div class="layui-auxiliar-moving" id="LAY-slider-moving"></div'].join(''))
|
||||
,createMoveElem = function(move, up){
|
||||
var upCall = function(){
|
||||
up && up();
|
||||
elemMove.remove();
|
||||
options.done && options.done(that.value);
|
||||
};
|
||||
$('#LAY-slider-moving')[0] || $('body').append(elemMove);
|
||||
elemMove.on('mousemove', move);
|
||||
elemMove.on('mouseup', upCall).on('mouseleave', upCall);
|
||||
};
|
||||
|
||||
//动态赋值
|
||||
if(setValue === 'set') return change(value - options.min, i, 'done');
|
||||
|
||||
//滑块滑动
|
||||
sliderAct.find('.' + SLIDER_WRAP_BTN).each(function(index){
|
||||
var othis = $(this);
|
||||
othis.on('mousedown', function(e){
|
||||
e = e || window.event;
|
||||
|
||||
var oldleft = othis.parent()[0].offsetLeft
|
||||
,oldx = e.clientX;
|
||||
if(options.type === 'vertical'){
|
||||
oldleft = sliderWidth() - othis.parent()[0].offsetTop - sliderWrap.height()
|
||||
oldx = e.clientY;
|
||||
};
|
||||
|
||||
var move = function(e){
|
||||
e = e || window.event;
|
||||
var left = oldleft + (options.type === 'vertical' ? (oldx - e.clientY) : (e.clientX - oldx));
|
||||
if(left < 0)left = 0;
|
||||
if(left > sliderWidth())left = sliderWidth();
|
||||
var reaLeft = left / sliderWidth() * 100 / step;
|
||||
change(reaLeft, index);
|
||||
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);
|
||||
var othis = $(this);
|
||||
if(!main.is(event.target) && main.has(event.target).length === 0 && main.length){
|
||||
var index;
|
||||
var offset = options.type === 'vertical'
|
||||
? (sliderWidth() - e.clientY + othis.offset().top - $(window).scrollTop())
|
||||
:(e.clientX - othis.offset().left - $(window).scrollLeft());
|
||||
|
||||
if(offset < 0)offset = 0;
|
||||
if(offset > sliderWidth()) offset = sliderWidth();
|
||||
var reaLeft = offset / sliderWidth() * 100 / step;
|
||||
if(options.range){
|
||||
if(options.type === 'vertical'){
|
||||
index = Math.abs(offset - parseInt($(sliderWrap[0]).css('bottom'))) > Math.abs(offset - parseInt($(sliderWrap[1]).css('bottom'))) ? 1 : 0;
|
||||
} else {
|
||||
index = Math.abs(offset - sliderWrap[0].offsetLeft) > Math.abs(offset - sliderWrap[1].offsetLeft) ? 1 : 0;
|
||||
}
|
||||
} else {
|
||||
index = 0;
|
||||
};
|
||||
change(reaLeft, index, 'done');
|
||||
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, 'done');
|
||||
});
|
||||
});
|
||||
|
||||
//获取输入框值
|
||||
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, 'done');
|
||||
};
|
||||
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);
|
||||
})
|
||||
3031
public/frontend/layui-main/src/modules/table.js
Executable file
3031
public/frontend/layui-main/src/modules/table.js
Executable file
File diff suppressed because it is too large
Load Diff
506
public/frontend/layui-main/src/modules/transfer.js
Executable file
506
public/frontend/layui-main/src/modules/transfer.js
Executable file
@@ -0,0 +1,506 @@
|
||||
/**
|
||||
* transfer 穿梭框组件
|
||||
*/
|
||||
|
||||
layui.define(['laytpl', 'form'], function(exports){
|
||||
"use strict";
|
||||
|
||||
var $ = layui.$;
|
||||
var laytpl = layui.laytpl;
|
||||
var form = layui.form;
|
||||
|
||||
// 模块名
|
||||
var MOD_NAME = 'transfer';
|
||||
|
||||
// 外部接口
|
||||
var 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);
|
||||
}
|
||||
};
|
||||
|
||||
// 操作当前实例
|
||||
var thisModule = function(){
|
||||
var that = this;
|
||||
var options = that.config;
|
||||
var 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);
|
||||
}
|
||||
}
|
||||
};
|
||||
|
||||
// 获取当前实例配置项
|
||||
var 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;
|
||||
};
|
||||
|
||||
// 字符常量
|
||||
var ELEM = 'layui-transfer';
|
||||
var HIDE = 'layui-hide';
|
||||
var DISABLED = 'layui-btn-disabled';
|
||||
var NONE = 'layui-none';
|
||||
var ELEM_BOX = 'layui-transfer-box';
|
||||
var ELEM_HEADER = 'layui-transfer-header';
|
||||
var ELEM_SEARCH = 'layui-transfer-search';
|
||||
var ELEM_ACTIVE = 'layui-transfer-active';
|
||||
var ELEM_DATA = 'layui-transfer-data';
|
||||
|
||||
// 穿梭框模板
|
||||
var 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="text" class="layui-input" placeholder="关键词搜索">'
|
||||
,'</div>'
|
||||
,'{{# } }}'
|
||||
,'<ul class="layui-transfer-data"></ul>'
|
||||
,'</div>'].join('');
|
||||
};
|
||||
|
||||
// 主模板
|
||||
var 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('');
|
||||
|
||||
// 构造器
|
||||
var 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;
|
||||
var options = that.config;
|
||||
|
||||
//解析模板
|
||||
var thisElem = that.elem = $(laytpl(TPL_MAIN, {
|
||||
open: '{{', // 标签符前缀
|
||||
close: '}}' // 标签符后缀
|
||||
}).render({
|
||||
data: options
|
||||
,index: that.index //索引
|
||||
}));
|
||||
|
||||
var othis = options.elem = $(options.elem);
|
||||
if(!othis[0]) return;
|
||||
|
||||
//初始化属性
|
||||
options.data = options.data || [];
|
||||
options.value = options.value || [];
|
||||
|
||||
// 初始化 id 属性 - 优先取 options > 元素 id > 自增索引
|
||||
options.id = 'id' in options ? options.id : (
|
||||
elem.attr('id') || that.index
|
||||
);
|
||||
that.key = options.id;
|
||||
|
||||
//插入组件结构
|
||||
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;
|
||||
var options = that.config;
|
||||
|
||||
// 左右穿梭框差异数据
|
||||
var arr = [{
|
||||
checkName: 'layTransferLeftCheck',
|
||||
views: []
|
||||
}, {
|
||||
checkName: 'layTransferRightCheck',
|
||||
views: []
|
||||
}];
|
||||
|
||||
// 解析格式
|
||||
that.parseData(function(item){
|
||||
// 标注为 selected 的为右边的数据
|
||||
var _index = item.selected ? 1 : 0
|
||||
var 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('');
|
||||
// 按照 options.value 顺序排列右侧数据
|
||||
if(_index){
|
||||
layui.each(options.value, function(i, v){
|
||||
if(v == item.value && item.selected){
|
||||
arr[_index].views[i] = listElem;
|
||||
}
|
||||
});
|
||||
} else {
|
||||
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.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;
|
||||
var thisDataElem = $(this).parents('.'+ ELEM_SEARCH).eq(0).siblings('.'+ ELEM_DATA);
|
||||
var thisListElem = thisDataElem.children('li');
|
||||
|
||||
thisListElem.each(function(){
|
||||
var thisList = $(this);
|
||||
var thisElemCheckbox = thisList.find('input[type="checkbox"]');
|
||||
var title = thisElemCheckbox[0].title;
|
||||
|
||||
// 是否区分大小写
|
||||
if(options.showSearch !== 'cs'){
|
||||
title = title.toLowerCase();
|
||||
value = value.toLowerCase();
|
||||
}
|
||||
|
||||
var isMatch = 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);
|
||||
});
|
||||
864
public/frontend/layui-main/src/modules/tree.js
Executable file
864
public/frontend/layui-main/src/modules/tree.js
Executable file
@@ -0,0 +1,864 @@
|
||||
/**
|
||||
* tree 树组件
|
||||
*/
|
||||
|
||||
layui.define('form', function(exports){
|
||||
"use strict";
|
||||
|
||||
var $ = layui.$;
|
||||
var form = layui.form;
|
||||
var layer = layui.layer;
|
||||
|
||||
// 模块名
|
||||
var MOD_NAME = 'tree';
|
||||
|
||||
// 外部接口
|
||||
var tree = {
|
||||
config: {
|
||||
customName: { // 自定义 data 字段名
|
||||
id: 'id',
|
||||
title: 'title',
|
||||
children: 'children'
|
||||
}
|
||||
},
|
||||
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);
|
||||
}
|
||||
};
|
||||
|
||||
// 操作当前实例
|
||||
var thisModule = function(){
|
||||
var that = this;
|
||||
var options = that.config;
|
||||
var 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);
|
||||
}
|
||||
}
|
||||
};
|
||||
|
||||
// 获取当前实例配置项
|
||||
var 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;
|
||||
}
|
||||
|
||||
// 字符常量
|
||||
var SHOW = 'layui-show';
|
||||
var HIDE = 'layui-hide';
|
||||
var NONE = 'layui-none';
|
||||
var DISABLED = 'layui-disabled';
|
||||
|
||||
var ELEM_VIEW = 'layui-tree';
|
||||
var ELEM_SET = 'layui-tree-set';
|
||||
var ICON_CLICK = 'layui-tree-iconClick';
|
||||
var ICON_ADD = 'layui-icon-addition';
|
||||
var ICON_SUB = 'layui-icon-subtraction';
|
||||
var ELEM_ENTRY = 'layui-tree-entry';
|
||||
var ELEM_MAIN = 'layui-tree-main';
|
||||
var ELEM_TEXT = 'layui-tree-txt';
|
||||
var ELEM_PACK = 'layui-tree-pack';
|
||||
var ELEM_SPREAD = 'layui-tree-spread';
|
||||
var ELEM_LINE_SHORT = 'layui-tree-setLineShort';
|
||||
var ELEM_SHOW = 'layui-tree-showLine';
|
||||
var ELEM_EXTEND = 'layui-tree-lineExtend';
|
||||
|
||||
// 构造器
|
||||
var 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;
|
||||
var options = that.config;
|
||||
|
||||
// 初始化自定义字段名
|
||||
options.customName = $.extend({}, tree.config.customName, options.customName);
|
||||
|
||||
that.checkids = [];
|
||||
|
||||
var temp = $('<div class="layui-tree layui-border-box'+ (options.showCheckbox ? " layui-form" : "") + (options.showLine ? " layui-tree-line" : "") +'" lay-filter="LAY-tree-'+ that.index +'"></div>');
|
||||
that.tree(temp);
|
||||
|
||||
var othis = options.elem = $(options.elem);
|
||||
if(!othis[0]) return;
|
||||
|
||||
// 索引
|
||||
that.key = options.id || that.index;
|
||||
|
||||
// 插入组件结构
|
||||
that.elem = temp;
|
||||
that.elemNone = $('<div class="layui-tree-emptyText">'+ options.text.none +'</div>');
|
||||
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;
|
||||
var options = that.config;
|
||||
var customName = options.customName;
|
||||
var data = children || options.data;
|
||||
|
||||
// 遍历数据
|
||||
layui.each(data, function(index, item){
|
||||
var hasChild = item[customName.children] && item[customName.children].length > 0;
|
||||
var packDiv = $('<div class="layui-tree-pack" '+ (item.spread ? 'style="display: block;"' : '') +'></div>');
|
||||
var entryDiv = $(['<div data-id="'+ item[customName.id] +'" class="layui-tree-set'+ (item.spread ? " layui-tree-spread" : "") + (item.checked ? " layui-tree-checkedFirst" : "") +'">'
|
||||
,'<div class="layui-tree-entry">'
|
||||
,'<div class="layui-tree-main">'
|
||||
// 箭头
|
||||
,function(){
|
||||
if(options.showLine){
|
||||
if(hasChild){
|
||||
return '<span class="layui-tree-iconClick layui-tree-icon"><i class="layui-icon '+ (item.spread ? "layui-icon-subtraction" : "layui-icon-addition") +'"></i></span>';
|
||||
}else{
|
||||
return '<span class="layui-tree-iconClick"><i class="layui-icon layui-icon-file"></i></span>';
|
||||
};
|
||||
}else{
|
||||
return '<span class="layui-tree-iconClick"><i class="layui-tree-iconArrow '+ (hasChild ? "": HIDE) +'"></i></span>';
|
||||
};
|
||||
}()
|
||||
|
||||
// 复选框
|
||||
,function(){
|
||||
return options.showCheckbox ? '<input type="checkbox" name="'+ (item.field || ('layuiTreeCheck_'+ item[customName.id])) +'" same="layuiTreeCheck" lay-skin="primary" '+ (item.disabled ? "disabled" : "") +' value="'+ item[customName.id] +'">' : '';
|
||||
}()
|
||||
|
||||
// 节点
|
||||
,function(){
|
||||
if(options.isJump && item.href){
|
||||
return '<a href="'+ item.href +'" target="_blank" class="'+ ELEM_TEXT +'">'+ (item[customName.title] || item.label || options.text.defaultNodeName) +'</a>';
|
||||
}else{
|
||||
return '<span class="'+ ELEM_TEXT + (item.disabled ? ' '+ DISABLED : '') +'">'+ (item[customName.title] || item.label || options.text.defaultNodeName) +'</span>';
|
||||
}
|
||||
}()
|
||||
,'</div>'
|
||||
|
||||
// 节点操作图标
|
||||
,function(){
|
||||
if(!options.edit) return '';
|
||||
|
||||
var editIcon = {
|
||||
add: '<i class="layui-icon layui-icon-add-1" data-type="add"></i>'
|
||||
,update: '<i class="layui-icon layui-icon-edit" data-type="update"></i>'
|
||||
,del: '<i class="layui-icon layui-icon-delete" data-type="del"></i>'
|
||||
}, arr = ['<div class="layui-btn-group layui-tree-btnGroup">'];
|
||||
|
||||
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('') + '</div>';
|
||||
}
|
||||
}()
|
||||
,'</div></div>'].join(''));
|
||||
|
||||
// 如果有子节点,则递归继续生成树
|
||||
if(hasChild){
|
||||
entryDiv.append(packDiv);
|
||||
that.tree(packDiv, item[customName.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[customName.id]);
|
||||
that.checkClick(entryDiv, item);
|
||||
}
|
||||
|
||||
// 操作节点
|
||||
options.edit && that.operate(entryDiv, item);
|
||||
|
||||
});
|
||||
};
|
||||
|
||||
// 展开节点
|
||||
Class.prototype.spread = function(elem, item){
|
||||
var that = this;
|
||||
var options = that.config;
|
||||
var entry = elem.children('.'+ELEM_ENTRY);
|
||||
var elemMain = entry.children('.'+ ELEM_MAIN);
|
||||
var elemCheckbox = elemMain.find('input[same="layuiTreeCheck"]');
|
||||
var elemIcon = entry.find('.'+ ICON_CLICK);
|
||||
var elemText = entry.find('.'+ ELEM_TEXT);
|
||||
var touchOpen = options.onlyIconControl ? elemIcon : elemMain; // 判断展开通过节点还是箭头图标
|
||||
var 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);
|
||||
that.updateFieldValue(item, 'spread', false);
|
||||
}else{
|
||||
elem.addClass(ELEM_SPREAD);
|
||||
packCont.slideDown(200);
|
||||
iconClick.addClass(ICON_SUB).removeClass(ICON_ADD);
|
||||
that.updateFieldValue(item, 'spread', true);
|
||||
|
||||
// 是否手风琴
|
||||
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';
|
||||
}
|
||||
|
||||
// 获取选中状态
|
||||
if(elemCheckbox[0]){
|
||||
that.updateFieldValue(item, 'checked', elemCheckbox.prop('checked'));
|
||||
}
|
||||
|
||||
// 点击产生的回调
|
||||
options.click && options.click({
|
||||
elem: elem,
|
||||
state: state,
|
||||
data: item
|
||||
});
|
||||
});
|
||||
};
|
||||
|
||||
// 更新数据源 checked,spread 字段值
|
||||
Class.prototype.updateFieldValue = function(obj, field, value){
|
||||
if(field in obj) obj[field] = value;
|
||||
};
|
||||
|
||||
// 计算复选框选中状态
|
||||
Class.prototype.setCheckbox = function(elem, item, elemCheckbox){
|
||||
var that = this;
|
||||
var options = that.config;
|
||||
var customName = options.customName;
|
||||
var checked = elemCheckbox.prop('checked');
|
||||
|
||||
if(elemCheckbox.prop('disabled')) return;
|
||||
|
||||
// 同步子节点选中状态
|
||||
if(typeof item[customName.children] === 'object' || elem.find('.'+ELEM_PACK)[0]){
|
||||
var elemCheckboxs = elem.find('.'+ ELEM_PACK).find('input[same="layuiTreeCheck"]');
|
||||
elemCheckboxs.each(function(index){
|
||||
if(this.disabled) return; // 不可点击则跳过
|
||||
var children = item[customName.children][index];
|
||||
if(children) that.updateFieldValue(children, 'checked', checked);
|
||||
that.updateFieldValue(this, 'checked', checked);
|
||||
});
|
||||
};
|
||||
|
||||
// 同步父节点选中状态
|
||||
var setParentsChecked = function(thisNodeElem){
|
||||
// 若无父节点,则终止递归
|
||||
if(!thisNodeElem.parents('.'+ ELEM_SET)[0]) return;
|
||||
|
||||
var state;
|
||||
var parentPack = thisNodeElem.parent('.'+ ELEM_PACK);
|
||||
var parentNodeElem = parentPack.parent();
|
||||
var 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;
|
||||
var options = that.config;
|
||||
var entry = elem.children('.'+ ELEM_ENTRY);
|
||||
var elemMain = entry.children('.'+ ELEM_MAIN);
|
||||
|
||||
|
||||
|
||||
// 点击复选框
|
||||
elemMain.on('click', 'input[same="layuiTreeCheck"]+', function(e){
|
||||
layui.stope(e); // 阻止点击节点事件
|
||||
|
||||
var elemCheckbox = $(this).prev();
|
||||
var checked = elemCheckbox.prop('checked');
|
||||
|
||||
if(elemCheckbox.prop('disabled')) return;
|
||||
|
||||
that.setCheckbox(elem, item, elemCheckbox);
|
||||
that.updateFieldValue(item, 'checked', checked);
|
||||
|
||||
// 复选框点击产生的回调
|
||||
options.oncheck && options.oncheck({
|
||||
elem: elem,
|
||||
checked: checked,
|
||||
data: item
|
||||
});
|
||||
});
|
||||
};
|
||||
|
||||
// 节点操作
|
||||
Class.prototype.operate = function(elem, item){
|
||||
var that = this;
|
||||
var options = that.config;
|
||||
var customName = options.customName;
|
||||
var entry = elem.children('.'+ ELEM_ENTRY);
|
||||
var elemMain = entry.children('.'+ ELEM_MAIN);
|
||||
|
||||
entry.children('.layui-tree-btnGroup').on('click', '.layui-icon', function(e){
|
||||
layui.stope(e); // 阻止节点操作
|
||||
|
||||
var type = $(this).data("type");
|
||||
var packCont = elem.children('.'+ELEM_PACK);
|
||||
var 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('<div class="layui-tree-pack"></div>');
|
||||
};
|
||||
|
||||
// 新增节点
|
||||
var key = options.operate && options.operate(returnObj);
|
||||
var obj = {};
|
||||
|
||||
obj[customName.title] = options.text.defaultNodeName;
|
||||
obj[customName.id] = key;
|
||||
that.tree(elem.children('.'+ELEM_PACK), [obj]);
|
||||
|
||||
// 放在新增后面,因为要对元素进行操作
|
||||
if(options.showLine){
|
||||
// 节点本身无子节点
|
||||
if(!packCont[0]){
|
||||
// 遍历兄弟节点,判断兄弟节点是否有子节点
|
||||
var siblings = elem.siblings('.'+ELEM_SET)
|
||||
var num = 1;
|
||||
var 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('<input type="text" class="layui-tree-editInput">');
|
||||
// 获取焦点
|
||||
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[customName.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('确认删除该节点 "<span style="color: #999;">'+ (item[customName.title] || '') +'</span>" 吗?', 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);
|
||||
var parentTree = elem.parent('.'+ELEM_PACK).prev();
|
||||
var checkState = parentTree.find('input[same="layuiTreeCheck"]')[0];
|
||||
var state = 1;
|
||||
var 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);
|
||||
var num = 1;
|
||||
var 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;
|
||||
var options = that.config;
|
||||
var checkWarp = that.elem.find('.layui-tree-checkedFirst');
|
||||
|
||||
// 初始选中
|
||||
that.setChecked(that.checkids);
|
||||
|
||||
// 搜索
|
||||
that.elem.find('.layui-tree-search').on('keyup', function(){
|
||||
var input = $(this);
|
||||
var val = input.val();
|
||||
var pack = input.nextAll();
|
||||
var 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;
|
||||
var options = that.config;
|
||||
var customName = options.customName;
|
||||
var checkId = [];
|
||||
var 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[customName.id] == item2){
|
||||
that.updateFieldValue(item, 'checked', true);
|
||||
|
||||
var cloneItem = $.extend({}, item);
|
||||
delete cloneItem[customName.children];
|
||||
|
||||
checkNode.push(cloneItem);
|
||||
|
||||
if(item[customName.children]){
|
||||
cloneItem[customName.children] = [];
|
||||
eachNodes(item[customName.children], cloneItem[customName.children]);
|
||||
}
|
||||
return true
|
||||
}
|
||||
});
|
||||
});
|
||||
};
|
||||
|
||||
eachNodes($.extend({}, options.data), checkData);
|
||||
|
||||
return checkData;
|
||||
};
|
||||
|
||||
// 设置选中节点
|
||||
Class.prototype.setChecked = function(checkedId){
|
||||
var that = this;
|
||||
var options = that.config;
|
||||
|
||||
// 初始选中
|
||||
that.elem.find('.'+ELEM_SET).each(function(i, item){
|
||||
var thisId = $(this).data('id');
|
||||
var input = $(item).children('.'+ELEM_ENTRY).find('input[same="layuiTreeCheck"]');
|
||||
var reInput = input.next();
|
||||
|
||||
// 若返回数字
|
||||
if(typeof checkedId === 'number'){
|
||||
if(thisId.toString() == checkedId.toString()){
|
||||
if(!input[0].checked){
|
||||
reInput.click();
|
||||
};
|
||||
return false;
|
||||
};
|
||||
}
|
||||
// 若返回数组
|
||||
else if(typeof checkedId === 'object'){
|
||||
layui.each(checkedId, function(index, value){
|
||||
if(value.toString() == thisId.toString() && !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);
|
||||
})
|
||||
1931
public/frontend/layui-main/src/modules/treeTable.js
Executable file
1931
public/frontend/layui-main/src/modules/treeTable.js
Executable file
File diff suppressed because it is too large
Load Diff
670
public/frontend/layui-main/src/modules/upload.js
Executable file
670
public/frontend/layui-main/src/modules/upload.js
Executable file
@@ -0,0 +1,670 @@
|
||||
/**
|
||||
* upload
|
||||
* 上传组件
|
||||
*/
|
||||
|
||||
layui.define(['lay','layer'], function(exports){
|
||||
"use strict";
|
||||
|
||||
var $ = layui.$;
|
||||
var layer = layui.layer;
|
||||
var device = layui.device();
|
||||
|
||||
// 外部接口
|
||||
var 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);
|
||||
}
|
||||
};
|
||||
|
||||
// 操作当前实例
|
||||
var 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
|
||||
}
|
||||
};
|
||||
|
||||
// 字符常量
|
||||
var MOD_NAME = 'upload';
|
||||
var ELEM = 'layui-upload';
|
||||
var THIS = 'layui-this';
|
||||
var SHOW = 'layui-show';
|
||||
var HIDE = 'layui-hide';
|
||||
var DISABLED = 'layui-disabled';
|
||||
|
||||
var ELEM_FILE = 'layui-upload-file';
|
||||
var ELEM_FORM = 'layui-upload-form';
|
||||
var ELEM_IFRAME = 'layui-upload-iframe';
|
||||
var ELEM_CHOOSE = 'layui-upload-choose';
|
||||
var ELEM_DRAG = 'layui-upload-drag';
|
||||
var UPLOADING = 'UPLOADING';
|
||||
|
||||
// 构造器
|
||||
var 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
|
||||
text: { // 自定义提示文本
|
||||
"cross-domain": "Cross-domain requests are not supported", // 跨域
|
||||
"data-format-error": "Please return JSON data format", // 数据格式错误
|
||||
"check-error": "", // 文件格式校验失败
|
||||
"error": "", // 上传失败
|
||||
"limit-number": null, // 限制 number 属性的提示 --- function
|
||||
"limit-size": null // 限制 size 属性的提示 --- function
|
||||
}
|
||||
};
|
||||
|
||||
// 初始渲染
|
||||
Class.prototype.render = function(){
|
||||
var that = this;
|
||||
var options = that.config;
|
||||
|
||||
options.elem = $(options.elem);
|
||||
options.bindAction = $(options.bindAction);
|
||||
|
||||
that.file();
|
||||
that.events();
|
||||
};
|
||||
|
||||
//追加文件域
|
||||
Class.prototype.file = function(){
|
||||
var that = this;
|
||||
var options = that.config;
|
||||
var elemFile = that.elemFile = $([
|
||||
'<input class="'+ ELEM_FILE +'" type="file" accept="'+ options.acceptMime +'" name="'+ options.field +'"'
|
||||
,(options.multiple ? ' multiple' : '')
|
||||
,'>'
|
||||
].join(''));
|
||||
var 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('<div class="layui-upload-wrap"></div>');
|
||||
}
|
||||
|
||||
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;
|
||||
var options = that.config;
|
||||
var iframe = $('<iframe id="'+ ELEM_IFRAME +'" class="'+ ELEM_IFRAME +'" name="'+ ELEM_IFRAME +'" frameborder="0"></iframe>');
|
||||
var elemForm = $(['<form target="'+ ELEM_IFRAME +'" class="'+ ELEM_FORM +'" method="post" key="set-mine" enctype="multipart/form-data" action="'+ options.url +'">'
|
||||
,'</form>'].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('<input type="hidden" name="'+ key +'" value="'+ value +'">')
|
||||
});
|
||||
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;
|
||||
var options = that.config;
|
||||
var text = options.text || {};
|
||||
var elemFile = that.elemFile[0];
|
||||
|
||||
// 获取文件队列
|
||||
var getFiles = function(){
|
||||
return files || that.files || that.chooseFiles || elemFile.files;
|
||||
};
|
||||
|
||||
// 高级浏览器处理方式,支持跨域
|
||||
var ajaxSend = function(){
|
||||
var successful = 0;
|
||||
var failed = 0;
|
||||
var items = getFiles();
|
||||
|
||||
// 多文件全部上传完毕的回调
|
||||
var allDone = function(){
|
||||
if(options.multiple && successful + failed === that.fileLength){
|
||||
typeof options.allDone === 'function' && options.allDone({
|
||||
total: that.fileLength,
|
||||
successful: successful,
|
||||
failed: failed
|
||||
});
|
||||
}
|
||||
};
|
||||
|
||||
// 发送请求
|
||||
var request = function(sets){
|
||||
var formData = new FormData();
|
||||
|
||||
// 删除正在上传中的文件队列
|
||||
var removeUploaded = function(index, file) {
|
||||
if (file[UPLOADING]) {
|
||||
delete items[index];
|
||||
return true;
|
||||
}
|
||||
};
|
||||
|
||||
// 追加额外的参数
|
||||
layui.each(options.data, function(key, value){
|
||||
value = typeof value === 'function' ? value() : value;
|
||||
formData.append(key, value);
|
||||
});
|
||||
|
||||
/*
|
||||
*添加 file 到表单域
|
||||
*/
|
||||
|
||||
// 是否统一上传
|
||||
if (sets.unified) {
|
||||
layui.each(items, function(index, file){
|
||||
if (removeUploaded(index, file)) return;
|
||||
file[UPLOADING] = true;
|
||||
formData.append(options.field, file);
|
||||
});
|
||||
} else { // 逐一上传
|
||||
if (removeUploaded(sets.index, sets.file)) return;
|
||||
formData.append(options.field, sets.file);
|
||||
}
|
||||
|
||||
sets.file[UPLOADING] = true; // 上传中的标记
|
||||
|
||||
// ajax 参数
|
||||
var opts = {
|
||||
url: options.url,
|
||||
type: 'post', // 统一采用 post 上传
|
||||
data: formData,
|
||||
contentType: false,
|
||||
processData: false,
|
||||
headers: options.headers || {},
|
||||
success: function(res){ // 成功回调
|
||||
options.unified ? (successful += that.fileLength) : successful++;
|
||||
done(sets.index, res);
|
||||
allDone();
|
||||
},
|
||||
error: function(e){ // 异常回调
|
||||
options.unified ? (failed += that.fileLength) : failed++;
|
||||
that.msg(text['error'] || [
|
||||
'Upload failed, please try again.',
|
||||
'status: '+ (e.status || '') +' - '+ (e.statusText || 'error')
|
||||
].join('<br>'));
|
||||
error(sets.index);
|
||||
allDone();
|
||||
}
|
||||
};
|
||||
// dataType
|
||||
if (options.dataType) {
|
||||
opts.dataType = options.dataType;
|
||||
} else if (options.force === 'json') {
|
||||
opts.dataType = options.force;
|
||||
}
|
||||
// 进度条
|
||||
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, sets.index);
|
||||
}
|
||||
});
|
||||
return xhr;
|
||||
}
|
||||
}
|
||||
$.ajax(opts);
|
||||
};
|
||||
|
||||
// 多文件是否一起上传
|
||||
if(options.unified){
|
||||
request({
|
||||
unified: true,
|
||||
index: 0
|
||||
});
|
||||
} else {
|
||||
layui.each(items, function(index, file){
|
||||
request({
|
||||
index: index,
|
||||
file: file
|
||||
});
|
||||
});
|
||||
}
|
||||
};
|
||||
|
||||
// 低版本 IE 处理方式,不支持跨域
|
||||
var 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(text['cross-domain']);
|
||||
clearInterval(Class.timer);
|
||||
error();
|
||||
}
|
||||
if(res){
|
||||
clearInterval(Class.timer);
|
||||
iframeBody.html('');
|
||||
done(0, res);
|
||||
}
|
||||
}, 30);
|
||||
};
|
||||
|
||||
// 统一回调
|
||||
var 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(text['data-format-error']);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
typeof options.done === 'function' && options.done(res, index || 0, function(files){
|
||||
that.upload(files);
|
||||
});
|
||||
};
|
||||
|
||||
// 统一网络异常回调
|
||||
var error = function(index){
|
||||
if(options.auto){
|
||||
elemFile.value = '';
|
||||
}
|
||||
typeof options.error === 'function' && options.error(index || 0, function(files){
|
||||
that.upload(files);
|
||||
});
|
||||
};
|
||||
|
||||
var check;
|
||||
var exts = options.exts;
|
||||
var value = function(){
|
||||
var arr = [];
|
||||
layui.each(files || that.chooseFiles, function(i, item){
|
||||
arr.push(item.name);
|
||||
});
|
||||
return arr;
|
||||
}();
|
||||
|
||||
// 回调函数返回的参数
|
||||
var 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;
|
||||
}
|
||||
};
|
||||
|
||||
// 提交上传
|
||||
var send = function(){
|
||||
// 上传前的回调 - 如果回调函数明确返回 false,则停止上传
|
||||
if(options.before && (options.before(args) === false)) return;
|
||||
|
||||
// IE 兼容处理
|
||||
if(device.ie){
|
||||
return device.ie > 9 ? ajaxSend() : iframeSend();
|
||||
}
|
||||
|
||||
ajaxSend();
|
||||
};
|
||||
|
||||
// 文件类型名称
|
||||
var 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|svg') +')$', 'i').test(escape(item))){
|
||||
return check = true;
|
||||
}
|
||||
});
|
||||
break;
|
||||
}
|
||||
|
||||
// 校验失败提示
|
||||
if(check){
|
||||
that.msg(text['check-error'] || ('选择的'+ typeName +'中包含不支持的格式'));
|
||||
return elemFile.value = '';
|
||||
}
|
||||
|
||||
// 选择文件的回调
|
||||
if(type === 'choose' || options.auto){
|
||||
options.choose && options.choose(args);
|
||||
if(type === 'choose'){
|
||||
return;
|
||||
}
|
||||
}
|
||||
|
||||
// 检验文件数量
|
||||
that.fileLength = function(){
|
||||
var length = 0;
|
||||
var items = getFiles();
|
||||
layui.each(items, function(){
|
||||
length++;
|
||||
});
|
||||
return length;
|
||||
}();
|
||||
|
||||
if(options.number && that.fileLength > options.number){
|
||||
return that.msg(typeof text['limit-number'] === 'function'
|
||||
? text['limit-number'](options, that.fileLength)
|
||||
: (
|
||||
'同时最多只能上传: '+ options.number + ' 个文件'
|
||||
+'<br>您当前已经选择了: '+ that.fileLength +' 个文件'
|
||||
));
|
||||
}
|
||||
|
||||
// 检验文件大小
|
||||
if(options.size > 0 && !(device.ie && device.ie < 10)){
|
||||
var limitSize;
|
||||
|
||||
layui.each(getFiles(), 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(typeof text['limit-size'] === 'function'
|
||||
? text['limit-size'](options, limitSize)
|
||||
: '文件大小不能超过 '+ limitSize);
|
||||
}
|
||||
|
||||
send();
|
||||
};
|
||||
|
||||
// 重置方法
|
||||
Class.prototype.reload = function(opts){
|
||||
opts = opts || {};
|
||||
delete opts.elem;
|
||||
delete opts.bindAction;
|
||||
|
||||
var that = this;
|
||||
var options = that.config = $.extend({}, that.config, upload.config, opts);
|
||||
var next = options.elem.next();
|
||||
|
||||
// 更新文件域相关属性
|
||||
next.attr({
|
||||
name: options.name,
|
||||
accept: options.acceptMime,
|
||||
multiple: options.multiple
|
||||
});
|
||||
};
|
||||
|
||||
//事件处理
|
||||
Class.prototype.events = function(){
|
||||
var that = this;
|
||||
var options = that.config;
|
||||
|
||||
// 设置当前选择的文件队列
|
||||
var setChooseFile = function(files){
|
||||
that.chooseFiles = {};
|
||||
layui.each(files, function(i, item){
|
||||
var time = new Date().getTime();
|
||||
that.chooseFiles[time + '-' + i] = item;
|
||||
});
|
||||
};
|
||||
|
||||
// 设置选择的文本
|
||||
var setChooseText = function(files, filename){
|
||||
var elemFile = that.elemFile;
|
||||
var item = options.item ? options.item : options.elem;
|
||||
var 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('<span class="layui-inline '+ ELEM_CHOOSE +'">'+ value +'</span>');
|
||||
};
|
||||
|
||||
// 合并 lay-options/lay-data 属性配置项
|
||||
var extendAttrs = function(){
|
||||
var othis = $(this);
|
||||
var data = othis.attr('lay-data') || othis.attr('lay-options'); // 优先兼容旧版本
|
||||
|
||||
if(data){
|
||||
that.config = $.extend({}, options, lay.options(this, {
|
||||
attr: othis.attr('lay-data') ? 'lay-data' : null
|
||||
}));
|
||||
}
|
||||
};
|
||||
|
||||
// 点击上传容器
|
||||
options.elem.off('upload.start').on('upload.start', function(){
|
||||
var othis = $(this);
|
||||
|
||||
extendAttrs.call(this);
|
||||
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);
|
||||
var files = param.originalEvent.dataTransfer.files || [];
|
||||
|
||||
othis.removeAttr('lay-over');
|
||||
extendAttrs.call(this);
|
||||
setChooseFile(files);
|
||||
|
||||
options.auto ? that.upload() : setChooseText(files); // 是否自动触发上传
|
||||
});
|
||||
}
|
||||
|
||||
// 文件选择
|
||||
that.elemFile.off('upload.change').on('upload.change', function(){
|
||||
var files = this.files || [];
|
||||
|
||||
if(files.length === 0) return;
|
||||
|
||||
extendAttrs.call(this);
|
||||
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);
|
||||
});
|
||||
|
||||
416
public/frontend/layui-main/src/modules/util.js
Executable file
416
public/frontend/layui-main/src/modules/util.js
Executable file
@@ -0,0 +1,416 @@
|
||||
/**
|
||||
* util 工具组件
|
||||
*/
|
||||
|
||||
layui.define('jquery', function(exports){
|
||||
"use strict";
|
||||
|
||||
var $ = layui.$;
|
||||
var hint = layui.hint();
|
||||
|
||||
// 外部接口
|
||||
var util = {
|
||||
// 固定块
|
||||
fixbar: function(options){
|
||||
var ELEM = 'layui-fixbar';
|
||||
var $doc = $(document);
|
||||
|
||||
// 默认可选项
|
||||
options = $.extend(true, {
|
||||
target: 'body', // fixbar 的插入目标选择器
|
||||
bars: [], // bar 信息
|
||||
"default": true, // 是否显示默认 bar
|
||||
margin: 160, // 出现 top bar 的滚动条高度临界值
|
||||
duration: 320 // top bar 等动画时长(毫秒)
|
||||
}, options);
|
||||
|
||||
// 目标元素对象
|
||||
var $target = $(options.target);
|
||||
|
||||
// 滚动条所在元素对象
|
||||
var $scroll = options.scroll
|
||||
? $(options.scroll)
|
||||
: $(options.target === 'body' ? $doc : $target)
|
||||
|
||||
// 是否提供默认图标
|
||||
if(options['default']){
|
||||
// 兼容旧版本的一些属性
|
||||
if(options.bar1){
|
||||
options.bars.push({
|
||||
type: 'bar1',
|
||||
icon: 'layui-icon-chat'
|
||||
});
|
||||
}
|
||||
if(options.bar2){
|
||||
options.bars.push({
|
||||
type: 'bar2',
|
||||
icon: 'layui-icon-help'
|
||||
});
|
||||
}
|
||||
// 默认 top bar
|
||||
options.bars.push({
|
||||
type: 'top',
|
||||
icon: 'layui-icon-top'
|
||||
});
|
||||
}
|
||||
|
||||
var elem = $('<ul>').addClass(ELEM);
|
||||
var elemTopBar;
|
||||
|
||||
// 遍历生成 bars 节点
|
||||
layui.each(options.bars, function(i, item){
|
||||
var elemBar = $('<li class="layui-icon">');
|
||||
|
||||
// 设置 bar 相关属性
|
||||
elemBar.addClass(item.icon).attr({
|
||||
'lay-type': item.type,
|
||||
'style': item.style || (options.bgcolor ? 'background-color: '+ options.bgcolor : '')
|
||||
}).html(item.content);
|
||||
|
||||
// bar 点击事件
|
||||
elemBar.on('click', function(){
|
||||
var type = $(this).attr('lay-type');
|
||||
if(type === 'top'){
|
||||
(
|
||||
options.target === 'body'
|
||||
? $('html,body')
|
||||
: $scroll
|
||||
).animate({
|
||||
scrollTop : 0
|
||||
}, options.duration);
|
||||
}
|
||||
typeof options.click === 'function' && options.click.call(this, type);
|
||||
});
|
||||
|
||||
// 自定义任意事件
|
||||
if(layui.type(options.on) === 'object'){
|
||||
layui.each(options.on, function(eventName, callback){
|
||||
elemBar.on(eventName, function(){
|
||||
var type = $(this).attr('lay-type');
|
||||
typeof callback === 'function' && callback.call(this, type);
|
||||
});
|
||||
})
|
||||
}
|
||||
|
||||
// 获得 top bar 节点
|
||||
if(item.type === 'top'){
|
||||
elemBar.addClass('layui-fixbar-top');
|
||||
elemTopBar = elemBar;
|
||||
}
|
||||
|
||||
elem.append(elemBar); // 插入 bar 节点
|
||||
});
|
||||
|
||||
// 若目标元素已存在 fixbar,则移除旧的节点
|
||||
$target.find('.'+ ELEM).remove();
|
||||
|
||||
// 向目标元素插入 fixbar 节点
|
||||
typeof options.css === 'object' && elem.css(options.css);
|
||||
$target.append(elem);
|
||||
|
||||
// top bar 的显示隐藏
|
||||
if(elemTopBar){
|
||||
var lock;
|
||||
var setTopBar = (function setTopBar(){
|
||||
var top = $scroll.scrollTop();
|
||||
if(top >= options.margin){
|
||||
lock || (elemTopBar.show(), lock = 1);
|
||||
} else {
|
||||
lock && (elemTopBar.hide(), lock = 0);
|
||||
}
|
||||
return setTopBar;
|
||||
})();
|
||||
}
|
||||
|
||||
// 根据 scrollbar 设置 fixbar 相关状态
|
||||
var timer;
|
||||
$scroll.on('scroll', function(){
|
||||
if(!setTopBar) return;
|
||||
clearTimeout(timer);
|
||||
timer = setTimeout(function(){
|
||||
setTopBar();
|
||||
}, 100);
|
||||
});
|
||||
},
|
||||
|
||||
// 倒计时
|
||||
countdown: function(options){
|
||||
var that = this;
|
||||
|
||||
// 默认可选项
|
||||
options = $.extend(true, {
|
||||
date: new Date(),
|
||||
now: new Date()
|
||||
}, options);
|
||||
|
||||
// 兼容旧版参数
|
||||
var args = arguments;
|
||||
if(args.length > 1){
|
||||
options.date = new Date(args[0]);
|
||||
options.now = new Date(args[1]);
|
||||
options.clock = args[2];
|
||||
}
|
||||
|
||||
// 实例对象
|
||||
var inst = {
|
||||
options: options,
|
||||
clear: function(){ // 清除计时器
|
||||
clearTimeout(inst.timer);
|
||||
},
|
||||
reload: function(opts){ // 重置倒计时
|
||||
this.clear();
|
||||
$.extend(true, this.options, {
|
||||
now: new Date()
|
||||
}, opts);
|
||||
count();
|
||||
}
|
||||
};
|
||||
|
||||
typeof options.ready === 'function' && options.ready();
|
||||
|
||||
// 计算倒计时
|
||||
var count = (function fn(){
|
||||
var date = new Date(options.date);
|
||||
var now = new Date(options.now);
|
||||
var countTime = function(time){
|
||||
return time > 0 ? time : 0;
|
||||
}(date.getTime() - now.getTime());
|
||||
var result = {
|
||||
d: Math.floor(countTime/(1000*60*60*24)), // 天
|
||||
h: Math.floor(countTime/(1000*60*60)) % 24, // 时
|
||||
m: Math.floor(countTime/(1000*60)) % 60, // 分
|
||||
s: Math.floor(countTime/1000) % 60 // 秒
|
||||
};
|
||||
var next = function(){
|
||||
now.setTime(now.getTime() + 1000);
|
||||
options.now = now;
|
||||
count();
|
||||
};
|
||||
|
||||
// 兼容旧版返回值
|
||||
if(args.length > 1) result = [result.d,result.h,result.m,result.s]
|
||||
|
||||
// 计时 - 以秒间隔
|
||||
inst.timer = setTimeout(next, 1000);
|
||||
typeof options.clock === 'function' && options.clock(result, inst);
|
||||
|
||||
// 计时完成
|
||||
if(countTime <= 0){
|
||||
clearTimeout(inst.timer);
|
||||
typeof options.done === 'function' && options.done(result, inst);
|
||||
};
|
||||
|
||||
return fn;
|
||||
})();
|
||||
|
||||
return inst;
|
||||
},
|
||||
|
||||
// 某个时间在当前时间的多久前
|
||||
timeAgo: function(time, onlyDate){
|
||||
var that = this;
|
||||
var arr = [[], []];
|
||||
var 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, options){
|
||||
// 若 null 或空字符,则返回空字符
|
||||
if(time === null || time === '') return '';
|
||||
|
||||
// 引用自 dayjs
|
||||
// https://github.com/iamkun/dayjs/blob/v1.11.9/src/constant.js#L30
|
||||
var REGEX_FORMAT = /\[([^\]]+)]|y{1,4}|M{1,2}|d{1,2}|H{1,2}|h{1,2}|a|A|m{1,2}|s{1,2}|SSS/g;
|
||||
var that = this;
|
||||
var date = new Date(function(){
|
||||
if(!time) return;
|
||||
return isNaN(time) ? time : (typeof time === 'string' ? parseInt(time) : time)
|
||||
}() || new Date())
|
||||
|
||||
if(!date.getDate()) return hint.error('Invalid Msec for "util.toDateString(Msec)"'), '';
|
||||
|
||||
var years = date.getFullYear();
|
||||
var month = date.getMonth();
|
||||
var days = date.getDate();
|
||||
var hours = date.getHours();
|
||||
var minutes = date.getMinutes();
|
||||
var seconds = date.getSeconds();
|
||||
var milliseconds = date.getMilliseconds();
|
||||
|
||||
var defaultMeridiem = function(hours, minutes){
|
||||
var hm = hours * 100 + minutes;
|
||||
if (hm < 600) {
|
||||
return '凌晨';
|
||||
} else if (hm < 900) {
|
||||
return '早上';
|
||||
} else if (hm < 1100) {
|
||||
return '上午';
|
||||
} else if (hm < 1300) {
|
||||
return '中午';
|
||||
} else if (hm < 1800) {
|
||||
return '下午';
|
||||
}
|
||||
return '晚上';
|
||||
};
|
||||
|
||||
var meridiem = (options && options.customMeridiem) || defaultMeridiem;
|
||||
|
||||
var matches = {
|
||||
yy: function(){return String(years).slice(-2);},
|
||||
yyyy: function(){return that.digit(years, 4);},
|
||||
M: function(){return String(month + 1);},
|
||||
MM: function(){return that.digit(month + 1);},
|
||||
d: function(){return String(days);},
|
||||
dd: function(){return that.digit(days);},
|
||||
H: function(){return String(hours);},
|
||||
HH: function(){return that.digit(hours);},
|
||||
h: function(){return String(hours % 12 || 12);},
|
||||
hh: function(){return that.digit(hours % 12 || 12);},
|
||||
A: function(){return meridiem(hours, minutes);},
|
||||
m: function(){return String(minutes);},
|
||||
mm: function(){return that.digit(minutes);},
|
||||
s: function(){return String(seconds);},
|
||||
ss: function(){return that.digit(seconds);},
|
||||
SSS: function(){return that.digit(milliseconds, 3);}
|
||||
}
|
||||
|
||||
format = format || 'yyyy-MM-dd HH:mm:ss';
|
||||
|
||||
return format.replace(REGEX_FORMAT, function(match, $1) {
|
||||
return $1 || (matches[match] && matches[match]()) || match;
|
||||
});
|
||||
},
|
||||
|
||||
// 转义 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, ''').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, '"');
|
||||
},
|
||||
|
||||
// 打开新窗口
|
||||
openWin: function(options){
|
||||
var win;
|
||||
options = options || {};
|
||||
win = options.window || window.open((options.url || ''), options.target, options.specs);
|
||||
if(options.url) return;
|
||||
win.document.open('text/html', 'replace');
|
||||
win.document.write(options.content || '');
|
||||
win.document.close();
|
||||
},
|
||||
|
||||
// 让指定的元素保持在可视区域
|
||||
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 // 滚动元素
|
||||
var thisElem = options.thisElem // 目标元素
|
||||
var vertical = options.type === 'y' // 是否垂直方向
|
||||
var SCROLL_NAME = vertical ? 'scrollTop' : 'scrollLeft' // 滚动方法
|
||||
var OFFSET_NAME = vertical ? 'top' : 'left' // 坐标方式
|
||||
var scrollValue = scrollElem[SCROLL_NAME]() // 当前滚动距离
|
||||
var size = scrollElem[vertical ? 'height' : 'width']() // 滚动元素的尺寸
|
||||
var scrollOffet = scrollElem.offset()[OFFSET_NAME] // 滚动元素所处位置
|
||||
var thisOffset = thisElem.offset()[OFFSET_NAME] - scrollOffet // 目标元素当前的所在位置
|
||||
var 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);
|
||||
var 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;
|
||||
|
||||
// 输出接口
|
||||
exports('util', util);
|
||||
});
|
||||
Reference in New Issue
Block a user