@cherry-markdown/cherry-markdown-dev 0.8.58-dev
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/package.json +149 -0
- package/src/Cherry.config.js +625 -0
- package/src/Cherry.js +1104 -0
- package/src/CherryStatic.js +70 -0
- package/src/Editor.js +748 -0
- package/src/Engine.js +381 -0
- package/src/Event.js +140 -0
- package/src/Factory.js +180 -0
- package/src/Logger.js +31 -0
- package/src/Previewer.js +1183 -0
- package/src/Sanitizer.js +4 -0
- package/src/Sanitizer.node.js +7 -0
- package/src/UrlCache.js +98 -0
- package/src/addons/advance/cherry-table-echarts-plugin.js +170 -0
- package/src/addons/cherry-code-block-mermaid-plugin.js +158 -0
- package/src/addons/cherry-code-block-plantuml-plugin.js +106 -0
- package/src/core/HookCenter.js +297 -0
- package/src/core/HooksConfig.js +100 -0
- package/src/core/ParagraphBase.js +332 -0
- package/src/core/SentenceBase.js +65 -0
- package/src/core/SyntaxBase.js +194 -0
- package/src/core/hooks/AutoLink.js +232 -0
- package/src/core/hooks/BackgroundColor.js +46 -0
- package/src/core/hooks/Blockquote.js +70 -0
- package/src/core/hooks/Br.js +85 -0
- package/src/core/hooks/CodeBlock.js +446 -0
- package/src/core/hooks/Color.js +46 -0
- package/src/core/hooks/CommentReference.js +96 -0
- package/src/core/hooks/Detail.js +108 -0
- package/src/core/hooks/Emoji.config.js +1825 -0
- package/src/core/hooks/Emoji.js +119 -0
- package/src/core/hooks/Emphasis.js +113 -0
- package/src/core/hooks/Footnote.js +125 -0
- package/src/core/hooks/FrontMatter.js +51 -0
- package/src/core/hooks/Header.js +234 -0
- package/src/core/hooks/HighLight.js +37 -0
- package/src/core/hooks/Hr.js +52 -0
- package/src/core/hooks/HtmlBlock.js +184 -0
- package/src/core/hooks/Image.js +174 -0
- package/src/core/hooks/InlineCode.js +48 -0
- package/src/core/hooks/InlineMath.js +107 -0
- package/src/core/hooks/Link.js +160 -0
- package/src/core/hooks/List.js +264 -0
- package/src/core/hooks/MathBlock.js +103 -0
- package/src/core/hooks/Panel.js +145 -0
- package/src/core/hooks/Paragraph.js +84 -0
- package/src/core/hooks/Ruby.js +34 -0
- package/src/core/hooks/Size.js +51 -0
- package/src/core/hooks/Strikethrough.js +54 -0
- package/src/core/hooks/Sub.js +47 -0
- package/src/core/hooks/SuggestList.js +333 -0
- package/src/core/hooks/Suggester.js +707 -0
- package/src/core/hooks/Sup.js +47 -0
- package/src/core/hooks/Table.js +275 -0
- package/src/core/hooks/Toc.js +292 -0
- package/src/core/hooks/Transfer.js +47 -0
- package/src/core/hooks/Underline.js +37 -0
- package/src/index.core.js +29 -0
- package/src/index.engine.core.js +68 -0
- package/src/index.engine.js +28 -0
- package/src/index.js +32 -0
- package/src/libs/mermaidAPI.8.4.8.js +1 -0
- package/src/libs/mermaidAPI.8.5.2.js +42 -0
- package/src/libs/rawdeflate.js +1663 -0
- package/src/locales/en_US.js +139 -0
- package/src/locales/index.js +25 -0
- package/src/locales/ru_RU.js +139 -0
- package/src/locales/zh_CN.js +142 -0
- package/src/sass/base.scss +26 -0
- package/src/sass/bubble_formula.scss +166 -0
- package/src/sass/ch-icon.scss +118 -0
- package/src/sass/cherry.scss +1116 -0
- package/src/sass/components/bubble.scss +173 -0
- package/src/sass/components/shortcut_key_config.scss +108 -0
- package/src/sass/formula_utils_bubble.scss +82 -0
- package/src/sass/icon_template.scss +24 -0
- package/src/sass/icons/uEA03-list.svg +19 -0
- package/src/sass/icons/uEA04-check.svg +14 -0
- package/src/sass/icons/uEA09-square.svg +10 -0
- package/src/sass/icons/uEA0A-bold.svg +20 -0
- package/src/sass/icons/uEA0B-code.svg +18 -0
- package/src/sass/icons/uEA0C-color.svg +13 -0
- package/src/sass/icons/uEA0D-header.svg +8 -0
- package/src/sass/icons/uEA0E-image.svg +15 -0
- package/src/sass/icons/uEA0F-italic.svg +8 -0
- package/src/sass/icons/uEA10-link.svg +16 -0
- package/src/sass/icons/uEA11-ol.svg +21 -0
- package/src/sass/icons/uEA12-size.svg +11 -0
- package/src/sass/icons/uEA13-strike.svg +16 -0
- package/src/sass/icons/uEA14-table.svg +12 -0
- package/src/sass/icons/uEA15-ul.svg +17 -0
- package/src/sass/icons/uEA16-underline.svg +13 -0
- package/src/sass/icons/uEA17-word.svg +16 -0
- package/src/sass/icons/uEA18-blockquote.svg +11 -0
- package/src/sass/icons/uEA19-font.svg +10 -0
- package/src/sass/icons/uEA1F-insertClass.svg +39 -0
- package/src/sass/icons/uEA20-insertFlow.svg +8 -0
- package/src/sass/icons/uEA21-insertFormula.svg +23 -0
- package/src/sass/icons/uEA22-insertGantt.svg +13 -0
- package/src/sass/icons/uEA23-insertGraph.svg +13 -0
- package/src/sass/icons/uEA24-insertPie.svg +19 -0
- package/src/sass/icons/uEA25-insertSeq.svg +20 -0
- package/src/sass/icons/uEA26-insertState.svg +35 -0
- package/src/sass/icons/uEA27-line.svg +11 -0
- package/src/sass/icons/uEA28-preview.svg +18 -0
- package/src/sass/icons/uEA29-previewClose.svg +24 -0
- package/src/sass/icons/uEA2A-toc.svg +24 -0
- package/src/sass/icons/uEA2D-sub.svg +15 -0
- package/src/sass/icons/uEA2E-sup.svg +15 -0
- package/src/sass/icons/uEA2F-h1.svg +16 -0
- package/src/sass/icons/uEA30-h2.svg +20 -0
- package/src/sass/icons/uEA31-h3.svg +23 -0
- package/src/sass/icons/uEA32-h4.svg +16 -0
- package/src/sass/icons/uEA33-h5.svg +20 -0
- package/src/sass/icons/uEA34-h6.svg +17 -0
- package/src/sass/icons/uEA35-video.svg +20 -0
- package/src/sass/icons/uEA36-insert.svg +25 -0
- package/src/sass/icons/uEA37-little_table.svg +30 -0
- package/src/sass/icons/uEA38-pdf.svg +27 -0
- package/src/sass/icons/uEA39-checklist.svg +22 -0
- package/src/sass/icons/uEA40-close.svg +12 -0
- package/src/sass/icons/uEA41-fullscreen.svg +81 -0
- package/src/sass/icons/uEA42-minscreen.svg +77 -0
- package/src/sass/icons/uEA43-insertChart.svg +23 -0
- package/src/sass/icons/uEA44-question.svg +25 -0
- package/src/sass/icons/uEA45-settings.svg +32 -0
- package/src/sass/icons/uEA46-ok.svg +7 -0
- package/src/sass/icons/uEA47-br.svg +22 -0
- package/src/sass/icons/uEA48-normal.svg +15 -0
- package/src/sass/icons/uEA49-undo.svg +19 -0
- package/src/sass/icons/uEA50-redo.svg +21 -0
- package/src/sass/icons/uEA51-copy.svg +6 -0
- package/src/sass/icons/uEA52-phone.svg +5 -0
- package/src/sass/icons/uEA53-cherry-table-delete.svg +17 -0
- package/src/sass/icons/uEA54-cherry-table-insert-bottom.svg +16 -0
- package/src/sass/icons/uEA55-cherry-table-insert-left.svg +15 -0
- package/src/sass/icons/uEA56-cherry-table-insert-right.svg +16 -0
- package/src/sass/icons/uEA57-cherry-table-insert-top.svg +16 -0
- package/src/sass/icons/uEA58-sort-s.svg +13 -0
- package/src/sass/icons/uEA59-pinyin.svg +1 -0
- package/src/sass/icons/uEA5A-create.svg +24 -0
- package/src/sass/icons/uEA5B-download.svg +34 -0
- package/src/sass/icons/uEA5C-edit.svg +3 -0
- package/src/sass/icons/uEA5D-export.svg +53 -0
- package/src/sass/icons/uEA5E-folder-open.svg +3 -0
- package/src/sass/icons/uEA5F-folder.svg +3 -0
- package/src/sass/icons/uEA60-help.svg +5 -0
- package/src/sass/icons/uEA61-pen-fill.svg +13 -0
- package/src/sass/icons/uEA62-pen.svg +3 -0
- package/src/sass/icons/uEA64-tips.svg +5 -0
- package/src/sass/icons/uEA65-warn.svg +5 -0
- package/src/sass/icons/uEA66-mistake.svg +4 -0
- package/src/sass/icons/uEA67-success.svg +4 -0
- package/src/sass/icons/uEA68-danger.svg +4 -0
- package/src/sass/icons/uEA69-info.svg +5 -0
- package/src/sass/icons/uEA6A-primary.svg +5 -0
- package/src/sass/icons/uEA6B-warning.svg +5 -0
- package/src/sass/icons/uEA6C-justify.svg +19 -0
- package/src/sass/icons/uEA6D-justifyCenter.svg +19 -0
- package/src/sass/icons/uEA6E-justifyLeft.svg +19 -0
- package/src/sass/icons/uEA6F-justifyRight.svg +19 -0
- package/src/sass/icons/uEA70-chevronsLeft.svg +1 -0
- package/src/sass/icons/uEA71-chevronsRight.svg +1 -0
- package/src/sass/icons/uEA72-trendingUp.svg +1 -0
- package/src/sass/icons/uEA74-codeBlock.svg +1 -0
- package/src/sass/icons/uEA75-expand.svg +3 -0
- package/src/sass/icons/uEA76-unExpand.svg +3 -0
- package/src/sass/icons/uEA77-swap-vert.svg +1 -0
- package/src/sass/icons/uEA78-swap.svg +1 -0
- package/src/sass/icons/uEA79-keyboard.svg +1 -0
- package/src/sass/icons/uEA7A-command.svg +1 -0
- package/src/sass/icons/uEA7B-search.svg +1 -0
- package/src/sass/index.scss +3 -0
- package/src/sass/markdown.scss +668 -0
- package/src/sass/markdown_pure.scss +9 -0
- package/src/sass/prettyprint/prettyprint.scss +118 -0
- package/src/sass/previewer.scss +179 -0
- package/src/sass/print.scss +13 -0
- package/src/sass/prism/coy.scss +220 -0
- package/src/sass/prism/dark.scss +132 -0
- package/src/sass/prism/default.scss +143 -0
- package/src/sass/prism/funky.scss +133 -0
- package/src/sass/prism/okaidia.scss +126 -0
- package/src/sass/prism/one-dark.scss +440 -0
- package/src/sass/prism/one-light.scss +428 -0
- package/src/sass/prism/solarized-light.scss +153 -0
- package/src/sass/prism/tomorrow-night.scss +125 -0
- package/src/sass/prism/twilight.scss +202 -0
- package/src/sass/prism/vs-dark.scss +275 -0
- package/src/sass/prism/vs-light.scss +168 -0
- package/src/sass/themes/blue.scss +411 -0
- package/src/sass/themes/dark.scss +517 -0
- package/src/sass/themes/default.scss +255 -0
- package/src/sass/themes/green.scss +395 -0
- package/src/sass/themes/light.scss +368 -0
- package/src/sass/themes/red.scss +397 -0
- package/src/sass/themes/violet.scss +410 -0
- package/src/sass/variable.scss +84 -0
- package/src/toolbars/Bubble.js +234 -0
- package/src/toolbars/BubbleFormula.js +298 -0
- package/src/toolbars/BubbleTable.js +147 -0
- package/src/toolbars/FloatMenu.js +131 -0
- package/src/toolbars/HiddenToolbar.js +36 -0
- package/src/toolbars/HookCenter.js +234 -0
- package/src/toolbars/MenuBase.js +569 -0
- package/src/toolbars/PreviewerBubble.js +608 -0
- package/src/toolbars/ShortcutKeyConfigPanel.js +345 -0
- package/src/toolbars/Sidebar.js +36 -0
- package/src/toolbars/Toc.js +242 -0
- package/src/toolbars/Toolbar.js +449 -0
- package/src/toolbars/ToolbarRight.js +37 -0
- package/src/toolbars/hooks/Audio.js +79 -0
- package/src/toolbars/hooks/BarTable.js +41 -0
- package/src/toolbars/hooks/Bold.js +73 -0
- package/src/toolbars/hooks/Br.js +34 -0
- package/src/toolbars/hooks/ChangeLocale.js +62 -0
- package/src/toolbars/hooks/ChatGpt.js +182 -0
- package/src/toolbars/hooks/CheckList.js +41 -0
- package/src/toolbars/hooks/Code.js +49 -0
- package/src/toolbars/hooks/CodeTheme.js +66 -0
- package/src/toolbars/hooks/Color.js +298 -0
- package/src/toolbars/hooks/Copy.js +141 -0
- package/src/toolbars/hooks/Detail.js +69 -0
- package/src/toolbars/hooks/DrawIo.js +57 -0
- package/src/toolbars/hooks/Export.js +49 -0
- package/src/toolbars/hooks/File.js +79 -0
- package/src/toolbars/hooks/Formula.js +69 -0
- package/src/toolbars/hooks/FullScreen.js +50 -0
- package/src/toolbars/hooks/Graph.js +263 -0
- package/src/toolbars/hooks/H1.js +71 -0
- package/src/toolbars/hooks/H2.js +71 -0
- package/src/toolbars/hooks/H3.js +71 -0
- package/src/toolbars/hooks/Header.js +118 -0
- package/src/toolbars/hooks/Hr.js +35 -0
- package/src/toolbars/hooks/Image.js +91 -0
- package/src/toolbars/hooks/InlineCode.js +53 -0
- package/src/toolbars/hooks/Insert.js +193 -0
- package/src/toolbars/hooks/Italic.js +72 -0
- package/src/toolbars/hooks/Justify.js +49 -0
- package/src/toolbars/hooks/LineTable.js +41 -0
- package/src/toolbars/hooks/Link.js +49 -0
- package/src/toolbars/hooks/List.js +55 -0
- package/src/toolbars/hooks/MobilePreview.js +44 -0
- package/src/toolbars/hooks/Ol.js +41 -0
- package/src/toolbars/hooks/Panel.js +140 -0
- package/src/toolbars/hooks/Pdf.js +78 -0
- package/src/toolbars/hooks/Publish.js +123 -0
- package/src/toolbars/hooks/QuickTable.js +43 -0
- package/src/toolbars/hooks/Quote.js +45 -0
- package/src/toolbars/hooks/Redo.js +33 -0
- package/src/toolbars/hooks/Ruby.js +59 -0
- package/src/toolbars/hooks/Search.js +53 -0
- package/src/toolbars/hooks/Settings.js +220 -0
- package/src/toolbars/hooks/ShortcutKey.js +62 -0
- package/src/toolbars/hooks/Size.js +118 -0
- package/src/toolbars/hooks/Split.js +37 -0
- package/src/toolbars/hooks/Strikethrough.js +71 -0
- package/src/toolbars/hooks/Sub.js +58 -0
- package/src/toolbars/hooks/Sup.js +58 -0
- package/src/toolbars/hooks/SwitchModel.js +56 -0
- package/src/toolbars/hooks/Table.js +56 -0
- package/src/toolbars/hooks/Theme.js +62 -0
- package/src/toolbars/hooks/Toc.js +35 -0
- package/src/toolbars/hooks/TogglePreview.js +91 -0
- package/src/toolbars/hooks/Ul.js +41 -0
- package/src/toolbars/hooks/Underline.js +68 -0
- package/src/toolbars/hooks/Undo.js +30 -0
- package/src/toolbars/hooks/Video.js +79 -0
- package/src/toolbars/hooks/Word.js +78 -0
- package/src/toolbars/hooks/WordCount.js +106 -0
- package/src/utils/autoindent.js +58 -0
- package/src/utils/cm-search-replace.js +794 -0
- package/src/utils/code-preview-language-setting.js +180 -0
- package/src/utils/codeBlockContentHandler.js +400 -0
- package/src/utils/config.js +174 -0
- package/src/utils/copy.js +55 -0
- package/src/utils/dialog.js +214 -0
- package/src/utils/dom.js +163 -0
- package/src/utils/downloadUtil.js +23 -0
- package/src/utils/env.js +22 -0
- package/src/utils/error.js +61 -0
- package/src/utils/event.js +38 -0
- package/src/utils/export.js +166 -0
- package/src/utils/file.js +164 -0
- package/src/utils/formulaUtilsHandler.js +232 -0
- package/src/utils/htmlparser.js +976 -0
- package/src/utils/image.js +99 -0
- package/src/utils/imgSizeHandler.js +279 -0
- package/src/utils/lazyLoadImg.js +327 -0
- package/src/utils/lineFeed.js +49 -0
- package/src/utils/listContentHandler.js +227 -0
- package/src/utils/lookbehind-replace.js +81 -0
- package/src/utils/mathjax.js +89 -0
- package/src/utils/myersDiff.js +211 -0
- package/src/utils/pasteHelper.js +253 -0
- package/src/utils/platformTransform.js +71 -0
- package/src/utils/recount-pos.js +59 -0
- package/src/utils/regexp.js +295 -0
- package/src/utils/sanitize.js +477 -0
- package/src/utils/selection.js +50 -0
- package/src/utils/shortcutKey.js +291 -0
- package/src/utils/svgUtils.js +96 -0
- package/src/utils/tableContentHandler.js +876 -0
- package/test/core/CommonMark.spec.ts +62 -0
- package/test/core/hooks/AutoLink.spec.ts +28 -0
- package/test/core/hooks/List.spec.ts +79 -0
- package/test/core/hooks/__snapshots__/List.spec.ts.snap +11 -0
- package/test/example.md +778 -0
- package/test/node.js +10 -0
- package/test/suites/commonmark.spec.json +5218 -0
- package/test/tsconfig.test.json +6 -0
- package/test/utils/regexp.spec.ts +28 -0
- package/types/cherry.d.ts +675 -0
- package/types/codemirror.d.ts +22 -0
- package/types/editor.d.ts +72 -0
- package/types/global.d.ts +16 -0
- package/types/menus.d.ts +24 -0
- package/types/previewer.d.ts +53 -0
- package/types/syntax.d.ts +52 -0
package/src/Engine.js
ADDED
|
@@ -0,0 +1,381 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Copyright (C) 2021 THL A29 Limited, a Tencent company.
|
|
3
|
+
*
|
|
4
|
+
* Licensed under the Apache License, Version 2.0 (the "License");
|
|
5
|
+
* you may not use this file except in compliance with the License.
|
|
6
|
+
* You may obtain a copy of the License at
|
|
7
|
+
*
|
|
8
|
+
* http://www.apache.org/licenses/LICENSE-2.0
|
|
9
|
+
*
|
|
10
|
+
* Unless required by applicable law or agreed to in writing, software
|
|
11
|
+
* distributed under the License is distributed on an "AS IS" BASIS,
|
|
12
|
+
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
|
13
|
+
* See the License for the specific language governing permissions and
|
|
14
|
+
* limitations under the License.
|
|
15
|
+
*/
|
|
16
|
+
import HookCenter from './core/HookCenter';
|
|
17
|
+
import hooksConfig from './core/HooksConfig';
|
|
18
|
+
import NestedError, { $expectTarget, $expectInherit, $expectInstance } from './utils/error';
|
|
19
|
+
import CryptoJS from 'crypto-js';
|
|
20
|
+
import SyntaxBase from './core/SyntaxBase';
|
|
21
|
+
import ParagraphBase from './core/ParagraphBase';
|
|
22
|
+
import { PUNCTUATION, longTextReg, imgBase64Reg, imgDrawioXmlReg } from './utils/regexp';
|
|
23
|
+
import { escapeHTMLSpecialChar } from './utils/sanitize';
|
|
24
|
+
import Logger from './Logger';
|
|
25
|
+
import { configureMathJax } from './utils/mathjax';
|
|
26
|
+
import UrlCache from './UrlCache';
|
|
27
|
+
import htmlParser from './utils/htmlparser';
|
|
28
|
+
import { isBrowser } from './utils/env';
|
|
29
|
+
|
|
30
|
+
export default class Engine {
|
|
31
|
+
/**
|
|
32
|
+
*
|
|
33
|
+
* @param {Partial<import('./Cherry').CherryOptions>} markdownParams 初始化Cherry时传入的选项
|
|
34
|
+
* @param {import('./Cherry').default} cherry Cherry实例
|
|
35
|
+
*/
|
|
36
|
+
constructor(markdownParams, cherry) {
|
|
37
|
+
this.$cherry = cherry;
|
|
38
|
+
// Deprecated
|
|
39
|
+
Object.defineProperty(this, '_cherry', {
|
|
40
|
+
get() {
|
|
41
|
+
Logger.warn('`_engine._cherry` is deprecated. Use `$engine.$cherry` instead.');
|
|
42
|
+
return this.$cherry;
|
|
43
|
+
},
|
|
44
|
+
});
|
|
45
|
+
this.initMath(markdownParams);
|
|
46
|
+
this.$configInit(markdownParams);
|
|
47
|
+
this.hookCenter = new HookCenter(hooksConfig, markdownParams, cherry);
|
|
48
|
+
this.hooks = this.hookCenter.getHookList();
|
|
49
|
+
this.hashCache = {};
|
|
50
|
+
this.hashStrMap = {};
|
|
51
|
+
this.cachedBigData = {};
|
|
52
|
+
this.markdownParams = markdownParams;
|
|
53
|
+
this.currentStrMd5 = [];
|
|
54
|
+
this.globalConfig = markdownParams.engine.global;
|
|
55
|
+
this.htmlWhiteListAppend = this.globalConfig.htmlWhiteList;
|
|
56
|
+
this.urlProcessorMap = {};
|
|
57
|
+
}
|
|
58
|
+
|
|
59
|
+
/**
|
|
60
|
+
* 重新生成html
|
|
61
|
+
* 这是为urlProcessor支持异步回调函数而实现的重新生成html的方法
|
|
62
|
+
* 该方法会清空所有缓存,所以降低了该方法的执行频率,1s内最多执行一次
|
|
63
|
+
*/
|
|
64
|
+
reMakeHtml() {
|
|
65
|
+
if (this.timer) {
|
|
66
|
+
clearTimeout(this.timer);
|
|
67
|
+
this.timer = null;
|
|
68
|
+
}
|
|
69
|
+
this.timer = setTimeout(() => {
|
|
70
|
+
this.$cherry.lastMarkdownText = '';
|
|
71
|
+
this.hashCache = {};
|
|
72
|
+
const markdownText = this.$cherry.editor.editor.getValue();
|
|
73
|
+
const html = this.makeHtml(markdownText);
|
|
74
|
+
this.$cherry.previewer.refresh(html);
|
|
75
|
+
this.$cherry.$event.emit('afterChange', {
|
|
76
|
+
markdownText,
|
|
77
|
+
html,
|
|
78
|
+
});
|
|
79
|
+
}, 1000);
|
|
80
|
+
}
|
|
81
|
+
|
|
82
|
+
urlProcessor(url, srcType) {
|
|
83
|
+
const key = `${srcType}_${url}`;
|
|
84
|
+
if (this.urlProcessorMap[key]) {
|
|
85
|
+
return this.urlProcessorMap[key];
|
|
86
|
+
}
|
|
87
|
+
const ret = this.$cherry.options.callback.urlProcessor(url, srcType, (/** @type {string} */ newUrl) => {
|
|
88
|
+
if (newUrl) {
|
|
89
|
+
if (!this.urlProcessorMap[key]) {
|
|
90
|
+
this.urlProcessorMap[key] = newUrl;
|
|
91
|
+
this.reMakeHtml();
|
|
92
|
+
}
|
|
93
|
+
} else {
|
|
94
|
+
delete this.urlProcessorMap[key];
|
|
95
|
+
}
|
|
96
|
+
return;
|
|
97
|
+
});
|
|
98
|
+
if (ret) {
|
|
99
|
+
return ret;
|
|
100
|
+
}
|
|
101
|
+
return url;
|
|
102
|
+
}
|
|
103
|
+
|
|
104
|
+
initMath(opts) {
|
|
105
|
+
// 无论MathJax还是Katex,都可以先进行MathJax配置
|
|
106
|
+
const { externals, engine } = opts;
|
|
107
|
+
const { syntax } = engine;
|
|
108
|
+
const { plugins } = syntax.mathBlock;
|
|
109
|
+
// 未开启公式
|
|
110
|
+
if (
|
|
111
|
+
!isBrowser() ||
|
|
112
|
+
(!syntax.mathBlock.src && !syntax.inlineMath.src && !syntax.mathBlock.engine && !syntax.inlineMath.engine)
|
|
113
|
+
) {
|
|
114
|
+
return;
|
|
115
|
+
}
|
|
116
|
+
// 已经加载过MathJax
|
|
117
|
+
if (externals.MathJax || window.MathJax) {
|
|
118
|
+
return;
|
|
119
|
+
}
|
|
120
|
+
configureMathJax(plugins);
|
|
121
|
+
// 等待MathJax各种插件加载
|
|
122
|
+
const script = document.createElement('script');
|
|
123
|
+
script.src = syntax.mathBlock.src ? syntax.mathBlock.src : syntax.inlineMath.src;
|
|
124
|
+
script.async = true;
|
|
125
|
+
if (script.src) document.head.appendChild(script);
|
|
126
|
+
}
|
|
127
|
+
|
|
128
|
+
$configInit(params) {
|
|
129
|
+
if (params.hooksConfig && $expectTarget(params.hooksConfig.hooksList, Array)) {
|
|
130
|
+
for (let key = 0; key < params.hooksConfig.hooksList.length; key++) {
|
|
131
|
+
const hook = params.hooksConfig.hooksList[key];
|
|
132
|
+
try {
|
|
133
|
+
if (hook.getType() === 'sentence') {
|
|
134
|
+
$expectInherit(hook, SyntaxBase);
|
|
135
|
+
}
|
|
136
|
+
|
|
137
|
+
if (hook.getType() === 'paragraph') {
|
|
138
|
+
$expectInherit(hook, ParagraphBase);
|
|
139
|
+
}
|
|
140
|
+
$expectInstance(hook);
|
|
141
|
+
hooksConfig.push(hook);
|
|
142
|
+
} catch (e) {
|
|
143
|
+
throw new Error('the hook does not correctly inherit');
|
|
144
|
+
}
|
|
145
|
+
}
|
|
146
|
+
}
|
|
147
|
+
}
|
|
148
|
+
|
|
149
|
+
$beforeMakeHtml(str) {
|
|
150
|
+
let $str = str.replace(/~/g, '~T');
|
|
151
|
+
$str = $str.replace(/\$/g, '~D');
|
|
152
|
+
$str = $str.replace(/\r\n/g, '\n'); // DOS to Unix
|
|
153
|
+
$str = $str.replace(/\r/g, '\n'); // Mac to Unix
|
|
154
|
+
if (
|
|
155
|
+
// @ts-ignore
|
|
156
|
+
this.$cherry.options.engine.syntax.fontEmphasis.selfClosing ||
|
|
157
|
+
this.$cherry.options.engine.global.flowSessionContext
|
|
158
|
+
) {
|
|
159
|
+
// 自动补全最后一行的加粗、斜体语法
|
|
160
|
+
if (/(^|\n)[^\n]*\*{1,3}[^\n]+$/.test($str) && $str.match(/(^|\n)([^\n]+)$/)) {
|
|
161
|
+
const lastLineStr = $str.match(/(^|\n)([^\n]+)$/)[2].split(/(\*{1,3})/g);
|
|
162
|
+
const emphasis = [];
|
|
163
|
+
for (let i = 0; i < lastLineStr.length; i++) {
|
|
164
|
+
if (/\*{1,3}/.test(lastLineStr[i])) {
|
|
165
|
+
const current = lastLineStr[i];
|
|
166
|
+
if (emphasis.length <= 0) {
|
|
167
|
+
emphasis.push(current);
|
|
168
|
+
} else {
|
|
169
|
+
if (emphasis[emphasis.length - 1] === current) {
|
|
170
|
+
emphasis.pop();
|
|
171
|
+
} else {
|
|
172
|
+
emphasis.push(current);
|
|
173
|
+
}
|
|
174
|
+
}
|
|
175
|
+
}
|
|
176
|
+
}
|
|
177
|
+
if (emphasis.length === 1) {
|
|
178
|
+
$str = $str.replace(/(\*{1,3})(\s*)([^*\n]+?)$/, '$1$2$3$2$1');
|
|
179
|
+
}
|
|
180
|
+
if (emphasis.length === 2) {
|
|
181
|
+
$str = $str.replace(/(\*{1,3})(\s*)([^*\n]+?)\*{0,2}$/, '$1$2$3$2$1');
|
|
182
|
+
}
|
|
183
|
+
}
|
|
184
|
+
}
|
|
185
|
+
// 避免正则性能问题,如/.+\n/.test(' '.repeat(99999)), 回溯次数过多
|
|
186
|
+
// 参考文章:http://www.alloyteam.com/2019/07/13574/
|
|
187
|
+
if ($str[$str.length - 1] !== '\n') {
|
|
188
|
+
$str += '\n';
|
|
189
|
+
}
|
|
190
|
+
$str = this.$fireHookAction($str, 'sentence', 'beforeMakeHtml');
|
|
191
|
+
$str = this.$fireHookAction($str, 'paragraph', 'beforeMakeHtml');
|
|
192
|
+
return $str;
|
|
193
|
+
}
|
|
194
|
+
|
|
195
|
+
$afterMakeHtml(str) {
|
|
196
|
+
let $str = this.$fireHookAction(str, 'paragraph', 'afterMakeHtml');
|
|
197
|
+
// str = this._fireHookAction(str, 'sentence', 'afterMakeHtml');
|
|
198
|
+
$str = $str.replace(/~D/g, '$');
|
|
199
|
+
$str = $str.replace(/~T/g, '~');
|
|
200
|
+
$str = $str.replace(/\\<\//g, '\\ </');
|
|
201
|
+
$str = $str
|
|
202
|
+
.replace(new RegExp(`\\\\(${PUNCTUATION})`, 'g'), (match, escapeChar) => {
|
|
203
|
+
if (escapeChar === '&') {
|
|
204
|
+
// & 字符需要特殊处理
|
|
205
|
+
return match;
|
|
206
|
+
}
|
|
207
|
+
return escapeHTMLSpecialChar(escapeChar);
|
|
208
|
+
})
|
|
209
|
+
.replace(/\\&(?!(amp|lt|gt|quot|apos);)/, () => '&');
|
|
210
|
+
$str = $str.replace(/\\ <\//g, '\\</');
|
|
211
|
+
$str = $str.replace(/id="safe_(?=.*?")/g, 'id="'); // transform header id to avoid being sanitized
|
|
212
|
+
$str = UrlCache.restoreAll($str);
|
|
213
|
+
return $str;
|
|
214
|
+
}
|
|
215
|
+
|
|
216
|
+
$dealSentenceByCache(md) {
|
|
217
|
+
return this.$checkCache(md, (str) => this.$dealSentence(str));
|
|
218
|
+
}
|
|
219
|
+
|
|
220
|
+
$dealSentence(md) {
|
|
221
|
+
return this.$fireHookAction(md, 'sentence', 'makeHtml', this.$dealSentenceByCache.bind(this));
|
|
222
|
+
}
|
|
223
|
+
|
|
224
|
+
$fireHookAction(md, type, action, actionArgs) {
|
|
225
|
+
let $md = md;
|
|
226
|
+
const method = action === 'afterMakeHtml' ? 'reduceRight' : 'reduce';
|
|
227
|
+
if (!this.hooks && !this.hooks[type] && !this.hooks[type][method]) {
|
|
228
|
+
return $md;
|
|
229
|
+
}
|
|
230
|
+
try {
|
|
231
|
+
$md = this.hooks[type][method]((newMd, oneHook) => {
|
|
232
|
+
if (!oneHook.$engine) {
|
|
233
|
+
oneHook.$engine = this;
|
|
234
|
+
// Deprecated
|
|
235
|
+
Object.defineProperty(oneHook, '_engine', {
|
|
236
|
+
get() {
|
|
237
|
+
Logger.warn('`this._engine` is deprecated. Use `this.$engine` instead.');
|
|
238
|
+
return this.$engine;
|
|
239
|
+
},
|
|
240
|
+
});
|
|
241
|
+
}
|
|
242
|
+
|
|
243
|
+
if (!oneHook[action]) {
|
|
244
|
+
return newMd;
|
|
245
|
+
}
|
|
246
|
+
return oneHook[action](newMd, actionArgs, this.markdownParams);
|
|
247
|
+
}, $md);
|
|
248
|
+
} catch (e) {
|
|
249
|
+
throw new NestedError(e);
|
|
250
|
+
}
|
|
251
|
+
return $md;
|
|
252
|
+
}
|
|
253
|
+
|
|
254
|
+
/**
|
|
255
|
+
* @deprecated 已废弃,推荐使用 .hash()
|
|
256
|
+
*/
|
|
257
|
+
md5(str) {
|
|
258
|
+
return this.hash(str);
|
|
259
|
+
}
|
|
260
|
+
|
|
261
|
+
/**
|
|
262
|
+
* 计算哈希值
|
|
263
|
+
* @param {String} str 被计算的字符串
|
|
264
|
+
* @returns {String} 哈希值
|
|
265
|
+
*/
|
|
266
|
+
hash(str) {
|
|
267
|
+
if (!this.hashStrMap[str]) {
|
|
268
|
+
this.hashStrMap[str] = CryptoJS.SHA256(str).toString();
|
|
269
|
+
}
|
|
270
|
+
return this.hashStrMap[str];
|
|
271
|
+
}
|
|
272
|
+
|
|
273
|
+
$checkCache(str, func) {
|
|
274
|
+
const sign = this.hash(str);
|
|
275
|
+
if (typeof this.hashCache[sign] === 'undefined') {
|
|
276
|
+
this.hashCache[sign] = func(str);
|
|
277
|
+
if (BUILD_ENV !== 'production') {
|
|
278
|
+
// 生产环境屏蔽
|
|
279
|
+
Logger.log('markdown引擎渲染了:', str);
|
|
280
|
+
}
|
|
281
|
+
}
|
|
282
|
+
return { sign, html: this.hashCache[sign] };
|
|
283
|
+
}
|
|
284
|
+
|
|
285
|
+
$dealParagraph(md) {
|
|
286
|
+
return this.$fireHookAction(md, 'paragraph', 'makeHtml', this.$dealSentenceByCache.bind(this));
|
|
287
|
+
}
|
|
288
|
+
|
|
289
|
+
// 缓存大文本数据,用以提升渲染性能
|
|
290
|
+
$cacheBigData(md) {
|
|
291
|
+
let $md = md.replace(imgBase64Reg, (whole, m1, m2) => {
|
|
292
|
+
const cacheKey = `bigDataBegin${this.hash(m2)}bigDataEnd`;
|
|
293
|
+
this.cachedBigData[cacheKey] = m2;
|
|
294
|
+
return `${m1}${cacheKey})`;
|
|
295
|
+
});
|
|
296
|
+
$md = $md.replace(imgDrawioXmlReg, (whole, m1, m2) => {
|
|
297
|
+
const cacheKey = `bigDataBegin${this.hash(m2)}bigDataEnd`;
|
|
298
|
+
this.cachedBigData[cacheKey] = m2;
|
|
299
|
+
return `${m1}${cacheKey}}`;
|
|
300
|
+
});
|
|
301
|
+
$md = $md.replace(longTextReg, (whole, m1, m2) => {
|
|
302
|
+
const cacheKey = `bigDataBegin${this.hash(m2)}bigDataEnd`;
|
|
303
|
+
this.cachedBigData[cacheKey] = m2;
|
|
304
|
+
return `${m1}${cacheKey}}`;
|
|
305
|
+
});
|
|
306
|
+
return $md;
|
|
307
|
+
}
|
|
308
|
+
|
|
309
|
+
$deCacheBigData(md) {
|
|
310
|
+
return md.replace(/bigDataBegin[^\n]+?bigDataEnd/g, (whole) => {
|
|
311
|
+
return this.cachedBigData[whole];
|
|
312
|
+
});
|
|
313
|
+
}
|
|
314
|
+
|
|
315
|
+
/**
|
|
316
|
+
* 流式输出场景时,在最后增加一个光标占位
|
|
317
|
+
* @param {string} md 内容
|
|
318
|
+
* @returns {string}
|
|
319
|
+
*/
|
|
320
|
+
$setFlowSessionCursorCache(md) {
|
|
321
|
+
if (this.$cherry.options.engine.global.flowSessionContext && this.$cherry.options.engine.global.flowSessionCursor) {
|
|
322
|
+
return `${md}CHERRY_FLOW_SESSION_CURSOR`;
|
|
323
|
+
}
|
|
324
|
+
return md;
|
|
325
|
+
}
|
|
326
|
+
|
|
327
|
+
/**
|
|
328
|
+
* 流式输出场景时,把最后的光标占位替换为配置的dom元素,并在一段时间后删除该元素
|
|
329
|
+
* @param {string} md 内容
|
|
330
|
+
* @returns {string}
|
|
331
|
+
*/
|
|
332
|
+
$clearFlowSessionCursorCache(md) {
|
|
333
|
+
if (this.$cherry.options.engine.global.flowSessionCursor) {
|
|
334
|
+
if (this.clearCursorTimer) {
|
|
335
|
+
clearTimeout(this.clearCursorTimer);
|
|
336
|
+
}
|
|
337
|
+
this.clearCursorTimer = setTimeout(() => {
|
|
338
|
+
this.$cherry.clearFlowSessionCursor();
|
|
339
|
+
}, 2560);
|
|
340
|
+
return md.replace(/CHERRY_FLOW_SESSION_CURSOR/g, this.$cherry.options.engine.global.flowSessionCursor);
|
|
341
|
+
}
|
|
342
|
+
return md;
|
|
343
|
+
}
|
|
344
|
+
|
|
345
|
+
/**
|
|
346
|
+
* @param {string} md md字符串
|
|
347
|
+
* @returns {string} 获取html
|
|
348
|
+
*/
|
|
349
|
+
makeHtml(md) {
|
|
350
|
+
let $md = this.$setFlowSessionCursorCache(md);
|
|
351
|
+
$md = this.$cacheBigData($md);
|
|
352
|
+
$md = this.$beforeMakeHtml($md);
|
|
353
|
+
$md = this.$dealParagraph($md);
|
|
354
|
+
$md = this.$afterMakeHtml($md);
|
|
355
|
+
this.$fireHookAction($md, 'paragraph', '$cleanCache');
|
|
356
|
+
$md = this.$deCacheBigData($md);
|
|
357
|
+
$md = this.$clearFlowSessionCursorCache($md);
|
|
358
|
+
return $md;
|
|
359
|
+
}
|
|
360
|
+
|
|
361
|
+
makeHtmlForBlockquote(md) {
|
|
362
|
+
let $md = md;
|
|
363
|
+
$md = this.$dealParagraph($md);
|
|
364
|
+
$md = this.$fireHookAction($md, 'paragraph', 'afterMakeHtml');
|
|
365
|
+
return $md;
|
|
366
|
+
}
|
|
367
|
+
|
|
368
|
+
mounted() {
|
|
369
|
+
this.$fireHookAction('', 'sentence', 'mounted');
|
|
370
|
+
this.$fireHookAction('', 'paragraph', 'mounted');
|
|
371
|
+
// UrlCache.clear();
|
|
372
|
+
}
|
|
373
|
+
|
|
374
|
+
/**
|
|
375
|
+
* @param {string} html html字符串
|
|
376
|
+
* @returns {string} 获取markdown
|
|
377
|
+
*/
|
|
378
|
+
makeMarkdown(html) {
|
|
379
|
+
return htmlParser.run(html);
|
|
380
|
+
}
|
|
381
|
+
}
|
package/src/Event.js
ADDED
|
@@ -0,0 +1,140 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Copyright (C) 2021 THL A29 Limited, a Tencent company.
|
|
3
|
+
*
|
|
4
|
+
* Licensed under the Apache License, Version 2.0 (the "License");
|
|
5
|
+
* you may not use this file except in compliance with the License.
|
|
6
|
+
* You may obtain a copy of the License at
|
|
7
|
+
*
|
|
8
|
+
* http://www.apache.org/licenses/LICENSE-2.0
|
|
9
|
+
*
|
|
10
|
+
* Unless required by applicable law or agreed to in writing, software
|
|
11
|
+
* distributed under the License is distributed on an "AS IS" BASIS,
|
|
12
|
+
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
|
13
|
+
* See the License for the specific language governing permissions and
|
|
14
|
+
* limitations under the License.
|
|
15
|
+
*/
|
|
16
|
+
import mitt from 'mitt';
|
|
17
|
+
|
|
18
|
+
/**
|
|
19
|
+
* 事件管理
|
|
20
|
+
*/
|
|
21
|
+
export default class Event {
|
|
22
|
+
constructor(instanceId) {
|
|
23
|
+
this.instanceId = instanceId;
|
|
24
|
+
}
|
|
25
|
+
/**
|
|
26
|
+
* 事件列表
|
|
27
|
+
* @property
|
|
28
|
+
*/
|
|
29
|
+
Events = {
|
|
30
|
+
previewerClose: 'previewerClose',
|
|
31
|
+
previewerOpen: 'previewerOpen',
|
|
32
|
+
editorClose: 'editorClose',
|
|
33
|
+
editorOpen: 'editorOpen',
|
|
34
|
+
toolbarHide: 'toolbarHide',
|
|
35
|
+
toolbarShow: 'toolbarShow',
|
|
36
|
+
cleanAllSubMenus: 'cleanAllSubMenus', // 清除所有子菜单弹窗
|
|
37
|
+
afterChange: 'afterChange', // 编辑器内容变化
|
|
38
|
+
afterInit: 'afterInit', // 编辑器初始化完成
|
|
39
|
+
focus: 'focus', // 焦点
|
|
40
|
+
blur: 'blur', // 失焦
|
|
41
|
+
selectionChange: 'selectionChange', // 选区内容改变时触发
|
|
42
|
+
afterChangeLocale: 'afterChangeLocale', // 语言改变
|
|
43
|
+
changeMainTheme: 'changeMainTheme', // 变更主题
|
|
44
|
+
changeCodeBlockTheme: 'changeCodeBlockTheme', // 变更代码块主题
|
|
45
|
+
};
|
|
46
|
+
|
|
47
|
+
/**
|
|
48
|
+
* @property
|
|
49
|
+
* @private
|
|
50
|
+
* @type {import('mitt').Emitter}
|
|
51
|
+
*/
|
|
52
|
+
emitter = mitt();
|
|
53
|
+
|
|
54
|
+
setInstanceId(instanceId) {
|
|
55
|
+
this.instanceId = instanceId;
|
|
56
|
+
}
|
|
57
|
+
|
|
58
|
+
getInstanceId() {
|
|
59
|
+
return this.instanceId;
|
|
60
|
+
}
|
|
61
|
+
|
|
62
|
+
clearAll() {
|
|
63
|
+
this.emitter.all.clear();
|
|
64
|
+
}
|
|
65
|
+
|
|
66
|
+
bindCallbacksByOptions(options) {
|
|
67
|
+
if (options.callback.afterChange) {
|
|
68
|
+
this.on(this.Events.afterChange, (msg) => {
|
|
69
|
+
options.callback.afterChange(msg.markdownText, msg.html);
|
|
70
|
+
});
|
|
71
|
+
}
|
|
72
|
+
if (options.callback.afterInit) {
|
|
73
|
+
this.on(this.Events.afterInit, (msg) => {
|
|
74
|
+
options.callback.afterInit(msg.markdownText, msg.html);
|
|
75
|
+
});
|
|
76
|
+
}
|
|
77
|
+
if (options.event.afterChange) {
|
|
78
|
+
this.on(this.Events.afterChange, (msg) => {
|
|
79
|
+
options.event.afterChange(msg.markdownText, msg.html);
|
|
80
|
+
});
|
|
81
|
+
}
|
|
82
|
+
if (options.event.afterInit) {
|
|
83
|
+
this.on(this.Events.afterInit, (msg) => {
|
|
84
|
+
options.event.afterInit(msg.markdownText, msg.html);
|
|
85
|
+
});
|
|
86
|
+
}
|
|
87
|
+
if (options.event.focus) {
|
|
88
|
+
this.on(this.Events.focus, (event) => {
|
|
89
|
+
options.event.focus(event);
|
|
90
|
+
});
|
|
91
|
+
}
|
|
92
|
+
if (options.event.blur) {
|
|
93
|
+
this.on(this.Events.blur, (event) => {
|
|
94
|
+
options.event.blur(event);
|
|
95
|
+
});
|
|
96
|
+
}
|
|
97
|
+
if (options.event.selectionChange) {
|
|
98
|
+
this.on(this.Events.selectionChange, (event) => {
|
|
99
|
+
options.event.selectionChange(event);
|
|
100
|
+
});
|
|
101
|
+
}
|
|
102
|
+
if (options.event.afterChangeLocale) {
|
|
103
|
+
this.on(this.Events.afterChangeLocale, (locale) => {
|
|
104
|
+
options.event.afterChangeLocale(locale);
|
|
105
|
+
});
|
|
106
|
+
}
|
|
107
|
+
if (options.event.changeMainTheme) {
|
|
108
|
+
this.on(this.Events.changeMainTheme, (theme) => {
|
|
109
|
+
options.event.changeMainTheme(theme);
|
|
110
|
+
});
|
|
111
|
+
}
|
|
112
|
+
if (options.event.changeCodeBlockTheme) {
|
|
113
|
+
this.on(this.Events.changeCodeBlockTheme, (theme) => {
|
|
114
|
+
options.event.changeCodeBlockTheme(theme);
|
|
115
|
+
});
|
|
116
|
+
}
|
|
117
|
+
}
|
|
118
|
+
|
|
119
|
+
/**
|
|
120
|
+
* 注册监听事件
|
|
121
|
+
* @param {string} event 要注册监听的事件
|
|
122
|
+
* @param {(event: any) => void} handler 事件回调
|
|
123
|
+
*/
|
|
124
|
+
on(event, handler) {
|
|
125
|
+
this.emitter.on(`${this.instanceId}:${event}`, handler);
|
|
126
|
+
}
|
|
127
|
+
|
|
128
|
+
off(event, handler) {
|
|
129
|
+
this.emitter.off(`${this.instanceId}:${event}`, handler);
|
|
130
|
+
}
|
|
131
|
+
|
|
132
|
+
/**
|
|
133
|
+
* 触发事件
|
|
134
|
+
* @param {string} event 要触发的事件
|
|
135
|
+
* @param {object} msg 消息体
|
|
136
|
+
*/
|
|
137
|
+
emit(event, msg) {
|
|
138
|
+
this.emitter.emit(`${this.instanceId}:${event}`, msg);
|
|
139
|
+
}
|
|
140
|
+
}
|
package/src/Factory.js
ADDED
|
@@ -0,0 +1,180 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Copyright (C) 2021 THL A29 Limited, a Tencent company.
|
|
3
|
+
*
|
|
4
|
+
* Licensed under the Apache License, Version 2.0 (the "License");
|
|
5
|
+
* you may not use this file except in compliance with the License.
|
|
6
|
+
* You may obtain a copy of the License at
|
|
7
|
+
*
|
|
8
|
+
* http://www.apache.org/licenses/LICENSE-2.0
|
|
9
|
+
*
|
|
10
|
+
* Unless required by applicable law or agreed to in writing, software
|
|
11
|
+
* distributed under the License is distributed on an "AS IS" BASIS,
|
|
12
|
+
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
|
13
|
+
* See the License for the specific language governing permissions and
|
|
14
|
+
* limitations under the License.
|
|
15
|
+
*/
|
|
16
|
+
import SyntaxBase, { HOOKS_TYPE_LIST } from './core/SyntaxBase';
|
|
17
|
+
import ParagraphBase from './core/ParagraphBase';
|
|
18
|
+
import MenuBase from './toolbars/MenuBase';
|
|
19
|
+
|
|
20
|
+
/**
|
|
21
|
+
* 属性类型匹配
|
|
22
|
+
* @param {object} obj 待匹配的对象
|
|
23
|
+
* @param {string} key 待匹配的属性名
|
|
24
|
+
* @param {any} type 匹配的类型
|
|
25
|
+
*/
|
|
26
|
+
function matchPropTypes(obj, key, type) {
|
|
27
|
+
if (typeof obj !== 'object' || !obj) {
|
|
28
|
+
throw TypeError(`first argument must be a object, but get ${typeof obj}`);
|
|
29
|
+
}
|
|
30
|
+
// 不用检测,会存在 undefined 的情况
|
|
31
|
+
// if (!Object.keys(obj).includes(key))
|
|
32
|
+
// 递归
|
|
33
|
+
if (
|
|
34
|
+
!Array.isArray(type) &&
|
|
35
|
+
typeof type === 'object' &&
|
|
36
|
+
type !== null &&
|
|
37
|
+
typeof obj[key] === 'object' &&
|
|
38
|
+
obj[key] !== null
|
|
39
|
+
) {
|
|
40
|
+
// 递归时,取对象里每个属性进行匹配,必须全部匹配才返回true
|
|
41
|
+
return Object.keys(obj[key]).every((objKey) => matchPropTypes(obj[key], objKey, type[objKey]));
|
|
42
|
+
}
|
|
43
|
+
if (typeof type === 'string' && typeof obj[key] === type) {
|
|
44
|
+
return true;
|
|
45
|
+
}
|
|
46
|
+
if (typeof type === 'function' && obj[key] instanceof type) {
|
|
47
|
+
return true;
|
|
48
|
+
}
|
|
49
|
+
// 联合类型
|
|
50
|
+
if (Array.isArray(type)) {
|
|
51
|
+
return type.some((type) => matchPropTypes(obj, key, type));
|
|
52
|
+
}
|
|
53
|
+
return false;
|
|
54
|
+
}
|
|
55
|
+
|
|
56
|
+
function filterOptions(options, whiteList, propTypes) {
|
|
57
|
+
const filteredOptions = {};
|
|
58
|
+
Object.keys(options).forEach((key) => {
|
|
59
|
+
if (whiteList.indexOf(key) === -1) {
|
|
60
|
+
return;
|
|
61
|
+
}
|
|
62
|
+
if (typeof propTypes === 'object') {
|
|
63
|
+
if (matchPropTypes(options, key, propTypes[key])) {
|
|
64
|
+
filteredOptions[key] = options[key];
|
|
65
|
+
}
|
|
66
|
+
} else if (typeof propTypes === 'string') {
|
|
67
|
+
if (typeof options[key] === propTypes) {
|
|
68
|
+
filteredOptions[key] = options[key];
|
|
69
|
+
}
|
|
70
|
+
}
|
|
71
|
+
});
|
|
72
|
+
return filteredOptions;
|
|
73
|
+
}
|
|
74
|
+
|
|
75
|
+
export function createSyntaxHook(name, type, options) {
|
|
76
|
+
const BaseClass = type === HOOKS_TYPE_LIST.PAR ? ParagraphBase : SyntaxBase;
|
|
77
|
+
const optionsWhiteList = ['beforeMakeHtml', 'makeHtml', 'afterMakeHtml', 'rule', 'test'];
|
|
78
|
+
const filteredOptions = filterOptions(options, optionsWhiteList, 'function');
|
|
79
|
+
const paragraphConfig = { needCache: options.needCache, defaultCache: options.defaultCache };
|
|
80
|
+
return class CustomSyntax extends BaseClass {
|
|
81
|
+
static HOOK_NAME = name;
|
|
82
|
+
|
|
83
|
+
constructor(editorConfig = {}) {
|
|
84
|
+
if (type === HOOKS_TYPE_LIST.PAR) {
|
|
85
|
+
super({ needCache: !!paragraphConfig.needCache, defaultCache: paragraphConfig.defaultCache });
|
|
86
|
+
} else {
|
|
87
|
+
super();
|
|
88
|
+
}
|
|
89
|
+
|
|
90
|
+
this.config = editorConfig.config;
|
|
91
|
+
}
|
|
92
|
+
|
|
93
|
+
beforeMakeHtml(...args) {
|
|
94
|
+
if (filteredOptions.beforeMakeHtml) {
|
|
95
|
+
return filteredOptions.beforeMakeHtml.apply(this, args);
|
|
96
|
+
}
|
|
97
|
+
return super.beforeMakeHtml(...args);
|
|
98
|
+
}
|
|
99
|
+
|
|
100
|
+
makeHtml(...args) {
|
|
101
|
+
if (filteredOptions.makeHtml) {
|
|
102
|
+
return filteredOptions.makeHtml.apply(this, args);
|
|
103
|
+
}
|
|
104
|
+
return super.makeHtml(...args);
|
|
105
|
+
}
|
|
106
|
+
|
|
107
|
+
afterMakeHtml(...args) {
|
|
108
|
+
if (filteredOptions.afterMakeHtml) {
|
|
109
|
+
return filteredOptions.afterMakeHtml.apply(this, args);
|
|
110
|
+
}
|
|
111
|
+
return super.afterMakeHtml(...args);
|
|
112
|
+
}
|
|
113
|
+
|
|
114
|
+
test(...args) {
|
|
115
|
+
if (filteredOptions.test) {
|
|
116
|
+
return filteredOptions.test.apply(this, args);
|
|
117
|
+
}
|
|
118
|
+
return super.test(...args);
|
|
119
|
+
}
|
|
120
|
+
|
|
121
|
+
rule(...args) {
|
|
122
|
+
if (filteredOptions.rule) {
|
|
123
|
+
return filteredOptions.rule.apply(this, args);
|
|
124
|
+
}
|
|
125
|
+
return super.rule(...args);
|
|
126
|
+
}
|
|
127
|
+
};
|
|
128
|
+
}
|
|
129
|
+
|
|
130
|
+
export function createMenuHook(name, options) {
|
|
131
|
+
const optionsWhiteList = ['subMenuConfig', 'onClick', 'shortcutKeys', 'iconName', 'icon'];
|
|
132
|
+
const propTypes = {
|
|
133
|
+
subMenuConfig: Array,
|
|
134
|
+
onClick: 'function',
|
|
135
|
+
shortcutKeys: Array,
|
|
136
|
+
iconName: 'string',
|
|
137
|
+
icon: [
|
|
138
|
+
'string',
|
|
139
|
+
{
|
|
140
|
+
type: 'string',
|
|
141
|
+
content: 'string',
|
|
142
|
+
iconStyle: ['string', 'undefined'],
|
|
143
|
+
iconClassName: ['string', 'undefined'],
|
|
144
|
+
},
|
|
145
|
+
],
|
|
146
|
+
};
|
|
147
|
+
const filteredOptions = filterOptions(options, optionsWhiteList, propTypes);
|
|
148
|
+
return class CustomMenu extends MenuBase {
|
|
149
|
+
constructor(editorInstance) {
|
|
150
|
+
super(editorInstance);
|
|
151
|
+
if (!filteredOptions.iconName && !filteredOptions.icon) {
|
|
152
|
+
this.noIcon = true;
|
|
153
|
+
}
|
|
154
|
+
if (filteredOptions.icon) {
|
|
155
|
+
this.$currentMenuOptions.icon = filteredOptions.icon;
|
|
156
|
+
this.name = name;
|
|
157
|
+
} else {
|
|
158
|
+
this.setName(name, filteredOptions.iconName);
|
|
159
|
+
}
|
|
160
|
+
this.subMenuConfig = filteredOptions.subMenuConfig || [];
|
|
161
|
+
}
|
|
162
|
+
|
|
163
|
+
onClick(...args) {
|
|
164
|
+
if (filteredOptions.onClick) {
|
|
165
|
+
return filteredOptions.onClick.apply(this, args);
|
|
166
|
+
}
|
|
167
|
+
return super.onClick(...args);
|
|
168
|
+
}
|
|
169
|
+
|
|
170
|
+
get shortcutKeys() {
|
|
171
|
+
console.warn(
|
|
172
|
+
'shortcutKeys will deprecated in the future, please use shortcutKeyMap instead, get more info at https://github.com/Tencent/cherry-markdown/wiki',
|
|
173
|
+
);
|
|
174
|
+
if (filteredOptions.shortcutKeys) {
|
|
175
|
+
return filteredOptions.shortcutKeys;
|
|
176
|
+
}
|
|
177
|
+
return [];
|
|
178
|
+
}
|
|
179
|
+
};
|
|
180
|
+
}
|