@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,976 @@
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
+ // @ts-nocheck
17
+ /**
18
+ * 将html内容转换成md内容的工具
19
+ * 调用方式为:htmlParser.run(htmlStr)
20
+ * 主要流程为:
21
+ * 1、接收html字符串
22
+ * 2、根据html字符串生成html语法树
23
+ * 3、递归遍历语法树,将标签替换为对应的markdown语法
24
+ **/
25
+ const htmlParser = {
26
+ /**
27
+ * 入口函数,负责将传入的html字符串转成对应的markdown源码
28
+ * @param {string} htmlStr
29
+ * @returns {string} 对应的markdown源码
30
+ */
31
+ run(htmlStr) {
32
+ let $htmlStr = `<div>${htmlStr}</div>`;
33
+ // 挂载对应的格式化引擎,这里挂载的是markdown逆向引擎,后续可以扩展支持其他标记语言
34
+ this.tagParser.formatEngine = this.mdFormatEngine;
35
+ // 去掉注释
36
+ $htmlStr = $htmlStr.replace(/<!--[\s\S]*?-->/g, '');
37
+ // 将html字符串解析成html语法树
38
+ let htmlparsedArrays = this.htmlParser.parseHtml($htmlStr);
39
+ // 预处理,去掉一些不需要的样式、属性
40
+ htmlparsedArrays = this.paragraphStyleClear(htmlparsedArrays);
41
+ // 核心逻辑,遍历html语法树,生成对应的markdown源码
42
+ return this.$dealHtml(htmlparsedArrays)
43
+ .replace(/\n{3,}/g, '\n\n\n')
44
+ .replace(/&gt;/g, '>')
45
+ .replace(/&lt;/g, '<')
46
+ .replace(/&amp;/g, '&')
47
+ .trim('\n');
48
+ },
49
+ /**
50
+ * 解析html语法树
51
+ * @param {Array} arr
52
+ * @returns {string} 对应的markdown源码
53
+ */
54
+ $dealHtml(arr) {
55
+ let ret = '';
56
+ for (let i = 0; i < arr.length; i++) {
57
+ const temObj = arr[i];
58
+ if (temObj.type === 'tag') ret = this.$handleTagObject(temObj, ret);
59
+ else if (temObj.type === 'text' && temObj.content.length > 0) {
60
+ ret += temObj.content
61
+ .replace(/&nbsp;/g, ' ')
62
+ .replace(/[\n]+/g, '\n')
63
+ .replace(/^[ \t\n]+\n\s*$/, '\n');
64
+ }
65
+ }
66
+ return ret;
67
+ },
68
+ /**
69
+ * 处理html标签内容
70
+ * @param {object} temObj
71
+ * @param {string} returnString
72
+ */
73
+ $handleTagObject(temObj, returnString) {
74
+ let ret = returnString;
75
+ if (temObj.attrs.class && /(ch-icon-square|ch-icon-check)/.test(temObj.attrs.class)) {
76
+ // 针对checklist
77
+ if (temObj.attrs.class.indexOf('ch-icon-check') >= 0) {
78
+ ret += '[x]';
79
+ } else {
80
+ ret += '[ ]';
81
+ }
82
+ } else if (temObj.attrs.class && /cherry-code-preview-lang-select/.test(temObj.attrs.class)) {
83
+ // 如果是代码块的选择语言标签,则不做任何处理
84
+ ret += '';
85
+ } else {
86
+ // 如果是标签
87
+ ret += this.$dealTag(temObj);
88
+ }
89
+ return ret;
90
+ },
91
+ /**
92
+ * 解析具体的html标签
93
+ * @param {HTMLElement} obj
94
+ * @returns {string} 对应的markdown源码
95
+ */
96
+ $dealTag(obj) {
97
+ const self = this;
98
+ let tmpText = '';
99
+ if (obj.children) {
100
+ // 递归每一个子元素
101
+ tmpText = self.$dealHtml(obj.children);
102
+ }
103
+ if (/(style|meta|link|script)/.test(obj.name)) {
104
+ return '';
105
+ }
106
+ if (obj.name === 'code' || obj.name === 'pre') {
107
+ // 解析代码块 或 行内代码
108
+ // pre时,强制转成代码块
109
+ return self.tagParser.codeParser(obj, self.$dealCodeTag(obj), obj.name === 'pre');
110
+ }
111
+ if (typeof self.tagParser[`${obj.name}Parser`] === 'function') {
112
+ // 解析对应的具体标签
113
+ return self.tagParser[`${obj.name}Parser`](obj, tmpText);
114
+ }
115
+ return tmpText;
116
+ },
117
+ /**
118
+ * 解析代码块
119
+ * 本函数认为代码块是由text标签和li标签组成的
120
+ * @param {HTMLElement} obj
121
+ * @returns {string} 对应的markdown源码
122
+ */
123
+ $dealCodeTag(obj) {
124
+ const self = this;
125
+ if (obj.children.length < 0) {
126
+ return '';
127
+ }
128
+ let ret = '';
129
+ for (let i = 0; i < obj.children.length; i++) {
130
+ const temObj = obj.children[i];
131
+ if (temObj.type !== 'text') {
132
+ // 如果是非text标签,则需要处理换行逻辑
133
+ if (temObj.name === 'li') {
134
+ ret += '\n';
135
+ }
136
+ if (temObj.name === 'br') {
137
+ ret += '\n';
138
+ }
139
+ // 递归找到对应的代码文本
140
+ ret += self.$dealCodeTag(temObj);
141
+ } else {
142
+ ret += temObj.content;
143
+ }
144
+ }
145
+ return ret;
146
+ },
147
+
148
+ /** **
149
+ * html解析器
150
+ * 将html解析成对象数组
151
+ * https://github.com/HenrikJoreteg/html-parse-stringify
152
+ **/
153
+ htmlParser: {
154
+ attrRE: /([\w-]+)|['"]{1}([^'"]*)['"]{1}/g,
155
+ lookup: {
156
+ area: true,
157
+ base: true,
158
+ br: true,
159
+ col: true,
160
+ embed: true,
161
+ hr: true,
162
+ img: true,
163
+ video: true,
164
+ input: true,
165
+ keygen: true,
166
+ link: true,
167
+ menuitem: true,
168
+ meta: true,
169
+ param: true,
170
+ source: true,
171
+ track: true,
172
+ wbr: true,
173
+ },
174
+ tagRE: /<(?:"[^"]*"['"]*|'[^']*'['"]*|[^'">])+>/g,
175
+ empty: Object.create ? Object.create(null) : {},
176
+ parseTags(tag) {
177
+ const self = this;
178
+ let i = 0;
179
+ let key;
180
+ const res = {
181
+ type: 'tag',
182
+ name: '',
183
+ voidElement: false,
184
+ attrs: {},
185
+ children: [],
186
+ };
187
+
188
+ tag.replace(this.attrRE, (match) => {
189
+ if (i % 2) {
190
+ key = match;
191
+ } else {
192
+ if (i === 0) {
193
+ if (self.lookup[match] || tag.charAt(tag.length - 2) === '/') {
194
+ res.voidElement = true;
195
+ }
196
+ res.name = match;
197
+ } else {
198
+ res.attrs[key] = match.replace(/['"]/g, '');
199
+ }
200
+ }
201
+ i += 1;
202
+ });
203
+
204
+ return res;
205
+ },
206
+ parseHtml(html, options) {
207
+ const self = this;
208
+ const $options = options || {};
209
+ $options.components || ($options.components = this.empty);
210
+ const result = [];
211
+ let current;
212
+ let level = -1;
213
+ const arr = [];
214
+ const byTag = {};
215
+ let inComponent = false;
216
+
217
+ html.replace(this.tagRE, (tag, index) => {
218
+ if (inComponent) {
219
+ if (tag !== `</${current.name}>`) {
220
+ return;
221
+ }
222
+ inComponent = false;
223
+ }
224
+ const isOpen = tag.charAt(1) !== '/';
225
+ const start = index + tag.length;
226
+ const nextChar = html.charAt(start);
227
+ let parent;
228
+
229
+ if (isOpen) {
230
+ level += 1;
231
+
232
+ current = self.parseTags(tag);
233
+ if (current.type === 'tag' && $options.components[current.name]) {
234
+ current.type = 'component';
235
+ inComponent = true;
236
+ }
237
+
238
+ if (!current.voidElement && !inComponent && nextChar && nextChar !== '<') {
239
+ current.children.push({
240
+ type: 'text',
241
+ content: html.slice(start, html.indexOf('<', start)),
242
+ });
243
+ }
244
+
245
+ byTag[current.tagName] = current;
246
+
247
+ // if we're at root, push new base node
248
+ if (level === 0) {
249
+ result.push(current);
250
+ }
251
+
252
+ parent = arr[level - 1];
253
+
254
+ if (parent) {
255
+ parent.children.push(current);
256
+ }
257
+
258
+ arr[level] = current;
259
+ }
260
+
261
+ if (!isOpen || current.voidElement) {
262
+ level -= 1;
263
+ if (!inComponent && nextChar !== '<' && nextChar) {
264
+ // trailing text node
265
+ if (arr[level]) {
266
+ arr[level].children.push({
267
+ type: 'text',
268
+ content: html.slice(start, html.indexOf('<', start)),
269
+ });
270
+ }
271
+ }
272
+ }
273
+ });
274
+ return result;
275
+ },
276
+ },
277
+
278
+ /** **
279
+ * 标签解析器
280
+ * 解析对应的标签,并调用格式化引擎生成对应格式内容
281
+ **/
282
+ tagParser: {
283
+ // 挂载的解析引擎,一次只能挂在一个解析引擎,目前只实现和挂载了markdown解析引擎
284
+ formatEngine: {},
285
+ /**
286
+ * 解析p标签
287
+ * @param {HTMLElement} obj
288
+ * @param {string} str 需要回填的字符串
289
+ * @returns {string} str
290
+ */
291
+ pParser(obj, str) {
292
+ const $str = str;
293
+ if (/\n$/.test($str)) {
294
+ return $str;
295
+ }
296
+ return `${$str}\n`;
297
+ },
298
+ /**
299
+ * 解析div标签
300
+ * @param {HTMLElement} obj
301
+ * @param {string} str 需要回填的字符串
302
+ * @returns {string} str
303
+ */
304
+ divParser(obj, str) {
305
+ const $str = str;
306
+ if (/\n$/.test($str)) {
307
+ return $str;
308
+ }
309
+ return `${$str}\n`;
310
+ },
311
+ /**
312
+ * 解析span标签
313
+ * @param {HTMLElement} obj
314
+ * @param {string} str 需要回填的字符串
315
+ * @returns {string} str
316
+ */
317
+ spanParser(obj, str) {
318
+ const $str = str.replace(/\t/g, '').replace(/\n/g, ' '); // span标签里不应该有\n的,有的话就转化成空格
319
+ if (obj.attrs && obj.attrs.style) {
320
+ // 先屏蔽字体颜色、字体大小、字体背景色的转义逻辑
321
+ // let color = this.styleParser.colorAttrParser(obj.attrs.style);
322
+ // let size = this.styleParser.sizeAttrParser(obj.attrs.style);
323
+ // bgcolor = this.styleParser.bgColorAttrParser(obj.attrs.style);
324
+ // str = this.formatEngine.convertColor(str, color);
325
+ // str = this.formatEngine.convertSize(str, size);
326
+ // str = this.formatEngine.convertBgColor(str, bgcolor);
327
+ // return str;
328
+ }
329
+ return $str;
330
+ },
331
+ /**
332
+ * 解析code标签
333
+ * @param {HTMLElement} obj
334
+ * @param {string} str 需要回填的字符串
335
+ * @param {boolean} isBlock 是否强制为代码块
336
+ * @returns {string} str
337
+ */
338
+ codeParser(obj, str, isBlock = false) {
339
+ return this.formatEngine.convertCode(str, isBlock);
340
+ },
341
+ /**
342
+ * 解析br标签
343
+ * @param {HTMLElement} obj
344
+ * @param {string} str 需要回填的字符串
345
+ * @returns {string} str
346
+ */
347
+ brParser(obj, str) {
348
+ return this.formatEngine.convertBr(str, '\n');
349
+ },
350
+ /**
351
+ * 解析img标签
352
+ * @param {HTMLElement} obj
353
+ * @param {string} str 需要回填的字符串
354
+ * @returns {string} str
355
+ */
356
+ imgParser(obj, str) {
357
+ if (obj.attrs && obj.attrs['data-control'] === 'tapd-graph') {
358
+ return this.formatEngine.convertGraph(obj.attrs.title, obj.attrs.src, obj.attrs['data-origin-xml'], obj);
359
+ }
360
+ if (obj.attrs && obj.attrs.src) {
361
+ return this.formatEngine.convertImg(obj.attrs.alt, obj.attrs.src);
362
+ }
363
+ },
364
+ /**
365
+ * 解析video标签
366
+ * @param {HTMLElement} obj
367
+ * @param {string} str 需要回填的字符串
368
+ * @returns {string} str
369
+ */
370
+ videoParser(obj, str) {
371
+ if (obj.attrs && obj.attrs.src) {
372
+ return this.formatEngine.convertVideo(str, obj.attrs.src, obj.attrs.poster, obj.attrs.title);
373
+ }
374
+ },
375
+ /**
376
+ * 解析b标签
377
+ * @param {HTMLElement} obj
378
+ * @param {string} str 需要回填的字符串
379
+ * @returns {string} str
380
+ */
381
+ bParser(obj, str) {
382
+ const strArr = str.split('\n');
383
+ const ret = [];
384
+ for (let i = 0; i < strArr.length; i++) {
385
+ ret.push(this.formatEngine.convertB(strArr[i]));
386
+ }
387
+ return ret.join('\n');
388
+ },
389
+ /**
390
+ * 解析i标签
391
+ * @param {HTMLElement} obj
392
+ * @param {string} str 需要回填的字符串
393
+ * @returns {string} str
394
+ */
395
+ iParser(obj, str) {
396
+ const strArr = str.split('\n');
397
+ const ret = [];
398
+ for (let i = 0; i < strArr.length; i++) {
399
+ ret.push(this.formatEngine.convertI(strArr[i]));
400
+ }
401
+ return ret.join('\n');
402
+ },
403
+ /**
404
+ * 解析strike标签
405
+ * @param {HTMLElement} obj
406
+ * @param {string} str 需要回填的字符串
407
+ * @returns {string} str
408
+ */
409
+ strikeParser(obj, str) {
410
+ const strArr = str.split('\n');
411
+ const ret = [];
412
+ for (let i = 0; i < strArr.length; i++) {
413
+ ret.push(this.formatEngine.convertStrike(strArr[i]));
414
+ }
415
+ return ret.join('\n');
416
+ },
417
+ /**
418
+ * 解析del标签
419
+ * @param {HTMLElement} obj
420
+ * @param {string} str 需要回填的字符串
421
+ * @returns {string} str
422
+ */
423
+ delParser(obj, str) {
424
+ const strArr = str.split('\n');
425
+ const ret = [];
426
+ for (let i = 0; i < strArr.length; i++) {
427
+ ret.push(this.formatEngine.convertDel(strArr[i]));
428
+ }
429
+ return ret.join('\n');
430
+ },
431
+ /**
432
+ * 解析u标签
433
+ * @param {HTMLElement} obj
434
+ * @param {string} str 需要回填的字符串
435
+ * @returns {string} str
436
+ */
437
+ uParser(obj, str) {
438
+ const strArr = str.split('\n');
439
+ const ret = [];
440
+ for (let i = 0; i < strArr.length; i++) {
441
+ ret.push(this.formatEngine.convertU(strArr[i]));
442
+ }
443
+ return ret.join('\n');
444
+ },
445
+ /**
446
+ * 解析a标签
447
+ * @param {HTMLElement} obj
448
+ * @param {string} str 需要回填的字符串
449
+ * @returns {string} str
450
+ */
451
+ aParser(obj, str) {
452
+ if (obj.attrs && obj.attrs.href) {
453
+ return this.formatEngine.convertA(str, obj.attrs.href);
454
+ }
455
+ return '';
456
+ },
457
+ /**
458
+ * 解析sup标签
459
+ * @param {HTMLElement} obj
460
+ * @param {string} str 需要回填的字符串
461
+ * @returns {string} str
462
+ */
463
+ supParser(obj, str) {
464
+ return this.formatEngine.convertSup(str);
465
+ },
466
+ /**
467
+ * 解析sub标签
468
+ * @param {HTMLElement} obj
469
+ * @param {string} str 需要回填的字符串
470
+ * @returns {string} str
471
+ */
472
+ subParser(obj, str) {
473
+ return this.formatEngine.convertSub(str);
474
+ },
475
+ /**
476
+ * 解析td标签
477
+ * @param {HTMLElement} obj
478
+ * @param {string} str 需要回填的字符串
479
+ * @returns {string} str
480
+ */
481
+ tdParser(obj, str) {
482
+ return this.formatEngine.convertTd(str);
483
+ },
484
+ /**
485
+ * 解析tr标签
486
+ * @param {HTMLElement} obj
487
+ * @param {string} str 需要回填的字符串
488
+ * @returns {string} str
489
+ */
490
+ trParser(obj, str) {
491
+ return this.formatEngine.convertTr(str);
492
+ },
493
+ /**
494
+ * 解析th标签
495
+ * @param {HTMLElement} obj
496
+ * @param {string} str 需要回填的字符串
497
+ * @returns {string} str
498
+ */
499
+ thParser(obj, str) {
500
+ return this.formatEngine.convertTh(str);
501
+ },
502
+ /**
503
+ * 解析thead标签
504
+ * @param {HTMLElement} obj
505
+ * @param {string} str 需要回填的字符串
506
+ * @returns {string} str
507
+ */
508
+ theadParser(obj, str) {
509
+ return this.formatEngine.convertThead(str);
510
+ },
511
+ /**
512
+ * 解析table标签
513
+ * @param {HTMLElement} obj
514
+ * @param {string} str 需要回填的字符串
515
+ * @returns {string} str
516
+ */
517
+ tableParser(obj, str) {
518
+ return this.formatEngine.convertTable(str);
519
+ },
520
+ /**
521
+ * 解析li标签
522
+ * @param {HTMLElement} obj
523
+ * @param {string} str 需要回填的字符串
524
+ * @returns {string} str
525
+ */
526
+ liParser(obj, str) {
527
+ return this.formatEngine.convertLi(str);
528
+ },
529
+ /**
530
+ * 解析ul标签
531
+ * @param {HTMLElement} obj
532
+ * @param {string} str 需要回填的字符串
533
+ * @returns {string} str
534
+ */
535
+ ulParser(obj, str) {
536
+ return this.formatEngine.convertUl(str);
537
+ },
538
+ /**
539
+ * 解析ol标签
540
+ * @param {HTMLElement} obj
541
+ * @param {string} str 需要回填的字符串
542
+ * @returns {string} str
543
+ */
544
+ olParser(obj, str) {
545
+ return this.formatEngine.convertOl(str);
546
+ },
547
+ /**
548
+ * 解析strong标签
549
+ * @param {HTMLElement} obj
550
+ * @param {string} str 需要回填的字符串
551
+ * @returns {string} str
552
+ */
553
+ strongParser(obj, str) {
554
+ return this.formatEngine.convertStrong(str);
555
+ },
556
+ /**
557
+ * 解析hr标签
558
+ * @param {HTMLElement} obj
559
+ * @param {string} str 需要回填的字符串
560
+ * @returns {string} str
561
+ */
562
+ hrParser(obj, str) {
563
+ return this.formatEngine.convertHr(str);
564
+ },
565
+ /**
566
+ * 解析h1标签
567
+ * @param {HTMLElement} obj
568
+ * @param {string} str 需要回填的字符串
569
+ * @returns {string} str
570
+ */
571
+ h1Parser(obj, str) {
572
+ return this.formatEngine.convertH1(str);
573
+ },
574
+ /**
575
+ * 解析h2标签
576
+ * @param {HTMLElement} obj
577
+ * @param {string} str 需要回填的字符串
578
+ * @returns {string} str
579
+ */
580
+ h2Parser(obj, str) {
581
+ return this.formatEngine.convertH2(str);
582
+ },
583
+ /**
584
+ * 解析h3标签
585
+ * @param {HTMLElement} obj
586
+ * @param {string} str 需要回填的字符串
587
+ * @returns {string} str
588
+ */
589
+ h3Parser(obj, str) {
590
+ return this.formatEngine.convertH3(str);
591
+ },
592
+ /**
593
+ * 解析h4标签
594
+ * @param {HTMLElement} obj
595
+ * @param {string} str 需要回填的字符串
596
+ * @returns {string} str
597
+ */
598
+ h4Parser(obj, str) {
599
+ return this.formatEngine.convertH4(str);
600
+ },
601
+ /**
602
+ * 解析h5标签
603
+ * @param {HTMLElement} obj
604
+ * @param {string} str 需要回填的字符串
605
+ * @returns {string} str
606
+ */
607
+ h5Parser(obj, str) {
608
+ return this.formatEngine.convertH5(str);
609
+ },
610
+ /**
611
+ * 解析h6标签
612
+ * @param {HTMLElement} obj
613
+ * @param {string} str 需要回填的字符串
614
+ * @returns {string} str
615
+ */
616
+ h6Parser(obj, str) {
617
+ return this.formatEngine.convertH6(str);
618
+ },
619
+ /**
620
+ * 解析blockquote标签
621
+ * @param {HTMLElement} obj
622
+ * @param {string} str 需要回填的字符串
623
+ * @returns {string} str
624
+ */
625
+ blockquoteParser(obj, str) {
626
+ return this.formatEngine.convertBlockquote(str.replace(/\n+/g, '\n'));
627
+ },
628
+ /**
629
+ * 解析address标签
630
+ * @param {HTMLElement} obj
631
+ * @param {string} str 需要回填的字符串
632
+ * @returns {string} str
633
+ */
634
+ addressParser(obj, str) {
635
+ return this.formatEngine.convertAddress(str.replace(/\n+/g, '\n'));
636
+ },
637
+ // 样式解析器
638
+ styleParser: {
639
+ // 识别字体颜色 color
640
+ colorAttrParser(style) {
641
+ const color = style.match(/color:\s*(#[a-zA-Z0-9]{3,6});/);
642
+ if (color && color[1]) {
643
+ return color[1];
644
+ }
645
+ return '';
646
+ },
647
+ // 识别字体大小 font-size
648
+ sizeAttrParser(style) {
649
+ const fontSize = style.match(/font-size:\s*([a-zA-Z0-9-]+?);/);
650
+ if (fontSize && fontSize[1]) {
651
+ let size = 0;
652
+ if (/[0-9]+px/.test(fontSize[1])) {
653
+ size = fontSize[1].replace(/px/, '').trim();
654
+ } else {
655
+ switch (fontSize[1]) {
656
+ case 'x-small':
657
+ size = 10;
658
+ break;
659
+ case 'small':
660
+ size = 12;
661
+ break;
662
+ case 'medium':
663
+ size = 16;
664
+ break;
665
+ case 'large':
666
+ size = 18;
667
+ break;
668
+ case 'x-large':
669
+ size = 24;
670
+ break;
671
+ case 'xx-large':
672
+ size = 32;
673
+ break;
674
+ default:
675
+ size = '';
676
+ }
677
+ }
678
+ return size > 0 ? size : '';
679
+ }
680
+ return '';
681
+ },
682
+ // 识别字体背景颜色 background-color
683
+ bgColorAttrParser(style) {
684
+ const color = style.match(/background-color:\s*([^;]+?);/);
685
+ if (color && color[1]) {
686
+ let bgColor = '';
687
+ if (/rgb\([ 0-9]+,[ 0-9]+,[ 0-9]+\)/.test(color[1])) {
688
+ const values = color[1].match(/rgb\(([ 0-9]+),([ 0-9]+),([ 0-9]+)\)/);
689
+ if (values[1] && values[2] && values[3]) {
690
+ values[1] = parseInt(values[1].trim(), 10);
691
+ values[2] = parseInt(values[2].trim(), 10);
692
+ values[3] = parseInt(values[3].trim(), 10);
693
+ bgColor = `#${values[1].toString(16)}${values[2].toString(16)}${values[3].toString(16)}`;
694
+ }
695
+ } else {
696
+ [, bgColor] = color;
697
+ }
698
+ return bgColor;
699
+ }
700
+ return '';
701
+ },
702
+ },
703
+ },
704
+
705
+ /**
706
+ * 一个格式化引擎
707
+ * 将字符串格式化成markdown语法的引擎
708
+ **/
709
+ mdFormatEngine: {
710
+ convertColor(str, attr) {
711
+ const $str = str.trim();
712
+ if (!$str || /\n/.test($str)) {
713
+ return $str;
714
+ }
715
+ return attr ? `!!${attr} ${$str}!!` : $str;
716
+ },
717
+ convertSize(str, attr) {
718
+ const $str = str.trim();
719
+ if (!$str || /\n/.test($str)) {
720
+ return $str;
721
+ }
722
+ return attr ? `!${attr} ${$str}!` : $str;
723
+ },
724
+ convertBgColor(str, attr) {
725
+ const $str = str.trim();
726
+ if (!$str || /\n/.test($str)) {
727
+ return $str;
728
+ }
729
+ return attr ? `!!!${attr} ${$str}!!!` : $str;
730
+ },
731
+ convertBr(str, attr) {
732
+ return str + attr;
733
+ },
734
+ convertCode(str, isBlock = false) {
735
+ if (/\n/.test(str) || isBlock) {
736
+ return `\`\`\`\n${str.replace(/\n+$/, '')}\n\`\`\``;
737
+ }
738
+ return `\`${str.replace(/`/g, '\\`')}\``;
739
+ },
740
+ convertB(str) {
741
+ return /^\s*$/.test(str) ? '' : `**${str}**`;
742
+ },
743
+ convertI(str) {
744
+ return /^\s*$/.test(str) ? '' : `*${str}*`;
745
+ },
746
+ convertU(str) {
747
+ return /^\s*$/.test(str) ? '' : ` /${str}/ `;
748
+ },
749
+ convertImg(alt, src) {
750
+ const $alt = alt && alt.length > 0 ? alt : 'image';
751
+ return `![${$alt}](${src})`;
752
+ },
753
+ convertGraph(str, attr, data, obj) {
754
+ const $str = str && str.length > 0 ? str : 'graph';
755
+ let moreAttrs = '';
756
+ if (obj) {
757
+ try {
758
+ const { attrs } = obj;
759
+ Object.keys(attrs).forEach((prop) => {
760
+ if (Object.prototype.hasOwnProperty.call(attrs, prop)) {
761
+ if (prop.indexOf('data-graph-') >= 0 && attrs[prop]) {
762
+ moreAttrs += ` ${prop}=${attrs[prop]}`;
763
+ }
764
+ }
765
+ });
766
+ } catch (error) {
767
+ // console.log('error', error)
768
+ }
769
+ }
770
+ return `![${$str}](${attr}){data-control=tapd-graph data-origin-xml=${data}${moreAttrs}}`;
771
+ },
772
+ convertVideo(str, src, poster, title) {
773
+ const $title = title && title.length > 0 ? title : 'video';
774
+ return `!video[${$title}](${src}){poster=${poster}}`;
775
+ },
776
+ convertA(str, attr) {
777
+ if (str === attr) {
778
+ return `${str} `;
779
+ }
780
+ const $str = str.trim();
781
+ if (!$str) {
782
+ return $str;
783
+ }
784
+ return `[${$str}](${attr})`;
785
+ },
786
+ convertSup(str) {
787
+ return `^${str.trim().replace(/\^/g, '\\^')}^`;
788
+ },
789
+ convertSub(str) {
790
+ return `^^${str.trim().replace(/\^\^/g, '\\^\\^')}^^`;
791
+ },
792
+ convertTd(str) {
793
+ return `~|${str
794
+ .trim()
795
+ .replace(/\n{1,}/g, '<br>')
796
+ .replace(/ /g, '~s~')} ~|`;
797
+ },
798
+ convertTh(str) {
799
+ if (/^\s*$/.test(str)) {
800
+ return '';
801
+ }
802
+ return `~|${str.trim().replace(/\n{1,}/g, '<br>')} ~|`;
803
+ },
804
+ convertTr(str) {
805
+ if (/^\s*$/.test(str)) {
806
+ return '';
807
+ }
808
+ return `${str.trim().replace(/\n/g, '')}\n`;
809
+ },
810
+ convertThead(str) {
811
+ const $str = `${str
812
+ .replace(/[ \t]+/g, '')
813
+ .replace(/~\|~\|/g, '~|')
814
+ .replace(/~\|/g, '|')}\n`;
815
+ const headsCount = $str.match(/\|/g).length - 1;
816
+ return `${$str}|${':-:|'.repeat(headsCount)}\n`;
817
+ },
818
+ convertTable(str) {
819
+ let ret = `\n${str
820
+ .replace(/[ \t]+/g, '')
821
+ .replace(/~\|~\|/g, '~|')
822
+ .replace(/~\|/g, '|')}\n`
823
+ .replace(/\n{2,}/g, '\n')
824
+ .replace(/\n[ \t]+\n/g, '\n')
825
+ .replace(/~s~/g, ' ');
826
+ if (!/\|:-:\|/.test(ret)) {
827
+ const headsCount = ret.match(/^\n[^\n]+\n/)[0].match(/\|/g).length - 1;
828
+ ret = `\n|${' |'.repeat(headsCount)}\n|${':-:|'.repeat(headsCount)}${ret}`;
829
+ }
830
+ return ret;
831
+ },
832
+ convertLi(str) {
833
+ return `- ${str.replace(/^\n/, '').replace(/\n+$/, '').replace(/\n+/g, '\n\t')}\n`;
834
+ },
835
+ convertUl(str) {
836
+ return `${str}\n`;
837
+ },
838
+ convertOl(str) {
839
+ const arr = str.split('\n');
840
+ let index = 1;
841
+ for (let i = 0; i < arr.length; i++) {
842
+ if (/^- /.test(arr[i])) {
843
+ arr[i] = arr[i].replace(/^- /, `${index}. `);
844
+ index += 1;
845
+ }
846
+ }
847
+ const $str = arr.join('\n');
848
+ return `${$str}\n`;
849
+ },
850
+ convertStrong(str) {
851
+ return /^\s*$/.test(str) ? '' : `**${str}**`;
852
+ },
853
+ convertStrike(str) {
854
+ return /^\s*$/.test(str) ? '' : `~~${str}~~`;
855
+ },
856
+ convertDel(str) {
857
+ return /^\s*$/.test(str) ? '' : `~~${str}~~`;
858
+ },
859
+ convertHr(str) {
860
+ return /^\s*$/.test(str) ? '\n\n----\n' : `\n\n----\n${str}`;
861
+ },
862
+ convertH1(str) {
863
+ return `# ${str.trim().replace(/\n+$/, '')}\n\n`;
864
+ },
865
+ convertH2(str) {
866
+ return `## ${str.trim().replace(/\n+$/, '')}\n\n`;
867
+ },
868
+ convertH3(str) {
869
+ return `### ${str.trim().replace(/\n+$/, '')}\n\n`;
870
+ },
871
+ convertH4(str) {
872
+ return `#### ${str.trim().replace(/\n+$/, '')}\n\n`;
873
+ },
874
+ convertH5(str) {
875
+ return `##### ${str.trim().replace(/\n+$/, '')}\n\n`;
876
+ },
877
+ convertH6(str) {
878
+ return `###### ${str.trim().replace(/\n+$/, '')}\n\n`;
879
+ },
880
+ convertBlockquote(str) {
881
+ return `>${str.trim()}\n\n`;
882
+ },
883
+ convertAddress(str) {
884
+ return `>${str.trim()}\n\n`;
885
+ },
886
+ },
887
+ /**
888
+ * 清除整段的样式、方便编辑
889
+ * 暂时先屏蔽字体色和背景色
890
+ * @param {Array} htmlparsedArrays 由HTMLElement组成的数组
891
+ */
892
+ paragraphStyleClear(htmlparsedArrays) {
893
+ for (let index = 0; index < htmlparsedArrays[0].children.length; index++) {
894
+ const htmlItem = htmlparsedArrays[0].children[index];
895
+ const stack = [htmlItem];
896
+ let paragraphs = [];
897
+ while (stack.length) {
898
+ const temp = stack.shift();
899
+ const childCount = this.notEmptyTagCount(temp);
900
+ if (childCount === 1) {
901
+ paragraphs.push(temp);
902
+ } else if (childCount > 1) {
903
+ for (let k = 0; k < temp.children.length; k++) {
904
+ stack.push(temp.children[k]);
905
+ }
906
+ } else {
907
+ if (paragraphs.length === 1) {
908
+ this.clearChildColorAttrs(paragraphs.pop());
909
+ }
910
+ paragraphs = [];
911
+ }
912
+ }
913
+ if (paragraphs.length === 1) {
914
+ this.clearChildColorAttrs(paragraphs.pop());
915
+ }
916
+ }
917
+
918
+ return htmlparsedArrays;
919
+ },
920
+ /**
921
+ * 非空子元素数量
922
+ */
923
+ notEmptyTagCount(htmlItem) {
924
+ if (
925
+ !htmlItem ||
926
+ htmlItem.voidElement ||
927
+ (htmlItem.type === 'tag' && !htmlItem.children.length) ||
928
+ (htmlItem.type === 'text' && !htmlItem.content.replace(/(\r|\n|\s)+/g, ''))
929
+ ) {
930
+ return 0;
931
+ }
932
+
933
+ if (htmlItem.children && htmlItem.children.length) {
934
+ let res = 0;
935
+ for (let index = 0; index < htmlItem.children.length; index++) {
936
+ res += this.notEmptyTagCount(htmlItem.children[index]);
937
+ }
938
+ return res;
939
+ }
940
+ return 1;
941
+ },
942
+ clearChildColorAttrs(htmlItems) {
943
+ const self = this;
944
+ this.forEachHtmlParsedItems(htmlItems, (htmlItem) => {
945
+ self.clearSelfNodeColorAttrs(htmlItem);
946
+ });
947
+ },
948
+ clearSelfNodeColorAttrs(htmlItem) {
949
+ if (htmlItem.attrs && htmlItem.attrs.style) {
950
+ const styles = htmlItem.attrs.style.split(';');
951
+ const newStyles = [];
952
+ for (let index = 0; index < styles.length; index++) {
953
+ if (styles[index] && styles[index].indexOf('color') === -1) {
954
+ newStyles.push(styles[index]);
955
+ }
956
+ }
957
+ if (newStyles.length) {
958
+ htmlItem.attrs.style = `${newStyles.join(';')};`;
959
+ } else {
960
+ delete htmlItem.attrs.style;
961
+ }
962
+ }
963
+ },
964
+ forEachHtmlParsedItems(htmlItems, cb) {
965
+ if (htmlItems) {
966
+ cb(htmlItems);
967
+ if (htmlItems.children && htmlItems.children.length) {
968
+ for (let index = 0; index < htmlItems.children.length; index++) {
969
+ this.forEachHtmlParsedItems(htmlItems.children[index], cb);
970
+ }
971
+ }
972
+ }
973
+ },
974
+ };
975
+
976
+ export default htmlParser;