artalk 2.6.4 → 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 +7794 -7483
  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 +5587 -5276
  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 -61
  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 +39 -152
  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 +1 -1
  242. package/types/{artalk-config.d.ts → config.ts} +16 -2
  243. package/types/context.ts +84 -0
  244. package/types/{artalk-data.d.ts → 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/artalk-data.d.ts +0 -230
  273. package/dist/types/plug.d.ts +0 -4
  274. package/src/api/api-base.ts +0 -27
  275. package/src/comment/render-ctx.ts +0 -30
  276. package/src/editor/edit-mode.ts +0 -105
  277. package/src/editor/funcs.ts +0 -150
  278. package/src/editor/index.ts +0 -3
  279. package/src/editor/mover.ts +0 -43
  280. package/src/editor/plug-manager.ts +0 -172
  281. package/src/editor/plugs/editor-plug.ts +0 -69
  282. package/src/editor/plugs/header-input-plug.ts +0 -79
  283. package/src/editor/plugs/preview-plug.ts +0 -44
  284. package/src/editor/plugs/upload-plug.ts +0 -122
  285. package/src/editor/reply.ts +0 -62
  286. package/src/editor/submit.ts +0 -99
  287. package/src/lib/dark-mode.ts +0 -48
  288. package/src/lib/stat.ts +0 -71
  289. package/src/list/index.ts +0 -3
  290. package/src/list/list-lite.ts +0 -424
  291. package/src/list/list-ui.ts +0 -137
  292. package/src/list/paginator/adaptors/index.ts +0 -21
  293. package/src/list/paginator/adaptors/pagination.ts +0 -42
  294. package/src/list/paginator/adaptors/read-more.ts +0 -56
  295. package/src/list/paginator/holder.ts +0 -56
  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
package/src/data.ts ADDED
@@ -0,0 +1,110 @@
1
+ import type { NotifyData, PageData, CommentData, DataManagerApi, ListFetchParams, ListLastFetchData, EventPayloadMap } from '~/types'
2
+ import EventManager from './lib/event-manager'
3
+
4
+ export class DataManager implements DataManagerApi {
5
+ private loading: boolean = false
6
+ private listLastFetch?: ListLastFetchData
7
+ private comments: CommentData[] = [] // Note: 无层级结构 + 无须排列
8
+ private unreads: NotifyData[] = []
9
+ private page?: PageData
10
+
11
+ constructor(
12
+ protected events: EventManager<EventPayloadMap>
13
+ ) {}
14
+
15
+ getLoading() {
16
+ return this.loading
17
+ }
18
+
19
+ setLoading(val: boolean) {
20
+ this.loading = val
21
+ }
22
+
23
+ getListLastFetch() {
24
+ return this.listLastFetch
25
+ }
26
+
27
+ setListLastFetch(val: ListLastFetchData) {
28
+ this.listLastFetch = val
29
+ }
30
+
31
+ // -------------------------------------------------------------------
32
+ // Comments
33
+ // -------------------------------------------------------------------
34
+ getComments() {
35
+ return this.comments
36
+ }
37
+
38
+ fetchComments(params: Partial<ListFetchParams>) {
39
+ this.events.trigger('list-fetch', params)
40
+ }
41
+
42
+ findComment(id: number) {
43
+ return this.comments.find(c => c.id === id)
44
+ }
45
+
46
+ clearComments() {
47
+ this.comments = []
48
+ this.events.trigger('list-loaded', this.comments)
49
+ }
50
+
51
+ loadComments(partialComments: CommentData[]) {
52
+ this.events.trigger('list-load', partialComments)
53
+
54
+ this.comments.push(...partialComments)
55
+
56
+ this.events.trigger('list-loaded', this.comments)
57
+ }
58
+
59
+ insertComment(comment: CommentData) {
60
+ this.comments.push(comment)
61
+
62
+ this.events.trigger('comment-inserted', comment)
63
+ this.events.trigger('list-loaded', this.comments) // list-loaded should always keep the last
64
+ }
65
+
66
+ updateComment(comment: CommentData) {
67
+ this.comments = this.comments.map(c => {
68
+ if (c.id === comment.id) return comment
69
+ return c
70
+ })
71
+
72
+ this.events.trigger('comment-updated', comment)
73
+ this.events.trigger('list-loaded', this.comments)
74
+ }
75
+
76
+ deleteComment(id: number) {
77
+ const comment = this.comments.find(c => c.id === id)
78
+ if (!comment) throw new Error(`Comment ${id} not found`)
79
+ this.comments = this.comments.filter(c => c.id !== id)
80
+
81
+ this.events.trigger('comment-deleted', comment)
82
+ this.events.trigger('list-loaded', this.comments)
83
+ }
84
+
85
+ // -------------------------------------------------------------------
86
+ // Unreads
87
+ // -------------------------------------------------------------------
88
+ getUnreads() {
89
+ return this.unreads
90
+ }
91
+
92
+ updateUnreads(unread: NotifyData[]) {
93
+ this.unreads = unread
94
+
95
+ this.events.trigger('unreads-updated', this.unreads)
96
+ }
97
+
98
+ // -------------------------------------------------------------------
99
+ // Page
100
+ // -------------------------------------------------------------------
101
+ getPage() {
102
+ return this.page
103
+ }
104
+
105
+ updatePage(pageData: PageData) {
106
+ this.page = pageData
107
+
108
+ this.events.trigger('page-loaded', pageData)
109
+ }
110
+ }
package/src/defaults.ts CHANGED
@@ -1,4 +1,4 @@
1
- import ArtalkConfig from "~/types/artalk-config"
1
+ import type { ArtalkConfig } from '~/types'
2
2
 
3
3
  const defaults: ArtalkConfig = {
4
4
  el: '',
@@ -1,114 +1,59 @@
1
- import type { CommentData } from '~/types/artalk-data'
2
- import type Context from '~/types/context'
1
+ import type { CommentData, ContextApi, EditorApi } from '~/types'
3
2
  import Component from '../lib/component'
4
- import * as Utils from '../lib/utils'
5
3
  import * as Ui from '../lib/ui'
6
4
  import marked from '../lib/marked'
7
- import User from '../lib/user'
8
- import initEditorFuncs from './funcs'
9
5
  import { render, EditorUI } from './ui'
10
- import { PlugManager } from './plug-manager'
11
- import { Mover } from './mover'
12
- import { ReplyManager } from './reply'
13
- import { EditModeManager } from './edit-mode'
14
- import { SubmitManager } from './submit'
15
-
16
- export default class Editor extends Component {
17
- /** 界面 */
18
- private ui: EditorUI
19
- public getUI() { return this.ui }
20
-
21
- /** 插件管理器 */
22
- private plugs?: PlugManager
23
- public getPlugs() { return this.plugs }
24
- public setPlugs(p: PlugManager) { this.plugs = p }
25
-
26
- /** 评论框移动 */
27
- private mover?: Mover
28
- public setMover(m: Mover) { this.mover = m }
29
-
30
- /** 回复评论 */
31
- private reply?: ReplyManager
32
- public setReplyManager(m: ReplyManager) { this.reply = m }
33
- public getReplyManager() { return this.reply }
34
- public get isReplyMode() { return !!this.reply?.comment }
6
+ import EditorStateManager from './state'
35
7
 
36
- /** 编辑评论 */
37
- private editMode?: EditModeManager
38
- public setEditModeManager(m: EditModeManager) { this.editMode = m }
39
- public get isEditMode() { return !!this.editMode?.comment }
40
-
41
- /** 提交评论 */
42
- private submitManager?: SubmitManager
43
- public setSubmitManager(m: SubmitManager) { this.submitManager = m }
44
- public getSubmitManager() { return this.submitManager }
8
+ class Editor extends Component implements EditorApi {
9
+ private ui: EditorUI
10
+ private state: EditorStateManager
45
11
 
46
- /** 已加载功能的 unmount 函数 */
47
- private unmountFuncs: (() => void)[] = []
12
+ getUI() { return this.ui }
13
+ getPlugs() { return this.ctx.get('editorPlugs') }
14
+ getState() { return this.state.get() }
48
15
 
49
- public constructor(ctx: Context) {
16
+ constructor(ctx: ContextApi) {
50
17
  super(ctx)
51
18
 
52
19
  // init editor ui
53
20
  this.ui = render()
54
21
  this.$el = this.ui.$el
55
22
 
56
- // event listen
57
- this.ctx.on('conf-loaded', () => {
58
- // call unmount funcs
59
- // (this will only be called while conf reloaded, not be called at first time)
60
- this.unmountFuncs?.forEach((unmount) => !!unmount && unmount())
61
-
62
- // call init will return unmount funcs and save it
63
- this.unmountFuncs = initEditorFuncs(this) // init editor funcs
64
- })
23
+ // init state manager
24
+ this.state = new EditorStateManager(this)
65
25
  }
66
26
 
67
- public getHeaderInputEls() {
27
+ getHeaderInputEls() {
68
28
  return { nick: this.ui.$nick, email: this.ui.$email, link: this.ui.$link }
69
29
  }
70
30
 
71
- public saveToLocalStorage() {
72
- window.localStorage.setItem('ArtalkContent', this.getContentOriginal().trim())
73
- }
74
-
75
- public refreshSendBtnText() {
76
- if (this.isEditMode) this.ui.$submitBtn.innerText = this.$t('save')
77
- else this.ui.$submitBtn.innerText = this.ctx.conf.sendBtn || this.$t('send')
78
- }
79
-
80
- /** 最终用于 submit 的数据 */
81
- public getFinalContent() {
82
- let content = this.getContentOriginal()
31
+ getContentFinal() {
32
+ let content = this.getContentRaw()
83
33
 
84
34
  // plug hook: final content transformer
85
- if (this.plugs) content = this.plugs.getTransformedContent(content)
35
+ const plugs = this.getPlugs()
36
+ if (plugs) content = plugs.getTransformedContent(content)
86
37
 
87
38
  return content
88
39
  }
89
40
 
90
- public getContentOriginal() {
91
- return this.ui.$textarea.value || '' // Tip: !!"0" === true
41
+ getContentRaw() {
42
+ return this.ui.$textarea.value || ''
92
43
  }
93
44
 
94
- public getContentMarked() {
95
- return marked(this.ctx, this.getFinalContent())
45
+ getContentMarked() {
46
+ return marked(this.getContentFinal())
96
47
  }
97
48
 
98
- public setContent(val: string) {
49
+ setContent(val: string) {
99
50
  this.ui.$textarea.value = val
100
- this.saveToLocalStorage()
101
51
 
102
52
  // plug hook: content updated
103
- if (this.plugs) this.plugs.triggerContentUpdatedEvt(val)
104
-
105
- // 延迟执行防止无效
106
- window.setTimeout(() => {
107
- this.adjustTextareaHeight()
108
- }, 80)
53
+ this.getPlugs()?.getEvents().trigger('content-updated', val)
109
54
  }
110
55
 
111
- public insertContent(val: string) {
56
+ insertContent(val: string) {
112
57
  if ((document as any).selection) {
113
58
  this.ui.$textarea.focus();
114
59
  (document as any).selection.createRange().text = val
@@ -128,100 +73,42 @@ export default class Editor extends Component {
128
73
  }
129
74
  }
130
75
 
131
- public adjustTextareaHeight() {
132
- const diff = this.ui.$textarea.offsetHeight - this.ui.$textarea.clientHeight
133
- this.ui.$textarea.style.height = '0px' // it's a magic. 若不加此行,内容减少,高度回不去
134
- this.ui.$textarea.style.height = `${this.ui.$textarea.scrollHeight + diff}px`
135
- }
136
-
137
- public focus() {
76
+ focus() {
138
77
  this.ui.$textarea.focus()
139
78
  }
140
79
 
141
- public reset() {
80
+ reset() {
142
81
  this.setContent('')
143
- this.cancelReply()
144
- this.cancelEditComment()
145
- }
146
-
147
- /** 设置回复评论 */
148
- public setReply(commentData: CommentData, $comment: HTMLElement, scroll = true) {
149
- this.reply?.setReply(commentData, $comment, scroll)
82
+ this.resetState()
150
83
  }
151
84
 
152
- /** 取消回复评论 */
153
- public cancelReply() {
154
- this.reply?.cancelReply()
85
+ resetState() {
86
+ this.state.switch('normal')
155
87
  }
156
88
 
157
- /** 设置编辑评论 */
158
- public setEditComment(commentData: CommentData, $comment: HTMLElement) {
159
- this.editMode?.setEdit(commentData, $comment)
89
+ setReply(comment: CommentData, $comment: HTMLElement) {
90
+ this.state.switch('reply', { comment, $comment })
160
91
  }
161
92
 
162
- /** 取消编辑评论 */
163
- public cancelEditComment() {
164
- this.editMode?.cancelEdit()
93
+ setEditComment(comment: CommentData, $comment: HTMLElement) {
94
+ this.state.switch('edit', { comment, $comment })
165
95
  }
166
96
 
167
- public showNotify(msg: string, type: "i"|"s"|"w"|"e") {
97
+ showNotify(msg: string, type: any) {
168
98
  Ui.showNotify(this.ui.$notifyWrap, msg, type)
169
99
  }
170
100
 
171
- public showLoading() {
101
+ showLoading() {
172
102
  Ui.showLoading(this.ui.$el)
173
103
  }
174
104
 
175
- public hideLoading() {
105
+ hideLoading() {
176
106
  Ui.hideLoading(this.ui.$el)
177
107
  }
178
108
 
179
- /** 点击评论提交按钮事件 */
180
- public async submit() {
181
- if (!this.submitManager) throw Error('submitManger not initialized')
182
- await this.submitManager.do()
183
- }
184
-
185
- /** 关闭评论 */
186
- public close() {
187
- if (!this.ui.$textareaWrap.querySelector('.atk-comment-closed'))
188
- this.ui.$textareaWrap.prepend(Utils.createElement(`<div class="atk-comment-closed">${this.$t('onlyAdminCanReply')}</div>`))
189
-
190
- if (!User.data.isAdmin) {
191
- this.ui.$textarea.style.display = 'none'
192
- this.closePlugPanel()
193
- this.ui.$bottom.style.display = 'none'
194
- } else {
195
- // 管理员一直打开评论
196
- this.ui.$textarea.style.display = ''
197
- this.ui.$bottom.style.display = ''
198
- }
199
- }
200
-
201
- /** 打开评论 */
202
- public open() {
203
- this.ui.$textareaWrap.querySelector('.atk-comment-closed')?.remove()
204
- this.ui.$textarea.style.display = ''
205
- this.ui.$bottom.style.display = ''
206
- }
207
-
208
- /** 移动评论框到置顶元素之后 */
209
- public travel($afterEl: HTMLElement) {
210
- this.mover?.move($afterEl)
211
- }
212
-
213
- /** 评论框归位 */
214
- public travelBack() {
215
- this.mover?.back()
216
- }
217
-
218
- /** 展开插件面板 */
219
- public openPlugPanel(plugName: string) {
220
- this.plugs?.openPlugPanel(plugName)
221
- }
222
-
223
- /** 收起插件面板 */
224
- public closePlugPanel() {
225
- this.plugs?.closePlugPanel()
109
+ submit() {
110
+ this.ctx.trigger('editor-submit')
226
111
  }
227
112
  }
113
+
114
+ export default Editor
@@ -0,0 +1,52 @@
1
+ import type { EditorState, CommentData } from '~/types'
2
+ import * as Ui from '@/lib/ui'
3
+ import type Editor from './editor'
4
+ import Mover from '../plugins/editor/mover'
5
+
6
+ export default class EditorStateManager {
7
+ constructor(private editor: Editor) {}
8
+
9
+ private stateCurt: EditorState = 'normal'
10
+ private stateUnmountFn: (() => void)|null = null
11
+
12
+ /** Get current state */
13
+ get() {
14
+ return this.stateCurt
15
+ }
16
+
17
+ /**
18
+ * Switch editor state
19
+ *
20
+ * @param state The state to switch
21
+ * @param payload The cause of state switch
22
+ */
23
+ switch(state: EditorState, payload?: { $comment: HTMLElement, comment: CommentData }) {
24
+ // trigger unmount
25
+ if (this.stateUnmountFn) {
26
+ this.stateUnmountFn()
27
+ this.stateUnmountFn = null
28
+
29
+ // move editor back to the initial position
30
+ this.editor.getPlugs()?.get(Mover)?.back()
31
+ }
32
+
33
+ // invoke effect function and save unmount function
34
+ if (state !== 'normal' && payload) {
35
+ // move editor position
36
+ let moveAfterEl = payload.$comment
37
+ if (!this.editor.conf.flatMode) moveAfterEl = moveAfterEl.querySelector<HTMLElement>('.atk-footer')!
38
+ this.editor.getPlugs()?.get(Mover)?.move(moveAfterEl)
39
+
40
+ const $relative = this.editor.ctx.conf.scrollRelativeTo && this.editor.ctx.conf.scrollRelativeTo()
41
+ Ui.scrollIntoView(this.editor.getUI().$el, true, $relative)
42
+
43
+ const plugin = this.editor.getPlugs()?.getPlugs().find(p => p.editorStateEffectWhen === state)
44
+ if (plugin && plugin.editorStateEffect) {
45
+ this.stateUnmountFn = plugin.editorStateEffect(payload.comment)
46
+ }
47
+ }
48
+
49
+ // change current state
50
+ this.stateCurt = state
51
+ }
52
+ }
package/src/i18n/zh-CN.ts CHANGED
@@ -1,4 +1,4 @@
1
- import { I18n } from '.'
1
+ import type { I18n } from '.'
2
2
 
3
3
  const zhCN: I18n = {
4
4
  /* Editor */
@@ -1,4 +1,4 @@
1
- import Layer, { getLayerWrap } from './layer'
2
-
3
- export default Layer
4
- export { getLayerWrap }
1
+ export * from './layer'
2
+ export * from './wrap'
3
+ export * from './scrollbar-helper'
4
+ export * from './layer-manager'
@@ -0,0 +1,32 @@
1
+ import type { ContextApi } from '~/types'
2
+ import { getScrollbarHelper } from './scrollbar-helper'
3
+ import { LayerWrap } from './wrap'
4
+ import { Layer } from './layer'
5
+
6
+ export class LayerManager {
7
+ private wrap: LayerWrap
8
+ private ctx: ContextApi
9
+
10
+ constructor(ctx: ContextApi) {
11
+ this.ctx = ctx
12
+
13
+ this.wrap = new LayerWrap()
14
+ document.body.appendChild(this.wrap.getWrap())
15
+
16
+ ctx.on('destroy', () => {
17
+ this.wrap.getWrap().remove()
18
+ })
19
+
20
+ // 记录页面原始 CSS 属性
21
+ getScrollbarHelper().init()
22
+ }
23
+
24
+ getEl() {
25
+ return this.wrap.getWrap()
26
+ }
27
+
28
+ create(name: string, el?: HTMLElement | undefined) {
29
+ const layer = new Layer(this.wrap, name, el)
30
+ return layer
31
+ }
32
+ }
@@ -1,51 +1,17 @@
1
- import Context from '~/types/context'
2
- import Component from '../lib/component'
3
- import * as Utils from '../lib/utils'
4
- import * as Ui from '../lib/ui'
1
+ import type { LayerWrap } from './wrap'
5
2
 
6
- export default class Layer extends Component {
7
- private name: string
8
- private $wrap: HTMLElement
9
- private $mask: HTMLElement
3
+ export class Layer {
4
+ private $el: HTMLElement
5
+ private wrap: LayerWrap
6
+ private onAfterHide?: () => void
10
7
 
11
- private maskClickHideEnable: boolean = true
12
-
13
- public static BodyOrgOverflow: string
14
- public static BodyOrgPaddingRight: string
15
-
16
- public afterHide?: Function
17
-
18
- constructor (ctx: Context, name: string, el?: HTMLElement) {
19
- super(ctx)
20
-
21
- this.name = name
22
- const { $wrap, $mask } = getLayerWrap()
23
- this.$wrap = $wrap
24
- this.$mask = $mask
25
-
26
- this.$el = this.$wrap.querySelector(`[data-layer-name="${name}"].atk-layer-item`)!
27
- if (this.$el === null) {
28
- // 若传递 layer 元素为空
29
- if (!el) {
30
- this.$el = Utils.createElement()
31
- this.$el.classList.add('atk-layer-item')
32
- } else {
33
- this.$el = el
34
- }
35
- }
36
- this.$el.setAttribute('data-layer-name', name)
37
- this.$el.style.display = 'none'
38
-
39
- // 添加到 layers wrap 中
40
- this.$wrap.append(this.$el)
41
- }
42
-
43
- getName() {
44
- return this.name
8
+ constructor(wrap: LayerWrap, name: string, el?: HTMLElement) {
9
+ this.wrap = wrap
10
+ this.$el = this.wrap.createItem(name, el)
45
11
  }
46
12
 
47
- getWrapEl() {
48
- return this.$wrap
13
+ setOnAfterHide(func: () => void) {
14
+ this.onAfterHide = func
49
15
  }
50
16
 
51
17
  getEl() {
@@ -53,111 +19,21 @@ export default class Layer extends Component {
53
19
  }
54
20
 
55
21
  show() {
56
- this.fireAllActionTimer()
57
-
58
- this.$wrap.style.display = 'block'
59
- this.$mask.style.display = 'block'
60
- this.$mask.classList.add('atk-fade-in')
61
22
  this.$el.style.display = ''
62
-
63
- this.$mask.onclick = () => {
64
- if (this.maskClickHideEnable) this.hide()
65
- }
66
-
67
- // body style 禁止滚动 + 防抖
68
- this.pageBodyScrollBarHide()
69
- }
70
-
71
- hide () {
72
- if (this.afterHide) this.afterHide()
73
- this.$wrap.classList.add('atk-fade-out')
74
- this.$el.style.display = 'none'
75
-
76
- // body style 禁止滚动解除
77
- this.pageBodyScrollBarShow()
78
-
79
- this.newActionTimer(() => {
80
- this.$wrap.style.display = 'none'
81
- this.checkCleanLayer()
82
- }, 450)
83
- this.newActionTimer(() => {
84
- this.$wrap.style.display = 'none'
85
- this.$wrap.classList.remove('atk-fade-out')
86
- }, 200)
23
+ this.wrap.show()
87
24
  }
88
25
 
89
- setMaskClickHide (enable: boolean) {
90
- this.maskClickHideEnable = enable
91
- }
92
-
93
- // 页面滚动条隐藏
94
- pageBodyScrollBarHide() {
95
- document.body.style.overflow = 'hidden'
96
-
97
- const bpr = parseInt(window.getComputedStyle(document.body, null).getPropertyValue('padding-right'), 10)
98
- document.body.style.paddingRight = `${Ui.getScrollBarWidth() + bpr || 0}px`
99
- }
100
-
101
- // 页面滚动条显示
102
- pageBodyScrollBarShow() {
103
- document.body.style.overflow = Layer.BodyOrgOverflow
104
- document.body.style.paddingRight = Layer.BodyOrgPaddingRight
105
- }
106
-
107
- // Timers
108
- private static actionTimers: {act: Function, tid: number}[] = []
109
-
110
- private newActionTimer(func: Function, delay: number) {
111
- const act = () => {
112
- func() // 执行
113
- Layer.actionTimers = Layer.actionTimers.filter(o => o.act !== act) // 删除
114
- }
115
-
116
- const tid = window.setTimeout(() => act(), delay)
117
-
118
- Layer.actionTimers.push({ act, tid })
119
- }
120
-
121
- private fireAllActionTimer() {
122
- Layer.actionTimers.forEach(item => {
123
- clearTimeout(item.tid)
124
- item.act() // 立即执行
26
+ hide() {
27
+ this.wrap.hide(() => {
28
+ this.$el.style.display = 'none'
29
+ this.onAfterHide && this.onAfterHide()
125
30
  })
126
31
  }
127
32
 
128
- /** 销毁 - 无动画 */
129
- disposeNow() {
130
- this.$el.remove()
131
- this.pageBodyScrollBarShow()
132
- // this.$el dispose
133
- this.checkCleanLayer()
134
- }
135
-
136
- /** 销毁 */
137
- dispose() {
138
- this.hide()
139
- this.$el.remove()
140
- // this.$el dispose
141
- this.checkCleanLayer()
142
- }
143
-
144
- checkCleanLayer() {
145
- if (this.getWrapEl().querySelectorAll('.atk-layer-item').length === 0) {
146
- this.$wrap.style.display = 'none'
147
- }
148
- }
149
- }
150
-
151
- export function getLayerWrap(): { $wrap: HTMLElement, $mask: HTMLElement } {
152
- let $wrap = document.querySelector<HTMLElement>(`.atk-layer-wrap`)
153
- if (!$wrap) {
154
- $wrap = Utils.createElement(
155
- `<div class="atk-layer-wrap" style="display: none;"><div class="atk-layer-mask"></div></div>`
156
- )
157
- document.body.appendChild($wrap)
33
+ destroy() {
34
+ this.wrap.hide(() => {
35
+ this.$el.remove()
36
+ this.onAfterHide && this.onAfterHide()
37
+ })
158
38
  }
159
-
160
- const $mask = $wrap.querySelector<HTMLElement>('.atk-layer-mask')!
161
-
162
- return { $wrap, $mask }
163
39
  }
@@ -0,0 +1,24 @@
1
+ import * as Ui from '@/lib/ui'
2
+
3
+ let bodyOrgOverflow: string
4
+ let bodyOrgPaddingRight: string
5
+
6
+ export function getScrollbarHelper() {
7
+ return {
8
+ init() {
9
+ bodyOrgOverflow = document.body.style.overflow
10
+ bodyOrgPaddingRight = document.body.style.paddingRight
11
+ },
12
+
13
+ unlock() {
14
+ document.body.style.overflow = bodyOrgOverflow
15
+ document.body.style.paddingRight = bodyOrgPaddingRight
16
+ },
17
+
18
+ lock() {
19
+ document.body.style.overflow = 'hidden'
20
+ const barPaddingRight = parseInt(window.getComputedStyle(document.body, null).getPropertyValue('padding-right'), 10)
21
+ document.body.style.paddingRight = `${Ui.getScrollBarWidth() + barPaddingRight || 0}px`
22
+ }
23
+ }
24
+ }