@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.
Files changed (319) hide show
  1. package/package.json +149 -0
  2. package/src/Cherry.config.js +625 -0
  3. package/src/Cherry.js +1104 -0
  4. package/src/CherryStatic.js +70 -0
  5. package/src/Editor.js +748 -0
  6. package/src/Engine.js +381 -0
  7. package/src/Event.js +140 -0
  8. package/src/Factory.js +180 -0
  9. package/src/Logger.js +31 -0
  10. package/src/Previewer.js +1183 -0
  11. package/src/Sanitizer.js +4 -0
  12. package/src/Sanitizer.node.js +7 -0
  13. package/src/UrlCache.js +98 -0
  14. package/src/addons/advance/cherry-table-echarts-plugin.js +170 -0
  15. package/src/addons/cherry-code-block-mermaid-plugin.js +158 -0
  16. package/src/addons/cherry-code-block-plantuml-plugin.js +106 -0
  17. package/src/core/HookCenter.js +297 -0
  18. package/src/core/HooksConfig.js +100 -0
  19. package/src/core/ParagraphBase.js +332 -0
  20. package/src/core/SentenceBase.js +65 -0
  21. package/src/core/SyntaxBase.js +194 -0
  22. package/src/core/hooks/AutoLink.js +232 -0
  23. package/src/core/hooks/BackgroundColor.js +46 -0
  24. package/src/core/hooks/Blockquote.js +70 -0
  25. package/src/core/hooks/Br.js +85 -0
  26. package/src/core/hooks/CodeBlock.js +446 -0
  27. package/src/core/hooks/Color.js +46 -0
  28. package/src/core/hooks/CommentReference.js +96 -0
  29. package/src/core/hooks/Detail.js +108 -0
  30. package/src/core/hooks/Emoji.config.js +1825 -0
  31. package/src/core/hooks/Emoji.js +119 -0
  32. package/src/core/hooks/Emphasis.js +113 -0
  33. package/src/core/hooks/Footnote.js +125 -0
  34. package/src/core/hooks/FrontMatter.js +51 -0
  35. package/src/core/hooks/Header.js +234 -0
  36. package/src/core/hooks/HighLight.js +37 -0
  37. package/src/core/hooks/Hr.js +52 -0
  38. package/src/core/hooks/HtmlBlock.js +184 -0
  39. package/src/core/hooks/Image.js +174 -0
  40. package/src/core/hooks/InlineCode.js +48 -0
  41. package/src/core/hooks/InlineMath.js +107 -0
  42. package/src/core/hooks/Link.js +160 -0
  43. package/src/core/hooks/List.js +264 -0
  44. package/src/core/hooks/MathBlock.js +103 -0
  45. package/src/core/hooks/Panel.js +145 -0
  46. package/src/core/hooks/Paragraph.js +84 -0
  47. package/src/core/hooks/Ruby.js +34 -0
  48. package/src/core/hooks/Size.js +51 -0
  49. package/src/core/hooks/Strikethrough.js +54 -0
  50. package/src/core/hooks/Sub.js +47 -0
  51. package/src/core/hooks/SuggestList.js +333 -0
  52. package/src/core/hooks/Suggester.js +707 -0
  53. package/src/core/hooks/Sup.js +47 -0
  54. package/src/core/hooks/Table.js +275 -0
  55. package/src/core/hooks/Toc.js +292 -0
  56. package/src/core/hooks/Transfer.js +47 -0
  57. package/src/core/hooks/Underline.js +37 -0
  58. package/src/index.core.js +29 -0
  59. package/src/index.engine.core.js +68 -0
  60. package/src/index.engine.js +28 -0
  61. package/src/index.js +32 -0
  62. package/src/libs/mermaidAPI.8.4.8.js +1 -0
  63. package/src/libs/mermaidAPI.8.5.2.js +42 -0
  64. package/src/libs/rawdeflate.js +1663 -0
  65. package/src/locales/en_US.js +139 -0
  66. package/src/locales/index.js +25 -0
  67. package/src/locales/ru_RU.js +139 -0
  68. package/src/locales/zh_CN.js +142 -0
  69. package/src/sass/base.scss +26 -0
  70. package/src/sass/bubble_formula.scss +166 -0
  71. package/src/sass/ch-icon.scss +118 -0
  72. package/src/sass/cherry.scss +1116 -0
  73. package/src/sass/components/bubble.scss +173 -0
  74. package/src/sass/components/shortcut_key_config.scss +108 -0
  75. package/src/sass/formula_utils_bubble.scss +82 -0
  76. package/src/sass/icon_template.scss +24 -0
  77. package/src/sass/icons/uEA03-list.svg +19 -0
  78. package/src/sass/icons/uEA04-check.svg +14 -0
  79. package/src/sass/icons/uEA09-square.svg +10 -0
  80. package/src/sass/icons/uEA0A-bold.svg +20 -0
  81. package/src/sass/icons/uEA0B-code.svg +18 -0
  82. package/src/sass/icons/uEA0C-color.svg +13 -0
  83. package/src/sass/icons/uEA0D-header.svg +8 -0
  84. package/src/sass/icons/uEA0E-image.svg +15 -0
  85. package/src/sass/icons/uEA0F-italic.svg +8 -0
  86. package/src/sass/icons/uEA10-link.svg +16 -0
  87. package/src/sass/icons/uEA11-ol.svg +21 -0
  88. package/src/sass/icons/uEA12-size.svg +11 -0
  89. package/src/sass/icons/uEA13-strike.svg +16 -0
  90. package/src/sass/icons/uEA14-table.svg +12 -0
  91. package/src/sass/icons/uEA15-ul.svg +17 -0
  92. package/src/sass/icons/uEA16-underline.svg +13 -0
  93. package/src/sass/icons/uEA17-word.svg +16 -0
  94. package/src/sass/icons/uEA18-blockquote.svg +11 -0
  95. package/src/sass/icons/uEA19-font.svg +10 -0
  96. package/src/sass/icons/uEA1F-insertClass.svg +39 -0
  97. package/src/sass/icons/uEA20-insertFlow.svg +8 -0
  98. package/src/sass/icons/uEA21-insertFormula.svg +23 -0
  99. package/src/sass/icons/uEA22-insertGantt.svg +13 -0
  100. package/src/sass/icons/uEA23-insertGraph.svg +13 -0
  101. package/src/sass/icons/uEA24-insertPie.svg +19 -0
  102. package/src/sass/icons/uEA25-insertSeq.svg +20 -0
  103. package/src/sass/icons/uEA26-insertState.svg +35 -0
  104. package/src/sass/icons/uEA27-line.svg +11 -0
  105. package/src/sass/icons/uEA28-preview.svg +18 -0
  106. package/src/sass/icons/uEA29-previewClose.svg +24 -0
  107. package/src/sass/icons/uEA2A-toc.svg +24 -0
  108. package/src/sass/icons/uEA2D-sub.svg +15 -0
  109. package/src/sass/icons/uEA2E-sup.svg +15 -0
  110. package/src/sass/icons/uEA2F-h1.svg +16 -0
  111. package/src/sass/icons/uEA30-h2.svg +20 -0
  112. package/src/sass/icons/uEA31-h3.svg +23 -0
  113. package/src/sass/icons/uEA32-h4.svg +16 -0
  114. package/src/sass/icons/uEA33-h5.svg +20 -0
  115. package/src/sass/icons/uEA34-h6.svg +17 -0
  116. package/src/sass/icons/uEA35-video.svg +20 -0
  117. package/src/sass/icons/uEA36-insert.svg +25 -0
  118. package/src/sass/icons/uEA37-little_table.svg +30 -0
  119. package/src/sass/icons/uEA38-pdf.svg +27 -0
  120. package/src/sass/icons/uEA39-checklist.svg +22 -0
  121. package/src/sass/icons/uEA40-close.svg +12 -0
  122. package/src/sass/icons/uEA41-fullscreen.svg +81 -0
  123. package/src/sass/icons/uEA42-minscreen.svg +77 -0
  124. package/src/sass/icons/uEA43-insertChart.svg +23 -0
  125. package/src/sass/icons/uEA44-question.svg +25 -0
  126. package/src/sass/icons/uEA45-settings.svg +32 -0
  127. package/src/sass/icons/uEA46-ok.svg +7 -0
  128. package/src/sass/icons/uEA47-br.svg +22 -0
  129. package/src/sass/icons/uEA48-normal.svg +15 -0
  130. package/src/sass/icons/uEA49-undo.svg +19 -0
  131. package/src/sass/icons/uEA50-redo.svg +21 -0
  132. package/src/sass/icons/uEA51-copy.svg +6 -0
  133. package/src/sass/icons/uEA52-phone.svg +5 -0
  134. package/src/sass/icons/uEA53-cherry-table-delete.svg +17 -0
  135. package/src/sass/icons/uEA54-cherry-table-insert-bottom.svg +16 -0
  136. package/src/sass/icons/uEA55-cherry-table-insert-left.svg +15 -0
  137. package/src/sass/icons/uEA56-cherry-table-insert-right.svg +16 -0
  138. package/src/sass/icons/uEA57-cherry-table-insert-top.svg +16 -0
  139. package/src/sass/icons/uEA58-sort-s.svg +13 -0
  140. package/src/sass/icons/uEA59-pinyin.svg +1 -0
  141. package/src/sass/icons/uEA5A-create.svg +24 -0
  142. package/src/sass/icons/uEA5B-download.svg +34 -0
  143. package/src/sass/icons/uEA5C-edit.svg +3 -0
  144. package/src/sass/icons/uEA5D-export.svg +53 -0
  145. package/src/sass/icons/uEA5E-folder-open.svg +3 -0
  146. package/src/sass/icons/uEA5F-folder.svg +3 -0
  147. package/src/sass/icons/uEA60-help.svg +5 -0
  148. package/src/sass/icons/uEA61-pen-fill.svg +13 -0
  149. package/src/sass/icons/uEA62-pen.svg +3 -0
  150. package/src/sass/icons/uEA64-tips.svg +5 -0
  151. package/src/sass/icons/uEA65-warn.svg +5 -0
  152. package/src/sass/icons/uEA66-mistake.svg +4 -0
  153. package/src/sass/icons/uEA67-success.svg +4 -0
  154. package/src/sass/icons/uEA68-danger.svg +4 -0
  155. package/src/sass/icons/uEA69-info.svg +5 -0
  156. package/src/sass/icons/uEA6A-primary.svg +5 -0
  157. package/src/sass/icons/uEA6B-warning.svg +5 -0
  158. package/src/sass/icons/uEA6C-justify.svg +19 -0
  159. package/src/sass/icons/uEA6D-justifyCenter.svg +19 -0
  160. package/src/sass/icons/uEA6E-justifyLeft.svg +19 -0
  161. package/src/sass/icons/uEA6F-justifyRight.svg +19 -0
  162. package/src/sass/icons/uEA70-chevronsLeft.svg +1 -0
  163. package/src/sass/icons/uEA71-chevronsRight.svg +1 -0
  164. package/src/sass/icons/uEA72-trendingUp.svg +1 -0
  165. package/src/sass/icons/uEA74-codeBlock.svg +1 -0
  166. package/src/sass/icons/uEA75-expand.svg +3 -0
  167. package/src/sass/icons/uEA76-unExpand.svg +3 -0
  168. package/src/sass/icons/uEA77-swap-vert.svg +1 -0
  169. package/src/sass/icons/uEA78-swap.svg +1 -0
  170. package/src/sass/icons/uEA79-keyboard.svg +1 -0
  171. package/src/sass/icons/uEA7A-command.svg +1 -0
  172. package/src/sass/icons/uEA7B-search.svg +1 -0
  173. package/src/sass/index.scss +3 -0
  174. package/src/sass/markdown.scss +668 -0
  175. package/src/sass/markdown_pure.scss +9 -0
  176. package/src/sass/prettyprint/prettyprint.scss +118 -0
  177. package/src/sass/previewer.scss +179 -0
  178. package/src/sass/print.scss +13 -0
  179. package/src/sass/prism/coy.scss +220 -0
  180. package/src/sass/prism/dark.scss +132 -0
  181. package/src/sass/prism/default.scss +143 -0
  182. package/src/sass/prism/funky.scss +133 -0
  183. package/src/sass/prism/okaidia.scss +126 -0
  184. package/src/sass/prism/one-dark.scss +440 -0
  185. package/src/sass/prism/one-light.scss +428 -0
  186. package/src/sass/prism/solarized-light.scss +153 -0
  187. package/src/sass/prism/tomorrow-night.scss +125 -0
  188. package/src/sass/prism/twilight.scss +202 -0
  189. package/src/sass/prism/vs-dark.scss +275 -0
  190. package/src/sass/prism/vs-light.scss +168 -0
  191. package/src/sass/themes/blue.scss +411 -0
  192. package/src/sass/themes/dark.scss +517 -0
  193. package/src/sass/themes/default.scss +255 -0
  194. package/src/sass/themes/green.scss +395 -0
  195. package/src/sass/themes/light.scss +368 -0
  196. package/src/sass/themes/red.scss +397 -0
  197. package/src/sass/themes/violet.scss +410 -0
  198. package/src/sass/variable.scss +84 -0
  199. package/src/toolbars/Bubble.js +234 -0
  200. package/src/toolbars/BubbleFormula.js +298 -0
  201. package/src/toolbars/BubbleTable.js +147 -0
  202. package/src/toolbars/FloatMenu.js +131 -0
  203. package/src/toolbars/HiddenToolbar.js +36 -0
  204. package/src/toolbars/HookCenter.js +234 -0
  205. package/src/toolbars/MenuBase.js +569 -0
  206. package/src/toolbars/PreviewerBubble.js +608 -0
  207. package/src/toolbars/ShortcutKeyConfigPanel.js +345 -0
  208. package/src/toolbars/Sidebar.js +36 -0
  209. package/src/toolbars/Toc.js +242 -0
  210. package/src/toolbars/Toolbar.js +449 -0
  211. package/src/toolbars/ToolbarRight.js +37 -0
  212. package/src/toolbars/hooks/Audio.js +79 -0
  213. package/src/toolbars/hooks/BarTable.js +41 -0
  214. package/src/toolbars/hooks/Bold.js +73 -0
  215. package/src/toolbars/hooks/Br.js +34 -0
  216. package/src/toolbars/hooks/ChangeLocale.js +62 -0
  217. package/src/toolbars/hooks/ChatGpt.js +182 -0
  218. package/src/toolbars/hooks/CheckList.js +41 -0
  219. package/src/toolbars/hooks/Code.js +49 -0
  220. package/src/toolbars/hooks/CodeTheme.js +66 -0
  221. package/src/toolbars/hooks/Color.js +298 -0
  222. package/src/toolbars/hooks/Copy.js +141 -0
  223. package/src/toolbars/hooks/Detail.js +69 -0
  224. package/src/toolbars/hooks/DrawIo.js +57 -0
  225. package/src/toolbars/hooks/Export.js +49 -0
  226. package/src/toolbars/hooks/File.js +79 -0
  227. package/src/toolbars/hooks/Formula.js +69 -0
  228. package/src/toolbars/hooks/FullScreen.js +50 -0
  229. package/src/toolbars/hooks/Graph.js +263 -0
  230. package/src/toolbars/hooks/H1.js +71 -0
  231. package/src/toolbars/hooks/H2.js +71 -0
  232. package/src/toolbars/hooks/H3.js +71 -0
  233. package/src/toolbars/hooks/Header.js +118 -0
  234. package/src/toolbars/hooks/Hr.js +35 -0
  235. package/src/toolbars/hooks/Image.js +91 -0
  236. package/src/toolbars/hooks/InlineCode.js +53 -0
  237. package/src/toolbars/hooks/Insert.js +193 -0
  238. package/src/toolbars/hooks/Italic.js +72 -0
  239. package/src/toolbars/hooks/Justify.js +49 -0
  240. package/src/toolbars/hooks/LineTable.js +41 -0
  241. package/src/toolbars/hooks/Link.js +49 -0
  242. package/src/toolbars/hooks/List.js +55 -0
  243. package/src/toolbars/hooks/MobilePreview.js +44 -0
  244. package/src/toolbars/hooks/Ol.js +41 -0
  245. package/src/toolbars/hooks/Panel.js +140 -0
  246. package/src/toolbars/hooks/Pdf.js +78 -0
  247. package/src/toolbars/hooks/Publish.js +123 -0
  248. package/src/toolbars/hooks/QuickTable.js +43 -0
  249. package/src/toolbars/hooks/Quote.js +45 -0
  250. package/src/toolbars/hooks/Redo.js +33 -0
  251. package/src/toolbars/hooks/Ruby.js +59 -0
  252. package/src/toolbars/hooks/Search.js +53 -0
  253. package/src/toolbars/hooks/Settings.js +220 -0
  254. package/src/toolbars/hooks/ShortcutKey.js +62 -0
  255. package/src/toolbars/hooks/Size.js +118 -0
  256. package/src/toolbars/hooks/Split.js +37 -0
  257. package/src/toolbars/hooks/Strikethrough.js +71 -0
  258. package/src/toolbars/hooks/Sub.js +58 -0
  259. package/src/toolbars/hooks/Sup.js +58 -0
  260. package/src/toolbars/hooks/SwitchModel.js +56 -0
  261. package/src/toolbars/hooks/Table.js +56 -0
  262. package/src/toolbars/hooks/Theme.js +62 -0
  263. package/src/toolbars/hooks/Toc.js +35 -0
  264. package/src/toolbars/hooks/TogglePreview.js +91 -0
  265. package/src/toolbars/hooks/Ul.js +41 -0
  266. package/src/toolbars/hooks/Underline.js +68 -0
  267. package/src/toolbars/hooks/Undo.js +30 -0
  268. package/src/toolbars/hooks/Video.js +79 -0
  269. package/src/toolbars/hooks/Word.js +78 -0
  270. package/src/toolbars/hooks/WordCount.js +106 -0
  271. package/src/utils/autoindent.js +58 -0
  272. package/src/utils/cm-search-replace.js +794 -0
  273. package/src/utils/code-preview-language-setting.js +180 -0
  274. package/src/utils/codeBlockContentHandler.js +400 -0
  275. package/src/utils/config.js +174 -0
  276. package/src/utils/copy.js +55 -0
  277. package/src/utils/dialog.js +214 -0
  278. package/src/utils/dom.js +163 -0
  279. package/src/utils/downloadUtil.js +23 -0
  280. package/src/utils/env.js +22 -0
  281. package/src/utils/error.js +61 -0
  282. package/src/utils/event.js +38 -0
  283. package/src/utils/export.js +166 -0
  284. package/src/utils/file.js +164 -0
  285. package/src/utils/formulaUtilsHandler.js +232 -0
  286. package/src/utils/htmlparser.js +976 -0
  287. package/src/utils/image.js +99 -0
  288. package/src/utils/imgSizeHandler.js +279 -0
  289. package/src/utils/lazyLoadImg.js +327 -0
  290. package/src/utils/lineFeed.js +49 -0
  291. package/src/utils/listContentHandler.js +227 -0
  292. package/src/utils/lookbehind-replace.js +81 -0
  293. package/src/utils/mathjax.js +89 -0
  294. package/src/utils/myersDiff.js +211 -0
  295. package/src/utils/pasteHelper.js +253 -0
  296. package/src/utils/platformTransform.js +71 -0
  297. package/src/utils/recount-pos.js +59 -0
  298. package/src/utils/regexp.js +295 -0
  299. package/src/utils/sanitize.js +477 -0
  300. package/src/utils/selection.js +50 -0
  301. package/src/utils/shortcutKey.js +291 -0
  302. package/src/utils/svgUtils.js +96 -0
  303. package/src/utils/tableContentHandler.js +876 -0
  304. package/test/core/CommonMark.spec.ts +62 -0
  305. package/test/core/hooks/AutoLink.spec.ts +28 -0
  306. package/test/core/hooks/List.spec.ts +79 -0
  307. package/test/core/hooks/__snapshots__/List.spec.ts.snap +11 -0
  308. package/test/example.md +778 -0
  309. package/test/node.js +10 -0
  310. package/test/suites/commonmark.spec.json +5218 -0
  311. package/test/tsconfig.test.json +6 -0
  312. package/test/utils/regexp.spec.ts +28 -0
  313. package/types/cherry.d.ts +675 -0
  314. package/types/codemirror.d.ts +22 -0
  315. package/types/editor.d.ts +72 -0
  316. package/types/global.d.ts +16 -0
  317. package/types/menus.d.ts +24 -0
  318. package/types/previewer.d.ts +53 -0
  319. package/types/syntax.d.ts +52 -0
@@ -0,0 +1,61 @@
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
+ /**
17
+ * 三个地方的错误异常校验
18
+ * 1. markdown 对象参数校验
19
+ * 2. editText 用户输入校验,执行engine过程以防异常
20
+ * 3. 自定义hook校验 对外开发者开发标准校验
21
+ */
22
+
23
+ export const $expectTarget = (target, Constructor) => {
24
+ if (
25
+ (!Array.isArray(target) && typeof target !== Constructor.name.toLowerCase()) ||
26
+ (!Array.isArray(target) && Constructor.name.toLowerCase() === 'array')
27
+ ) {
28
+ throw new TypeError(`parameter given must be ${Constructor.name}`);
29
+ }
30
+
31
+ return true;
32
+ };
33
+
34
+ export const $expectInherit = (target, parent) => {
35
+ if (!(target instanceof parent)) {
36
+ throw new Error('the hook does not correctly inherit');
37
+ }
38
+ return true;
39
+ };
40
+
41
+ export const $expectInstance = (target) => {
42
+ if (typeof target !== 'object') {
43
+ throw new Error('the hook must be a instance, not a class');
44
+ }
45
+ return true;
46
+ };
47
+
48
+ // ref: https://github.com/mdlavin/nested-error-stacks
49
+ export default class NestedError extends Error {
50
+ constructor(message, nested) {
51
+ super(message);
52
+ this.name = 'Error';
53
+ this.stack = this.buildStackTrace(nested);
54
+ }
55
+
56
+ buildStackTrace(nested) {
57
+ const stack = nested && nested.stack ? nested.stack : '';
58
+ const newStack = `${this.stack}\nCaused By: ${stack}`;
59
+ return newStack;
60
+ }
61
+ }
@@ -0,0 +1,38 @@
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
+ export function addEvent(elm, evType, fn, useCapture) {
17
+ if (elm.addEventListener) {
18
+ elm.addEventListener(evType, fn, useCapture); // DOM2.0
19
+ return true;
20
+ }
21
+
22
+ if (elm.attachEvent) {
23
+ const r = elm.attachEvent(`on${evType}`, fn); // IE5+
24
+ return r;
25
+ }
26
+ elm[`on${evType}`] = fn; // DOM 0
27
+ }
28
+
29
+ export function removeEvent(elm, evType, fn, useCapture) {
30
+ if (elm.removeEventListener) {
31
+ elm.removeEventListener(evType, fn, useCapture); // DOM2.0
32
+ } else if (elm.detachEvent) {
33
+ const r = elm.detachEvent(`on${evType}`, fn); // IE5+
34
+ return r;
35
+ } else {
36
+ elm[`on${evType}`] = null; // DOM 0
37
+ }
38
+ }
@@ -0,0 +1,166 @@
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 html2canvas from 'html2canvas';
17
+
18
+ /**
19
+ * 先把body上的内容隐藏起来
20
+ * @returns {Array} displayList 记录body子元素原始的显隐信息
21
+ */
22
+ const hideBodyChildren = () => {
23
+ const displayList = [];
24
+ /** @type {HTMLElement[]}*/ (Array.from(document.body.children)).forEach((dom, index) => {
25
+ displayList[index] = dom.style.display;
26
+ dom.style.display = 'none';
27
+ });
28
+ return displayList;
29
+ };
30
+
31
+ /**
32
+ * 复原body上被隐藏的内容
33
+ * @param {Array} displayList 记录body子元素原始的显隐信息
34
+ */
35
+ const undoHideBodyChildren = (displayList = []) => {
36
+ /** @type {HTMLElement[]}*/ (Array.from(document.body.children)).forEach((dom, index) => {
37
+ if (typeof displayList[index] !== 'undefined') {
38
+ dom.style.display = displayList[index];
39
+ }
40
+ });
41
+ };
42
+
43
+ /**
44
+ * 将预览区域的内容放在body上准备后续导出操作
45
+ * @param {HTMLElement} previewDom 预览区域的dom
46
+ * @param {function} cb 准备好导出后开始执行导出操作
47
+ */
48
+ const getReadyToExport = (previewDom, cb) => {
49
+ const cherryPreviewer = /** @type {HTMLElement}*/ (previewDom.cloneNode(true));
50
+ // 强制去掉预览区的隐藏class
51
+ cherryPreviewer.className = cherryPreviewer.className.replace('cherry-previewer--hidden', '');
52
+ cherryPreviewer.style.width = '100%';
53
+ const mmls = cherryPreviewer.querySelectorAll('mjx-assistive-mml');
54
+ // a fix for html2canvas
55
+ mmls.forEach((e) => {
56
+ if (e instanceof HTMLElement) e.style.setProperty('visibility', 'hidden');
57
+ });
58
+ const cherryWrapper = document.createElement('div');
59
+ cherryWrapper.appendChild(cherryPreviewer);
60
+ const displayList = hideBodyChildren();
61
+ document.body.appendChild(cherryWrapper);
62
+ const bodyOverflow = document.body.style.overflow;
63
+ document.body.style.overflow = 'visible';
64
+ cb(cherryPreviewer, () => {
65
+ cherryWrapper.remove();
66
+ undoHideBodyChildren(displayList);
67
+ document.body.style.overflow = bodyOverflow;
68
+ });
69
+ };
70
+
71
+ /**
72
+ * 下载文件
73
+ * @param {String} downloadUrl 图片本地地址
74
+ * @param {String} fileName 导出图片文件名
75
+ */
76
+ const fileDownload = (downloadUrl, fileName) => {
77
+ const aLink = document.createElement('a');
78
+ aLink.style.display = 'none';
79
+ aLink.href = downloadUrl;
80
+ aLink.download = `${fileName}.png`;
81
+ document.body.appendChild(aLink);
82
+ aLink.click();
83
+ document.body.removeChild(aLink);
84
+ };
85
+
86
+ /**
87
+ * 利用window.print导出成PDF
88
+ * @param {HTMLElement} previewDom 预览区域的dom
89
+ * @param {String} fileName 导出PDF文件名
90
+ */
91
+ export function exportPDF(previewDom, fileName) {
92
+ const oldTitle = document.title;
93
+ document.title = fileName;
94
+ getReadyToExport(previewDom, (/** @type {HTMLElement}*/ cherryPreviewer, /** @type {function}*/ thenFinish) => {
95
+ // 强制展开所有代码块
96
+ cherryPreviewer.innerHTML = cherryPreviewer.innerHTML.replace(
97
+ /class="cherry-code-unExpand("| )/g,
98
+ 'class="cherry-code-expand$1',
99
+ );
100
+ window.print();
101
+ thenFinish();
102
+ document.title = oldTitle;
103
+ });
104
+ }
105
+
106
+ /**
107
+ * 利用canvas将html内容导出成图片
108
+ * @param {HTMLElement} previewDom 预览区域的dom
109
+ * @param {String} fileName 导出图片文件名
110
+ */
111
+ export function exportScreenShot(previewDom, fileName) {
112
+ getReadyToExport(previewDom, (/** @type {HTMLElement}*/ cherryPreviewer, /** @type {function}*/ thenFinish) => {
113
+ window.scrollTo(0, 0);
114
+ // 去掉audio和video标签
115
+ cherryPreviewer.innerHTML = cherryPreviewer.innerHTML.replace(/<audio [^>]+?>([^\n]*?)<\/audio>/g, '$1');
116
+ cherryPreviewer.innerHTML = cherryPreviewer.innerHTML.replace(/<video [^>]+?>([^\n]*?)<\/video>/g, '$1');
117
+ // 强制展开所有代码块
118
+ cherryPreviewer.innerHTML = cherryPreviewer.innerHTML.replace(
119
+ /class="cherry-code-unExpand("| )/g,
120
+ 'class="cherry-code-expand$1',
121
+ );
122
+ html2canvas(cherryPreviewer, {
123
+ allowTaint: true,
124
+ height: cherryPreviewer.clientHeight,
125
+ width: cherryPreviewer.clientWidth,
126
+ scrollY: 0,
127
+ scrollX: 0,
128
+ }).then((canvas) => {
129
+ const imgData = canvas.toDataURL('image/jpeg');
130
+ fileDownload(imgData, fileName);
131
+ thenFinish();
132
+ });
133
+ });
134
+ }
135
+
136
+ /**
137
+ * 导出 markdown 文件
138
+ * @param {String} markdownText markdown文本
139
+ * @param {String} fileName 导出markdown文件名
140
+ */
141
+ export function exportMarkdownFile(markdownText, fileName) {
142
+ const blob = new Blob([markdownText], { type: 'text/markdown;charset=utf-8' });
143
+ const aLink = document.createElement('a');
144
+ aLink.style.display = 'none';
145
+ aLink.href = URL.createObjectURL(blob);
146
+ aLink.download = `${fileName}.md`;
147
+ document.body.appendChild(aLink);
148
+ aLink.click();
149
+ document.body.removeChild(aLink);
150
+ }
151
+
152
+ /**
153
+ * 导出预览区 HTML 文件
154
+ * @param {String} HTMLText HTML文本
155
+ * @param {String} fileName 导出HTML文件名
156
+ */
157
+ export function exportHTMLFile(HTMLText, fileName) {
158
+ const blob = new Blob([HTMLText], { type: 'text/markdown;charset=utf-8' });
159
+ const aLink = document.createElement('a');
160
+ aLink.style.display = 'none';
161
+ aLink.href = URL.createObjectURL(blob);
162
+ aLink.download = `${fileName}.html`;
163
+ document.body.appendChild(aLink);
164
+ aLink.click();
165
+ document.body.removeChild(aLink);
166
+ }
@@ -0,0 +1,164 @@
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
+
17
+ /**
18
+ * 多选上传文件的逻辑,如果有callback,则不再走默认的替换文本的逻辑,而是调用callback
19
+ * @param {string} type 上传文件的类型
20
+ */
21
+ export function handleUploadMulti(editor, type = 'image', accept = '*', callback = null) {
22
+ // type为上传文件类型 image|video|audio|pdf|word
23
+ const input = document.createElement('input');
24
+ const inputMultiple = editor.$cherry.options.multipleFileSelection || false;
25
+ input.type = 'file';
26
+ input.id = 'fileUpload';
27
+ input.value = '';
28
+ input.style.display = 'none';
29
+ input.accept = accept;
30
+ input.multiple = inputMultiple;
31
+ // document.body.appendChild(input);
32
+ input.addEventListener('change', (event) => {
33
+ // @ts-ignore
34
+ const { files } = event.target;
35
+ // 文件上传后的回调函数可以由调用方自己实现
36
+ editor.$cherry.options.callback.fileUploadMulti(files, (arr) => {
37
+ // 文件上传的默认回调行数,调用方可以完全不使用该函数
38
+ if (arr.length === 0) {
39
+ return;
40
+ }
41
+ if (callback) {
42
+ return callback(arr);
43
+ }
44
+ let code = '';
45
+ for (const file of files) {
46
+ const { url } = file;
47
+ code += `${handleType(type, file, url)}/n`;
48
+ }
49
+ // 替换选中区域
50
+ // @ts-ignore
51
+ editor.editor.doc.replaceSelection(code);
52
+ });
53
+ });
54
+ input.click();
55
+ }
56
+
57
+ /**
58
+ * 上传文件的逻辑,如果有callback,则不再走默认的替换文本的逻辑,而是调用callback
59
+ * @param {string} type 上传文件的类型
60
+ */
61
+ export function handleUpload(editor, type = 'image', accept = '*', callback = null) {
62
+ // type为上传文件类型 image|video|audio|pdf|word
63
+ const input = document.createElement('input');
64
+ input.type = 'file';
65
+ input.id = 'fileUpload';
66
+ input.value = '';
67
+ input.style.display = 'none';
68
+ input.accept = accept;
69
+ // document.body.appendChild(input);
70
+ input.addEventListener('change', (event) => {
71
+ // @ts-ignore
72
+ const [file] = event.target.files;
73
+ // 文件上传后的回调函数可以由调用方自己实现
74
+ editor.$cherry.options.callback.fileUpload(file, (url, params = {}) => {
75
+ // 文件上传的默认回调行数,调用方可以完全不使用该函数
76
+ if (typeof url !== 'string' || !url) {
77
+ return;
78
+ }
79
+ if (callback) {
80
+ return callback(file.name, url, params);
81
+ }
82
+ let code = '';
83
+ code = handleType(type, file, url);
84
+ // 替换选中区域
85
+ // @ts-ignore
86
+ editor.editor.doc.replaceSelection(code);
87
+ });
88
+ });
89
+ input.click();
90
+ }
91
+
92
+ /**
93
+ * 处理要插入的代码
94
+ * @param type 文件类型
95
+ * @param file 文件
96
+ * @param url 路径
97
+ * @returns string
98
+ */
99
+ const handleType = (type, file, url) => {
100
+ if (type === 'image') {
101
+ // 如果是图片,则返回固定的图片markdown源码
102
+ return `![${file.name}](${url})`;
103
+ }
104
+ if (type === 'video') {
105
+ // 如果是视频,则返回固定的视频markdown源码
106
+ return `!video[${file.name}](${url})`;
107
+ }
108
+ if (type === 'audio') {
109
+ // 如果是音频,则返回固定的音频markdown源码
110
+ return `!audio[${file.name}](${url})`;
111
+ }
112
+ // 默认返回超链接
113
+ return `[${file.name}](${url})`;
114
+ };
115
+
116
+ /**
117
+ * 解析params参数
118
+ * @param params?.isBorder 是否有边框样式(图片场景下生效)
119
+ * @param params?.isShadow 是否有阴影样式(图片场景下生效)
120
+ * @param params?.isRadius 是否有圆角样式(图片场景下生效)
121
+ * @param params?.width 设置宽度,可以是像素、也可以是百分比(图片、视频场景下生效)
122
+ * @param params?.height 设置高度,可以是像素、也可以是百分比(图片、视频场景下生效)
123
+ */
124
+ export function handleParams(params) {
125
+ const ret = [];
126
+ if (params?.isBorder) {
127
+ ret.push('#B');
128
+ }
129
+ if (params?.isShadow) {
130
+ ret.push('#S');
131
+ }
132
+ if (params?.isRadius) {
133
+ ret.push('#R');
134
+ }
135
+ if (params?.width) {
136
+ ret.push(`#${params.width}`);
137
+ }
138
+ if (params?.height) {
139
+ if (!params.width) {
140
+ ret.push('#auto');
141
+ }
142
+ ret.push(`#${params.height}`);
143
+ }
144
+ return ret.join(' ');
145
+ }
146
+
147
+ export function handleFileUploadCallback(url, params, file) {
148
+ const name = params?.name ?? file.name;
149
+ let type = '';
150
+ let poster = '';
151
+ if (/video/i.test(file.type)) {
152
+ type = '!video';
153
+ poster = params?.poster ? `{poster=${params.poster}}` : '';
154
+ }
155
+ if (/audio/i.test(file.type)) {
156
+ type = '!audio';
157
+ }
158
+ if (/image/i.test(file.type)) {
159
+ type = '!';
160
+ }
161
+ const style = type ? handleParams(params) : '';
162
+ const { before = '', after = '' } = params;
163
+ return `${before}${type}[${name}${style}](${url})${poster}${after}`;
164
+ }
@@ -0,0 +1,232 @@
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
+
17
+ import { svg2img, getSvgString } from '@/utils/svgUtils';
18
+ import { copyTextByClipboard } from '@/utils/copy';
19
+ import MathBlock from '@/core/hooks/MathBlock';
20
+
21
+ export default class FormulaHandler {
22
+ /** @type{HTMLElement} */
23
+ bubbleContainer = null;
24
+ /**
25
+ * @param {string} trigger 触发方式
26
+ * @param {Element} target 目标dom
27
+ * @param {HTMLDivElement} container bubble容器
28
+ * @param {HTMLDivElement} previewerDom 预览器dom
29
+ * @param {import('../Editor').default} editor 编辑器实例
30
+ */
31
+ constructor(trigger, target, container, previewerDom, editor) {
32
+ this.trigger = trigger;
33
+ this.target = target;
34
+ this.container = container;
35
+ this.previewerDom = previewerDom;
36
+ this.editor = editor;
37
+ }
38
+
39
+ /**
40
+ * 触发事件
41
+ * @param {string} type 事件类型
42
+ * @param {Event} event 事件对象
43
+ */
44
+ // @ts-ignore
45
+ emit(type, event) {
46
+ switch (type) {
47
+ case 'remove':
48
+ case 'scroll':
49
+ return this.remove();
50
+ }
51
+ }
52
+
53
+ /**
54
+ * 绘制公式操作bubble容器
55
+ */
56
+ drawBubble() {
57
+ const bubbleContainer = document.createElement('div');
58
+ bubbleContainer.innerHTML = `<div class="formula-utils-btn formula-utils-img">
59
+ <button>输出图片</button>
60
+ <div class="formula-utils-submenu formula-utils-img-submenu">
61
+ <div class="formula-utils-submenu-btn formula-utils-img-svg">
62
+ <button data-name="svg">svg</button>
63
+ </div>
64
+ <div class="formula-utils-submenu-btn formula-utils-img-png">
65
+ <button data-name="png">png</button>
66
+ </div>
67
+ <div class="formula-utils-submenu-btn formula-utils-img-jpg">
68
+ <button data-name="jpg">jpg</button>
69
+ </div>
70
+ </div>
71
+ </div>
72
+ <div class="formula-utils-btn formula-utils-code">
73
+ <button>输出代码</button>
74
+ <div class="formula-utils-submenu formula-utils-code-submenu">
75
+ <div class="formula-utils-submenu-btn formula-utils-code-latex">
76
+ <button data-name="latex">latex</button>
77
+ </div>
78
+ <div class="formula-utils-submenu-btn formula-utils-code-html">
79
+ <button data-name="html">html</button>
80
+ </div>
81
+ <div class="formula-utils-submenu-btn formula-utils-code-svgcode">
82
+ <button data-name="svgcode">svgcode</button>
83
+ </div>
84
+ </div>
85
+ </div>
86
+ <div class="formula-utils-btn formula-utils-word">
87
+ <button>输出mathml</button>
88
+ <div class="formula-utils-submenu formula-utils-word-submenu">
89
+ <div class="formula-utils-submenu-btn formula-utils-word-mathml">
90
+ <button data-name="mathml">mathml</button>
91
+ </div>
92
+ </div>
93
+ </div>
94
+ <div class="formula-utils-btn formula-utils-transfer">
95
+ <button>转义</button>
96
+ <div class="formula-utils-submenu formula-utils-transfer-submenu">
97
+ <div class="formula-utils-submenu-btn formula-utils-transfer-backslash">
98
+ <button data-name="\\">反斜杠</button>
99
+ </div>
100
+ <div class="formula-utils-submenu-btn formula-utils-transfer-dollar">
101
+ <button data-name="$">$包裹</button>
102
+ </div>
103
+ <div class="formula-utils-submenu-btn formula-utils-transfer-double-dollar">
104
+ <button data-name="$$">$$包裹</button>
105
+ </div>
106
+ </div>
107
+ </div>`;
108
+ bubbleContainer.id = 'formula-utils-bubble-container'; // 方便 namedItem 获取
109
+ bubbleContainer.className = ['formula-utils-bubble-container'].join(' ');
110
+ this.bubbleContainer = bubbleContainer;
111
+ this?.editor?.$cherry?.wrapperDom?.appendChild(bubbleContainer);
112
+ }
113
+
114
+ /**
115
+ * 显示bubble
116
+ * @param {number} x
117
+ * @param {number} y
118
+ */
119
+ showBubble(x, y) {
120
+ const bubbleContainer = this?.editor?.$cherry?.wrapperDom?.children?.namedItem('formula-utils-bubble-container');
121
+ const targetRect = this.target.getBoundingClientRect();
122
+ if (bubbleContainer instanceof HTMLElement) {
123
+ this.bubbleContainer = bubbleContainer;
124
+ } else {
125
+ this.drawBubble();
126
+ }
127
+ this.bubbleContainer.style.display = 'flex';
128
+ this.bubbleContainer.style.top = `${y || targetRect.top}px`;
129
+ this.bubbleContainer.style.left = `${x || targetRect.left}px`;
130
+ this.bubbleContainer.addEventListener('click', this.bubbleClickHandler.bind(this), { once: true });
131
+ this.collectFormulaCode();
132
+ }
133
+
134
+ collectFormulaCode() {
135
+ const formulaCode = [];
136
+ // @ts-ignore
137
+ this.editor.editor.getValue().replace(/(\$+)\s*([\w\W]*?)\s*(\1)/g, (whole, start, content, end, offset) => {
138
+ formulaCode.push({
139
+ code: content,
140
+ offset,
141
+ });
142
+ });
143
+ this.formulaCode = formulaCode;
144
+ }
145
+
146
+ remove() {
147
+ if (this.bubbleContainer) {
148
+ this.bubbleContainer.style.display = 'none';
149
+ }
150
+ }
151
+
152
+ /**
153
+ * bubble 上的点击事件
154
+ * @param {Event} e
155
+ */
156
+ bubbleClickHandler(e) {
157
+ e.preventDefault();
158
+ e.stopPropagation();
159
+ const { target } = e;
160
+ if (target instanceof HTMLButtonElement) {
161
+ const { name = '' } = target.dataset;
162
+ switch (name) {
163
+ case 'svg':
164
+ case 'png':
165
+ case 'jpg':
166
+ // 涉及到图片的操作
167
+ if (this.target instanceof SVGSVGElement) {
168
+ svg2img(this.target, { format: name });
169
+ }
170
+ break;
171
+ case 'html':
172
+ case 'svgcode':
173
+ // 涉及到代码的操作
174
+ if (this.target instanceof SVGSVGElement) {
175
+ if (name === 'svgcode') {
176
+ copyTextByClipboard(getSvgString(this.target));
177
+ } else {
178
+ const mathElement = this.target.parentElement.querySelector('math');
179
+ mathElement.setAttribute('xmlns', 'http://www.w3.org/1998/Math/MathML');
180
+ copyTextByClipboard(mathElement.outerHTML);
181
+ }
182
+ }
183
+ break;
184
+ case '\\':
185
+ case '$':
186
+ case '$$':
187
+ case 'latex':
188
+ case 'mathml':
189
+ case 'docx':
190
+ // 涉及到公式API的操作
191
+ {
192
+ const allMjx = this.previewerDom.querySelectorAll('mjx-container');
193
+ let mjxIndex = -1;
194
+ allMjx.forEach((mjx, index) => {
195
+ if (mjx === this.target.parentElement) {
196
+ mjxIndex = index;
197
+ }
198
+ });
199
+ if (mjxIndex >= 0 && this.formulaCode[mjxIndex]) {
200
+ const { code } = this.formulaCode[mjxIndex];
201
+ if (name === 'mathml' || name === 'docx') {
202
+ /** @type {MathBlock} */
203
+ // @ts-ignore
204
+ const hook = this.editor.$cherry.engine.hooks.paragraph.find((hook) => hook instanceof MathBlock);
205
+ if (hook && hook.engine === 'MathJax') {
206
+ window.MathJax?.texReset();
207
+ window.MathJax?.tex2mmlPromise?.(code, { display: true }).then((mml) => {
208
+ if (name === 'mathml') {
209
+ copyTextByClipboard(mml);
210
+ } else {
211
+ // TODO: docx
212
+ }
213
+ });
214
+ }
215
+ // TODO: other engine
216
+ } else if (name === 'latex') {
217
+ copyTextByClipboard(code);
218
+ } else if (name === '$') {
219
+ copyTextByClipboard(`${name}${code}${name}`);
220
+ } else if (name === '$$') {
221
+ copyTextByClipboard(`${name}\n${code}\n${name}`);
222
+ } else if (name === '\\') {
223
+ copyTextByClipboard(`\\${code}`);
224
+ }
225
+ }
226
+ }
227
+ break;
228
+ }
229
+ }
230
+ this.remove();
231
+ }
232
+ }