From 178a6acddd38c17ec109a194139bba175428a64b Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?sunsonliu=28=E5=88=98=E9=98=B3=29?= Date: Sun, 18 Dec 2022 00:00:00 +0800 Subject: [PATCH 1/2] =?UTF-8?q?fix:=20=E8=B7=A8=E5=8D=95=E5=85=83=E6=A0=BC?= =?UTF-8?q?=E7=9A=84=E8=A1=8C=E5=86=85=E5=85=AC=E5=BC=8F=E3=80=81=E8=A1=8C?= =?UTF-8?q?=E5=86=85=E4=BB=A3=E7=A0=81=E8=AF=AD=E6=B3=95=E6=94=B9=E6=88=90?= =?UTF-8?q?=E4=B8=8D=E7=94=9F=E6=95=88?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- src/core/hooks/CodeBlock.js | 34 +++++++++++++++++++++++++--------- src/core/hooks/InlineMath.js | 17 ++++++++++++++++- src/utils/regexp.js | 5 +++-- 3 files changed, 44 insertions(+), 12 deletions(-) diff --git a/src/core/hooks/CodeBlock.js b/src/core/hooks/CodeBlock.js index 7e4c6cc19..313567463 100644 --- a/src/core/hooks/CodeBlock.js +++ b/src/core/hooks/CodeBlock.js @@ -16,7 +16,7 @@ import ParagraphBase from '@/core/ParagraphBase'; import Prism from 'prismjs'; import { escapeHTMLSpecialChar } from '@/utils/sanitize'; -import { getCodeBlockRule } from '@/utils/regexp'; +import { getTableRule, getCodeBlockRule } from '@/utils/regexp'; import { prependLineFeedForParagraph } from '@/utils/lineFeed'; Prism.manual = true; @@ -39,6 +39,7 @@ export default class CodeBlock extends ParagraphBase { this.lineNumber = config.lineNumber; // 是否显示行号 this.copyCode = config.copyCode; // 是否显示“复制”按钮 this.indentedCodeBlock = typeof config.indentedCodeBlock === 'undefined' ? true : config.indentedCodeBlock; // 是否支持缩进代码块 + this.INLINE_CODE_REGEX = /(`+)(.+?(?:\n.+?)*?)\1/g; if (config && config.customRenderer) { this.customLang = Object.keys(config.customRenderer).map((lang) => lang.toLowerCase()); this.customParser = { ...config.customRenderer }; @@ -266,7 +267,7 @@ export default class CodeBlock extends ParagraphBase { // 预处理缩进代码块 $str = this.$replaceCodeInIndent($str); - $str = $str.replace(this.RULE.reg, (match, leadingContent, lang, code) => { + $str = $str.replace(this.RULE.reg, (match, leadingContent, begin, lang, code) => { let $code = code; const { sign, lines } = this.computeLines(match, leadingContent, code); // 从缓存中获取html @@ -311,12 +312,31 @@ export default class CodeBlock extends ParagraphBase { cacheCode = this.$codeCache(sign, cacheCode); return this.getCacheWithSpace(this.pushCache(cacheCode, sign, lines), match); }); + // 表格里处理行内代码,让一个td里的行内代码语法生效,让跨td的行内代码语法失效 + $str = $str.replace(getTableRule(true), (whole, ...args) => { + return whole + .split('|') + .map((oneTd) => { + return this.makeInlineCode(oneTd); + }) + .join('|') + .replace(/`/g, '\\`'); + }); // 为了避免InlineCode被HtmlBlock转义,需要在这里提前缓存 // InlineBlock只需要在afterMakeHtml还原即可 - const INLINE_CODE_REGEX = /(`+)(.+?(?:\n.+?)*?)\1/g; - if (INLINE_CODE_REGEX.test($str)) { + $str = this.makeInlineCode($str); + + // 处理缩进代码块 + $str = this.$getIndentCodeBlock($str); + + return $str; + } + + makeInlineCode(str) { + let $str = str; + if (this.INLINE_CODE_REGEX.test($str)) { $str = $str.replace(/\\`/g, '~~not~inlineCode'); - $str = $str.replace(INLINE_CODE_REGEX, (match, syntax, code) => { + $str = $str.replace(this.INLINE_CODE_REGEX, (match, syntax, code) => { if (code.trim() === '`') { return match; } @@ -330,10 +350,6 @@ export default class CodeBlock extends ParagraphBase { }); $str = $str.replace(/~~not~inlineCode/g, '\\`'); } - - // 处理缩进代码块 - $str = this.$getIndentCodeBlock($str); - return $str; } diff --git a/src/core/hooks/InlineMath.js b/src/core/hooks/InlineMath.js index 9c8040025..829feb896 100644 --- a/src/core/hooks/InlineMath.js +++ b/src/core/hooks/InlineMath.js @@ -17,7 +17,7 @@ import ParagraphBase from '@/core/ParagraphBase'; import { escapeFormulaPunctuations, LoadMathModule } from '@/utils/mathjax'; import { getHTML } from '@/utils/dom'; import { isBrowser } from '@/utils/env'; -import { isLookbehindSupported } from '@/utils/regexp'; +import { getTableRule, isLookbehindSupported } from '@/utils/regexp'; import { replaceLookbehind } from '@/utils/lookbehind-replace'; /** @@ -67,6 +67,21 @@ export default class InlineMath extends ParagraphBase { } beforeMakeHtml(str) { + let $str = str; + // 格里处理行内公式,让一个td里的行内公式语法生效,让跨td的行内公式语法失效 + $str = $str.replace(getTableRule(true), (whole, ...args) => { + return whole + .split('|') + .map((oneTd) => { + return this.makeInlineMath(oneTd); + }) + .join('|') + .replace(/~D/g, '\\~D'); + }); + return this.makeInlineMath($str); + } + + makeInlineMath(str) { if (!this.test(str)) { return str; } diff --git a/src/utils/regexp.js b/src/utils/regexp.js index 4e27aa0a6..a6cd84bb0 100644 --- a/src/utils/regexp.js +++ b/src/utils/regexp.js @@ -159,10 +159,11 @@ export function getCodeBlockRule() { * (?:^|\n)是区块的通用开头 * (\n*)捕获区块前的所有换行 * (?:[^\S\n]*)捕获```前置的空格字符 + * 只要有连续3个及以上`并且前后`的数量相等,则认为是代码快语法 */ - begin: /(?:^|\n)(\n*(?:[^\S\n]*))```([^`]*?)\n/, + begin: /(?:^|\n)(\n*(?:[^\S\n]*))(`{3,})([^`]*?)\n/, content: /([\w\W]*?)/, // '([\\w\\W]*?)', - end: /[^\S\n]*```[ \t]*(?=$|\n+)/, // '\\s*```[ \\t]*(?=$|\\n+)', + end: /[^\S\n]*\2[ \t]*(?=$|\n+)/, // '\\s*```[ \\t]*(?=$|\\n+)', }; codeBlock.reg = new RegExp(codeBlock.begin.source + codeBlock.content.source + codeBlock.end.source, 'g'); return codeBlock; From c3476407f5dd12ae85cd0069c18b44d0c09fbe12 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?sunsonliu=28=E5=88=98=E9=98=B3=29?= Date: Sun, 18 Dec 2022 00:17:45 +0800 Subject: [PATCH 2/2] =?UTF-8?q?feat:=20#370=20=E5=A2=9E=E5=8A=A0refreshPre?= =?UTF-8?q?viewer=E6=96=B9=E6=B3=95=EF=BC=8C=E5=8F=AF=E4=BB=A5=E5=BC=BA?= =?UTF-8?q?=E5=88=B6=E9=87=8D=E6=96=B0=E6=B8=B2=E6=9F=93=E9=A2=84=E8=A7=88?= =?UTF-8?q?=E5=8C=BA=E5=9F=9F?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- src/Cherry.js | 13 +++++++++++++ src/Previewer.js | 8 ++++++++ 2 files changed, 21 insertions(+) diff --git a/src/Cherry.js b/src/Cherry.js index d740f7468..2233ffcdc 100644 --- a/src/Cherry.js +++ b/src/Cherry.js @@ -338,6 +338,19 @@ export default class Cherry extends CherryStatic { return this.insert(content, isSelect, anchor, focus); } + /** + * 强制重新渲染预览区域 + */ + refreshPreviewer() { + try { + const markdownText = this.getValue(); + const html = this.engine.makeHtml(markdownText); + this.previewer.refresh(html); + } catch (e) { + throw new NestedError(e); + } + } + /** * 覆盖编辑区的内容 * @param {string} content markdown内容 diff --git a/src/Previewer.js b/src/Previewer.js index 03bf50967..3282c6708 100644 --- a/src/Previewer.js +++ b/src/Previewer.js @@ -643,6 +643,14 @@ export default class Previewer { } } + /** + * 强制重新渲染预览区域 + */ + refresh(html) { + const domContainer = this.getDomContainer(); + domContainer.innerHTML = html; + } + update(html) { // 更新时保留图片懒加载逻辑 const newHtml = this.lazyLoadImg.changeSrc2DataSrc(html);