Initial commit
This commit is contained in:
@@ -0,0 +1,26 @@
|
||||
# highlight
|
||||
功能:代码块高亮显示
|
||||
支持平台:
|
||||
|
||||
| 微信小程序 | QQ 小程序 | 百度小程序 | 支付宝小程序 | 头条小程序 | uni-app |
|
||||
|:---:|:---:|:---:|:---:|:---:|:---:|
|
||||
| √ | √ | √ | √ | √ | √ |
|
||||
|
||||
说明:
|
||||
大小:*≈16KB*
|
||||
编辑 *plugins/highlight/config.js* 顶部的选项,可以选择是否需要以下功能:
|
||||
- *copyByLongPress* 是否需要长按代码块时显示复制代码内容菜单(*uni-app nvue* 暂不支持)
|
||||
- *showLanguageName* 是否在代码块右上角显示语言的名称
|
||||
- *showLineNumber* 是否在左侧显示行号
|
||||
|
||||
> 修改该配置后需要重新生成组件包,在构建后的组件包中修改配置无法生效
|
||||
|
||||
引入本插件后,*html* 中符合以下格式的 *pre* 将被高亮处理:
|
||||
```html
|
||||
<!-- pre 中内含一个 code,并在 pre 或 code 的 class 中设置 language- -->
|
||||
<pre><code class="language-css">p { color: red }</code></pre>
|
||||
```
|
||||
|
||||
> 与 *editable* 插件共用时,编辑状态下,不会进行高亮,可以直接修改代码文本
|
||||
|
||||
> 本插件的高亮功能依赖于 [prismjs](https://prismjs.com/),默认配置中仅支持 *html*、*css*、*c-like*、*javascript* 语言和 *Tomorrow Night* 主题,如果需要更多语言或更换主题请前往 [官网](https://prismjs.com/download.html) 下载对应的 *prism.min.js* 和 *prism.css* 并替换 *plugins/highlight/* 目录下的文件
|
||||
@@ -0,0 +1,5 @@
|
||||
module.exports = {
|
||||
copyByLongPress: false, // 是否需要长按代码块时显示复制代码内容菜单
|
||||
showLanguageName: false, // 是否在代码块右上角显示语言的名称
|
||||
showLineNumber: false // 是否显示行号
|
||||
}
|
||||
@@ -0,0 +1,96 @@
|
||||
/**
|
||||
* @fileoverview highlight 插件
|
||||
* Include prismjs (https://prismjs.com)
|
||||
*/
|
||||
const prism = require('./prism.min')
|
||||
const config = require('./config')
|
||||
const Parser = require('../parser')
|
||||
|
||||
function Highlight (vm) {
|
||||
this.vm = vm
|
||||
}
|
||||
|
||||
Highlight.prototype.onParse = function (node, vm) {
|
||||
if (node.name === 'pre') {
|
||||
if (vm.options.editable) {
|
||||
node.attrs.class = (node.attrs.class || '') + ' hl-pre'
|
||||
return
|
||||
}
|
||||
let i
|
||||
for (i = node.children.length; i--;) {
|
||||
if (node.children[i].name === 'code') break
|
||||
}
|
||||
if (i === -1) return
|
||||
const code = node.children[i]
|
||||
let className = code.attrs.class + ' ' + node.attrs.class
|
||||
i = className.indexOf('language-')
|
||||
if (i === -1) {
|
||||
i = className.indexOf('lang-')
|
||||
if (i === -1) {
|
||||
className = 'language-text'
|
||||
i = 9
|
||||
} else {
|
||||
i += 5
|
||||
}
|
||||
} else {
|
||||
i += 9
|
||||
}
|
||||
let j
|
||||
for (j = i; j < className.length; j++) {
|
||||
if (className[j] === ' ') break
|
||||
}
|
||||
const lang = className.substring(i, j)
|
||||
if (code.children.length) {
|
||||
const text = this.vm.getText(code.children).replace(/&/g, '&')
|
||||
if (!text) return
|
||||
if (node.c) {
|
||||
node.c = undefined
|
||||
}
|
||||
if (prism.languages[lang]) {
|
||||
code.children = (new Parser(this.vm).parse(
|
||||
// 加一层 pre 保留空白符
|
||||
'<pre>' + prism.highlight(text, prism.languages[lang], lang).replace(/token /g, 'hl-') + '</pre>'))[0].children
|
||||
}
|
||||
node.attrs.class = 'hl-pre'
|
||||
code.attrs.class = 'hl-code'
|
||||
if (config.showLanguageName) {
|
||||
node.children.push({
|
||||
name: 'div',
|
||||
attrs: {
|
||||
class: 'hl-language',
|
||||
style: 'user-select:none'
|
||||
},
|
||||
children: [{
|
||||
type: 'text',
|
||||
text: lang
|
||||
}]
|
||||
})
|
||||
}
|
||||
if (config.copyByLongPress) {
|
||||
node.attrs.style += (node.attrs.style || '') + ';user-select:none'
|
||||
node.attrs['data-content'] = text
|
||||
vm.expose()
|
||||
}
|
||||
if (config.showLineNumber) {
|
||||
const line = text.split('\n').length; const children = []
|
||||
for (let k = line; k--;) {
|
||||
children.push({
|
||||
name: 'span',
|
||||
attrs: {
|
||||
class: 'span'
|
||||
}
|
||||
})
|
||||
}
|
||||
node.children.push({
|
||||
name: 'span',
|
||||
attrs: {
|
||||
class: 'line-numbers-rows'
|
||||
},
|
||||
children
|
||||
})
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
module.exports = Highlight
|
||||
@@ -0,0 +1,88 @@
|
||||
const config = require('../config')
|
||||
|
||||
const build = {
|
||||
import: 'prism.css',
|
||||
handler (file) {
|
||||
if (file.path.includes('prism.css')) {
|
||||
// 将标签名选择器和属性选择器转为 class 选择器(组件内仅支持 class 选择器)
|
||||
file.contents = Buffer.from(file.contents.toString().replace(/pre([[)])/g, '.hl-pre$1').replace(/code/g, '.hl-code').replace(/\[class\*="?language-"?\]/g, '').replace(/:not[^,}]+[,}]*/g, '').replace(/\.token\./g, '.hl-'))
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
if (config.showLanguageName || config.showLineNumber) {
|
||||
// pre 内部的 code 进行滚动,避免行号和语言名称跟随滚动
|
||||
build.style = `.hl-pre {
|
||||
position: relative;
|
||||
}
|
||||
.hl-code {
|
||||
overflow: auto;
|
||||
display: block;
|
||||
}`
|
||||
}
|
||||
|
||||
if (config.copyByLongPress) {
|
||||
build.template = '<rich-text wx:if="{{n.attrs[\'data-content\']}}" nodes="{{[n]}}" data-content="{{n.attrs[\'data-content\']}}" data-lang="{{n.attrs[\'data-lang\']}}" bindlongpress="copyCode" />'
|
||||
build.methods = {
|
||||
copyCode (e) {
|
||||
wx.showActionSheet({
|
||||
itemList: ['复制代码'],
|
||||
success: () =>
|
||||
wx.setClipboardData({
|
||||
data: e.currentTarget.dataset.content
|
||||
})
|
||||
})
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
if (config.showLanguageName) {
|
||||
build.style = (build.style || '') +
|
||||
`.hl-language {
|
||||
font-size: 12px;
|
||||
font-weight: 600;
|
||||
position: absolute;
|
||||
right: 8px;
|
||||
text-align: right;
|
||||
top: 3px;
|
||||
}
|
||||
.hl-pre {
|
||||
padding-top: 1.5em;
|
||||
}`
|
||||
}
|
||||
|
||||
if (config.showLineNumber) {
|
||||
build.style = (build.style || '') +
|
||||
`.hl-pre {
|
||||
font-size: 14px;
|
||||
padding-left: 3.8em;
|
||||
counter-reset: linenumber;
|
||||
}
|
||||
.line-numbers-rows {
|
||||
position: absolute;
|
||||
pointer-events: none;
|
||||
top: ${config.showLanguageName ? 1.5 : 1}em;
|
||||
font-size: 100%;
|
||||
left: 0;
|
||||
width: 3em; /* works for line-numbers below 1000 lines */
|
||||
letter-spacing: -1px;
|
||||
border-right: 1px solid #999;
|
||||
-webkit-user-select: none;
|
||||
-moz-user-select: none;
|
||||
-ms-user-select: none;
|
||||
user-select: none;
|
||||
}
|
||||
.line-numbers-rows .span {
|
||||
display: block;
|
||||
counter-increment: linenumber;
|
||||
}
|
||||
.line-numbers-rows .span:before {
|
||||
content: counter(linenumber);
|
||||
color: #999;
|
||||
display: block;
|
||||
padding-right: 0.8em;
|
||||
text-align: right;
|
||||
}`
|
||||
}
|
||||
|
||||
module.exports = build
|
||||
@@ -0,0 +1,125 @@
|
||||
/* PrismJS 1.22.0
|
||||
https://prismjs.com/download.html#themes=prism-tomorrow&languages=markup+css+clike+javascript */
|
||||
/**
|
||||
* prism.js tomorrow night eighties for JavaScript, CoffeeScript, CSS and HTML
|
||||
* Based on https://github.com/chriskempson/tomorrow-theme
|
||||
* @author Rose Pritchard
|
||||
*/
|
||||
|
||||
code[class*="language-"],
|
||||
pre[class*="language-"] {
|
||||
color: #ccc;
|
||||
background: none;
|
||||
font-family: Consolas, Monaco, 'Andale Mono', 'Ubuntu Mono', monospace;
|
||||
font-size: 1em;
|
||||
text-align: left;
|
||||
white-space: pre;
|
||||
word-spacing: normal;
|
||||
word-break: normal;
|
||||
word-wrap: normal;
|
||||
line-height: 1.5;
|
||||
|
||||
-moz-tab-size: 4;
|
||||
-o-tab-size: 4;
|
||||
tab-size: 4;
|
||||
|
||||
-webkit-hyphens: none;
|
||||
-moz-hyphens: none;
|
||||
-ms-hyphens: none;
|
||||
hyphens: none;
|
||||
|
||||
}
|
||||
|
||||
/* Code blocks */
|
||||
pre[class*="language-"] {
|
||||
padding: 1em;
|
||||
margin: .5em 0;
|
||||
overflow: auto;
|
||||
}
|
||||
|
||||
:not(pre) > code[class*="language-"],
|
||||
pre[class*="language-"] {
|
||||
background: #2d2d2d;
|
||||
}
|
||||
|
||||
/* Inline code */
|
||||
:not(pre) > code[class*="language-"] {
|
||||
padding: .1em;
|
||||
border-radius: .3em;
|
||||
white-space: normal;
|
||||
}
|
||||
|
||||
.token.comment,
|
||||
.token.block-comment,
|
||||
.token.prolog,
|
||||
.token.doctype,
|
||||
.token.cdata {
|
||||
color: #999;
|
||||
}
|
||||
|
||||
.token.punctuation {
|
||||
color: #ccc;
|
||||
}
|
||||
|
||||
.token.tag,
|
||||
.token.attr-name,
|
||||
.token.namespace,
|
||||
.token.deleted {
|
||||
color: #e2777a;
|
||||
}
|
||||
|
||||
.token.function-name {
|
||||
color: #6196cc;
|
||||
}
|
||||
|
||||
.token.boolean,
|
||||
.token.number,
|
||||
.token.function {
|
||||
color: #f08d49;
|
||||
}
|
||||
|
||||
.token.property,
|
||||
.token.class-name,
|
||||
.token.constant,
|
||||
.token.symbol {
|
||||
color: #f8c555;
|
||||
}
|
||||
|
||||
.token.selector,
|
||||
.token.important,
|
||||
.token.atrule,
|
||||
.token.keyword,
|
||||
.token.builtin {
|
||||
color: #cc99cd;
|
||||
}
|
||||
|
||||
.token.string,
|
||||
.token.char,
|
||||
.token.attr-value,
|
||||
.token.regex,
|
||||
.token.variable {
|
||||
color: #7ec699;
|
||||
}
|
||||
|
||||
.token.operator,
|
||||
.token.entity,
|
||||
.token.url {
|
||||
color: #67cdcc;
|
||||
}
|
||||
|
||||
.token.important,
|
||||
.token.bold {
|
||||
font-weight: bold;
|
||||
}
|
||||
.token.italic {
|
||||
font-style: italic;
|
||||
}
|
||||
|
||||
.token.entity {
|
||||
cursor: help;
|
||||
}
|
||||
|
||||
.token.inserted {
|
||||
color: green;
|
||||
}
|
||||
|
||||
7
wechat-mini-program/components/mp-html/plugins/highlight/prism.min.js
vendored
Normal file
7
wechat-mini-program/components/mp-html/plugins/highlight/prism.min.js
vendored
Normal file
File diff suppressed because one or more lines are too long
@@ -0,0 +1,88 @@
|
||||
const config = require('../config')
|
||||
|
||||
const build = {
|
||||
import: 'prism.css',
|
||||
handler (file) {
|
||||
if (file.path.includes('prism.css')) {
|
||||
// 将标签名选择器和属性选择器转为 class 选择器(组件内仅支持 class 选择器)
|
||||
file.contents = Buffer.from(file.contents.toString().replace(/pre([[)])/g, '.hl-pre$1').replace(/code/g, '.hl-code').replace(/\[class\*="?language-"?\]/g, '').replace(/:not[^,}]+[,}]*/g, '').replace(/\.token\./g, '.hl-'))
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
if (config.showLanguageName || config.showLineNumber) {
|
||||
// pre 内部的 code 进行滚动,避免行号和语言名称跟随滚动
|
||||
build.style = `.hl-pre {
|
||||
position: relative;
|
||||
}
|
||||
.hl-code {
|
||||
overflow: auto;
|
||||
display: block;
|
||||
}`
|
||||
}
|
||||
|
||||
if (config.copyByLongPress) {
|
||||
build.template = '<rich-text v-if="n.attrs&&n.attrs[\'data-content\']" :nodes="[n]" :data-content="n.attrs[\'data-content\']" :data-lang="n.attrs[\'data-lang\']" @longpress="copyCode" />'
|
||||
build.methods = {
|
||||
copyCode (e) {
|
||||
uni.showActionSheet({
|
||||
itemList: ['复制代码'],
|
||||
success: () =>
|
||||
uni.setClipboardData({
|
||||
data: e.currentTarget.dataset.content
|
||||
})
|
||||
})
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
if (config.showLanguageName) {
|
||||
build.style = (build.style || '') +
|
||||
`.hl-language {
|
||||
font-size: 12px;
|
||||
font-weight: 600;
|
||||
position: absolute;
|
||||
right: 8px;
|
||||
text-align: right;
|
||||
top: 3px;
|
||||
}
|
||||
.hl-pre {
|
||||
padding-top: 1.5em;
|
||||
}`
|
||||
}
|
||||
|
||||
if (config.showLineNumber) {
|
||||
build.style = (build.style || '') +
|
||||
`.hl-pre {
|
||||
font-size: 14px;
|
||||
padding-left: 3.8em;
|
||||
counter-reset: linenumber;
|
||||
}
|
||||
.line-numbers-rows {
|
||||
position: absolute;
|
||||
pointer-events: none;
|
||||
top: ${config.showLanguageName ? 1.5 : 1}em;
|
||||
font-size: 100%;
|
||||
left: 0;
|
||||
width: 3em; /* works for line-numbers below 1000 lines */
|
||||
letter-spacing: -1px;
|
||||
border-right: 1px solid #999;
|
||||
-webkit-user-select: none;
|
||||
-moz-user-select: none;
|
||||
-ms-user-select: none;
|
||||
user-select: none;
|
||||
}
|
||||
.line-numbers-rows .span {
|
||||
display: block;
|
||||
counter-increment: linenumber;
|
||||
}
|
||||
.line-numbers-rows .span:before {
|
||||
content: counter(linenumber);
|
||||
color: #999;
|
||||
display: block;
|
||||
padding-right: 0.8em;
|
||||
text-align: right;
|
||||
}`
|
||||
}
|
||||
|
||||
module.exports = build
|
||||
Reference in New Issue
Block a user