@cherry-markdown/cherry-markdown-dev 0.9.0-dev.202504110650.834443a → 0.9.0-dev.202504160300.d23d141

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 (327) hide show
  1. package/README.md +2 -2
  2. package/dist/addons/advance/cherry-table-echarts-plugin.js +1 -1
  3. package/dist/addons/cherry-code-block-mermaid-plugin.js +1 -1
  4. package/dist/cherry-markdown.core.common.js +1 -1
  5. package/dist/cherry-markdown.core.js +1 -1
  6. package/dist/cherry-markdown.engine.core.common.js +1 -1
  7. package/dist/cherry-markdown.engine.core.esm.js +1 -1
  8. package/dist/cherry-markdown.engine.core.js +1 -1
  9. package/dist/cherry-markdown.esm.js +1 -1
  10. package/dist/cherry-markdown.js +1 -1
  11. package/dist/cherry-markdown.min.js +1 -1
  12. package/dist/fonts/ch-icon.eot +0 -0
  13. package/dist/fonts/ch-icon.ttf +0 -0
  14. package/dist/fonts/ch-icon.woff +0 -0
  15. package/dist/fonts/ch-icon.woff2 +0 -0
  16. package/package.json +1 -3
  17. package/src/Cherry.config.js +0 -634
  18. package/src/Cherry.js +0 -1104
  19. package/src/CherryStatic.js +0 -70
  20. package/src/Editor.js +0 -748
  21. package/src/Engine.js +0 -402
  22. package/src/Event.js +0 -140
  23. package/src/Factory.js +0 -180
  24. package/src/Logger.js +0 -31
  25. package/src/Previewer.js +0 -1192
  26. package/src/Sanitizer.js +0 -4
  27. package/src/Sanitizer.node.js +0 -7
  28. package/src/UrlCache.js +0 -98
  29. package/src/addons/advance/cherry-table-echarts-plugin.js +0 -170
  30. package/src/addons/cherry-code-block-mermaid-plugin.js +0 -158
  31. package/src/addons/cherry-code-block-plantuml-plugin.js +0 -106
  32. package/src/core/HookCenter.js +0 -297
  33. package/src/core/HooksConfig.js +0 -105
  34. package/src/core/ParagraphBase.js +0 -332
  35. package/src/core/SentenceBase.js +0 -65
  36. package/src/core/SyntaxBase.js +0 -194
  37. package/src/core/hooks/AutoLink.js +0 -232
  38. package/src/core/hooks/BackgroundColor.js +0 -46
  39. package/src/core/hooks/Blockquote.js +0 -70
  40. package/src/core/hooks/Br.js +0 -85
  41. package/src/core/hooks/CodeBlock.js +0 -456
  42. package/src/core/hooks/Color.js +0 -46
  43. package/src/core/hooks/CommentReference.js +0 -96
  44. package/src/core/hooks/Detail.js +0 -108
  45. package/src/core/hooks/Emoji.config.js +0 -1825
  46. package/src/core/hooks/Emoji.js +0 -119
  47. package/src/core/hooks/Emphasis.js +0 -113
  48. package/src/core/hooks/Footnote.js +0 -125
  49. package/src/core/hooks/FrontMatter.js +0 -51
  50. package/src/core/hooks/Header.js +0 -234
  51. package/src/core/hooks/HighLight.js +0 -37
  52. package/src/core/hooks/Hr.js +0 -52
  53. package/src/core/hooks/HtmlBlock.js +0 -199
  54. package/src/core/hooks/Image.js +0 -174
  55. package/src/core/hooks/InlineCode.js +0 -48
  56. package/src/core/hooks/InlineMath.js +0 -108
  57. package/src/core/hooks/Link.js +0 -160
  58. package/src/core/hooks/List.js +0 -264
  59. package/src/core/hooks/MathBlock.js +0 -104
  60. package/src/core/hooks/Panel.js +0 -145
  61. package/src/core/hooks/Paragraph.js +0 -84
  62. package/src/core/hooks/Ruby.js +0 -34
  63. package/src/core/hooks/Size.js +0 -51
  64. package/src/core/hooks/Strikethrough.js +0 -54
  65. package/src/core/hooks/Sub.js +0 -47
  66. package/src/core/hooks/SuggestList.js +0 -333
  67. package/src/core/hooks/Suggester.js +0 -707
  68. package/src/core/hooks/Sup.js +0 -47
  69. package/src/core/hooks/Table.js +0 -275
  70. package/src/core/hooks/Toc.js +0 -292
  71. package/src/core/hooks/Transfer.js +0 -47
  72. package/src/core/hooks/Underline.js +0 -37
  73. package/src/index.core.js +0 -29
  74. package/src/index.engine.core.js +0 -68
  75. package/src/index.engine.js +0 -28
  76. package/src/index.js +0 -32
  77. package/src/libs/mermaidAPI.8.4.8.js +0 -1
  78. package/src/libs/mermaidAPI.8.5.2.js +0 -42
  79. package/src/libs/rawdeflate.js +0 -1663
  80. package/src/locales/en_US.js +0 -139
  81. package/src/locales/index.js +0 -25
  82. package/src/locales/ru_RU.js +0 -139
  83. package/src/locales/zh_CN.js +0 -142
  84. package/src/sass/base.scss +0 -26
  85. package/src/sass/bubble_formula.scss +0 -166
  86. package/src/sass/ch-icon.scss +0 -118
  87. package/src/sass/cherry.scss +0 -1116
  88. package/src/sass/components/bubble.scss +0 -173
  89. package/src/sass/components/shortcut_key_config.scss +0 -108
  90. package/src/sass/formula_utils_bubble.scss +0 -82
  91. package/src/sass/icon_template.scss +0 -24
  92. package/src/sass/icons/uEA03-list.svg +0 -19
  93. package/src/sass/icons/uEA04-check.svg +0 -14
  94. package/src/sass/icons/uEA09-square.svg +0 -10
  95. package/src/sass/icons/uEA0A-bold.svg +0 -20
  96. package/src/sass/icons/uEA0B-code.svg +0 -18
  97. package/src/sass/icons/uEA0C-color.svg +0 -13
  98. package/src/sass/icons/uEA0D-header.svg +0 -8
  99. package/src/sass/icons/uEA0E-image.svg +0 -15
  100. package/src/sass/icons/uEA0F-italic.svg +0 -8
  101. package/src/sass/icons/uEA10-link.svg +0 -16
  102. package/src/sass/icons/uEA11-ol.svg +0 -21
  103. package/src/sass/icons/uEA12-size.svg +0 -11
  104. package/src/sass/icons/uEA13-strike.svg +0 -16
  105. package/src/sass/icons/uEA14-table.svg +0 -12
  106. package/src/sass/icons/uEA15-ul.svg +0 -17
  107. package/src/sass/icons/uEA16-underline.svg +0 -13
  108. package/src/sass/icons/uEA17-word.svg +0 -16
  109. package/src/sass/icons/uEA18-blockquote.svg +0 -11
  110. package/src/sass/icons/uEA19-font.svg +0 -10
  111. package/src/sass/icons/uEA1F-insertClass.svg +0 -39
  112. package/src/sass/icons/uEA20-insertFlow.svg +0 -8
  113. package/src/sass/icons/uEA21-insertFormula.svg +0 -23
  114. package/src/sass/icons/uEA22-insertGantt.svg +0 -13
  115. package/src/sass/icons/uEA23-insertGraph.svg +0 -13
  116. package/src/sass/icons/uEA24-insertPie.svg +0 -19
  117. package/src/sass/icons/uEA25-insertSeq.svg +0 -20
  118. package/src/sass/icons/uEA26-insertState.svg +0 -35
  119. package/src/sass/icons/uEA27-line.svg +0 -11
  120. package/src/sass/icons/uEA28-preview.svg +0 -18
  121. package/src/sass/icons/uEA29-previewClose.svg +0 -24
  122. package/src/sass/icons/uEA2A-toc.svg +0 -24
  123. package/src/sass/icons/uEA2D-sub.svg +0 -15
  124. package/src/sass/icons/uEA2E-sup.svg +0 -15
  125. package/src/sass/icons/uEA2F-h1.svg +0 -16
  126. package/src/sass/icons/uEA30-h2.svg +0 -20
  127. package/src/sass/icons/uEA31-h3.svg +0 -23
  128. package/src/sass/icons/uEA32-h4.svg +0 -16
  129. package/src/sass/icons/uEA33-h5.svg +0 -20
  130. package/src/sass/icons/uEA34-h6.svg +0 -17
  131. package/src/sass/icons/uEA35-video.svg +0 -20
  132. package/src/sass/icons/uEA36-insert.svg +0 -25
  133. package/src/sass/icons/uEA37-little_table.svg +0 -30
  134. package/src/sass/icons/uEA38-pdf.svg +0 -27
  135. package/src/sass/icons/uEA39-checklist.svg +0 -22
  136. package/src/sass/icons/uEA40-close.svg +0 -12
  137. package/src/sass/icons/uEA41-fullscreen.svg +0 -81
  138. package/src/sass/icons/uEA42-minscreen.svg +0 -77
  139. package/src/sass/icons/uEA43-insertChart.svg +0 -23
  140. package/src/sass/icons/uEA44-question.svg +0 -25
  141. package/src/sass/icons/uEA45-settings.svg +0 -32
  142. package/src/sass/icons/uEA46-ok.svg +0 -7
  143. package/src/sass/icons/uEA47-br.svg +0 -22
  144. package/src/sass/icons/uEA48-normal.svg +0 -15
  145. package/src/sass/icons/uEA49-undo.svg +0 -19
  146. package/src/sass/icons/uEA50-redo.svg +0 -21
  147. package/src/sass/icons/uEA51-copy.svg +0 -6
  148. package/src/sass/icons/uEA52-phone.svg +0 -5
  149. package/src/sass/icons/uEA53-cherry-table-delete.svg +0 -17
  150. package/src/sass/icons/uEA54-cherry-table-insert-bottom.svg +0 -16
  151. package/src/sass/icons/uEA55-cherry-table-insert-left.svg +0 -15
  152. package/src/sass/icons/uEA56-cherry-table-insert-right.svg +0 -16
  153. package/src/sass/icons/uEA57-cherry-table-insert-top.svg +0 -16
  154. package/src/sass/icons/uEA58-sort-s.svg +0 -13
  155. package/src/sass/icons/uEA59-pinyin.svg +0 -1
  156. package/src/sass/icons/uEA5A-create.svg +0 -24
  157. package/src/sass/icons/uEA5B-download.svg +0 -34
  158. package/src/sass/icons/uEA5C-edit.svg +0 -3
  159. package/src/sass/icons/uEA5D-export.svg +0 -53
  160. package/src/sass/icons/uEA5E-folder-open.svg +0 -3
  161. package/src/sass/icons/uEA5F-folder.svg +0 -3
  162. package/src/sass/icons/uEA60-help.svg +0 -5
  163. package/src/sass/icons/uEA61-pen-fill.svg +0 -13
  164. package/src/sass/icons/uEA62-pen.svg +0 -3
  165. package/src/sass/icons/uEA64-tips.svg +0 -5
  166. package/src/sass/icons/uEA65-warn.svg +0 -5
  167. package/src/sass/icons/uEA66-mistake.svg +0 -4
  168. package/src/sass/icons/uEA67-success.svg +0 -4
  169. package/src/sass/icons/uEA68-danger.svg +0 -4
  170. package/src/sass/icons/uEA69-info.svg +0 -5
  171. package/src/sass/icons/uEA6A-primary.svg +0 -5
  172. package/src/sass/icons/uEA6B-warning.svg +0 -5
  173. package/src/sass/icons/uEA6C-justify.svg +0 -19
  174. package/src/sass/icons/uEA6D-justifyCenter.svg +0 -19
  175. package/src/sass/icons/uEA6E-justifyLeft.svg +0 -19
  176. package/src/sass/icons/uEA6F-justifyRight.svg +0 -19
  177. package/src/sass/icons/uEA70-chevronsLeft.svg +0 -1
  178. package/src/sass/icons/uEA71-chevronsRight.svg +0 -1
  179. package/src/sass/icons/uEA72-trendingUp.svg +0 -1
  180. package/src/sass/icons/uEA74-codeBlock.svg +0 -1
  181. package/src/sass/icons/uEA75-expand.svg +0 -3
  182. package/src/sass/icons/uEA76-unExpand.svg +0 -3
  183. package/src/sass/icons/uEA77-swap-vert.svg +0 -1
  184. package/src/sass/icons/uEA78-swap.svg +0 -1
  185. package/src/sass/icons/uEA79-keyboard.svg +0 -1
  186. package/src/sass/icons/uEA7A-command.svg +0 -1
  187. package/src/sass/icons/uEA7B-search.svg +0 -1
  188. package/src/sass/index.scss +0 -3
  189. package/src/sass/markdown.scss +0 -668
  190. package/src/sass/markdown_pure.scss +0 -9
  191. package/src/sass/prettyprint/prettyprint.scss +0 -118
  192. package/src/sass/previewer.scss +0 -179
  193. package/src/sass/print.scss +0 -13
  194. package/src/sass/prism/coy.scss +0 -220
  195. package/src/sass/prism/dark.scss +0 -132
  196. package/src/sass/prism/default.scss +0 -143
  197. package/src/sass/prism/funky.scss +0 -133
  198. package/src/sass/prism/okaidia.scss +0 -126
  199. package/src/sass/prism/one-dark.scss +0 -440
  200. package/src/sass/prism/one-light.scss +0 -428
  201. package/src/sass/prism/solarized-light.scss +0 -153
  202. package/src/sass/prism/tomorrow-night.scss +0 -125
  203. package/src/sass/prism/twilight.scss +0 -202
  204. package/src/sass/prism/vs-dark.scss +0 -275
  205. package/src/sass/prism/vs-light.scss +0 -168
  206. package/src/sass/themes/blue.scss +0 -411
  207. package/src/sass/themes/dark.scss +0 -517
  208. package/src/sass/themes/default.scss +0 -255
  209. package/src/sass/themes/green.scss +0 -395
  210. package/src/sass/themes/light.scss +0 -368
  211. package/src/sass/themes/red.scss +0 -397
  212. package/src/sass/themes/violet.scss +0 -410
  213. package/src/sass/variable.scss +0 -84
  214. package/src/toolbars/Bubble.js +0 -234
  215. package/src/toolbars/BubbleFormula.js +0 -298
  216. package/src/toolbars/BubbleTable.js +0 -147
  217. package/src/toolbars/FloatMenu.js +0 -131
  218. package/src/toolbars/HiddenToolbar.js +0 -36
  219. package/src/toolbars/HookCenter.js +0 -231
  220. package/src/toolbars/MenuBase.js +0 -569
  221. package/src/toolbars/PreviewerBubble.js +0 -608
  222. package/src/toolbars/ShortcutKeyConfigPanel.js +0 -345
  223. package/src/toolbars/Sidebar.js +0 -36
  224. package/src/toolbars/Toc.js +0 -242
  225. package/src/toolbars/Toolbar.js +0 -449
  226. package/src/toolbars/ToolbarRight.js +0 -37
  227. package/src/toolbars/hooks/Audio.js +0 -79
  228. package/src/toolbars/hooks/BarTable.js +0 -41
  229. package/src/toolbars/hooks/Bold.js +0 -73
  230. package/src/toolbars/hooks/Br.js +0 -34
  231. package/src/toolbars/hooks/ChangeLocale.js +0 -62
  232. package/src/toolbars/hooks/ChatGpt.js +0 -182
  233. package/src/toolbars/hooks/CheckList.js +0 -41
  234. package/src/toolbars/hooks/Code.js +0 -49
  235. package/src/toolbars/hooks/CodeTheme.js +0 -66
  236. package/src/toolbars/hooks/Color.js +0 -298
  237. package/src/toolbars/hooks/Copy.js +0 -141
  238. package/src/toolbars/hooks/Detail.js +0 -69
  239. package/src/toolbars/hooks/DrawIo.js +0 -57
  240. package/src/toolbars/hooks/Export.js +0 -49
  241. package/src/toolbars/hooks/File.js +0 -79
  242. package/src/toolbars/hooks/Formula.js +0 -69
  243. package/src/toolbars/hooks/FullScreen.js +0 -50
  244. package/src/toolbars/hooks/Graph.js +0 -263
  245. package/src/toolbars/hooks/H1.js +0 -71
  246. package/src/toolbars/hooks/H2.js +0 -71
  247. package/src/toolbars/hooks/H3.js +0 -71
  248. package/src/toolbars/hooks/Header.js +0 -118
  249. package/src/toolbars/hooks/Hr.js +0 -35
  250. package/src/toolbars/hooks/Image.js +0 -91
  251. package/src/toolbars/hooks/InlineCode.js +0 -53
  252. package/src/toolbars/hooks/Insert.js +0 -193
  253. package/src/toolbars/hooks/Italic.js +0 -72
  254. package/src/toolbars/hooks/Justify.js +0 -49
  255. package/src/toolbars/hooks/LineTable.js +0 -41
  256. package/src/toolbars/hooks/Link.js +0 -49
  257. package/src/toolbars/hooks/List.js +0 -55
  258. package/src/toolbars/hooks/MobilePreview.js +0 -44
  259. package/src/toolbars/hooks/Ol.js +0 -41
  260. package/src/toolbars/hooks/Panel.js +0 -140
  261. package/src/toolbars/hooks/Pdf.js +0 -78
  262. package/src/toolbars/hooks/Publish.js +0 -123
  263. package/src/toolbars/hooks/QuickTable.js +0 -43
  264. package/src/toolbars/hooks/Quote.js +0 -45
  265. package/src/toolbars/hooks/Redo.js +0 -33
  266. package/src/toolbars/hooks/Ruby.js +0 -59
  267. package/src/toolbars/hooks/Search.js +0 -53
  268. package/src/toolbars/hooks/Settings.js +0 -220
  269. package/src/toolbars/hooks/ShortcutKey.js +0 -62
  270. package/src/toolbars/hooks/Size.js +0 -118
  271. package/src/toolbars/hooks/Split.js +0 -37
  272. package/src/toolbars/hooks/Strikethrough.js +0 -71
  273. package/src/toolbars/hooks/Sub.js +0 -58
  274. package/src/toolbars/hooks/Sup.js +0 -58
  275. package/src/toolbars/hooks/SwitchModel.js +0 -56
  276. package/src/toolbars/hooks/Table.js +0 -56
  277. package/src/toolbars/hooks/Theme.js +0 -62
  278. package/src/toolbars/hooks/Toc.js +0 -35
  279. package/src/toolbars/hooks/TogglePreview.js +0 -91
  280. package/src/toolbars/hooks/Ul.js +0 -41
  281. package/src/toolbars/hooks/Underline.js +0 -68
  282. package/src/toolbars/hooks/Undo.js +0 -30
  283. package/src/toolbars/hooks/Video.js +0 -79
  284. package/src/toolbars/hooks/Word.js +0 -78
  285. package/src/toolbars/hooks/WordCount.js +0 -106
  286. package/src/utils/autoindent.js +0 -58
  287. package/src/utils/cm-search-replace.js +0 -794
  288. package/src/utils/code-preview-language-setting.js +0 -180
  289. package/src/utils/codeBlockContentHandler.js +0 -400
  290. package/src/utils/config.js +0 -174
  291. package/src/utils/copy.js +0 -55
  292. package/src/utils/dialog.js +0 -214
  293. package/src/utils/dom.js +0 -163
  294. package/src/utils/downloadUtil.js +0 -23
  295. package/src/utils/env.js +0 -22
  296. package/src/utils/error.js +0 -61
  297. package/src/utils/event.js +0 -38
  298. package/src/utils/export.js +0 -166
  299. package/src/utils/file.js +0 -164
  300. package/src/utils/formulaUtilsHandler.js +0 -232
  301. package/src/utils/htmlparser.js +0 -976
  302. package/src/utils/image.js +0 -99
  303. package/src/utils/imgSizeHandler.js +0 -279
  304. package/src/utils/lazyLoadImg.js +0 -327
  305. package/src/utils/lineFeed.js +0 -49
  306. package/src/utils/listContentHandler.js +0 -227
  307. package/src/utils/lookbehind-replace.js +0 -81
  308. package/src/utils/mathjax.js +0 -89
  309. package/src/utils/myersDiff.js +0 -211
  310. package/src/utils/pasteHelper.js +0 -253
  311. package/src/utils/platformTransform.js +0 -71
  312. package/src/utils/recount-pos.js +0 -59
  313. package/src/utils/regexp.js +0 -295
  314. package/src/utils/sanitize.js +0 -477
  315. package/src/utils/selection.js +0 -50
  316. package/src/utils/shortcutKey.js +0 -291
  317. package/src/utils/svgUtils.js +0 -96
  318. package/src/utils/tableContentHandler.js +0 -876
  319. package/test/core/CommonMark.spec.ts +0 -62
  320. package/test/core/hooks/AutoLink.spec.ts +0 -28
  321. package/test/core/hooks/List.spec.ts +0 -79
  322. package/test/core/hooks/__snapshots__/List.spec.ts.snap +0 -11
  323. package/test/example.md +0 -778
  324. package/test/node.js +0 -10
  325. package/test/suites/commonmark.spec.json +0 -5218
  326. package/test/tsconfig.test.json +0 -6
  327. package/test/utils/regexp.spec.ts +0 -28
package/src/Cherry.js DELETED
@@ -1,1104 +0,0 @@
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 mergeWith from 'lodash/mergeWith';
17
- import Editor from './Editor';
18
- import Engine from './Engine';
19
- import Previewer from './Previewer';
20
- import Bubble from './toolbars/Bubble';
21
- import FloatMenu from './toolbars/FloatMenu';
22
- import Toolbar from './toolbars/Toolbar';
23
- import ToolbarRight from './toolbars/ToolbarRight';
24
- import Toc from './toolbars/Toc';
25
- import { createElement } from './utils/dom';
26
- import Sidebar from './toolbars/Sidebar';
27
- import HiddenToolbar from './toolbars/HiddenToolbar';
28
- import {
29
- customizer,
30
- getThemeFromLocal,
31
- changeTheme,
32
- getCodeThemeFromLocal,
33
- testHasLocal,
34
- changeCodeTheme,
35
- getCodeWrapFromLocal,
36
- saveCodeWrapToLocal,
37
- } from './utils/config';
38
- import NestedError, { $expectTarget } from './utils/error';
39
- import getPosBydiffs from './utils/recount-pos';
40
- import defaultConfig from './Cherry.config';
41
- import cloneDeep from 'lodash/cloneDeep';
42
- import Event from './Event';
43
- import locales from '@/locales/index';
44
-
45
- import { urlProcessorProxy } from './UrlCache';
46
- import { CherryStatic } from './CherryStatic';
47
- import { LIST_CONTENT } from '@/utils/regexp';
48
-
49
- /** @typedef {import('~types/cherry').CherryOptions} CherryOptions */
50
- export default class Cherry extends CherryStatic {
51
- /**
52
- * @protected
53
- */
54
- static initialized = false;
55
- /**
56
- * @readonly
57
- */
58
- static config = {
59
- /** @type {CherryOptions} */
60
- defaults: defaultConfig,
61
- };
62
-
63
- /**
64
- * @param {CherryOptions} options
65
- */
66
- constructor(options) {
67
- super();
68
- Cherry.initialized = true;
69
- const defaultConfigCopy = cloneDeep(Cherry.config.defaults);
70
- this.defaultToolbar = defaultConfigCopy.toolbars.toolbar;
71
- $expectTarget(options, Object);
72
- /**
73
- * @property
74
- * @type {CherryOptions}
75
- */
76
- this.options = mergeWith({}, defaultConfigCopy, options, customizer);
77
-
78
- this.storageFloatPreviewerWrapData = {
79
- x: 50,
80
- y: 58,
81
- width: 800,
82
- height: 500,
83
- };
84
-
85
- this.locales = locales;
86
- if (this.options.locales) {
87
- this.locales = {
88
- ...this.options.locales,
89
- ...this.locales,
90
- };
91
- }
92
-
93
- // loading the locale
94
- this.locale = this.locales[this.options.locale];
95
-
96
- if (typeof this.options.engine.global.urlProcessor === 'function') {
97
- this.options.engine.global.urlProcessor = urlProcessorProxy(this.options.engine.global.urlProcessor);
98
- this.options.callback.urlProcessor = this.options.engine.global.urlProcessor;
99
- } else {
100
- this.options.callback.urlProcessor = urlProcessorProxy(this.options.callback.urlProcessor);
101
- }
102
-
103
- this.status = {
104
- toolbar: 'show',
105
- previewer: 'show',
106
- editor: 'show',
107
- };
108
-
109
- if (this.options.isPreviewOnly || this.options.editor.defaultModel === 'previewOnly') {
110
- this.options.toolbars.showToolbar = false;
111
- this.options.editor.defaultModel = 'previewOnly';
112
- this.status.editor = 'hide';
113
- this.status.toolbar = 'hide';
114
- }
115
-
116
- /**
117
- * @property
118
- * @type {string} 实例ID
119
- */
120
- this.instanceId = `cherry-${new Date().getTime()}${Math.random()}`;
121
- this.options.instanceId = this.instanceId;
122
- this.lastMarkdownText = '';
123
- this.$event = new Event(this.instanceId);
124
-
125
- if (this.options.engine.global.flowSessionCursor === 'default') {
126
- this.options.engine.global.flowSessionCursor = '<span class="cherry-flow-session-cursor"></span>';
127
- }
128
- /**
129
- * @type {import('./Engine').default}
130
- */
131
- this.engine = new Engine(this.options, this);
132
- this.init();
133
- }
134
-
135
- /**
136
- * 初始化工具栏、编辑区、预览区等
137
- * @private
138
- */
139
- init() {
140
- this.storeDocumentScroll();
141
- let mountEl = this.options.id ? document.getElementById(this.options.id) : this.options.el;
142
-
143
- if (!mountEl) {
144
- if (!this.options.forceAppend) {
145
- return false;
146
- }
147
- this.noMountEl = true;
148
- mountEl = document.createElement('div');
149
- mountEl.id = this.options.id || 'cherry-markdown';
150
- document.body.appendChild(mountEl);
151
- }
152
-
153
- if (!mountEl.style.height) {
154
- mountEl.style.height = this.options.editor.height;
155
- }
156
- this.cherryDom = mountEl;
157
-
158
- // 生成名称空间
159
- if (typeof this.options.themeNameSpace === 'string') {
160
- this.nameSpace = this.options.themeNameSpace;
161
- } else {
162
- this.nameSpace = this.options.nameSpace;
163
- }
164
-
165
- // 蒙层dom,用来拖拽编辑区&预览区宽度时展示蒙层
166
- const wrapperDom = this.createWrapper();
167
- // 创建编辑区
168
- const editor = this.createEditor();
169
- // 创建预览区
170
- const previewer = this.createPreviewer();
171
-
172
- if (this.options.toolbars.showToolbar === false || this.options.toolbars.toolbar === false) {
173
- // 即便配置了不展示工具栏,也要让工具栏加载对应的语法hook
174
- wrapperDom.classList.add('cherry--no-toolbar');
175
- this.options.toolbars.toolbar = this.options.toolbars.toolbar
176
- ? this.options.toolbars.toolbar
177
- : this.defaultToolbar;
178
- }
179
- $expectTarget(this.options.toolbars.toolbar, Array);
180
- // 创建顶部工具栏
181
- this.createToolbar();
182
- this.createToolbarRight();
183
-
184
- const wrapperFragment = document.createDocumentFragment();
185
- wrapperFragment.appendChild(this.toolbar.options.dom);
186
- wrapperFragment.appendChild(editor.options.editorDom);
187
- if (!this.options.previewer.dom) {
188
- wrapperFragment.appendChild(previewer.options.previewerDom);
189
- }
190
- wrapperFragment.appendChild(previewer.options.virtualDragLineDom);
191
- wrapperFragment.appendChild(previewer.options.editorMaskDom);
192
- wrapperFragment.appendChild(previewer.options.previewerMaskDom);
193
-
194
- wrapperDom.appendChild(wrapperFragment);
195
- this.wrapperDom = wrapperDom;
196
- // 创建预览区域的侧边工具栏
197
- this.createSidebar();
198
- this.createHiddenToolbar();
199
- mountEl.appendChild(wrapperDom);
200
-
201
- editor.init(previewer);
202
- // 创建bubble工具栏,所谓bubble工具栏,是指在编辑区选中文本时悬浮出现的工具栏
203
- this.createBubble();
204
- // 创建float工具栏,所谓float工具栏,是指当编辑区光标处于新行时,在行内联想出的工具栏
205
- this.createFloatMenu();
206
- previewer.init(editor);
207
-
208
- previewer.registerAfterUpdate(this.engine.mounted.bind(this.engine));
209
-
210
- // default value init
211
- this.initText(editor.editor);
212
-
213
- this.$event.on('toolbarHide', () => {
214
- this.status.toolbar = 'hide';
215
- });
216
- this.$event.on('toolbarShow', () => {
217
- this.status.toolbar = 'show';
218
- });
219
- this.$event.on('previewerClose', () => {
220
- this.status.previewer = 'hide';
221
- });
222
- this.$event.on('previewerOpen', () => {
223
- this.status.previewer = 'show';
224
- });
225
- this.$event.on('editorClose', () => {
226
- this.status.editor = 'hide';
227
- // 关闭编辑区时,需要清除所有高亮
228
- this.previewer.highlightLine(0);
229
- });
230
- this.$event.on('editorOpen', () => {
231
- this.status.editor = 'show';
232
- });
233
-
234
- // 切换模式,有纯预览模式、纯编辑模式、双栏编辑模式
235
- this.switchModel(this.options.editor.defaultModel, this.options.toolbars.showToolbar);
236
-
237
- // 如果配置了初始化后根据hash自动滚动
238
- if (this.options.autoScrollByHashAfterInit) {
239
- setTimeout(this.scrollByHash.bind(this));
240
- }
241
- // 强制进行一次渲染 // 不记得为啥要强制渲染了,先屏蔽了
242
- // this.editText(null, this.editor.editor);
243
- this.createToc();
244
- this.$event.bindCallbacksByOptions(this.options);
245
- this.restoreDocumentScroll();
246
- }
247
-
248
- /**
249
- * 记忆页面的滚动高度,在cherry初始化后恢复到这个高度
250
- */
251
- storeDocumentScroll() {
252
- if (!this.options.editor.keepDocumentScrollAfterInit) {
253
- return;
254
- }
255
- this.needRestoreDocumentScroll = true;
256
- this.documentElementScrollTop = document.documentElement.scrollTop;
257
- this.documentElementScrollLeft = document.documentElement.scrollLeft;
258
- }
259
-
260
- /**
261
- * 在cherry初始化后恢复到这个高度
262
- */
263
- restoreDocumentScroll() {
264
- if (!this.options.editor.keepDocumentScrollAfterInit || !this.needRestoreDocumentScroll) {
265
- return;
266
- }
267
- this.needRestoreDocumentScroll = false;
268
- window.scrollTo(this.documentElementScrollLeft, this.documentElementScrollTop);
269
- }
270
-
271
- destroy() {
272
- if (this.noMountEl) {
273
- this.cherryDom.remove();
274
- } else {
275
- this.wrapperDom.remove();
276
- }
277
- this.$event.clearAll();
278
- }
279
-
280
- on(eventName, callback) {
281
- if (this.$event.Events[eventName]) {
282
- if (/^(afterInit|afterChange)$/.test(eventName)) {
283
- // 做特殊处理
284
- return this.$event.on(eventName, (msg) => {
285
- callback(msg.markdownText, msg.html);
286
- });
287
- }
288
- return this.$event.on(eventName, callback);
289
- }
290
- switch (eventName) {
291
- case 'urlProcessor':
292
- this.options.callback.urlProcessor = urlProcessorProxy(callback);
293
- break;
294
- default:
295
- this.options.callback[eventName] = callback;
296
- }
297
- }
298
-
299
- off(eventName, callback) {
300
- if (this.$event.Events[eventName]) {
301
- return this.$event.off(eventName, callback);
302
- }
303
- this.options.callback[eventName] = () => {};
304
- }
305
-
306
- createToc() {
307
- if (this.options.toolbars.toc === false) {
308
- this.toc = false;
309
- return;
310
- }
311
- this.toc = new Toc({
312
- $cherry: this,
313
- // @ts-ignore
314
- updateLocationHash: this.options.toolbars.toc.updateLocationHash ?? true,
315
- // @ts-ignore
316
- position: this.options.toolbars.toc.position ?? 'absolute',
317
- // @ts-ignore
318
- cssText: this.options.toolbars.toc.cssText ?? '',
319
- // @ts-ignore
320
- defaultModel: this.options.toolbars.toc.defaultModel ?? 'pure',
321
- // @ts-ignore
322
- showAutoNumber: this.options.toolbars.toc.showAutoNumber ?? false,
323
- });
324
- }
325
-
326
- /**
327
- * 滚动到hash位置,实际上就是通过修改location.hash来触发hashChange事件,剩下的就交给浏览器了
328
- */
329
- scrollByHash() {
330
- if (location.hash) {
331
- try {
332
- const { hash } = location;
333
- // 检查是否有对应id的元素
334
- const testDom = document.getElementById(hash.replace('#', ''));
335
- if (testDom && this.previewer.getDomContainer().contains(testDom)) {
336
- location.hash = '';
337
- location.hash = hash;
338
- }
339
- } catch (error) {
340
- // empty
341
- }
342
- }
343
- }
344
-
345
- $t(str) {
346
- return this.locale[str] ? this.locale[str] : str;
347
- }
348
-
349
- addLocale(key, value) {
350
- this.locale[key] = value;
351
- }
352
-
353
- addLocales(locales) {
354
- this.locale = Object.assign(this.locale, locales);
355
- }
356
-
357
- getLocales() {
358
- return this.locale;
359
- }
360
-
361
- /**
362
- * 切换编辑模式
363
- * @param {'edit&preview'|'editOnly'|'previewOnly'} [model=edit&preview] 模式类型
364
- * 一般纯预览模式和纯编辑模式适合在屏幕较小的终端使用,比如手机移动端
365
- */
366
- switchModel(model = 'edit&preview', showToolbar = true) {
367
- switch (model) {
368
- case 'edit&preview':
369
- if (this.previewer) {
370
- this.previewer.editOnly(true);
371
- this.previewer.recoverPreviewer();
372
- }
373
- if (this.toolbar && showToolbar) {
374
- this.toolbar.showToolbar();
375
- }
376
- if (showToolbar) {
377
- this.wrapperDom.classList.remove('cherry--no-toolbar');
378
- } else {
379
- this.wrapperDom.classList.add('cherry--no-toolbar');
380
- }
381
- break;
382
- case 'editOnly':
383
- if (!this.previewer.isPreviewerHidden()) {
384
- this.previewer.editOnly(true);
385
- }
386
- if (this.toolbar && showToolbar) {
387
- this.toolbar.showToolbar();
388
- }
389
- if (showToolbar) {
390
- this.wrapperDom.classList.remove('cherry--no-toolbar');
391
- } else {
392
- this.wrapperDom.classList.add('cherry--no-toolbar');
393
- }
394
- break;
395
- case 'previewOnly':
396
- this.previewer.previewOnly();
397
- this.toolbar && this.toolbar.previewOnly();
398
- this.wrapperDom.classList.add('cherry--no-toolbar');
399
- break;
400
- }
401
- }
402
-
403
- /**
404
- * 获取实例id
405
- * @returns {string}
406
- * @public
407
- */
408
- getInstanceId() {
409
- return this.instanceId;
410
- }
411
-
412
- /**
413
- * 获取编辑器状态
414
- * @returns {Object}
415
- */
416
- getStatus() {
417
- return this.status;
418
- }
419
-
420
- /**
421
- * 获取编辑区内的markdown源码内容
422
- * @returns markdown源码内容
423
- */
424
- getValue() {
425
- return this.editor.editor.getValue();
426
- }
427
-
428
- /**
429
- * 获取编辑区内的markdown源码内容
430
- * @returns {string} markdown源码内容
431
- */
432
- getMarkdown() {
433
- return this.getValue();
434
- }
435
-
436
- /**
437
- * 获取CodeMirror 实例
438
- * @returns { CodeMirror.Editor } CodeMirror实例
439
- */
440
- getCodeMirror() {
441
- return this.editor.editor;
442
- }
443
-
444
- /**
445
- * 获取预览区内的html内容
446
- * @param {boolean} [wrapTheme=true] 是否在外层包裹主题class
447
- * @returns {string} html内容
448
- */
449
- getHtml(wrapTheme = true) {
450
- return this.previewer.getValue(wrapTheme);
451
- }
452
- /**
453
- * 获取Previewer 预览实例
454
- * @returns {Previewer} Previewer 预览实例
455
- */
456
- getPreviewer() {
457
- return this.previewer;
458
- }
459
-
460
- /**
461
- * @typedef {{
462
- * level: number;
463
- * id: string;
464
- * text: string;
465
- * }[]} HeaderList
466
- * 获取目录,目录由head1~6组成
467
- * @returns {HeaderList} 标题head数组
468
- */
469
- getToc() {
470
- const str = this.getHtml();
471
- /** @type {({level: number;id: string;text: string})[]} */
472
- const headerList = [];
473
- const headerRegex = /<h([1-6]).*?id="([^"]+?)".*?>(.+?)<\/h[0-6]>/g;
474
- str.replace(headerRegex, (match, level, id, text) => {
475
- headerList.push({ level: +level, id, text: text.replace(/<a .+?<\/a>/, '') });
476
- return match;
477
- });
478
- return headerList;
479
- }
480
-
481
- /**
482
- * 覆盖编辑区的内容
483
- * @param {string} content markdown内容
484
- * @param {boolean} keepCursor 是否保持光标位置
485
- */
486
- setValue(content, keepCursor = false) {
487
- if (keepCursor === false) {
488
- return this.editor.editor.setValue(content);
489
- }
490
- const codemirror = this.editor.editor;
491
- const old = this.getValue();
492
- const pos = codemirror.getDoc().indexFromPos(codemirror.getCursor());
493
- const newPos = getPosBydiffs(pos, old, content);
494
- codemirror.setValue(content);
495
- const cursor = codemirror.getDoc().posFromIndex(newPos);
496
- codemirror.setCursor(cursor);
497
- this.editor.dealSpecialWords();
498
- }
499
-
500
- /**
501
- * 在光标处或者指定行+偏移量插入内容
502
- * @param {string} content 被插入的文本
503
- * @param {boolean} [isSelect=false] 是否选中刚插入的内容
504
- * @param {[number, number]|false} [anchor=false] [x,y] 代表x+1行,y+1字符偏移量,默认false 会从光标处插入
505
- * @param {boolean} [focus=true] 保持编辑器处于focus状态
506
- */
507
- insert(content, isSelect = false, anchor = false, focus = true) {
508
- if (anchor) {
509
- this.editor.editor.setSelection({ line: anchor[0], ch: anchor[1] }, { line: anchor[0], ch: anchor[1] });
510
- }
511
- this.editor.editor.replaceSelection(content, isSelect ? 'around' : 'end');
512
- focus && this.editor.editor.focus();
513
- }
514
-
515
- /**
516
- * 在光标处或者指定行+偏移量插入内容
517
- * @param {string} content 被插入的文本
518
- * @param {boolean} [isSelect=false] 是否选中刚插入的内容
519
- * @param {[number, number]|false} [anchor=false] [x,y] 代表x+1行,y+1字符偏移量,默认false 会从光标处插入
520
- * @param {boolean} [focus=true] 保持编辑器处于focus状态
521
- * @returns
522
- */
523
- insertValue(content, isSelect = false, anchor = false, focus = true) {
524
- return this.insert(content, isSelect, anchor, focus);
525
- }
526
-
527
- /**
528
- * 强制重新渲染预览区域
529
- */
530
- refreshPreviewer() {
531
- try {
532
- const markdownText = this.getValue();
533
- const html = this.engine.makeHtml(markdownText);
534
- this.previewer.refresh(html);
535
- } catch (e) {
536
- throw new NestedError(e);
537
- }
538
- }
539
-
540
- /**
541
- * 覆盖编辑区的内容
542
- * @param {string} content markdown内容
543
- * @param {boolean} [keepCursor=false] 是否保持光标位置
544
- */
545
- setMarkdown(content, keepCursor = false) {
546
- return this.setValue(content, keepCursor);
547
- }
548
-
549
- /**
550
- * @private
551
- * @returns
552
- */
553
- createWrapper() {
554
- let mainTheme = '';
555
- let toolbarTheme = '';
556
- let inlineCodeTheme = '';
557
- let codeBlockTheme = '';
558
- if (testHasLocal(this.nameSpace, 'theme')) {
559
- mainTheme = getThemeFromLocal(true, this.nameSpace);
560
- } else {
561
- mainTheme = this.options.themeSettings.mainTheme;
562
- mainTheme = mainTheme.replace(/theme__/g, '');
563
- mainTheme = `theme__${mainTheme}`;
564
- }
565
- if (typeof this.options.toolbars.theme === 'string') {
566
- toolbarTheme = this.options.toolbars.theme === 'dark' ? 'dark' : 'light';
567
- } else {
568
- toolbarTheme = this.options.themeSettings.toolbarTheme === 'dark' ? 'dark' : 'light';
569
- }
570
- // @ts-ignore
571
- if (typeof this.options.engine.syntax.inlineCode.theme === 'string') {
572
- inlineCodeTheme =
573
- /** @type {{theme?: string;}} */ (this.options.engine.syntax.inlineCode).theme === 'black' ? 'black' : 'red';
574
- } else {
575
- inlineCodeTheme = this.options.themeSettings.inlineCodeTheme === 'black' ? 'black' : 'red';
576
- }
577
- // @ts-ignore
578
- if (typeof this.options.engine.syntax.codeBlock.theme === 'string') {
579
- codeBlockTheme = /** @type {{theme?: string;}} */ (this.options.engine.syntax.codeBlock).theme;
580
- } else {
581
- codeBlockTheme = this.options.themeSettings.codeBlockTheme;
582
- }
583
- if (testHasLocal(this.nameSpace, 'codeTheme')) {
584
- codeBlockTheme = getCodeThemeFromLocal(this.nameSpace);
585
- }
586
- if (codeBlockTheme === 'dark') codeBlockTheme = 'tomorrow-night';
587
- else if (codeBlockTheme === 'light') codeBlockTheme = 'solarized-light';
588
- // @ts-ignore
589
- const codeWrap = getCodeWrapFromLocal(this.nameSpace, this.options.engine.syntax.codeBlock.wrap);
590
- const wrapperDom = createElement('div', ['cherry', 'clearfix', mainTheme].join(' '), {
591
- 'data-toolbarTheme': toolbarTheme,
592
- 'data-inlineCodeTheme': inlineCodeTheme,
593
- 'data-codeBlockTheme': codeBlockTheme,
594
- 'data-codeWrap': codeWrap === 'wrap' ? 'wrap' : 'nowrap',
595
- });
596
- this.wrapperDom = wrapperDom;
597
- return wrapperDom;
598
- }
599
-
600
- getCodeWrap() {
601
- return this.wrapperDom.dataset.codeWrap || 'wrap';
602
- }
603
-
604
- setCodeWrap(codeWrap) {
605
- this.wrapperDom.dataset.codeWrap = codeWrap === 'wrap' ? 'wrap' : 'nowrap';
606
- saveCodeWrapToLocal(this.nameSpace, codeWrap);
607
- }
608
-
609
- /**
610
- * @private
611
- * @returns {Toolbar}
612
- */
613
- createToolbar() {
614
- if (!this.toolbarContainer) {
615
- const dom = createElement('div', 'cherry-toolbar');
616
- this.toolbarContainer = dom;
617
- }
618
- if (this.options.toolbars.shortcutKey && Object.keys(this.options.toolbars.shortcutKey).length > 0) {
619
- console.warn(
620
- 'options.shortcutKey is deprecated, please use shortcutKeySettings.shortcutKeyMap instead, get more info at https://github.com/Tencent/cherry-markdown/wiki',
621
- );
622
- }
623
- this.toolbar = new Toolbar({
624
- dom: this.toolbarContainer,
625
- $cherry: this,
626
- buttonConfig: this.options.toolbars.toolbar,
627
- customMenu: this.options.toolbars.customMenu,
628
- });
629
- return this.toolbar;
630
- }
631
-
632
- /**
633
- * 动态重置工具栏配置
634
- * @public
635
- * @param {'toolbar'|'toolbarRight'|'sidebar'|'bubble'|'float'} [type] 修改工具栏的类型
636
- * @param {Array} [toolbar] 要重置的对应工具栏配置
637
- * @returns {Boolean}
638
- */
639
- resetToolbar(type, toolbar) {
640
- const $type = /(toolbar|toolbarRight|sidebar|bubble|float|toc)/.test(type) ? type : false;
641
- if ($type === false) {
642
- return false;
643
- }
644
- if (this.toolbarContainer) {
645
- this.toolbarContainer.innerHTML = '';
646
- }
647
- if (this.toolbarFloatContainer) {
648
- this.toolbarFloatContainer.innerHTML = '';
649
- }
650
- if (this.toolbarBubbleContainer) {
651
- this.toolbarBubbleContainer.innerHTML = '';
652
- }
653
- if (this.sidebarDom) {
654
- this.sidebarDom.innerHTML = '';
655
- }
656
- if (this.toc) {
657
- // @ts-ignore
658
- this.toc.tocDom.remove();
659
- }
660
- this.cherryDom.querySelectorAll('.cherry-dropdown').forEach((item) => {
661
- item.remove();
662
- });
663
- this.options.toolbars[type] = toolbar;
664
- this.createToolbar();
665
- this.createToolbarRight();
666
- this.createBubble();
667
- this.createFloatMenu();
668
- this.createSidebar();
669
- this.createHiddenToolbar();
670
- this.createToc();
671
- return true;
672
- }
673
-
674
- /**
675
- * @private
676
- * @returns {Toolbar}
677
- */
678
- createToolbarRight() {
679
- this.toolbarRight = new ToolbarRight({
680
- dom: this.toolbarContainer,
681
- $cherry: this,
682
- buttonConfig: this.options.toolbars.toolbarRight,
683
- customMenu: this.options.toolbars.customMenu,
684
- });
685
- this.toolbar.collectMenuInfo(this.toolbarRight);
686
- return this.toolbarRight;
687
- }
688
-
689
- /**
690
- * @private
691
- * @returns
692
- */
693
- createSidebar() {
694
- if (this.options.toolbars.sidebar) {
695
- $expectTarget(this.options.toolbars.sidebar, Array);
696
- let init = false;
697
- if (!this.sidebarDom) {
698
- init = true;
699
- const externalClass = this.options.toolbars.theme === 'dark' ? 'dark' : '';
700
- const dom = createElement('div', `cherry-sidebar ${externalClass}`);
701
- this.sidebarDom = dom;
702
- }
703
- this.sidebar = new Sidebar({
704
- dom: this.sidebarDom,
705
- $cherry: this,
706
- buttonConfig: this.options.toolbars.sidebar,
707
- customMenu: this.options.toolbars.customMenu,
708
- });
709
- this.toolbar.collectMenuInfo(this.sidebar);
710
- if (init === true) {
711
- this.wrapperDom.appendChild(this.sidebarDom);
712
- }
713
- }
714
- }
715
-
716
- createHiddenToolbar() {
717
- if (this.options.toolbars.hiddenToolbar) {
718
- $expectTarget(this.options.toolbars.hiddenToolbar, Array);
719
- this.hiddenToolbar = new HiddenToolbar({
720
- $cherry: this,
721
- buttonConfig: this.options.toolbars.hiddenToolbar,
722
- customMenu: this.options.toolbars.customMenu,
723
- });
724
- this.toolbar.collectMenuInfo(this.hiddenToolbar);
725
- }
726
- }
727
-
728
- /**
729
- * @private
730
- * @returns
731
- */
732
- createFloatMenu() {
733
- if (this.options.toolbars.float) {
734
- if (!this.toolbarFloatContainer) {
735
- const dom = createElement('div', 'cherry-floatmenu');
736
- this.toolbarFloatContainer = dom;
737
- }
738
- $expectTarget(this.options.toolbars.float, Array);
739
- this.floatMenu = new FloatMenu({
740
- dom: this.toolbarFloatContainer,
741
- $cherry: this,
742
- buttonConfig: this.options.toolbars.float,
743
- customMenu: this.options.toolbars.customMenu,
744
- });
745
- this.toolbar.collectMenuInfo(this.floatMenu);
746
- }
747
- }
748
-
749
- /**
750
- * @private
751
- * @returns
752
- */
753
- createBubble() {
754
- if (this.options.toolbars.bubble) {
755
- if (!this.toolbarBubbleContainer) {
756
- const dom = createElement('div', 'cherry-bubble');
757
- this.toolbarBubbleContainer = dom;
758
- }
759
- $expectTarget(this.options.toolbars.bubble, Array);
760
- this.bubble = new Bubble({
761
- dom: this.toolbarBubbleContainer,
762
- $cherry: this,
763
- buttonConfig: this.options.toolbars.bubble,
764
- customMenu: this.options.toolbars.customMenu,
765
- engine: this.engine,
766
- });
767
- this.toolbar.collectMenuInfo(this.bubble);
768
- }
769
- }
770
-
771
- /**
772
- * @private
773
- * @returns {import('@/Editor').default}
774
- */
775
- createEditor() {
776
- const textArea = createElement('textarea', '', {
777
- id: this.options.editor.id ?? 'code',
778
- name: this.options.editor.name ?? 'code',
779
- });
780
- textArea.textContent = this.options.value;
781
- const editor = createElement('div', 'cherry-editor');
782
- editor.appendChild(textArea);
783
-
784
- if (typeof this.options.fileUpload === 'function') {
785
- this.options.callback.fileUpload = this.options.fileUpload;
786
- }
787
-
788
- this.editor = new Editor({
789
- $cherry: this,
790
- editorDom: editor,
791
- wrapperDom: this.wrapperDom,
792
- value: this.options.value,
793
- onKeydown: this.fireShortcutKey.bind(this),
794
- onChange: this.editText.bind(this),
795
- toolbars: this.options.toolbars,
796
- autoScrollByCursor: this.options.autoScrollByCursor,
797
- ...this.options.editor,
798
- });
799
- return this.editor;
800
- }
801
-
802
- /**
803
- * @private
804
- * @returns {import('@/Previewer').default}
805
- */
806
- createPreviewer() {
807
- /** @type {HTMLDivElement} */
808
- let previewer;
809
- const anchorStyle =
810
- (this.options.engine.syntax.header && this.options.engine.syntax.header.anchorStyle) || 'default';
811
- const autonumberClass = anchorStyle === 'autonumber' ? ' head-num' : '';
812
- const { className, dom, enablePreviewerBubble, floatWhenClosePreviewer } = this.options.previewer;
813
- let mainTheme = '';
814
- if (testHasLocal(this.nameSpace, 'theme')) {
815
- mainTheme = getThemeFromLocal(true, this.nameSpace);
816
- } else {
817
- mainTheme = this.options.themeSettings.mainTheme;
818
- }
819
- const previewerClassName = ['cherry-previewer cherry-markdown', className || '', autonumberClass, mainTheme].join(
820
- ' ',
821
- );
822
- if (dom) {
823
- previewer = dom;
824
- previewer.className += ` ${previewerClassName}`;
825
- } else {
826
- previewer = createElement('div', previewerClassName);
827
- }
828
- const virtualDragLine = createElement('div', 'cherry-drag');
829
- const editorMask = createElement('div', 'cherry-editor-mask');
830
- const previewerMask = createElement('div', 'cherry-previewer-mask');
831
-
832
- this.previewer = new Previewer({
833
- $cherry: this,
834
- virtualDragLineDom: virtualDragLine,
835
- editorMaskDom: editorMask,
836
- previewerMaskDom: previewerMask,
837
- previewerDom: previewer,
838
- value: this.options.value,
839
- isPreviewOnly: this.options.isPreviewOnly,
840
- enablePreviewerBubble,
841
- floatWhenClosePreviewer,
842
- lazyLoadImg: this.options.previewer.lazyLoadImg,
843
- });
844
-
845
- return this.previewer;
846
- }
847
-
848
- clearFloatPreviewer() {
849
- this.wrapperDom.appendChild(this.previewer.getDom());
850
- this.storageFloatPreviewerWrapData = {
851
- x: this.floatPreviewerWrapDom.offsetLeft,
852
- y: this.floatPreviewerWrapDom.offsetTop,
853
- height: this.floatPreviewerWrapDom.offsetHeight,
854
- width: this.floatPreviewerWrapDom.offsetWidth,
855
- };
856
- this.floatPreviewerWrapDom.remove();
857
- this.removeFloatPreviewerListener();
858
- }
859
-
860
- handleFloatPreviewerMouseDown = (evt) => {
861
- if (evt.target !== this.floatPreviewerHeaderDom) return;
862
- evt.preventDefault();
863
- this.floatPreviewerInitOffsetX = evt.offsetX;
864
- this.floatPreviewerInitOffsetY = evt.offsetY;
865
- this.floatPreviewerWrapDom.classList.add('float-previewer-dragging');
866
- };
867
-
868
- handleFloatPreviewerMouseMove = (evt) => {
869
- if (!this.floatPreviewerWrapDom.classList.contains('float-previewer-dragging')) return;
870
- evt.preventDefault();
871
- const { clientX, clientY } = evt;
872
- let newRight = clientX - this.floatPreviewerInitOffsetX;
873
- let newTop = clientY - this.floatPreviewerInitOffsetY;
874
- if (newRight < 0) {
875
- newRight = 0;
876
- }
877
- if (newTop < 0) {
878
- newTop = 0;
879
- }
880
- if (newRight + this.floatPreviewerWrapDom.offsetWidth > this.pageWidth) {
881
- newRight = this.pageWidth - this.floatPreviewerWrapDom.offsetWidth;
882
- }
883
- if (newTop + this.floatPreviewerWrapDom.offsetHeight > this.pageHeight) {
884
- newTop = this.pageHeight - this.floatPreviewerWrapDom.offsetHeight;
885
- }
886
- requestAnimationFrame(() => {
887
- this.floatPreviewerWrapDom.style.left = `${newRight}px`;
888
- this.floatPreviewerWrapDom.style.top = `${newTop}px`;
889
- });
890
- };
891
-
892
- handleFloatPreviewerMouseUp = (evt) => {
893
- this.floatPreviewerWrapDom.classList.remove('float-previewer-dragging');
894
- };
895
-
896
- createFloatPreviewerListener() {
897
- document.addEventListener('mousedown', this.handleFloatPreviewerMouseDown);
898
- document.addEventListener('mousemove', this.handleFloatPreviewerMouseMove);
899
- document.addEventListener('mouseup', this.handleFloatPreviewerMouseUp);
900
- }
901
-
902
- removeFloatPreviewerListener() {
903
- document.removeEventListener('mousedown', this.handleFloatPreviewerMouseDown);
904
- document.removeEventListener('mousemove', this.handleFloatPreviewerMouseMove);
905
- document.removeEventListener('mouseup', this.handleFloatPreviewerMouseUp);
906
- }
907
-
908
- createFloatPreviewer() {
909
- const floatPreviewerWrap = createElement('div', 'float-previewer-wrap');
910
- const floatPreviewerHeader = createElement('div', 'float-previewer-header');
911
- const floatPreviewerTitle = createElement('div', 'float-previewer-title');
912
- floatPreviewerTitle.innerHTML = '预览';
913
- floatPreviewerWrap.style.left = `${this.storageFloatPreviewerWrapData.x}px`;
914
- floatPreviewerWrap.style.top = `${this.storageFloatPreviewerWrapData.y}px`;
915
- floatPreviewerWrap.style.height = `${this.storageFloatPreviewerWrapData.height}px`;
916
- floatPreviewerWrap.style.width = `${this.storageFloatPreviewerWrapData.width}px`;
917
- floatPreviewerHeader.appendChild(floatPreviewerTitle);
918
- floatPreviewerWrap.appendChild(floatPreviewerHeader);
919
- floatPreviewerWrap.appendChild(this.previewer.getDom());
920
- this.wrapperDom.appendChild(floatPreviewerWrap);
921
-
922
- this.floatPreviewerHeaderDom = floatPreviewerHeader;
923
- this.floatPreviewerWrapDom = floatPreviewerWrap;
924
- this.pageWidth = document.body.clientWidth;
925
- this.pageHeight = document.body.clientHeight;
926
-
927
- this.createFloatPreviewerListener();
928
- }
929
-
930
- /**
931
- * @private
932
- * @param {import('codemirror').Editor} codemirror
933
- */
934
- initText(codemirror) {
935
- try {
936
- const markdownText = codemirror.getValue();
937
- this.lastMarkdownText = markdownText;
938
- const html = this.engine.makeHtml(markdownText);
939
- this.previewer.update(html);
940
- this.$event.emit('afterInit', { markdownText, html });
941
- } catch (e) {
942
- throw new NestedError(e);
943
- }
944
- }
945
-
946
- /**
947
- * @private
948
- * @param {Event} _evt
949
- * @param {import('codemirror').Editor} codemirror
950
- */
951
- editText(_evt, codemirror) {
952
- try {
953
- if (this.timer) {
954
- clearTimeout(this.timer);
955
- this.timer = null;
956
- }
957
- const interval = this.options.engine.global.flowSessionContext ? 10 : 50;
958
- this.timer = setTimeout(() => {
959
- const markdownText = codemirror.getValue();
960
- if (markdownText !== this.lastMarkdownText) {
961
- this.lastMarkdownText = markdownText;
962
- const html = this.engine.makeHtml(markdownText);
963
- this.previewer.update(html);
964
- this.$event.emit('afterChange', {
965
- markdownText,
966
- html,
967
- });
968
- }
969
- // 强制每次编辑(包括undo、redo)编辑器都会自动滚动到光标位置
970
- if (!this.options.editor.keepDocumentScrollAfterInit) {
971
- codemirror.scrollIntoView(null);
972
- }
973
- }, interval);
974
- } catch (e) {
975
- throw new NestedError(e);
976
- }
977
- }
978
-
979
- /**
980
- * @private
981
- * @param {any} cb
982
- */
983
- onChange(cb) {
984
- this.editor.editor.on('change', (codeMirror) => {
985
- cb({
986
- markdown: codeMirror.getValue(), // 后续可以按需增加html或其他状态
987
- });
988
- });
989
- }
990
-
991
- /**
992
- * @private
993
- * @param {KeyboardEvent} evt
994
- */
995
- fireShortcutKey(evt) {
996
- const cursor = this.editor.editor.getCursor();
997
- const lineContent = this.editor.editor.getLine(cursor.line);
998
- // shift + tab 已经被绑定为缩进,所以这里不做处理
999
- if (!evt.shiftKey && evt.key === 'Tab' && LIST_CONTENT.test(lineContent)) {
1000
- // 每按一次Tab,如果当前光标在行首或者行尾,就在行首加一个\t
1001
- if (cursor.ch === 0 || cursor.ch === lineContent.length || cursor.ch === lineContent.length + 1) {
1002
- evt.preventDefault();
1003
- this.editor.editor.setSelection({ line: cursor.line, ch: 0 }, { line: cursor.line, ch: lineContent.length });
1004
- this.editor.editor.replaceSelection(`\t${lineContent}`, 'around');
1005
- const newCursor = this.editor.editor.getCursor();
1006
- this.editor.editor.setSelection(newCursor, newCursor);
1007
- }
1008
- }
1009
- if (this.toolbar.matchShortcutKey(evt)) {
1010
- // 快捷键
1011
- const needPreventDefault = this.toolbar.fireShortcutKey(evt);
1012
- if (needPreventDefault) {
1013
- evt.preventDefault();
1014
- }
1015
- }
1016
- }
1017
-
1018
- /**
1019
- * 导出预览区域内容
1020
- * @public
1021
- * @param {'pdf' | 'img' | 'markdown' | 'html'} [type='pdf']
1022
- * 'pdf':导出成pdf文件; 'img':导出成png图片; 'markdown':导出成markdown文件; 'html':导出成html文件;
1023
- * @param {string} [fileName] 导出文件名(默认为当前第一行内容|'cherry-export')
1024
- */
1025
- export(type = 'pdf', fileName = '') {
1026
- this.previewer.export(type, fileName);
1027
- }
1028
-
1029
- /**
1030
- * 修改主题
1031
- * @param {string} theme option.themeSettings.themeList 里的className
1032
- */
1033
- setTheme(theme = 'default') {
1034
- this.$event.emit('changeMainTheme', theme);
1035
- changeTheme(this, theme);
1036
- }
1037
-
1038
- /**
1039
- * 修改代码块主题
1040
- * @param {string} theme option.themeSettings.codeBlockTheme
1041
- */
1042
- setCodeBlockTheme(theme = 'default') {
1043
- this.$event.emit('changeCodeBlockTheme', theme);
1044
- changeCodeTheme(this, theme);
1045
- }
1046
-
1047
- /**
1048
- * 修改书写风格
1049
- * @param {string} writingStyle normal 普通 | typewriter 打字机 | focus 专注
1050
- */
1051
- setWritingStyle(writingStyle) {
1052
- this.editor.setWritingStyle(writingStyle);
1053
- }
1054
-
1055
- /**
1056
- * 修改语言
1057
- * @param {string} locale
1058
- * @returns {boolean} false: 修改失败,因为没有对应的语言;true: 修改成功
1059
- */
1060
- setLocale(locale) {
1061
- if (!this.locales[locale]) {
1062
- return false;
1063
- }
1064
- this.options.locale = locale;
1065
- this.locale = this.locales[locale];
1066
- this.$event.emit('afterChangeLocale', locale);
1067
- this.resetToolbar('toolbar', this.options.toolbars.toolbar || []);
1068
- return true;
1069
- }
1070
-
1071
- /**
1072
- * 切换TOC的模式(极简 or 展开)
1073
- * @param {'full'|'pure'|''} focusModel 是否强制切换模式,如果为空,则根据当前模式切换
1074
- */
1075
- toggleToc(focusModel = '') {
1076
- if (!this.toc) {
1077
- return;
1078
- }
1079
- let targetModel = 'full';
1080
- if (focusModel === '') {
1081
- // @ts-ignore
1082
- const { model } = this.toc;
1083
- targetModel = model === 'full' ? 'pure' : 'full';
1084
- } else {
1085
- targetModel = focusModel;
1086
- }
1087
- // @ts-ignore
1088
- this.toc.$switchModel(targetModel);
1089
- // @ts-ignore
1090
- this.toc.setModelToLocalStorage(targetModel);
1091
- }
1092
-
1093
- /**
1094
- * 清空流程会话中添加的虚拟光标
1095
- */
1096
- clearFlowSessionCursor() {
1097
- if (this.options.engine.global.flowSessionCursor) {
1098
- this.previewer.getDom().innerHTML = this.previewer
1099
- .getDom()
1100
- // @ts-ignore
1101
- .innerHTML.replaceAll(this.options.engine.global.flowSessionCursor, '');
1102
- }
1103
- }
1104
- }