/** * 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 [ '
'); // 此处的闭合标签是为了兼容 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('');
}
// 兼容旧版本 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 = $('');
headerElem.html(options.title || options.text.code);
othis.prepend(headerElem);
}
// 创建 code 区域固定条
var elemFixbar = $('');
// 若开启复制,且未开启预览,则单独生成复制图标
if(options.copy && !options.preview){
var copyElem = $(['',
'',
''].join(''));
// 点击复制
copyElem.on('click', function(){
tools.copy.event();
});
elemFixbar.append(copyElem);
}
// 创建 language marker
if (options.langMarker) {
elemFixbar.append('' + options.lang + '');
}
// 创建 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');
}