artalk 2.6.3 → 2.7.0

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 (300) hide show
  1. package/dist/Artalk.css +1 -1
  2. package/dist/Artalk.es.js +7673 -7330
  3. package/dist/Artalk.iife.js +1 -1
  4. package/dist/Artalk.js +1 -1
  5. package/dist/ArtalkLite.css +1 -1
  6. package/dist/ArtalkLite.es.js +5304 -4961
  7. package/dist/ArtalkLite.iife.js +1 -1
  8. package/dist/ArtalkLite.js +1 -1
  9. package/dist/src/api/{api-base.d.ts → _base.d.ts} +3 -7
  10. package/dist/src/api/_options.d.ts +19 -0
  11. package/dist/src/api/{request.d.ts → _request.d.ts} +3 -3
  12. package/dist/src/api/admin.d.ts +1 -1
  13. package/dist/src/api/captcha.d.ts +1 -1
  14. package/dist/src/api/comment.d.ts +2 -2
  15. package/dist/src/api/index.d.ts +2 -4
  16. package/dist/src/api/page.d.ts +3 -3
  17. package/dist/src/api/site.d.ts +2 -2
  18. package/dist/src/api/system.d.ts +13 -3
  19. package/dist/src/api/upload.d.ts +1 -1
  20. package/dist/src/api/user.d.ts +2 -2
  21. package/dist/src/artalk.d.ts +14 -37
  22. package/dist/src/comment/actions.d.ts +1 -1
  23. package/dist/src/comment/comment.d.ts +3 -4
  24. package/dist/src/comment/render.d.ts +21 -3
  25. package/dist/src/comment/renders/actions.d.ts +2 -2
  26. package/dist/src/comment/renders/avatar.d.ts +2 -2
  27. package/dist/src/comment/renders/content.d.ts +2 -2
  28. package/dist/src/comment/renders/header.d.ts +2 -2
  29. package/dist/src/comment/renders/index.d.ts +2 -2
  30. package/dist/src/comment/renders/pending.d.ts +2 -2
  31. package/dist/src/comment/renders/reply-at.d.ts +2 -2
  32. package/dist/src/comment/renders/reply-to.d.ts +2 -2
  33. package/dist/src/components/action-btn.d.ts +3 -5
  34. package/dist/src/{lib → components}/checker/admin.d.ts +1 -1
  35. package/dist/src/{lib → components}/checker/captcha-renders.d.ts +1 -1
  36. package/dist/src/{lib → components}/checker/captcha.d.ts +1 -1
  37. package/dist/src/{lib → components}/checker/index.d.ts +10 -7
  38. package/dist/src/components/dark-mode.d.ts +2 -0
  39. package/dist/src/components/dialog.d.ts +1 -3
  40. package/dist/src/components/error-dialog.d.ts +8 -0
  41. package/dist/src/components/pagination.d.ts +4 -3
  42. package/dist/src/components/read-more-btn.d.ts +3 -3
  43. package/dist/src/config.d.ts +24 -8
  44. package/dist/src/context.d.ts +16 -35
  45. package/dist/src/data.d.ts +27 -0
  46. package/dist/src/defaults.d.ts +1 -1
  47. package/dist/src/editor/editor.d.ts +14 -59
  48. package/dist/src/editor/state.d.ts +20 -0
  49. package/dist/src/i18n/zh-CN.d.ts +1 -1
  50. package/dist/src/layer/index.d.ts +4 -3
  51. package/dist/src/layer/layer-manager.d.ts +9 -0
  52. package/dist/src/layer/layer.d.ts +8 -28
  53. package/dist/src/layer/scrollbar-helper.d.ts +5 -0
  54. package/dist/src/layer/sidebar-layer.d.ts +6 -6
  55. package/dist/src/layer/wrap.d.ts +13 -0
  56. package/dist/src/lib/component.d.ts +3 -8
  57. package/dist/src/lib/event-manager.d.ts +28 -0
  58. package/dist/src/lib/highlight.d.ts +1 -0
  59. package/dist/src/lib/marked-renderer.d.ts +4 -0
  60. package/dist/src/lib/marked.d.ts +4 -2
  61. package/dist/src/lib/sanitizer.d.ts +1 -0
  62. package/dist/src/lib/ui.d.ts +3 -2
  63. package/dist/src/lib/user.d.ts +8 -5
  64. package/dist/src/lib/utils.d.ts +11 -5
  65. package/dist/src/list/comment.d.ts +3 -0
  66. package/dist/src/list/layout.d.ts +23 -0
  67. package/dist/src/list/list.d.ts +13 -25
  68. package/dist/src/list/{list-nest.d.ts → nest.d.ts} +1 -1
  69. package/dist/src/list/page.d.ts +2 -0
  70. package/dist/src/list/paginator/index.d.ts +22 -7
  71. package/dist/src/list/paginator/read-more.d.ts +18 -0
  72. package/dist/src/list/paginator/up-down.d.ts +14 -0
  73. package/dist/src/main.d.ts +2 -0
  74. package/dist/src/plugins/admin-only-elem.d.ts +2 -0
  75. package/dist/src/plugins/conf-remoter.d.ts +2 -0
  76. package/dist/src/plugins/dark-mode.d.ts +2 -0
  77. package/dist/src/plugins/editor/_kit.d.ts +27 -0
  78. package/dist/src/plugins/editor/_plug.d.ts +29 -0
  79. package/dist/src/plugins/editor/_sample.d.ts +5 -0
  80. package/dist/src/plugins/editor/closable.d.ts +7 -0
  81. package/dist/src/{editor/plugs/emoticons-plug.d.ts → plugins/editor/emoticons.d.ts} +10 -16
  82. package/dist/src/plugins/editor/header-event.d.ts +6 -0
  83. package/dist/src/plugins/editor/header-link.d.ts +6 -0
  84. package/dist/src/plugins/editor/header-user.d.ts +16 -0
  85. package/dist/src/plugins/editor/index.d.ts +6 -0
  86. package/dist/src/plugins/editor/local-storage.d.ts +6 -0
  87. package/dist/src/plugins/editor/mover.d.ts +6 -0
  88. package/dist/src/plugins/editor/preview.d.ts +7 -0
  89. package/dist/src/plugins/editor/state-edit.d.ts +11 -0
  90. package/dist/src/plugins/editor/state-reply.d.ts +8 -0
  91. package/dist/src/plugins/editor/submit-add.d.ts +18 -0
  92. package/dist/src/plugins/editor/submit-btn.d.ts +5 -0
  93. package/dist/src/plugins/editor/submit.d.ts +17 -0
  94. package/dist/src/plugins/editor/textarea.d.ts +8 -0
  95. package/dist/src/plugins/editor/upload.d.ts +9 -0
  96. package/dist/src/plugins/editor-kit.d.ts +42 -0
  97. package/dist/src/plugins/index.d.ts +2 -0
  98. package/dist/src/plugins/list/copyright.d.ts +2 -0
  99. package/dist/src/plugins/list/count.d.ts +2 -0
  100. package/dist/src/plugins/list/dropdown.d.ts +2 -0
  101. package/dist/src/plugins/list/error-dialog.d.ts +2 -0
  102. package/dist/src/plugins/list/fetch.d.ts +2 -0
  103. package/dist/src/plugins/list/goto-first.d.ts +3 -0
  104. package/dist/src/plugins/list/goto.d.ts +2 -0
  105. package/dist/src/plugins/list/index.d.ts +3 -0
  106. package/dist/src/plugins/list/loading.d.ts +2 -0
  107. package/dist/src/plugins/list/no-comment.d.ts +2 -0
  108. package/dist/src/plugins/list/reach-bottom.d.ts +2 -0
  109. package/dist/src/plugins/list/sidebar-btn.d.ts +2 -0
  110. package/dist/src/plugins/list/time-ticking.d.ts +3 -0
  111. package/dist/src/plugins/list/unread-badge.d.ts +2 -0
  112. package/dist/src/plugins/list/unread.d.ts +2 -0
  113. package/dist/src/plugins/list/with-editor.d.ts +2 -0
  114. package/dist/src/plugins/markdown.d.ts +2 -0
  115. package/dist/src/plugins/stat.d.ts +13 -0
  116. package/dist/src/plugins/version-check.d.ts +2 -0
  117. package/dist/src/service.d.ts +19 -23
  118. package/dist/tests/e2e/comment-add.spec.d.ts +1 -0
  119. package/dist/types/config.d.ts +110 -0
  120. package/dist/types/context.d.ts +56 -136
  121. package/dist/types/data.d.ts +194 -0
  122. package/dist/types/editor.d.ts +76 -0
  123. package/dist/types/event.d.ts +36 -25
  124. package/dist/types/index.d.ts +7 -0
  125. package/dist/types/plugin.d.ts +2 -0
  126. package/dist/types/sidebar.d.ts +3 -0
  127. package/package.json +5 -2
  128. package/src/api/_base.ts +18 -0
  129. package/src/api/_options.ts +25 -0
  130. package/src/api/{request.ts → _request.ts} +19 -18
  131. package/src/api/admin.ts +1 -1
  132. package/src/api/captcha.ts +1 -1
  133. package/src/api/comment.ts +4 -4
  134. package/src/api/index.ts +3 -12
  135. package/src/api/page.ts +5 -5
  136. package/src/api/site.ts +2 -2
  137. package/src/api/system.ts +19 -7
  138. package/src/api/upload.ts +3 -3
  139. package/src/api/user.ts +3 -3
  140. package/src/artalk.ts +49 -97
  141. package/src/comment/actions.ts +1 -4
  142. package/src/comment/comment.ts +9 -6
  143. package/src/comment/render.ts +27 -5
  144. package/src/comment/renders/actions.ts +45 -45
  145. package/src/comment/renders/avatar.ts +7 -7
  146. package/src/comment/renders/content.ts +18 -18
  147. package/src/comment/renders/header.ts +13 -13
  148. package/src/comment/renders/index.ts +3 -3
  149. package/src/comment/renders/pending.ts +5 -5
  150. package/src/comment/renders/reply-at.ts +8 -8
  151. package/src/comment/renders/reply-to.ts +13 -13
  152. package/src/components/action-btn.ts +11 -13
  153. package/src/{lib → components}/checker/admin.ts +6 -6
  154. package/src/{lib → components}/checker/captcha-renders.ts +7 -6
  155. package/src/{lib → components}/checker/captcha.ts +1 -1
  156. package/src/{lib → components}/checker/index.ts +21 -26
  157. package/src/components/dark-mode.ts +30 -0
  158. package/src/components/dialog.ts +4 -9
  159. package/src/components/error-dialog.ts +35 -0
  160. package/src/components/pagination.ts +10 -6
  161. package/src/components/read-more-btn.ts +7 -7
  162. package/src/config.ts +60 -6
  163. package/src/context.ts +39 -144
  164. package/src/data.ts +110 -0
  165. package/src/defaults.ts +1 -1
  166. package/src/editor/editor.ts +41 -146
  167. package/src/editor/state.ts +52 -0
  168. package/src/i18n/zh-CN.ts +1 -1
  169. package/src/layer/index.ts +4 -4
  170. package/src/layer/layer-manager.ts +32 -0
  171. package/src/layer/layer.ts +20 -144
  172. package/src/layer/scrollbar-helper.ts +24 -0
  173. package/src/layer/sidebar-layer.ts +74 -64
  174. package/src/layer/wrap.ts +77 -0
  175. package/src/lib/component.ts +4 -11
  176. package/src/lib/detect.ts +1 -1
  177. package/src/lib/event-manager.ts +47 -0
  178. package/src/lib/highlight.ts +5 -0
  179. package/src/lib/marked-renderer.ts +32 -0
  180. package/src/lib/marked.ts +43 -104
  181. package/src/lib/sanitizer.ts +57 -0
  182. package/src/lib/ui.ts +22 -15
  183. package/src/lib/user.ts +21 -16
  184. package/src/lib/utils.ts +29 -18
  185. package/src/list/comment.ts +20 -0
  186. package/src/list/layout.ts +120 -0
  187. package/src/list/list.html +3 -1
  188. package/src/list/list.ts +56 -200
  189. package/src/list/{list-nest.ts → nest.ts} +1 -1
  190. package/src/list/page.ts +97 -0
  191. package/src/list/paginator/index.ts +20 -8
  192. package/src/list/paginator/read-more.ts +67 -0
  193. package/src/list/paginator/up-down.ts +51 -0
  194. package/src/main.ts +2 -0
  195. package/src/plugins/admin-only-elem.ts +40 -0
  196. package/src/plugins/conf-remoter.ts +54 -0
  197. package/src/plugins/dark-mode.ts +12 -0
  198. package/src/plugins/editor/_kit.ts +57 -0
  199. package/src/plugins/editor/_plug.ts +60 -0
  200. package/src/plugins/editor/_sample.ts +8 -0
  201. package/src/plugins/editor/closable.ts +44 -0
  202. package/src/{editor/plugs/emoticons-plug.ts → plugins/editor/emoticons.ts} +51 -52
  203. package/src/plugins/editor/header-event.ts +35 -0
  204. package/src/plugins/editor/header-link.ts +31 -0
  205. package/src/plugins/editor/header-user.ts +98 -0
  206. package/src/plugins/editor/index.ts +40 -0
  207. package/src/plugins/editor/local-storage.ts +36 -0
  208. package/src/plugins/editor/mover.ts +29 -0
  209. package/src/plugins/editor/preview.ts +41 -0
  210. package/src/plugins/editor/state-edit.ts +116 -0
  211. package/src/plugins/editor/state-reply.ts +91 -0
  212. package/src/plugins/editor/submit-add.ts +33 -0
  213. package/src/plugins/editor/submit-btn.ts +25 -0
  214. package/src/plugins/editor/submit.ts +73 -0
  215. package/src/plugins/editor/textarea.ts +55 -0
  216. package/src/plugins/editor/upload.ts +145 -0
  217. package/src/plugins/editor-kit.ts +161 -0
  218. package/src/plugins/index.ts +16 -0
  219. package/src/plugins/list/copyright.ts +16 -0
  220. package/src/plugins/list/count.ts +31 -0
  221. package/src/plugins/list/dropdown.ts +95 -0
  222. package/src/plugins/list/error-dialog.ts +22 -0
  223. package/src/plugins/list/fetch.ts +64 -0
  224. package/src/plugins/list/goto-first.ts +23 -0
  225. package/src/plugins/list/goto.ts +72 -0
  226. package/src/plugins/list/index.ts +25 -0
  227. package/src/plugins/list/loading.ts +17 -0
  228. package/src/plugins/list/no-comment.ts +25 -0
  229. package/src/plugins/list/reach-bottom.ts +46 -0
  230. package/src/plugins/list/sidebar-btn.ts +39 -0
  231. package/src/plugins/list/time-ticking.ts +22 -0
  232. package/src/plugins/list/unread-badge.ts +26 -0
  233. package/src/plugins/list/unread.ts +38 -0
  234. package/src/plugins/list/with-editor.ts +59 -0
  235. package/src/plugins/markdown.ts +10 -0
  236. package/src/plugins/stat.ts +79 -0
  237. package/src/plugins/version-check.ts +37 -0
  238. package/src/service.ts +34 -61
  239. package/src/style/comment.scss +5 -7
  240. package/src/style/editor.scss +5 -0
  241. package/src/style/list.scss +2 -7
  242. package/types/{artalk-config.d.ts → config.ts} +16 -2
  243. package/types/context.ts +84 -0
  244. package/{dist/types/artalk-data.d.ts → types/data.ts} +41 -0
  245. package/types/editor.ts +95 -0
  246. package/types/event.ts +40 -0
  247. package/types/index.ts +7 -0
  248. package/types/plugin.ts +3 -0
  249. package/types/sidebar.ts +3 -0
  250. package/dist/src/comment/render-ctx.d.ts +0 -23
  251. package/dist/src/editor/edit-mode.d.ts +0 -9
  252. package/dist/src/editor/funcs.d.ts +0 -2
  253. package/dist/src/editor/index.d.ts +0 -2
  254. package/dist/src/editor/mover.d.ts +0 -8
  255. package/dist/src/editor/plug-manager.d.ts +0 -17
  256. package/dist/src/editor/plugs/editor-plug.d.ts +0 -38
  257. package/dist/src/editor/plugs/header-input-plug.d.ts +0 -13
  258. package/dist/src/editor/plugs/preview-plug.d.ts +0 -10
  259. package/dist/src/editor/plugs/upload-plug.d.ts +0 -10
  260. package/dist/src/editor/reply.d.ts +0 -9
  261. package/dist/src/editor/submit.d.ts +0 -16
  262. package/dist/src/lib/dark-mode.d.ts +0 -4
  263. package/dist/src/lib/stat.d.ts +0 -15
  264. package/dist/src/list/index.d.ts +0 -2
  265. package/dist/src/list/list-lite.d.ts +0 -77
  266. package/dist/src/list/list-ui.d.ts +0 -16
  267. package/dist/src/list/paginator/adaptors/index.d.ts +0 -12
  268. package/dist/src/list/paginator/adaptors/pagination.d.ts +0 -9
  269. package/dist/src/list/paginator/adaptors/read-more.d.ts +0 -10
  270. package/dist/src/list/paginator/holder.d.ts +0 -16
  271. package/dist/types/artalk-config.d.ts +0 -139
  272. package/dist/types/plug.d.ts +0 -4
  273. package/src/api/api-base.ts +0 -27
  274. package/src/comment/render-ctx.ts +0 -30
  275. package/src/editor/edit-mode.ts +0 -103
  276. package/src/editor/funcs.ts +0 -97
  277. package/src/editor/index.ts +0 -3
  278. package/src/editor/mover.ts +0 -43
  279. package/src/editor/plug-manager.ts +0 -172
  280. package/src/editor/plugs/editor-plug.ts +0 -69
  281. package/src/editor/plugs/header-input-plug.ts +0 -79
  282. package/src/editor/plugs/preview-plug.ts +0 -44
  283. package/src/editor/plugs/upload-plug.ts +0 -122
  284. package/src/editor/reply.ts +0 -62
  285. package/src/editor/submit.ts +0 -99
  286. package/src/lib/dark-mode.ts +0 -48
  287. package/src/lib/stat.ts +0 -71
  288. package/src/list/index.ts +0 -3
  289. package/src/list/list-lite.ts +0 -424
  290. package/src/list/list-ui.ts +0 -137
  291. package/src/list/paginator/adaptors/index.ts +0 -21
  292. package/src/list/paginator/adaptors/pagination.ts +0 -42
  293. package/src/list/paginator/adaptors/read-more.ts +0 -56
  294. package/src/list/paginator/holder.ts +0 -56
  295. package/types/artalk-data.d.ts +0 -230
  296. package/types/context.d.ts +0 -142
  297. package/types/event.d.ts +0 -28
  298. package/types/plug.d.ts +0 -4
  299. /package/src/{editor/plugs/emoticons-plug.scss → plugins/editor/emoticons.scss} +0 -0
  300. /package/src/{editor/plugs/preview-plug.scss → plugins/editor/preview.scss} +0 -0
@@ -1,172 +0,0 @@
1
- import type ArtalkConfig from '~/types/artalk-config'
2
- import EmoticonsPlug from './plugs/emoticons-plug'
3
- import UploadPlug from './plugs/upload-plug'
4
- import PreviewPlug from './plugs/preview-plug'
5
- import HeaderInputPlug from './plugs/header-input-plug'
6
- import EditorPlug from './plugs/editor-plug'
7
- import Editor from './editor'
8
-
9
- /** The default enabled plugs */
10
- const ENABLED_PLUGS = [ EmoticonsPlug, UploadPlug, PreviewPlug, HeaderInputPlug ]
11
-
12
- /** Context of an editor plug manager */
13
- export interface PlugManager {
14
- editor: Editor
15
- plugList: { [name: string]: EditorPlug }
16
- openedPlugName: string|null
17
-
18
- openPlugPanel(plugName: string): void
19
- closePlugPanel(): void
20
-
21
- triggerHeaderInputEvt(field: string, $input: HTMLInputElement): void
22
- triggerContentUpdatedEvt(content: string): void
23
- getTransformedContent(raw: string): string
24
- }
25
-
26
- /** Create an editor plug manager */
27
- export function createPlugManager(editor: Editor): PlugManager {
28
- const ctx: PlugManager = {
29
- editor,
30
- plugList: {},
31
- openedPlugName: null,
32
- openPlugPanel: (p: string) => openPlugPanel(ctx, p),
33
- closePlugPanel: () => closePlugPanel(ctx),
34
-
35
- triggerHeaderInputEvt: (f, $) => triggerHeaderInputEvt(ctx, f, $),
36
- triggerContentUpdatedEvt: (c) => triggerContentUpdatedEvt(ctx, c),
37
- getTransformedContent: (r) => getTransformedContent(ctx, r),
38
- }
39
-
40
- // handle ui
41
- editor.getUI().$plugPanelWrap.innerHTML = ''
42
- editor.getUI().$plugPanelWrap.style.display = 'none'
43
- editor.getUI().$plugBtnWrap.innerHTML = ''
44
-
45
- // init the all enabled plugs
46
- const DISABLED = getDisabledPlugNames(editor.conf)
47
-
48
- ENABLED_PLUGS
49
- .filter(p => !DISABLED.includes(p.Name)) // 禁用的插件
50
- .forEach((Plug) => {
51
- initPlugItem(ctx, Plug)
52
- })
53
-
54
- return ctx
55
- }
56
-
57
- /** Get the name list of disabled plugs */
58
- function getDisabledPlugNames(conf: ArtalkConfig) {
59
- return [
60
- {k: 'upload', v: conf.imgUpload},
61
- {k: 'emoticons', v: conf.emoticons},
62
- {k: 'preview', v: conf.preview}
63
- ].filter(n => !n.v).flatMap(n => n.k)
64
- }
65
-
66
- /** Initialization of a plug item */
67
- function initPlugItem(ctx: PlugManager, Plug: typeof ENABLED_PLUGS[number]) {
68
- const plugName = Plug.Name
69
-
70
- // create the plug instance
71
- const plug = new Plug(ctx.editor)
72
- ctx.plugList[plugName] = plug
73
-
74
- // gen plug ui
75
- genPlugBtn(ctx, plugName, plug)
76
- }
77
-
78
- /** Gen the plug btn (and plug panel) on editor ui */
79
- function genPlugBtn(ctx: PlugManager, plugName: string, plug: EditorPlug) {
80
- const $btn = plug.getBtn()
81
- if (!$btn) return
82
- ctx.editor.getUI().$plugBtnWrap.appendChild($btn)
83
- $btn.onclick = $btn.onclick || (() => {
84
- // the event when click plug btn
85
-
86
- // removing the active class from all the buttons
87
- ctx.editor.getUI().$plugBtnWrap
88
- .querySelectorAll('.active')
89
- .forEach(item => item.classList.remove('active'))
90
-
91
-
92
- // if the plugName is the same as the openedPlugName, then close the plugPanel
93
- if (plugName === ctx.openedPlugName) {
94
- closePlugPanel(ctx)
95
- return
96
- }
97
-
98
- // open the plug current clicked plug panel
99
- openPlugPanel(ctx, plugName)
100
-
101
- // add active class for current plug panel
102
- $btn.classList.add('active')
103
- })
104
-
105
- // initialization of plug panel
106
- const $panel = plug.getPanel()
107
- if ($panel) {
108
- $panel.setAttribute('data-plug-name', plugName)
109
- $panel.style.display = 'none'
110
- ctx.editor.getUI().$plugPanelWrap.appendChild($panel)
111
- }
112
- }
113
-
114
- /** Open the editor plug panel */
115
- function openPlugPanel(ctx: PlugManager, plugName: string) {
116
- Object.entries(ctx.plugList).forEach(([aPlugName, plug]) => {
117
- const plugPanel = plug.getPanel()
118
- if (!plugPanel) return
119
-
120
- if (aPlugName === plugName) {
121
- plugPanel.style.display = ''
122
- if (plug.onPanelShow) plug.onPanelShow()
123
- } else {
124
- plugPanel.style.display = 'none'
125
- if (plug.onPanelHide) plug.onPanelHide()
126
- }
127
- })
128
-
129
- ctx.editor.getUI().$plugPanelWrap.style.display = ''
130
- ctx.openedPlugName = plugName
131
- }
132
-
133
- /** Close the editor plug panel */
134
- function closePlugPanel(ctx: PlugManager) {
135
- if (!ctx.openedPlugName) return
136
-
137
- const plug = ctx.plugList[ctx.openedPlugName]
138
- if (!plug) return
139
-
140
- if (plug.onPanelHide) plug.onPanelHide()
141
-
142
- ctx.editor.getUI().$plugPanelWrap.style.display = 'none'
143
- ctx.openedPlugName = null
144
- }
145
-
146
- // ============== Events ====================
147
-
148
- /** Trigger event when editor header input changed */
149
- function triggerHeaderInputEvt(ctx: PlugManager, field: string, $input: HTMLInputElement) {
150
- Object.entries(ctx.plugList).forEach(([plugName, plug]) => {
151
- if (!plug.onHeaderInput) return
152
- plug.onHeaderInput(field, $input)
153
- })
154
- }
155
-
156
- /** Trigger event when editor content updated */
157
- function triggerContentUpdatedEvt(ctx: PlugManager, content: string) {
158
- Object.entries(ctx.plugList).forEach(([plugName, plug]) => {
159
- if (!plug.onContentUpdated) return
160
- plug.onContentUpdated(content)
161
- })
162
- }
163
-
164
- /** Get the content which is transformed by plugs */
165
- function getTransformedContent(ctx: PlugManager, rawContent: string) {
166
- let result = rawContent
167
- Object.entries(ctx.plugList).forEach(([plugName, plug]) => {
168
- if (!plug.contentTransformer) return
169
- result = plug.contentTransformer(result)
170
- })
171
- return result
172
- }
@@ -1,69 +0,0 @@
1
- import * as Utils from '@/lib/utils'
2
- import Editor from '../editor'
3
-
4
- /**
5
- * Editor 插件
6
- *
7
- * @desc 使用 Interface x Abstract 合并声明
8
- * @see https://www.typescriptlang.org/docs/handbook/declaration-merging.html#merging-interfaces
9
- */
10
- interface EditorPlug {
11
- onPanelShow?(): void
12
- onPanelHide?(): void
13
- }
14
-
15
- abstract class EditorPlug {
16
- protected editor: Editor
17
- protected get ctx() { return this.editor.ctx }
18
- protected $panel?: HTMLElement
19
- protected $btn?: HTMLElement
20
- public onHeaderInput?: (key: string, $input: HTMLElement) => void
21
- public contentTransformer?: (rawContent: string) => string
22
- public onContentUpdated?: (content: string) => void
23
-
24
- public constructor(editor: Editor) {
25
- this.editor = editor
26
- }
27
-
28
- /** Name of plug */
29
- public static Name: string
30
-
31
- /** Register plug panel will provide a plug el */
32
- protected registerPanel(html: string = '<div></div>') {
33
- this.$panel = Utils.createElement(html)
34
- return this.$panel
35
- }
36
-
37
- /** Register plug btn will add a btn on the bottom of editor */
38
- protected registerBtn(html: string) {
39
- this.$btn = Utils.createElement(`<span class="atk-plug-btn" data-plug-name="${this.constructor.name}">${html}</span>`)
40
- return this.$btn
41
- }
42
-
43
- /** Register the event of header input is changed */
44
- protected registerHeaderInputEvt(func: (key: string, $input: HTMLElement) => void) {
45
- this.onHeaderInput = func
46
- }
47
-
48
- /** Register the content transformer to handle the content of the last submit by the editor */
49
- protected registerContentTransformer(func: (raw: string) => string) {
50
- this.contentTransformer = func
51
- }
52
-
53
- /** Register the event of editor content is updated */
54
- protected registerContentUpdatedEvt(func: (content: string) => void) {
55
- this.onContentUpdated = func
56
- }
57
-
58
- /** Get panel element of plug */
59
- public getPanel() {
60
- return this.$panel
61
- }
62
-
63
- /** Get btn element of plug */
64
- public getBtn() {
65
- return this.$btn
66
- }
67
- }
68
-
69
- export default EditorPlug
@@ -1,79 +0,0 @@
1
- import Editor from '../editor'
2
- import User from '../../lib/user'
3
- import EditorPlug from './editor-plug'
4
-
5
- export default class HeaderInputPlug extends EditorPlug {
6
- public static Name = 'headerInput'
7
-
8
- public constructor(editor: Editor) {
9
- super(editor)
10
-
11
- this.registerHeaderInputEvt((key, $input) => {
12
- if (key === 'nick' || key === 'email') {
13
- this.fetchUserInfo()
14
- }
15
- })
16
-
17
- // Link URL 自动补全协议
18
- this.editor.getUI().$link.addEventListener('change', () => {
19
- const link = this.editor.getUI().$link.value.trim()
20
- if (!!link && !/^(http|https):\/\//.test(link)) {
21
- this.editor.getUI().$link.value = `https://${link}`
22
- User.update({ link: this.editor.getUI().$link.value })
23
- }
24
- })
25
- }
26
-
27
- queryUserInfo = {
28
- timeout: <number|null>null,
29
- abortFunc: <(() => void)|null>null
30
- }
31
-
32
- /** 远程获取用户数据 */
33
- fetchUserInfo() {
34
- User.logout()
35
-
36
- // 获取用户信息
37
- if (this.queryUserInfo.timeout) window.clearTimeout(this.queryUserInfo.timeout) // 清除待发出的请求
38
- if (this.queryUserInfo.abortFunc) this.queryUserInfo.abortFunc() // 之前发出未完成的请求立刻中止
39
-
40
- this.queryUserInfo.timeout = window.setTimeout(() => {
41
- this.queryUserInfo.timeout = null // 清理
42
-
43
- const {req, abort} = this.ctx.getApi().user.userGet(
44
- User.data.nick, User.data.email
45
- )
46
- this.queryUserInfo.abortFunc = abort
47
- req.then(data => {
48
- if (!data.is_login) {
49
- User.logout()
50
- }
51
-
52
- // 未读消息更新
53
- this.ctx.updateNotifies(data.unread)
54
-
55
- // 若用户为管理员,执行登陆操作
56
- if (User.checkHasBasicUserInfo() && !data.is_login && data.user?.is_admin) {
57
- this.showLoginDialog()
58
- }
59
-
60
- // 自动填入 link
61
- if (data.user && data.user.link) {
62
- this.editor.getUI().$link.value = data.user.link
63
- User.update({ link: data.user.link })
64
- }
65
- })
66
- .catch(() => {})
67
- .finally(() => {
68
- this.queryUserInfo.abortFunc = null // 清理
69
- })
70
- }, 400) // 延迟执行,减少请求次数
71
- }
72
-
73
- showLoginDialog() {
74
- this.ctx.checkAdmin({
75
- onSuccess: () => {
76
- }
77
- })
78
- }
79
- }
@@ -1,44 +0,0 @@
1
- import './preview-plug.scss'
2
-
3
- import Editor from '../editor'
4
- import EditorPlug from './editor-plug'
5
-
6
- export default class PreviewPlug extends EditorPlug {
7
- public static Name = 'preview'
8
- declare protected $panel: HTMLElement
9
-
10
- private isBind = false
11
-
12
- public constructor(editor: Editor) {
13
- super(editor)
14
-
15
- this.registerPanel(`<div class="atk-editor-plug-preview"></div>`)
16
-
17
- let btnText = this.editor.$t('preview')
18
- if (this.ctx.getMarkedInstance()) btnText += ` <i title="Markdown is supported"><svg class="markdown" viewBox="0 0 16 16" version="1.1" width="16" height="16" aria-hidden="true"><path fill-rule="evenodd" d="M14.85 3H1.15C.52 3 0 3.52 0 4.15v7.69C0 12.48.52 13 1.15 13h13.69c.64 0 1.15-.52 1.15-1.15v-7.7C16 3.52 15.48 3 14.85 3zM9 11H7V8L5.5 9.92 4 8v3H2V5h2l1.5 2L7 5h2v6zm2.99.5L9.5 8H11V5h2v3h1.5l-2.51 3.5z"></path></svg></i>`
19
- this.registerBtn(btnText)
20
-
21
- this.registerContentUpdatedEvt((content) => {
22
- this.updateContent()
23
- })
24
- }
25
-
26
- public onPanelShow() {
27
- this.updateContent()
28
-
29
- if (!this.isBind) {
30
- const event = () => {
31
- this.updateContent()
32
- }
33
- this.editor.getUI().$textarea.addEventListener('input', event)
34
- this.editor.getUI().$textarea.addEventListener('change', event)
35
- this.isBind = true
36
- }
37
- }
38
-
39
- public updateContent() {
40
- if (this.$panel.style.display !== 'none') {
41
- this.$panel.innerHTML = this.editor.getContentMarked()
42
- }
43
- }
44
- }
@@ -1,122 +0,0 @@
1
- import * as Utils from '@/lib/utils'
2
- import Editor from '../editor'
3
- import User from '../../lib/user'
4
- import EditorPlug from './editor-plug'
5
-
6
- export default class UploadPlug extends EditorPlug {
7
- public static Name = 'upload'
8
-
9
- public $imgUploadInput?: HTMLInputElement
10
-
11
- /** 允许的图片格式 */
12
- allowImgExts = ['png', 'jpg', 'jpeg', 'gif', 'bmp', 'svg', 'webp']
13
-
14
- public constructor(editor: Editor) {
15
- super(editor)
16
-
17
- this.$imgUploadInput = document.createElement('input')
18
- this.$imgUploadInput.type = 'file'
19
- this.$imgUploadInput.style.display = 'none'
20
- this.$imgUploadInput.accept = this.allowImgExts.map(o => `.${o}`).join(',')
21
-
22
- const $btn = this.registerBtn(`${this.ctx.$t('image')}`)
23
- $btn.after(this.$imgUploadInput)
24
- $btn.onclick = () => {
25
- // 选择图片
26
- const $input = this.$imgUploadInput!
27
- $input.onchange = () => {
28
- (async () => { // 解决阻塞 UI 问题
29
- if (!$input.files || $input.files.length === 0) return
30
- const file = $input.files[0]
31
- this.uploadImg(file)
32
- })()
33
- }
34
- $input.click() // 显示选择图片对话框
35
- }
36
-
37
- if (!this.ctx.conf.imgUpload) {
38
- this.getBtn()!.setAttribute('atk-only-admin-show', '')
39
- }
40
-
41
- // 统一从 FileList 获取文件并上传图片方法
42
- const uploadFromFileList = (files?: FileList) => {
43
- if (!files) return
44
-
45
- for (let i = 0; i < files.length; i++) {
46
- const file = files[i]
47
- this.uploadImg(file)
48
- }
49
- }
50
-
51
- // 拖拽图片
52
- // @link https://developer.mozilla.org/zh-CN/docs/Web/API/HTML_Drag_and_Drop_API/File_drag_and_drop
53
- // 阻止浏览器的默认释放行为
54
- this.editor.getUI().$textarea.addEventListener('dragover', (evt) => {
55
- evt.stopPropagation()
56
- evt.preventDefault()
57
- })
58
-
59
- this.editor.getUI().$textarea.addEventListener('drop', (evt) => {
60
- const files = evt.dataTransfer?.files
61
- if (files?.length) {
62
- evt.preventDefault()
63
- uploadFromFileList(files)
64
- }
65
- })
66
-
67
- // 粘贴图片
68
- this.editor.getUI().$textarea.addEventListener('paste', (evt) => {
69
- const files = evt.clipboardData?.files
70
- if (files?.length) {
71
- evt.preventDefault()
72
- uploadFromFileList(files)
73
- }
74
- })
75
- }
76
-
77
- public async uploadImg(file: File) {
78
- const fileExt = /[^.]+$/.exec(file.name)
79
- if (!fileExt || !this.allowImgExts.includes(fileExt[0])) return
80
-
81
- // 未登录提示
82
- if (!User.checkHasBasicUserInfo()) {
83
- this.editor.showNotify(this.ctx.$t('uploadLoginMsg'), 'w')
84
- return
85
- }
86
-
87
- // 插入图片前换一行
88
- let insertPrefix = '\n'
89
- if (this.editor.getUI().$textarea.value.trim() === '') insertPrefix = ''
90
-
91
- // 插入占位加载文字
92
- const uploadPlaceholderTxt = `${insertPrefix}![](Uploading ${file.name}...)`
93
- this.editor.insertContent(uploadPlaceholderTxt)
94
-
95
- // 上传图片
96
- let resp: any
97
- try {
98
- if (!this.ctx.conf.imgUploader) {
99
- // 使用 Artalk 进行图片上传
100
- resp = await this.ctx.getApi().upload.imgUpload(file)
101
- } else {
102
- // 使用自定义的图片上传器
103
- resp = {img_url: await this.ctx.conf.imgUploader(file)}
104
- }
105
- } catch (err: any) {
106
- console.error(err)
107
- this.editor.showNotify(`${this.ctx.$t('uploadFail')},${err.msg}`, 'e')
108
- }
109
- if (!!resp && resp.img_url) {
110
- let imgURL = resp.img_url as string
111
-
112
- // 若为相对路径,加上 artalk server
113
- if (!Utils.isValidURL(imgURL)) imgURL = Utils.getURLBasedOnApi(this.ctx, imgURL)
114
-
115
- // 上传成功插入图片
116
- this.editor.setContent(this.editor.getUI().$textarea.value.replace(uploadPlaceholderTxt, `${insertPrefix}![](${imgURL})`))
117
- } else {
118
- // 上传失败删除加载文字
119
- this.editor.setContent(this.editor.getUI().$textarea.value.replace(uploadPlaceholderTxt, ''))
120
- }
121
- }
122
- }
@@ -1,62 +0,0 @@
1
- import type { CommentData } from '~/types/artalk-data'
2
- import Editor from './editor'
3
- import * as Utils from '../lib/utils'
4
- import * as Ui from '../lib/ui'
5
-
6
- export interface ReplyManager {
7
- editor: Editor
8
- comment?: CommentData
9
- setReply(comment: CommentData, $comment: HTMLElement, scroll?: boolean): void
10
- cancelReply(): void
11
- }
12
-
13
- export function createReplyManager(editor: Editor): ReplyManager {
14
- const m: ReplyManager = {
15
- editor,
16
- comment: undefined,
17
- setReply: (c, $, s) => setReply(m, c, $, s),
18
- cancelReply: () => cancelReply(m)
19
- }
20
-
21
- return m
22
- }
23
-
24
- function setReply(m: ReplyManager, commentData: CommentData, $comment: HTMLElement, scroll = true) {
25
- m.editor.cancelEditComment()
26
- cancelReply(m)
27
-
28
- const ui = m.editor.getUI()
29
- if (!ui.$sendReply) {
30
- ui.$sendReply = Utils.createElement(
31
- `<div class="atk-send-reply">` +
32
- `${m.editor.$t('reply')} ` +
33
- `<span class="atk-text"></span><span class="atk-cancel">×</span>` +
34
- `</div>`
35
- )
36
- ui.$sendReply.querySelector<HTMLElement>('.atk-text')!.innerText = `@${commentData.nick}`
37
- ui.$sendReply.addEventListener('click', () => {
38
- m.editor.cancelReply()
39
- })
40
- ui.$textareaWrap.append(ui.$sendReply)
41
- }
42
-
43
- m.comment = commentData
44
- m.editor.travel($comment)
45
-
46
- if (scroll) Ui.scrollIntoView(ui.$el)
47
-
48
- ui.$textarea.focus()
49
- }
50
-
51
- function cancelReply(m: ReplyManager) {
52
- if (!m.comment) return
53
-
54
- const ui = m.editor.getUI()
55
- if (ui.$sendReply) {
56
- ui.$sendReply.remove()
57
- ui.$sendReply = undefined
58
- }
59
- m.comment = undefined
60
-
61
- m.editor.travelBack()
62
- }
@@ -1,99 +0,0 @@
1
- import type { CommentData } from '~/types/artalk-data'
2
- import Editor from './editor'
3
- import User from '../lib/user'
4
-
5
- export interface SubmitManager {
6
- editor: Editor
7
- do: () => Promise<void>
8
- customs: CustomSubmit[]
9
- registerCustom(c: CustomSubmit): void
10
- }
11
-
12
- export function createSubmitManager(editor: Editor) {
13
- const m: SubmitManager = {
14
- editor,
15
- do: () => Do(m),
16
- customs: [],
17
- registerCustom: (c) => { m.customs.push(c) }
18
- }
19
-
20
- return m
21
- }
22
-
23
- async function Do(m: SubmitManager) {
24
- if (m.editor.getFinalContent().trim() === '') {
25
- m.editor.focus()
26
- return
27
- }
28
-
29
- const custom = m.customs.find(o => o.activeCond())
30
-
31
- m.editor.ctx.trigger('editor-submit')
32
- m.editor.showLoading()
33
-
34
- try {
35
- // pre submit
36
- if (custom?.pre) custom.pre()
37
-
38
- let nComment: CommentData
39
-
40
- // submit request
41
- if (custom?.req) nComment = await custom.req()
42
- else nComment = await reqAdd(m)
43
-
44
- // post submit
45
- if (custom?.post) custom.post(nComment)
46
- else postSubmitAdd(m, nComment)
47
- } catch (err: any) {
48
- // submit error
49
- console.error(err)
50
- m.editor.showNotify(`${m.editor.$t('commentFail')},${err.msg || String(err)}`, 'e')
51
- return
52
- } finally {
53
- m.editor.hideLoading()
54
- }
55
-
56
- m.editor.reset() // 复原编辑器
57
- m.editor.ctx.trigger('editor-submitted')
58
- }
59
-
60
- interface CustomSubmit {
61
- activeCond: () => void
62
- pre?: () => void
63
- req?: () => Promise<CommentData>
64
- post?: (nComment: CommentData) => void
65
- }
66
-
67
- // ================== Submit Add =======================
68
- function getSubmitAddParams(m: SubmitManager) {
69
- const { nick, email, link } = User.data
70
- const conf = m.editor.ctx.conf
71
- const reply = m.editor.getReplyManager()?.comment
72
-
73
- return {
74
- content: m.editor.getFinalContent(),
75
- nick, email, link,
76
- rid: (!reply) ? 0 : reply.id,
77
- page_key: (!reply) ? conf.pageKey : reply.page_key,
78
- page_title: (!reply) ? conf.pageTitle : undefined,
79
- site_name: (!reply) ? conf.site : reply.site_name
80
- }
81
- }
82
-
83
- async function reqAdd(m: SubmitManager) {
84
- const nComment = await m.editor.ctx.getApi().comment.add({
85
- ...getSubmitAddParams(m)
86
- })
87
- return nComment
88
- }
89
-
90
- function postSubmitAdd(m: SubmitManager, commentNew: CommentData) {
91
- // 回复不同页面的评论,跳转到新页面
92
- const reply = m.editor.getReplyManager()
93
- const conf = m.editor.ctx.conf
94
- if (!!reply?.comment && reply.comment.page_key !== conf.pageKey) {
95
- window.open(`${reply.comment.page_url}#atk-comment-${commentNew.id}`)
96
- }
97
-
98
- m.editor.ctx.insertComment(commentNew)
99
- }
@@ -1,48 +0,0 @@
1
- import type Context from '~/types/context'
2
- import { getLayerWrap } from '../layer'
3
-
4
- const darkModeMedia = window.matchMedia('(prefers-color-scheme: dark)')
5
- let darkModeAutoFunc: (evt: MediaQueryListEvent) => void
6
-
7
- export function syncDarkModeConf(ctx: Context) {
8
- setDarkMode(ctx, ctx.conf.darkMode, false) // ref `conf.darkMode` data, so no need to `alterConf`
9
- }
10
-
11
- export function setDarkMode(ctx: Context, darkMode: boolean|'auto', alterConf = true) {
12
- const apply = (d: boolean) => {
13
- updateClassName(ctx, d)
14
- if (alterConf) alterCtxConf(ctx, d)
15
- }
16
-
17
- if (darkMode === 'auto') {
18
- if (!darkModeAutoFunc) { // 自动切换夜间模式,事件监听
19
- darkModeAutoFunc = (evt) => apply(evt.matches)
20
- darkModeMedia.addEventListener('change', darkModeAutoFunc)
21
- }
22
-
23
- apply(darkModeMedia.matches)
24
- } else {
25
- // if the type of darkMode is boolean
26
- if (darkModeAutoFunc) // 解除事件监听绑定
27
- darkModeMedia.removeEventListener('change', darkModeAutoFunc)
28
-
29
- apply(darkMode)
30
- }
31
- }
32
-
33
- function alterCtxConf(ctx: Context, darkMode: boolean) {
34
- ctx.conf.darkMode = darkMode
35
- }
36
-
37
- const DarkModeClassName = 'atk-dark-mode'
38
- export function updateClassName(ctx: Context, darkMode: boolean) {
39
- if (darkMode) ctx.$root.classList.add(DarkModeClassName)
40
- else ctx.$root.classList.remove(DarkModeClassName)
41
-
42
- // for Layer
43
- const { $wrap: $layerWrap } = getLayerWrap()
44
- if ($layerWrap) {
45
- if (darkMode) $layerWrap.classList.add(DarkModeClassName)
46
- else $layerWrap.classList.remove(DarkModeClassName)
47
- }
48
- }