修复代码高亮的字符转义;优化js代码高亮逻辑
parent
d0d09f0c9c
commit
bcfdacce70
|
@ -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,20 +41,38 @@ 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, '&').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] ')
|
||||||
.replace(KEYWOWRD3, '[key]$1[/key]')
|
.replace(KEYWOWRD3, '[key]$1[/key]')
|
||||||
.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, '&')
|
||||||
|
.replace(/</g, '<')
|
||||||
|
.replace(/>/g, '>')
|
||||||
|
.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, '&')
|
||||||
|
.replace(/</g, '<')
|
||||||
|
.replace(/>/g, '>')
|
||||||
return `[cm]${str}[/cm]`
|
return `[cm]${str}[/cm]`
|
||||||
})
|
})
|
||||||
}
|
}
|
||||||
|
@ -109,7 +131,7 @@ export function colorHtml(code) {
|
||||||
})
|
})
|
||||||
.replace(TAG_START_EXP, (m, tag, attr) => {
|
.replace(TAG_START_EXP, (m, tag, attr) => {
|
||||||
if (attr) {
|
if (attr) {
|
||||||
attr = attr.replace(TAG_ATTR_EXP, function(t) {
|
attr = attr.replace(TAG_ATTR_EXP, function (t) {
|
||||||
if (~t.indexOf('=')) {
|
if (~t.indexOf('=')) {
|
||||||
t = t.split('=')
|
t = t.split('=')
|
||||||
let a = t.shift()
|
let a = t.shift()
|
||||||
|
|
|
@ -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(/&/g, '&')
|
|
||||||
.replace(/</g, '<')
|
|
||||||
.replace(/>/g, '>')
|
|
||||||
|
|
||||||
this.state.content = txt
|
this.state.content = txt
|
||||||
|
|
||||||
switch (this.props.lang) {
|
switch (this.props.lang) {
|
||||||
|
|
|
@ -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>`
|
||||||
|
|
|
@ -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)
|
||||||
},
|
},
|
||||||
|
|
||||||
|
|
|
@ -7,7 +7,7 @@
|
||||||
import ICONS from './svg'
|
import ICONS from './svg'
|
||||||
|
|
||||||
const ELEMS = {
|
const ELEMS = {
|
||||||
a: function(str, attr, inner) {
|
a: function (str, attr, inner) {
|
||||||
let href = attr.match(attrExp('href'))
|
let href = attr.match(attrExp('href'))
|
||||||
let title = attr.match(attrExp('title'))
|
let title = attr.match(attrExp('title'))
|
||||||
let tar = attr.match(attrExp('target'))
|
let tar = attr.match(attrExp('target'))
|
||||||
|
@ -27,23 +27,23 @@ const ELEMS = {
|
||||||
|
|
||||||
return `[${inner || href}](${href} "${attrs}")`
|
return `[${inner || href}](${href} "${attrs}")`
|
||||||
},
|
},
|
||||||
em: function(str, attr, inner) {
|
em: function (str, attr, inner) {
|
||||||
return (inner && '_' + inner + '_') || ''
|
return (inner && '_' + inner + '_') || ''
|
||||||
},
|
},
|
||||||
strong: function(str, attr, inner) {
|
strong: function (str, attr, inner) {
|
||||||
return (inner && '**' + inner + '**') || ''
|
return (inner && '**' + inner + '**') || ''
|
||||||
},
|
},
|
||||||
pre: function(str, attr, inner) {
|
pre: function (str, attr, inner) {
|
||||||
inner = inner.replace(/<[/]?code>/g, '')
|
inner = inner.replace(/<[/]?code>/g, '')
|
||||||
return '\n\n```\n' + inner + '\n```\n'
|
return '\n\n```\n' + inner + '\n```\n'
|
||||||
},
|
},
|
||||||
code: function(str, attr, inner) {
|
code: function (str, attr, inner) {
|
||||||
return (inner && '`' + inner + '`') || ''
|
return (inner && '`' + inner + '`') || ''
|
||||||
},
|
},
|
||||||
blockquote: function(str, attr, inner) {
|
blockquote: function (str, attr, inner) {
|
||||||
return '> ' + inner.trim()
|
return '> ' + inner.trim()
|
||||||
},
|
},
|
||||||
img: function(str, attr, inner) {
|
img: function (str, attr, inner) {
|
||||||
var src = attr.match(attrExp('src')),
|
var src = attr.match(attrExp('src')),
|
||||||
alt = attr.match(attrExp('alt'))
|
alt = attr.match(attrExp('alt'))
|
||||||
|
|
||||||
|
@ -52,11 +52,11 @@ const ELEMS = {
|
||||||
|
|
||||||
return '![' + alt + '](' + src + ')'
|
return '![' + alt + '](' + src + ')'
|
||||||
},
|
},
|
||||||
p: function(str, attr, inner) {
|
p: function (str, attr, inner) {
|
||||||
return inner ? '\n' + inner : ''
|
return inner ? '\n' + inner : ''
|
||||||
},
|
},
|
||||||
br: '\n',
|
br: '\n',
|
||||||
'h([1-6])': function(str, level, attr, inner) {
|
'h([1-6])': function (str, level, attr, inner) {
|
||||||
let h = '#'.repeat(level)
|
let h = '#'.repeat(level)
|
||||||
return '\n' + h + ' ' + inner + '\n'
|
return '\n' + h + ' ' + inner + '\n'
|
||||||
},
|
},
|
||||||
|
@ -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('')
|
||||||
}
|
}
|
||||||
|
@ -188,35 +184,34 @@ 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>')
|
||||||
) {
|
li.pop()
|
||||||
let li = inner.split('</li>')
|
|
||||||
li.pop()
|
|
||||||
|
|
||||||
for (let i = 0, len = li.length; i < len; i++) {
|
for (let i = 0, len = li.length; i < len; i++) {
|
||||||
let pre = t === 'ol' ? i + 1 + '. ' : '* '
|
let pre = t === 'ol' ? i + 1 + '. ' : '* '
|
||||||
li[i] =
|
li[i] =
|
||||||
pre +
|
pre +
|
||||||
li[i]
|
li[i]
|
||||||
.replace(/\s*<li>([\s\S]*)/i, function(m, n) {
|
.replace(/\s*<li>([\s\S]*)/i, function (m, n) {
|
||||||
n = n.trim().replace(/\n/g, '\n ')
|
n = n.trim().replace(/\n/g, '\n ')
|
||||||
return n
|
return n
|
||||||
})
|
})
|
||||||
.replace(/<[\/]?[\w]*[^>]*>/g, '')
|
.replace(/<[\/]?[\w]*[^>]*>/g, '')
|
||||||
|
}
|
||||||
|
return li.join('\n')
|
||||||
}
|
}
|
||||||
return li.join('\n')
|
)
|
||||||
})
|
|
||||||
return '\n' + match.trim()
|
return '\n' + match.trim()
|
||||||
})
|
})
|
||||||
}
|
}
|
||||||
str = str
|
str = str
|
||||||
|
|
||||||
.replace(/<[\/]?[\w]*[^>]*>/g, '')
|
.replace(/<[\/]?[\w]*[^>]*>/g, '')
|
||||||
.replace(/```([\w\W]*)```/g, function(str, inner) {
|
.replace(/```([\w\W]*)```/g, function (str, inner) {
|
||||||
inner = inner
|
inner = inner
|
||||||
.replace(/&/g, '&')
|
.replace(/&/g, '&')
|
||||||
.replace(/</g, '<')
|
.replace(/</g, '<')
|
||||||
|
|
|
@ -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, '')
|
||||||
|
|
Reference in New Issue