This repository has been archived on 2023-08-30. You can view files and clone it, but cannot push or open issues/pull-requests.
bytedo
/
wcui
Archived
1
0
Fork 0

修复代码高亮的字符转义;优化js代码高亮逻辑

old
yutent 2023-01-12 17:03:23 +08:00
parent d0d09f0c9c
commit bcfdacce70
6 changed files with 84 additions and 61 deletions

View File

@ -7,18 +7,22 @@
const DOCTYPE_EXP = /<\!DOCTYPE html>/ const DOCTYPE_EXP = /<\!DOCTYPE html>/
const TAG_START_EXP = /<([\w\-]+)([\w\W]*?)>/g const TAG_START_EXP = /<([\w\-]+)([\w\W]*?)>/g
const TAG_END_EXP = /<\/([\w\-]+)>/g const TAG_END_EXP = /<\/([\w\-]+)>/g
const TAG_ATTR_EXP = /[@a-zA-Z\-.]+=(["'])[^"]+\1|[@a-zA-Z\-.]+=[a-zA-Z0-9]+|[@a-zA-Z\-.]+/g const TAG_ATTR_EXP =
/[@a-zA-Z\-.]+=(["'])[^"]+\1|[@a-zA-Z\-.]+=[a-zA-Z0-9]+|[@a-zA-Z\-.]+/g
const TAG_CM_EXP = /<!--([\w\W]*?)-->/g const TAG_CM_EXP = /<!--([\w\W]*?)-->/g
const SCRIPT_TAG = /(<script[^>]*?>)([\w\W]*?)(<\/script>)/g const SCRIPT_TAG = /(<script[^>]*?>)([\w\W]*?)(<\/script>)/g
const KEYWOWRD1 = /\b(var|const|let|function|for|switch|with|if|else|export|import|async|await|break|continue|return|class|try|catch|throw|new|while|this|super|default|case|debugger|delete|do|goto|in|static|get|set|public|private|protected|package|typeof|void)\b/g const KEYWOWRD1 =
const KEYWOWRD2 = /\b\s(=|-|\+|\/|\*|<|>|%)\s\b/g /\b(var|const|let|function|for|switch|with|if|else|export|import|from|async|await|break|continue|return|class|try|catch|throw|new|while|this|super|default|case|debugger|delete|do|goto|in|static|get|set|public|private|protected|package|typeof|void)\b/g
const KEYWOWRD3 = /(\+\=|-=|\/=|\*=|--|\+\+|==|===)/g const KEYWOWRD2 = /\s(=|-|\+|\/|\*|<|>|%)\s/g
const KEYWOWRD3 = /(\+\=|-=|\/=|\*=|--|\+\+|===|==|=>|\.\.\.|\.|&&|\|\|)/g
const BUILDIN1 = /\b(null|undefined|true|false|NaN|Infinity)\b/g const BUILDIN1 = /\b(null|undefined|true|false|NaN|Infinity)\b/g
const BUILDIN2 = /\b(Object|String|Array|Boolean|Number|Function|class)\b/g const BUILDIN2 =
const STR = /(['"`])(.*?)\1/g /\b(Object|String|Array|Boolean|Number|Function|class|Promise|Map|Set|WeakMap|WeakSet|URL)\b/g
const STR = /(['"`])(.*?)(?<!\\)\1/g
const NUM = /\b(\d+)\b/g const NUM = /\b(\d+)\b/g
const FN = /([\.\s])([a-zA-Z$][\da-zA-Z_]*)(\(.*?\))/g const FN = /([\.\s])([a-zA-Z$][\da-zA-Z_]*)(\(.*?\))/g
const CM = /(?=\s)?([ ]*\/\/.*)|(^\/\/.*)/g const CM = /(?=\s)?([ ]*\/\/.*)|(^\/\/.*)/g
const EXP = /([=\(][ ]*)\/(.+?)\/([gmi]*)/g
const INLINE = { const INLINE = {
code: /`([^`]*?[^`\\\s])`/g, code: /`([^`]*?[^`\\\s])`/g,
codeBlock: /^```(.*?)$/gm, codeBlock: /^```(.*?)$/gm,
@ -37,7 +41,15 @@ const INLINE = {
} }
function parseJs(code) { function parseJs(code) {
// console.log(code)
return code return code
.replace(EXP, (m, pun, str, flag) => {
str = str.replace(/&/g, '&amp;').replace(/(\\.)/g, '[fn]$1[/fn]')
return `${pun}[type]/[/type][cm]${str}[/cm][type]/[/type]${
flag ? `[num]${flag}[/num]` : ''
}`
})
.replace(FN, '$1[fn]$2[/fn]$3') .replace(FN, '$1[fn]$2[/fn]$3')
.replace(KEYWOWRD1, '[key]$1[/key]') .replace(KEYWOWRD1, '[key]$1[/key]')
.replace(KEYWOWRD2, ' [key]$1[/key] ') .replace(KEYWOWRD2, ' [key]$1[/key] ')
@ -45,12 +57,22 @@ function parseJs(code) {
.replace(BUILDIN1, '[num]<em>$1</em>[/num]') .replace(BUILDIN1, '[num]<em>$1</em>[/num]')
.replace(BUILDIN2, '[type]<strong><em>$1</em></strong>[/type]') .replace(BUILDIN2, '[type]<strong><em>$1</em></strong>[/type]')
.replace(NUM, '[num]$1[/num]') .replace(NUM, '[num]$1[/num]')
.replace(STR, (m, q, str) => { .replace(STR, (m, pun, str) => {
str = str.replace(/\[(\w+)\](.*?)\[\/\1\]/g, '$2') str = str
return `[str]${q}${str}${q}[/str]` .replace(/\[(\w+)\](.*?)\[\/\1\]/g, '$2')
.replace(/&/g, '&amp;')
.replace(/</g, '&lt;')
.replace(/>/g, '&gt;')
.replace(/(\\.)/g, '[fn]$1[/fn]')
return `[cm]${pun}[/cm][str]${str}[/str][cm]${pun}[/cm]`
}) })
.replace(CM, (m, str) => { .replace(CM, (m, str) => {
str = str.replace(/\[(\w+)\](.*?)\[\/\1\]/g, '$2') str = str
.replace(/\[(\w+)\](.*?)\[\/\1\]/g, '$2')
.replace(/&/g, '&amp;')
.replace(/</g, '&lt;')
.replace(/>/g, '&gt;')
return `[cm]${str}[/cm]` return `[cm]${str}[/cm]`
}) })
} }

View File

@ -78,6 +78,7 @@
} }
.scroll { .scroll {
overflow: hidden;
flex: 1; flex: 1;
padding: 5px 0 0; padding: 5px 0 0;
line-height: 20px; line-height: 20px;
@ -112,10 +113,10 @@
} }
.r { .r {
color: var(--color-red-1); color: var(--color-red-2);
} }
.b { .b {
color: var(--color-blue-1); color: var(--color-blue-2);
} }
.g { .g {
color: var(--color-green-2); color: var(--color-green-2);
@ -124,10 +125,10 @@
color: var(--color-grey-2); color: var(--color-grey-2);
} }
.o { .o {
color: var(--color-orange-2); color: var(--color-orange-1);
} }
.pp { .pp {
color: #6a1ea8; color: #a46ad3;
} }
.link { .link {
font-style: italic; font-style: italic;
@ -207,11 +208,6 @@ export default class Code {
} }
set code(txt) { set code(txt) {
txt = txt
.replace(/&amp;/g, '&')
.replace(/&lt;/g, '<')
.replace(/&gt;/g, '>')
this.state.content = txt this.state.content = txt
switch (this.props.lang) { switch (this.props.lang) {

View File

@ -309,7 +309,9 @@ function renderToolbar(list) {
it => it =>
`<span data-act="${it}"><svg class="icon" viewBox="0 0 1024 1024"><path d="${ `<span data-act="${it}"><svg class="icon" viewBox="0 0 1024 1024"><path d="${
ICONS[it] ICONS[it]
}"/></svg>${it === 'image' ? '<input type="file">' : ''}</span>` }"/></svg>${
it === 'image' ? '<input type="file" accept="image/*">' : ''
}</span>`
) )
.join('') + .join('') +
`<span data-act="copy"><svg class="icon" viewBox="0 0 1024 1024"><path d="${ICONS.copy}"/></svg></span>` `<span data-act="copy"><svg class="icon" viewBox="0 0 1024 1024"><path d="${ICONS.copy}"/></svg></span>`

View File

@ -108,12 +108,18 @@ export default {
}, },
image(elem) { image(elem) {
var $file = this.__ATTACH_ADDON__.querySelector('input')
this._attach = 'image' this._attach = 'image'
$file.setAttribute('accept', 'image/*')
showDialog(this.__ATTACH_ADDON__, elem) showDialog(this.__ATTACH_ADDON__, elem)
}, },
attach(elem) { attach(elem) {
var $file = this.__ATTACH_ADDON__.querySelector('input')
this._attach = 'file' this._attach = 'file'
$file.removeAttribute('accept')
showDialog(this.__ATTACH_ADDON__, elem) showDialog(this.__ATTACH_ADDON__, elem)
}, },

View File

@ -107,8 +107,6 @@ export const TOOL_TITLE = {
preview: '预览' preview: '预览'
} }
export const IMAGE_EXP = /image\/(jpeg|gif|png|webp|bmp|vnd\.microsoft\.icon|svg\+xml)/
const LI_EXP = /<(ul|ol)>(?:(?!<ul|<ol)[\s\S])*?<\/\1>/gi const LI_EXP = /<(ul|ol)>(?:(?!<ul|<ol)[\s\S])*?<\/\1>/gi
// html标签的属性正则 // html标签的属性正则
@ -136,9 +134,7 @@ export function renderToolbar(list, tag = 'span', dict = {}, showText = false) {
var title = showText ? '' : `title="${dict[it] || ''}"` var title = showText ? '' : `title="${dict[it] || ''}"`
var text = showText ? dict[it] || '' : '' var text = showText ? dict[it] || '' : ''
return `<${tag} data-act="${it}" ${title}><svg class="icon" viewBox="0 0 1024 1024"><path d="${ return `<${tag} data-act="${it}" ${title}><svg class="icon" viewBox="0 0 1024 1024"><path d="${ICONS[it]}"/></svg>${text}</${tag}>`
ICONS[it]
}"/></svg>${text}</${tag}>`
}) })
.join('') .join('')
} }
@ -189,11 +185,9 @@ export function html2md(str) {
while (str.match(LI_EXP)) { while (str.match(LI_EXP)) {
str = str.replace(LI_EXP, function (match) { str = str.replace(LI_EXP, function (match) {
match = match.replace(/<(ul|ol)>([\s\S]*?)<\/\1>/gi, function( match = match.replace(
m, /<(ul|ol)>([\s\S]*?)<\/\1>/gi,
t, function (m, t, inner) {
inner
) {
let li = inner.split('</li>') let li = inner.split('</li>')
li.pop() li.pop()
@ -209,7 +203,8 @@ export function html2md(str) {
.replace(/<[\/]?[\w]*[^>]*>/g, '') .replace(/<[\/]?[\w]*[^>]*>/g, '')
} }
return li.join('\n') return li.join('\n')
}) }
)
return '\n' + match.trim() return '\n' + match.trim()
}) })
} }

View File

@ -377,7 +377,7 @@ import '../form/radio'
import '../layer/index' import '../layer/index'
import '../markd/index' import '../markd/index'
import { renderToolbar, html2md, TOOL_TITLE, IMAGE_EXP } from './helper' import { renderToolbar, html2md, TOOL_TITLE } from './helper'
import Addon from './addon' import Addon from './addon'
export default class Meditor { export default class Meditor {
@ -606,8 +606,10 @@ export default class Meditor {
var file = ev.dataTransfer.files[0] var file = ev.dataTransfer.files[0]
if (file) { if (file) {
if (this._attach === 'image') { if (this._attach === 'image') {
if (IMAGE_EXP.test(file.type)) { if (file.type.includes('image')) {
this._handleUpload(file) this._handleUpload(file)
} else {
layer.toast('只支持图片格式', 'warning')
} }
} else { } else {
this._handleUpload(file, '') this._handleUpload(file, '')
@ -621,7 +623,7 @@ export default class Meditor {
if (file) { if (file) {
ev.target.value = '' ev.target.value = ''
if (this._attach === 'image') { if (this._attach === 'image') {
if (IMAGE_EXP.test(file.type)) { if (file.type.includes('image')) {
this._handleUpload(file) this._handleUpload(file)
} }
} else { } else {
@ -964,7 +966,7 @@ export default class Meditor {
break break
} }
if (file) { if (file) {
if (IMAGE_EXP.test(file.type)) { if (file.type.includes('image')) {
this._handleUpload(file) this._handleUpload(file)
} else { } else {
this._handleUpload(file, '') this._handleUpload(file, '')