From 1dc48629d6030137c6da7166cc7c6e1062b2a7d8 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?=E8=B4=A4=E5=BF=83?= <3277200+sentsim@users.noreply.github.com> Date: Tue, 5 Sep 2023 16:30:07 +0800 Subject: [PATCH] =?UTF-8?q?=E4=BC=98=E5=8C=96=20code=20=E8=8B=A5=E5=B9=B2?= =?UTF-8?q?=E5=B0=8F=E9=97=AE=E9=A2=98?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- src/css/layui.css | 4 +- src/css/modules/code.css | 36 +- src/modules/code.js | 701 +++++++++++++++++++++------------------ 3 files changed, 395 insertions(+), 346 deletions(-) diff --git a/src/css/layui.css b/src/css/layui.css index 5fa04183..7ae264d8 100644 --- a/src/css/layui.css +++ b/src/css/layui.css @@ -665,7 +665,7 @@ a cite{font-style: normal; *cursor:pointer;} .layui-text a:not(.layui-btn){color: #01AAED;} .layui-text a:not(.layui-btn):hover{text-decoration: underline;} .layui-text blockquote:not(.layui-elem-quote){padding: 5px 15px; border-left: 5px solid #eee;} -.layui-text pre > code:not(.layui-code){padding: 15px; font-family: Courier New,Lucida Console,Consolas; background-color: #fafafa;} +.layui-text pre > code:not(.layui-code){padding: 15px; font-family: "Courier New",Consolas,monospace;} /* 字体大小 */ .layui-font-12{font-size: 12px !important;} @@ -1470,7 +1470,7 @@ body .layui-util-face .layui-layer-content{padding:0; background-color:#fff; co .layui-util-face ul li:hover{position: relative; z-index: 2; border: 1px solid #eb7350; background: #fff9ec;} /** 代码文本修饰 **/ -.layui-code{position: relative; margin: 10px 0; padding: 15px; line-height: 20px; border: 1px solid #eee; border-left-width: 6px; background-color: #fafafa; color: #333; font-family: Courier New,Lucida Console,Consolas; font-size: 12px;} +.layui-code{display: block; position: relative; margin: 10px 0; padding: 15px; line-height: 20px; border: 1px solid #eee; border-left-width: 6px; background-color: #fff; color: #333; font-family: "Courier New",Consolas,monospace; font-size: 12px;} /** 穿梭框 **/ .layui-transfer-box, diff --git a/src/css/modules/code.css b/src/css/modules/code.css index cb798110..3c9dd498 100644 --- a/src/css/modules/code.css +++ b/src/css/modules/code.css @@ -5,28 +5,32 @@ /* 加载就绪标志 */ html #layuicss-skincodecss{display:none; position: absolute; width:1989px;} -/* 默认风格 */ -.layui-code-view{display: block; position: relative; margin: 11px 0; padding: 0 !important; border: 1px solid #eee; border-left-width: 6px; background-color: #FAFAFA; color: #333; font-family: 'Courier New'; font-size: 13px; white-space: pre; overflow: auto;} -.layui-code-view.layui-code-line-numbers-mode{padding-left: 45px !important;} +/* 字体 */ +.layui-code-view, +.layui-code-view > .layui-code-lines{font-size: 13px; font-family: "Courier New",Consolas,monospace;} + +/* 基础结构 */ +.layui-code-view{display: block; position: relative; margin: 11px 0; padding: 0; border: 1px solid #eee; border-left-width: 6px; background-color: #fff; color: #333; white-space: pre; overflow: auto;} +.layui-code-view.layui-code-line-numbers-mode{padding-left: 45px;} .layui-code-title{position: relative; padding: 0 10px; height: 40px; line-height: 40px; border-bottom: 1px solid #eee; font-size: 12px;} .layui-code-title > .layui-code-about{position: absolute; right: 10px; top: 0; color: #B7B7B7;} .layui-code-line-numbers-mode .layui-code-title{margin-left: -45px;} .layui-code-title ~ .layui-code-line-numbers{margin-top: 40px;} .layui-code-about > a{padding-left: 10px;} -.layui-code-view > .layui-code-lines{display:block; max-height: 100%; padding: 15px 10px !important; position: relative;background-color: #fff;font-family: 'Courier New'} +.layui-code-view > .layui-code-lines{display: block; position: relative; max-height: 100%; padding: 15px 10px !important;} .layui-code-view > .layui-code-lines > .layui-code-line{position: relative; display: block; line-height: 20px;} .layui-code-view pre{margin: 0;} -.layui-code-line-numbers{position: absolute;top: 0;bottom: 0;left: 0;width: 45px; border-right: 1px solid #e2e2e2; text-align: center; padding: 15px 0; line-height: 20px; user-select: none;} +.layui-code-line-numbers{position: absolute; top: 0; bottom: 0; left: 0; min-width: 45px; border-right: 1px solid #eee; border-color: rgb(126 122 122 / 15%); text-align: center; padding: 15px 8px; line-height: 20px; background-color: #fafafa; user-select: none;} .layui-code-line-number{display: block;} .layui-code-lang-marker{position: absolute; top: 2px; right: 11px; color: currentColor;} .layui-code-view:hover > .layui-code-lang-marker{display: none;} -/* 深色风格 */ -.layui-code-dark{border: 1px solid #0C0C0C; border-left-color: #3F3F3F; background-color: #0C0C0C; color: #C2BE9E} -.layui-code-dark > .layui-code-title{border-bottom: none;} -.layui-code-dark > .layui-code-lines{background-color: #3F3F3F !important; border-left: none !important;} -.layui-code-dark > .layui-code-lines{margin-left: 6px;} -.layui-code-dark.layui-code-line-numbers-mode > .layui-code-lines{margin-left: 0;} +/* 深色主题 */ +.layui-code-theme-dark{border: 1px solid #2a2a2a; border-left-color: #2a2a2a; background-color: #1f1f1f; color: #ccc;} +.layui-code-theme-dark > .layui-code-title{border-bottom: none;} +.layui-code-theme-dark > .layui-code-line-numbers{border-right-color: #2a2a2a; background: none; color: #6e7681;} +.layui-code-theme-dark > .layui-code-lines{margin-left: 0; background: none;} + /* 代码预览 */ .layui-code textarea{display: none;} @@ -51,21 +55,19 @@ html #layuicss-skincodecss{display:none; position: absolute; width:1989px;} .layui-code-copy .layui-icon{color: #777; transition: all .3s;} .layui-code-copy:hover .layui-icon{color: #16b777;} .layui-code-view:hover > .layui-code-copy{display: block;} -.layui-code-copy-offset{margin-right: 17px;} .layui-code-preview > .layui-code-view > .layui-code-copy{display: none !important;} /* 全屏风格 */ .layui-code-full{position: fixed; left: 0; top: 0; z-index: 1111111; width: 100%; height: 100%; background-color: #fff;} .layui-code-full .layui-code-item{width: 100% !important; border-width: 0 !important; border-top-width: 1px !important;} .layui-code-full .layui-code-item, -.layui-code-full .layui-code-view{max-height: calc(100vh - 51px) !important; box-sizing: border-box;} +.layui-code-full .layui-code-view{height: calc(100vh - 51px) !important; box-sizing: border-box;} /* 代码高亮重置 */ -.layui-code-view[class*=language-]{ - font-size: 13px !important; +.layui-code-view.layui-code-hl{ line-height: 20px !important; } -.layui-code-view[class*=language-] > .layui-code-lines, -.layui-code-view[class*=language-] > .layui-code-line-numbers{ +.layui-code-view.layui-code-hl > .layui-code-lines, +.layui-code-view.layui-code-hl > .layui-code-line-numbers{ background-color: transparent; } diff --git a/src/modules/code.js b/src/modules/code.js index f437f96e..4c73f800 100644 --- a/src/modules/code.js +++ b/src/modules/code.js @@ -24,6 +24,7 @@ layui.define(['lay', 'util', 'element', 'form'], function(exports){ ELEM_SHOW: 'layui-show', ELEM_LINE: 'layui-code-line', ELEM_LINES: 'layui-code-lines', + ELEM_LINE_NUMS: 'layui-code-line-numbers', ELEM_LINE_NUMBERS_MODE: 'layui-code-line-numbers-mode', }; @@ -45,8 +46,12 @@ layui.define(['lay', 'util', 'element', 'form'], function(exports){ langMarker: false, // 代码区域是否显示语言类型标记 }; + // 初始索引 + var codeIndex = layui.code ? (layui.code.index + 10000) : 0; + + // 去除尾部空格 var trimEnd = function(str){ - return String(str).replace(/\s+$/, ''); + return String(str).replace(/\s+$/, ''); } // 保留首行缩进 var trim = function(str){ @@ -57,381 +62,423 @@ layui.define(['lay', 'util', 'element', 'form'], function(exports){ exports('code', function(options){ var opts = options = $.extend(true, {}, config, options); - // 目标元素是否存在 - options.elem = $(options.elem); - if(!options.elem[0]) return; - - // 从内至外渲染 - layui.each(options.elem.get().reverse(), function(index, item){ - var othis = $(item); - - // 合并属性上的参数,并兼容旧版本属性写法 lay-* - var options = $.extend(true, {}, opts, lay.options(item), 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; - - // 获得初始代码 - var rawCode = othis.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; - }(); - - othis.data('code', rawCode); - - // code - var html = finalCode = rawCode.join(''); - - // 外部重新解析 code - if(typeof options.codeParse === 'function'){ - html = finalCode = options.codeParse(html); + // 实例对象 + var inst = { + reload: function(sets) { // 重载 + sets = sets || {}; + delete sets.elem; + sets = $.extend(true, options, sets); + layui.code(sets); } + }; + + // 若 elem 非唯一 + var elem = $(options.elem); + if(elem.length > 1){ + // 是否正向渲染 + layui.each(options.obverse ? elem : elem.get().reverse(), function(){ + layui.code($.extend({}, options, { + elem: this + })); + }); + return inst; + } + + // 目标元素是否存在 + var othis = options.elem = $(options.elem); + var item = othis[0]; + if(!othis[0]) return inst; + + // 合并属性上的参数,并兼容旧版本属性写法 lay-* + var options = $.extend(true, {}, opts, lay.options(item), 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; + }({})); + + var index = layui.code.index = ++codeIndex; + + // codeRender 需要关闭编码 + // 未使用 codeRender 时若开启了预览,则强制开启编码 + options.encode = (options.encode || options.preview) && !options.codeRender; + + // 最终显示的代码 + var finalCode; + + // 获得初始代码 + var rawCode = othis.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; + }(); + + othis.data('code', rawCode); + + // 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(el, type){ + 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); + } + } + }; + + // 是否开启预览 + if(options.preview){ + var FILTER_VALUE = 'LAY-CODE-DF-'+ index; + var layout = options.layout || ['code', 'preview']; + var isIframePreview = options.preview === 'iframe'; + + // 追加 Tab 组件 + var elemView = $('
'); + var elemTabView = $('
'); + var elemHeaderView = $('
'); + var elemPreviewView = $('
'); + var elemToolbar = $('
'); + var elemViewHas = othis.parent('.' + CONST.ELEM_PREVIEW); + var elemTabHas = othis.prev('.'+ CONST.ELEM_TAB); + var elemPreviewViewHas = othis.next('.' + CONST.ELEM_ITEM +'-preview'); + + 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 = $('
  • '); + if(i === 0) li.addClass('layui-this'); + li.html(options.text[v]); + elemHeaderView.append(li); + }); // 工具栏 - var tools = { - copy: { - className: 'file-b', - title: ['复制代码'], + $.extend(tools, { + 'full': { + className: 'screen-full', + title: ['最大化显示', '还原显示'], event: function(el, type){ - var code = util.unescape(finalCode); + 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'; - // 写入剪切板 - lay.clipboard.writeText({ - text: code, - done: function() { - layer.msg('已复制', {icon: 1}); - }, - error: function() { - layer.msg('复制失败', {icon: 2}); - } + 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(el, type){ + util.openWin({ + content: finalCode }); - - typeof options.onCopy === 'function' && options.onCopy(code); } } - }; + }); - // 是否开启预览 - if(options.preview){ - var FILTER_VALUE = 'LAY-CODE-DF-'+ index; - var layout = options.layout || ['code', 'preview']; - var isIframePreview = options.preview === 'iframe'; - - // 追加 Tab 组件 - var elemView = $('
    '); - var elemTabView = $('
    '); - var elemHeaderView = $('
    '); - var elemPreviewView = $('
    '); - var elemToolbar = $('
    '); - var elemViewHas = othis.parent('.' + CONST.ELEM_PREVIEW); - var elemTabHas = othis.prev('.'+ CONST.ELEM_TAB); - var elemPreviewViewHas = othis.next('.' + CONST.ELEM_ITEM +'-preview'); - - 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 = $('
  • '); - if(i === 0) li.addClass('layui-this'); - li.html(options.text[v]); - elemHeaderView.append(li); - }); - - // 工具栏 - $.extend(tools, { - 'full': { - className: 'screen-full', - title: ['最大化显示', '还原显示'], - event: function(el, type){ - 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(el, type){ - 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']; + // 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'); + // 工具栏事件 + elemToolbar.on('click', '>i', function(){ + var oi = $(this); + var type = oi.data('type'); - // 内部 tools event - tools[type] && typeof tools[type].event === 'function' && tools[type].event(oi, type); + // 内部 tools event + tools[type] && typeof tools[type].event === 'function' && tools[type].event(oi, type); - // 外部 tools event - typeof options.toolsEvent === 'function' && options.toolsEvent({ - elem: oi, - type: type, - rawCode: rawCode.join(''), // 原始 code - finalCode: util.unescape(finalCode) // 最终 code - }); + // 外部 tools event + typeof options.toolsEvent === 'function' && options.toolsEvent({ + elem: oi, + type: type, + rawCode: rawCode.join(''), // 原始 code + finalCode: util.unescape(finalCode) // 最终 code }); + }); - // 渲染工具栏 - 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; - - elemToolbar.append( - '' - ); - }); - - // 移除旧结构 - if(elemTabHas[0]) elemTabHas.remove(); // 移除 tab - if(elemPreviewViewHas[0]) elemPreviewViewHas.remove(); // 移除预览区域 - if(elemViewHas[0]) othis.unwrap(); // 移除外层容器 - - elemTabView.append(elemHeaderView); // 追加标签头 - options.tools && elemTabView.append(elemToolbar); // 追加工具栏 - othis.wrap(elemView).addClass(CONST.ELEM_ITEM).before(elemTabView); // 追加标签结构 - - - // 追加预览 - if(isIframePreview){ - elemPreviewView.html(''); - } - - // 执行预览 - var run = function(thisItemBody){ - var iframe = thisItemBody.children('iframe')[0]; - if(isIframePreview && iframe){ - iframe.srcdoc = finalCode; - } else { - thisItemBody.html(rawCode.join('')); + // 渲染工具栏 + 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; + + elemToolbar.append( + '' + ); + }); + + // 移除旧结构 + if(elemTabHas[0]) elemTabHas.remove(); // 移除 tab + if(elemPreviewViewHas[0]) elemPreviewViewHas.remove(); // 移除预览区域 + if(elemViewHas[0]) othis.unwrap(); // 移除外层容器 + + elemTabView.append(elemHeaderView); // 追加标签头 + options.tools && elemTabView.append(elemToolbar); // 追加工具栏 + othis.wrap(elemView).addClass(CONST.ELEM_ITEM).before(elemTabView); // 追加标签结构 + + + // 追加预览 + if(isIframePreview){ + elemPreviewView.html(''); + } + + // 执行预览 + 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(); } - // 回调的返回参数 - 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); + // 当前实例预览完毕后的回调 + 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.codeStyle = [options.style, options.codeStyle].join(''); + options.previewStyle = [options.style, options.previewStyle].join(''); + // othis.attr('style', options.codeStyle); + 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); } - // 内容项初始化样式 - options.codeStyle = [options.style, options.codeStyle].join(''); - options.previewStyle = [options.style, options.previewStyle].join(''); - // othis.attr('style', options.codeStyle); - elemPreviewView.attr('style', options.previewStyle); + setCodeLayout(); + }); + } - // 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); + // 创建 code 容器 + var codeElem = $(''); // 此处的闭合标签是为了兼容 IE8 - elemItemBody.removeClass(CONST.ELEM_SHOW); - thisItemBody.addClass(CONST.ELEM_SHOW); + // 添加主容器 className + othis.addClass('layui-code-view layui-border-box'); - if($this.attr('lay-id') === 'preview'){ - run(thisItemBody); - } - }); - } + // 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); + } - var listElem = $(''); // 此处的闭合标签是为了兼容 IE8 + // 添加高亮必要的 className + if (options.highlighter) { + othis.addClass([ + options.highlighter, + 'language-' + options.lang, + 'layui-code-hl' + ].join(' ')); + } - // header - var headerElem = $('
    '); + // 转义 HTML 标签 + if(options.encode) html = util.escape(html); // 编码 - // 添加组件 className - othis.addClass('layui-code-view layui-box'); + // codeRender + if(typeof options.codeRender === 'function') html = options.codeRender(html, options); - // 自定义风格 - if(options.skin){ - if(options.skin === 'notepad') options.skin = 'dark'; - othis.removeClass('layui-code-dark layui-code-light'); - othis.addClass('layui-code-'+ options.skin); - } + // code 行 + var lines = String(html).split(/\r?\n/g); - // 高亮 - if(options.highlighter) othis.addClass(options.highlighter + ' language-' + options.lang); + // 包裹 code 行元素 + html = (options.codeRender && !options.highlighter) + ? html + : $.map(lines, function(line){ + return ['
    ', (line || ' '), '
    '].join(''); // 空行填充空格,以保证换行效果 + }).join('') - // 转义 HTML 标签 - if(options.encode) html = util.escape(html); // 编码 + // 插入 code + othis.html(codeElem.html(html)); - // code 转 html - if(typeof options.codeRender === 'function') html = options.codeRender(html, options); - var lines = html.split(/\r?\n/g); - html = (options.codeRender && !options.highlighter) - ? html - : $.map(lines, function(line){ - return ['
    ', (line || ' '), '
    '].join(''); // 空行填充空格,以保证换行效果 - }).join('') + // code 区域样式 + if (options.codeStyle) { + othis.attr('style', function(i, val) { + return (val || '') + options.codeStyle; + }); + } - // 生成列表 - othis.html(listElem.html(html)); + // 兼容旧版本 height 属性 + if (options.height) othis.css('max-height', options.height); - // 创建行号 - if(options.ln) { - var lineNumbersCode = ['
    '] + // 创建行号 + var lineNumsElem = function() { + if (options.ln) { + var lineNumbersCode = ['
    '] layui.each(lines, function(index){ lineNumbersCode.push('' + util.digit(index + 1) +'.') }); lineNumbersCode.push('
    '); othis.addClass(CONST.ELEM_LINE_NUMBERS_MODE); - othis.append(lineNumbersCode.join('')); - othis.children('.layui-code-line-numbers').css({ - height: listElem.height(), - }) + othis.prepend(lineNumbersCode.join('')); } + return othis.children('.'+ CONST.ELEM_LINE_NUMS); + }() - // 创建 header - if(options.header && !othis.children('.'+ CONST.ELEM_TITLE)[0]){ - headerElem.html((options.title || options.text.code) + ( - options.about - ? '
    ' + options.about + '
    ' - : '' - )); - othis.prepend(headerElem); - } + // 设置 code 布局 + var setCodeLayout = (function fn() { + lineNumsElem.css({ + height: othis.prop('scrollHeight') // 与外容器高度保持一致 + }); - // 所有实例渲染完毕后的回调 - if(options.elem.length === index + 1){ - typeof options.allDone === 'function' && options.allDone(); - } + // 根据行号容器宽度,适配 code 容器左内边距 + othis.css('padding-left', function(multiLine) { + var width = lineNumsElem.outerWidth(); + return multiLine && width > 45 ? width : null; + }(Math.floor(lines.length / 100) && options.ln)); - // 按行数适配左边距 - (function(autoIncNums){ - if(autoIncNums > 0){ - othis.css('margin-left', autoIncNums + 'px'); - } - })(Math.floor(listElem.find('.' + CONST.ELEM_LINE).length/100)); + return fn; + })(); - // 限制 Code 最大高度 - if(options.height){ // 兼容旧版本 - othis.css('max-height', options.height); - } - // Code 内容区域样式 - if(options.codeStyle){ - othis.attr('style', function(_, origVal){ - return (origVal || '') + options.codeStyle; - }); - } + // 创建 header --- 后续版本将废弃该属性 + if(options.header && !othis.children('.'+ CONST.ELEM_TITLE)[0]){ + var headerElem = $('
    '); + headerElem.html((options.title || options.text.code) + ( + options.about + ? '
    ' + options.about + '
    ' + : '' + )); + othis.prepend(headerElem); + } - // 是否开启代码复制 - if(options.copy && !options.preview){ - var elemCopy = $(['', - '', - ''].join('')); - var elemCopyHas = othis.children('.'+ CONST.ELEM_COPY); - var isHeight = othis[0].style.height || othis[0].style.maxHeight; + // 所有实例渲染完毕后的回调 + if(options.elem.length === index + 1){ + typeof options.allDone === 'function' && options.allDone(); + } - if(isHeight) elemCopy.addClass(CONST.ELEM_COPY + '-offset'); // 偏移 - if(elemCopyHas[0]) elemCopyHas.remove(); // 移除旧的复制元素 - othis.append(elemCopy); + // 若开启复制,且未开启预览时,单独生成复制图标 + if(options.copy && !options.preview){ + var elemCopy = $(['', + '', + ''].join('')); + var elemCopyHas = othis.children('.'+ CONST.ELEM_COPY); - // 点击复制 - elemCopy.on('click', function(){ - tools.copy.event(); - }); - } + if(elemCopyHas[0]) elemCopyHas.remove(); // 移除旧的复制元素 + othis.append(elemCopy); - // language marker - if(options.langMarker){ - var elemMarker = $('' + options.lang + '') - var isHeight = othis[0].style.height || othis[0].style.maxHeight; - var elemMarkerHas = othis.children("." + CONST.ELEM_MARKER); - if(isHeight) elemMarker.css('margin-right', '17px') - if(elemMarkerHas) elemMarkerHas.remove(); - othis.append(elemMarker); - } + // 点击复制 + elemCopy.on('click', function(){ + tools.copy.event(); + }); + } - }); + // language marker + if(options.langMarker){ + var elemMarker = $('' + options.lang + '') + var elemMarkerHas = othis.children("." + CONST.ELEM_MARKER); + if(elemMarkerHas[0]) elemMarkerHas.remove(); + othis.append(elemMarker); + } + // code 渲染完毕后的回调 + if (!options.preview) { + setTimeout(function(){ + typeof options.done === 'function' && options.done({}); + },3); + } + + return inst; }); });