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,11 +1,11 @@
1
- import Context from '~/types/context'
1
+ import type Api from '@/api'
2
2
  import Dialog from '@/components/dialog'
3
- import Layer from '@/layer'
4
- import * as Utils from '../utils'
3
+ import $t from '@/i18n'
4
+ import type { ContextApi } from '~/types'
5
+ import type { Layer } from '@/layer'
6
+ import * as Utils from '@/lib/utils'
5
7
  import CaptchaChecker from './captcha'
6
8
  import AdminChecker from './admin'
7
- import type Api from '../../api'
8
- import type User from '../user'
9
9
 
10
10
  export interface CheckerCaptchaPayload extends CheckerPayload {
11
11
  imgData?: string
@@ -18,16 +18,18 @@ export interface CheckerPayload {
18
18
  onCancel?: () => void
19
19
  }
20
20
 
21
+ export interface CheckerLauncherOptions {
22
+ getCtx: () => ContextApi
23
+ getApi: () => Api
24
+ getIframeURLBase: () => string
25
+ onReload: () => void
26
+ }
27
+
21
28
  /**
22
29
  * Checker 发射台
23
30
  */
24
31
  export default class CheckerLauncher {
25
- public ctx: Context
26
- public launched: Checker[] = []
27
-
28
- constructor(ctx: Context) {
29
- this.ctx = ctx
30
- }
32
+ constructor(private opts: CheckerLauncherOptions) { }
31
33
 
32
34
  public checkCaptcha(payload: CheckerCaptchaPayload) {
33
35
  this.fire(CaptchaChecker, payload, (ctx) => {
@@ -41,12 +43,8 @@ export default class CheckerLauncher {
41
43
  }
42
44
 
43
45
  public fire(checker: Checker, payload: CheckerPayload, postFire?: (c: CheckerCtx) => void) {
44
- if (this.launched.includes(checker)) return // 阻止同时 fire 相同的 checker
45
- this.launched.push(checker)
46
-
47
- // 创建层
48
- const layer = new Layer(this.ctx, `checker-${new Date().getTime()}`)
49
- layer.setMaskClickHide(false)
46
+ // 显示层
47
+ const layer = this.opts.getCtx().get('layerManager').create(`checker-${new Date().getTime()}`)
50
48
  layer.show()
51
49
 
52
50
  // 构建 Checker 的上下文
@@ -55,9 +53,8 @@ export default class CheckerLauncher {
55
53
  const checkerCtx: CheckerCtx = {
56
54
  set: (key, val) => { checkerStore[key] = val },
57
55
  get: (key) => (checkerStore[key]),
58
- getCtx: () => (this.ctx),
59
- getApi: () => (this.ctx.getApi()),
60
- getLayer: () => layer,
56
+ getOpts: () => (this.opts),
57
+ getApi: () => this.opts.getApi(),
61
58
  hideInteractInput: () => {
62
59
  hideInteractInput = true
63
60
  },
@@ -98,7 +95,7 @@ export default class CheckerLauncher {
98
95
  }
99
96
 
100
97
  let btnTextOrg: string | undefined
101
- const dialog = new Dialog(this.ctx, formEl)
98
+ const dialog = new Dialog(formEl)
102
99
 
103
100
  // 确认按钮
104
101
  dialog.setYes((btnEl) => {
@@ -115,7 +112,7 @@ export default class CheckerLauncher {
115
112
  btnEl.classList.remove('error')
116
113
  }
117
114
 
118
- btnEl.innerText = `${this.ctx.$t('loading')}...`
115
+ btnEl.innerText = `${$t('loading')}...`
119
116
 
120
117
  // 发送请求
121
118
  checker
@@ -165,8 +162,7 @@ export default class CheckerLauncher {
165
162
 
166
163
  // 关闭 checker 对话框
167
164
  private close(checker: Checker, layer: Layer) {
168
- layer.disposeNow()
169
- this.launched = this.launched.filter(c => c !== checker)
165
+ layer.destroy()
170
166
  }
171
167
  }
172
168
 
@@ -188,9 +184,8 @@ interface CheckerStore {
188
184
  export interface CheckerCtx {
189
185
  get<K extends keyof CheckerStore>(key: K): CheckerStore[K]
190
186
  set<K extends keyof CheckerStore>(key: K, val: CheckerStore[K]): void
191
- getCtx(): Context
187
+ getOpts(): CheckerLauncherOptions
192
188
  getApi(): Api
193
- getLayer(): Layer
194
189
  hideInteractInput(): void
195
190
  triggerSuccess(): void
196
191
  cancel(): void
@@ -0,0 +1,30 @@
1
+ const darkModeMedia = window.matchMedia('(prefers-color-scheme: dark)')
2
+ let darkModeAutoFunc: (evt: MediaQueryListEvent) => void
3
+
4
+ export function applyDarkMode($els: HTMLElement[], darkMode: boolean|'auto') {
5
+ const apply = (d: boolean) => {
6
+ $els.forEach($el => updateClassName($el, d))
7
+ }
8
+
9
+ if (darkMode === 'auto') {
10
+ if (!darkModeAutoFunc) { // 自动切换夜间模式,事件监听
11
+ darkModeAutoFunc = (evt) => apply(evt.matches)
12
+ darkModeMedia.addEventListener('change', darkModeAutoFunc)
13
+ }
14
+
15
+ apply(darkModeMedia.matches)
16
+ } else {
17
+ // if the type of darkMode is boolean
18
+ if (darkModeAutoFunc) // 解除事件监听绑定
19
+ darkModeMedia.removeEventListener('change', darkModeAutoFunc)
20
+
21
+ apply(darkMode)
22
+ }
23
+ }
24
+
25
+ export const DarkModeClassName = 'atk-dark-mode'
26
+
27
+ function updateClassName($el: HTMLElement, darkMode: boolean) {
28
+ if (darkMode) $el.classList.add(DarkModeClassName)
29
+ else $el.classList.remove(DarkModeClassName)
30
+ }
@@ -1,4 +1,4 @@
1
- import Context from '~/types/context'
1
+ import $t from '@/i18n'
2
2
  import * as Utils from '../lib/utils'
3
3
 
4
4
  type BtnClickHandler = (btnEl: HTMLElement, dialog: Dialog) => boolean|void
@@ -7,14 +7,11 @@ type BtnClickHandler = (btnEl: HTMLElement, dialog: Dialog) => boolean|void
7
7
  * 对话框
8
8
  */
9
9
  export default class Dialog {
10
- public ctx: Context
11
10
  public $el: HTMLElement
12
11
  public $content: HTMLElement
13
12
  public $actions: HTMLElement
14
13
 
15
- constructor (ctx: Context, contentEl: HTMLElement) {
16
- this.ctx = ctx
17
-
14
+ constructor (contentEl: HTMLElement) {
18
15
  this.$el = Utils.createElement(
19
16
  `<div class="atk-layer-dialog-wrap">
20
17
  <div class="atk-layer-dialog">
@@ -30,14 +27,12 @@ export default class Dialog {
30
27
  // 内容
31
28
  this.$content = this.$el.querySelector('.atk-layer-dialog-content')!
32
29
  this.$content.appendChild(contentEl)
33
-
34
- return this
35
30
  }
36
31
 
37
32
  /** 按钮 · 确定 */
38
33
  public setYes(handler: BtnClickHandler) {
39
34
  const btn = Utils.createElement<HTMLButtonElement>(
40
- `<button data-action="confirm">${this.ctx.$t('confirm')}</button>`
35
+ `<button data-action="confirm">${$t('confirm')}</button>`
41
36
  )
42
37
  btn.onclick = this.onBtnClick(handler)
43
38
  this.$actions.appendChild(btn)
@@ -48,7 +43,7 @@ export default class Dialog {
48
43
  /** 按钮 · 取消 */
49
44
  public setNo(handler: BtnClickHandler) {
50
45
  const btn = Utils.createElement<HTMLButtonElement>(
51
- `<button data-action="cancel">${this.ctx.$t('cancel')}</button>`
46
+ `<button data-action="cancel">${$t('cancel')}</button>`
52
47
  )
53
48
  btn.onclick = this.onBtnClick(handler)
54
49
  this.$actions.appendChild(btn)
@@ -0,0 +1,35 @@
1
+ import * as Utils from '@/lib/utils'
2
+ import * as Ui from '@/lib/ui'
3
+ import User from '@/lib/user'
4
+ import $t from '@/i18n'
5
+
6
+ export interface ErrorDialogOptions {
7
+ $err: HTMLElement
8
+
9
+ errMsg: string
10
+ errData?: any
11
+ retryFn?: () => void
12
+
13
+ onOpenSidebar?: () => void
14
+ }
15
+
16
+ export function showErrorDialog(opts: ErrorDialogOptions) {
17
+ const errEl = Utils.createElement(`<span>${opts.errMsg},${$t('listLoadFailMsg')}<br/></span>`)
18
+
19
+ if (opts.retryFn) {
20
+ const $retryBtn = Utils.createElement(`<span style="cursor:pointer;">${$t('listRetry')}</span>`)
21
+ $retryBtn.onclick = () => opts.retryFn && opts.retryFn()
22
+ errEl.appendChild($retryBtn)
23
+ }
24
+
25
+ if (opts.onOpenSidebar) {
26
+ const $openSidebar = Utils.createElement('<span atk-only-admin-show> | <span style="cursor:pointer;">打开控制台</span></span>')
27
+ errEl.appendChild($openSidebar)
28
+ if (!User.data.isAdmin) { // only display if user is admin
29
+ $openSidebar.classList.add('atk-hide')
30
+ }
31
+ $openSidebar.onclick = () => opts.onOpenSidebar && opts.onOpenSidebar()
32
+ }
33
+
34
+ Ui.setError(opts.$err, errEl)
35
+ }
@@ -1,7 +1,7 @@
1
1
  import * as Utils from '../lib/utils'
2
2
  import * as Ui from '../lib/ui'
3
3
 
4
- export interface PaginationConf {
4
+ export interface PaginationOptions {
5
5
  /** 每页条数 */
6
6
  pageSize: number
7
7
 
@@ -10,7 +10,7 @@ export interface PaginationConf {
10
10
  }
11
11
 
12
12
  export default class Pagination {
13
- private conf: PaginationConf
13
+ private opts: PaginationOptions
14
14
  public total: number
15
15
  public $el: HTMLElement
16
16
  public $input: HTMLInputElement
@@ -20,7 +20,7 @@ export default class Pagination {
20
20
 
21
21
  public page: number = 1
22
22
  get pageSize(): number {
23
- return this.conf.pageSize
23
+ return this.opts.pageSize
24
24
  }
25
25
  get offset(): number {
26
26
  return this.pageSize * (this.page - 1)
@@ -29,9 +29,9 @@ export default class Pagination {
29
29
  return Math.ceil(this.total / this.pageSize)
30
30
  }
31
31
 
32
- public constructor(total: number, conf: PaginationConf) {
32
+ public constructor(total: number, opts: PaginationOptions) {
33
33
  this.total = total
34
- this.conf = conf
34
+ this.opts = opts
35
35
 
36
36
  this.$el = Utils.createElement(
37
37
  `<div class="atk-pagination-wrap">
@@ -99,9 +99,13 @@ export default class Pagination {
99
99
  this.change(page)
100
100
  }
101
101
 
102
+ public getHasMore() {
103
+ return this.page + 1 <= this.maxPage
104
+ }
105
+
102
106
  public change(page: number) {
103
107
  this.page = page
104
- this.conf.onChange(this.offset)
108
+ this.opts.onChange(this.offset)
105
109
  this.setInput(page)
106
110
  this.checkDisabled()
107
111
  }
@@ -1,6 +1,6 @@
1
1
  import * as Utils from '../lib/utils'
2
2
 
3
- export interface ReadMoreBtnConf {
3
+ export interface ReadMoreBtnOptions {
4
4
  /** 回调函数 */
5
5
  onClick: (offset: number) => void
6
6
 
@@ -13,7 +13,7 @@ export interface ReadMoreBtnConf {
13
13
  * 阅读更多按钮
14
14
  */
15
15
  export default class ReadMoreBtn {
16
- public conf: ReadMoreBtnConf
16
+ public opts: ReadMoreBtnOptions
17
17
  public $el: HTMLElement
18
18
  private $loading: HTMLElement
19
19
  private $text: HTMLElement
@@ -23,12 +23,12 @@ export default class ReadMoreBtn {
23
23
 
24
24
  /** 是否有更多内容 */
25
25
  get hasMore() {
26
- return this.total > (this.offset + this.conf.pageSize)
26
+ return this.total > (this.offset + this.opts.pageSize)
27
27
  }
28
28
 
29
- public constructor(conf: ReadMoreBtnConf) {
30
- this.conf = conf
31
- this.origText = this.conf.text || this.origText
29
+ public constructor(opts: ReadMoreBtnOptions) {
30
+ this.opts = opts
31
+ this.origText = this.opts.text || this.origText
32
32
 
33
33
  this.$el = Utils.createElement(
34
34
  `<div class="atk-list-read-more" style="display: none;">
@@ -45,7 +45,7 @@ export default class ReadMoreBtn {
45
45
  }
46
46
 
47
47
  click() {
48
- if (this.hasMore) this.conf.onClick(this.offset + this.conf.pageSize)
48
+ if (this.hasMore) this.opts.onClick(this.offset + this.opts.pageSize)
49
49
  this.checkDisabled()
50
50
  }
51
51
 
package/src/config.ts CHANGED
@@ -1,14 +1,21 @@
1
- import type ArtalkConfig from '~/types/artalk-config'
1
+ import type { ArtalkConfig, ContextApi } from '~/types'
2
+ import type { ApiOptions } from './api/_options'
2
3
  import * as Utils from './lib/utils'
3
4
  import Defaults from './defaults'
4
5
 
5
- export default { handelBaseConf }
6
-
7
- /** 基本配置初始化 */
8
- export function handelBaseConf(customConf: Partial<ArtalkConfig>): ArtalkConfig {
6
+ /**
7
+ * Merges the user custom config with the default config
8
+ *
9
+ * @param customConf - The custom config object which is provided by the user
10
+ * @returns The config for Artalk instance creation
11
+ */
12
+ export function handelCustomConf(customConf: Partial<ArtalkConfig>): ArtalkConfig {
9
13
  // 合并默认配置
10
14
  const conf: ArtalkConfig = Utils.mergeDeep(Defaults, customConf)
11
15
 
16
+ // TODO the type of el options may HTMLElement, use it directly instead of from mergeDeep
17
+ if (customConf.el) conf.el = customConf.el
18
+
12
19
  // 绑定元素
13
20
  if (typeof conf.el === 'string' && !!conf.el) {
14
21
  try {
@@ -40,10 +47,24 @@ export function handelBaseConf(customConf: Partial<ArtalkConfig>): ArtalkConfig
40
47
  conf.locale = navigator.language
41
48
  }
42
49
 
50
+ // flatMode
51
+ if (conf.flatMode === true || Number(conf.nestMax) <= 1)
52
+ conf.flatMode = true
53
+
54
+ // 自动判断启用平铺模式
55
+ if (conf.flatMode === 'auto')
56
+ conf.flatMode = window.matchMedia("(max-width: 768px)").matches
57
+
43
58
  return conf
44
59
  }
45
60
 
46
- export function handleBackendRefConf(conf: Partial<ArtalkConfig>) {
61
+ /**
62
+ * Handle the config which is provided by the server
63
+ *
64
+ * @param conf - The Server response config for control the frontend of Artalk remotely
65
+ * @returns The config for Artalk instance creation
66
+ */
67
+ export function handleConfFormServer(conf: Partial<ArtalkConfig>) {
47
68
  const DisabledKeys: (keyof ArtalkConfig)[] = [
48
69
  'el', 'pageKey', 'pageTitle', 'server', 'site', 'darkMode'
49
70
  ]
@@ -63,3 +84,36 @@ export function handleBackendRefConf(conf: Partial<ArtalkConfig>) {
63
84
 
64
85
  return conf
65
86
  }
87
+
88
+ /**
89
+ * Convert Artalk Config to ApiOptions for Api client
90
+ *
91
+ * @param conf - Artalk config
92
+ * @param ctx - If `ctx` not provided, `checkAdmin` and `checkCaptcha` will be disabled
93
+ * @returns ApiOptions for Api client instance creation
94
+ */
95
+ export function convertApiOptions(conf: Partial<ArtalkConfig>, ctx?: ContextApi): ApiOptions {
96
+ return {
97
+ baseURL: `${conf.server}/api`,
98
+ siteName: conf.site || '',
99
+ pageKey: conf.pageKey || '',
100
+ pageTitle: conf.pageTitle || '',
101
+ timeout: conf.reqTimeout,
102
+
103
+ onNeedCheckAdmin(payload) {
104
+ ctx?.checkAdmin({
105
+ onSuccess: () => { payload.recall() },
106
+ onCancel: () => { payload.reject() },
107
+ })
108
+ },
109
+
110
+ onNeedCheckCaptcha(payload) {
111
+ ctx?.checkCaptcha({
112
+ imgData: payload.data.imgData,
113
+ iframe: payload.data.iframe,
114
+ onSuccess: () => { payload.recall() },
115
+ onCancel: () => { payload.reject() },
116
+ })
117
+ },
118
+ }
119
+ }
package/src/context.ts CHANGED
@@ -1,20 +1,16 @@
1
- import type ArtalkConfig from '~/types/artalk-config'
2
- import type { CommentData, NotifyData } from '~/types/artalk-data'
3
- import type { Event } from '~/types/event'
4
- import type ContextApi from '~/types/context'
1
+ import type { ArtalkConfig, CommentData, ListFetchParams, ContextApi, EventPayloadMap, SidebarShowPayload } from '~/types'
5
2
  import type { TInjectedServices } from './service'
3
+ import Api from './api'
6
4
 
7
5
  import * as Utils from './lib/utils'
8
- import * as DarkMode from './lib/dark-mode'
9
6
  import * as marked from './lib/marked'
10
- import { CheckerCaptchaPayload, CheckerPayload } from './lib/checker'
7
+ import { CheckerCaptchaPayload, CheckerPayload } from './components/checker'
11
8
 
9
+ import { DataManager } from './data'
12
10
  import * as I18n from './i18n'
13
- import { getLayerWrap } from './layer'
14
- import { SidebarShowPayload } from './layer/sidebar-layer'
15
- import Comment from './comment'
16
- import Api from './api'
17
- import List from './list'
11
+
12
+ import EventManager from './lib/event-manager'
13
+ import { convertApiOptions, handelCustomConf } from './config'
18
14
 
19
15
  // Auto dependency injection
20
16
  interface Context extends TInjectedServices { }
@@ -25,13 +21,11 @@ interface Context extends TInjectedServices { }
25
21
  class Context implements ContextApi {
26
22
  /* 运行参数 */
27
23
  public conf: ArtalkConfig
24
+ public data: DataManager
28
25
  public $root: HTMLElement
29
- public markedReplacers: ((raw: string) => string)[] = []
30
26
 
31
- private commentList: Comment[] = [] // Note: 无层级结构 + 无须排列
32
-
33
- /* 订阅者模式 */
34
- private eventList: Event[] = []
27
+ /* Event Manager */
28
+ private events = new EventManager<EventPayloadMap>()
35
29
 
36
30
  public constructor(conf: ArtalkConfig, $root?: HTMLElement) {
37
31
  this.conf = conf
@@ -39,6 +33,8 @@ class Context implements ContextApi {
39
33
  this.$root = $root || document.createElement('div')
40
34
  this.$root.classList.add('artalk')
41
35
  this.$root.innerHTML = ''
36
+
37
+ this.data = new DataManager(this.events)
42
38
  }
43
39
 
44
40
  public inject(depName: string, obj: any) {
@@ -50,108 +46,34 @@ class Context implements ContextApi {
50
46
  }
51
47
 
52
48
  public getApi() {
53
- return this.api
54
- }
55
-
56
- /* 评论操作 */
57
- public getCommentList() {
58
- return this.commentList
59
- }
60
-
61
- public getCommentDataList() {
62
- return this.commentList.map(c => c.getData())
63
- }
64
-
65
- public findComment(id: number): Comment|undefined {
66
- return this.commentList.find(c => c.getData().id === id)
67
- }
68
-
69
- public deleteComment(_comment: number|Comment) {
70
- let comment: Comment
71
- if (typeof _comment === 'number') {
72
- const findComment = this.findComment(_comment)
73
- if (!findComment) throw Error(`Comment ${_comment} cannot be found`)
74
- comment = findComment
75
- } else comment = _comment
76
-
77
- comment.getEl().remove()
78
- this.commentList.splice(this.commentList.indexOf(comment), 1)
79
-
80
- if (this.list) {
81
- const listData = this.list.getData()
82
- if (listData) listData.total -= 1 // 评论数减 1
83
-
84
- this.list.refreshUI()
85
- }
86
- }
87
-
88
- public clearAllComments() {
89
- if (this.list) {
90
- this.list.getCommentsWrapEl().innerHTML = ''
91
- this.list.clearData()
92
- }
93
-
94
- this.commentList = []
95
- }
96
-
97
- public insertComment(commentData: CommentData) {
98
- this.list?.insertComment(commentData)
49
+ return new Api(convertApiOptions(this.conf, this))
99
50
  }
100
51
 
101
- public updateComment(commentData: CommentData): void {
102
- this.list?.updateComment(commentData)
52
+ public getData() {
53
+ return this.data
103
54
  }
104
55
 
105
- public replyComment(commentData: CommentData, $comment: HTMLElement, scroll?: boolean): void {
106
- this.editor.setReply(commentData, $comment, scroll)
107
- }
108
-
109
- public cancelReplyComment(): void {
110
- this.editor.cancelReply()
56
+ public replyComment(commentData: CommentData, $comment: HTMLElement): void {
57
+ this.editor.setReply(commentData, $comment)
111
58
  }
112
59
 
113
60
  public editComment(commentData: CommentData, $comment: HTMLElement): void {
114
61
  this.editor.setEditComment(commentData, $comment)
115
62
  }
116
63
 
117
- public cancelEditComment(): void {
118
- this.editor.cancelEditComment()
119
- }
120
-
121
- public updateNotifies(notifies: NotifyData[]): void {
122
- this.list?.updateUnread(notifies)
123
- }
124
-
125
- /* 评论列表 */
126
- public listReload(): void {
127
- this.list?.reload()
64
+ public fetch(params: Partial<ListFetchParams>): void {
65
+ this.data.fetchComments(params)
128
66
  }
129
67
 
130
68
  public reload(): void {
131
- this.listReload()
69
+ this.data.fetchComments({ offset: 0 })
132
70
  }
133
71
 
134
- public listRefreshUI(): void {
135
- this.list?.refreshUI()
136
- }
137
-
138
- public listHashGotoCheck(): void {
139
- if (!this.list || !(this.list instanceof List)) return
140
- const list = this.list as List
141
-
142
- list.goToCommentDelay = false
143
- list.checkGoToCommentByUrlHash()
72
+ public listGotoFirst(): void {
73
+ this.trigger('list-goto-first')
144
74
  }
145
75
 
146
76
  /* 编辑器 */
147
- public editorOpen(): void {
148
- this.editor.open()
149
- }
150
-
151
- public editorClose(): void {
152
- this.editor.close()
153
- }
154
-
155
77
  public editorShowLoading(): void {
156
78
  this.editor.showLoading()
157
79
  }
@@ -164,12 +86,8 @@ class Context implements ContextApi {
164
86
  this.editor.showNotify(msg, type)
165
87
  }
166
88
 
167
- public editorTravel($el: HTMLElement): void {
168
- this.editor.travel($el)
169
- }
170
-
171
- public editorTravelBack(): void {
172
- this.editor.travelBack()
89
+ public editorResetState(): void {
90
+ this.editor.resetState()
173
91
  }
174
92
 
175
93
  /* 侧边栏 */
@@ -190,43 +108,17 @@ class Context implements ContextApi {
190
108
  this.checkerLauncher.checkCaptcha(payload)
191
109
  }
192
110
 
193
- public checkAdminShowEl() {
194
- const items: HTMLElement[] = []
195
-
196
- this.$root.querySelectorAll<HTMLElement>(`[atk-only-admin-show]`).forEach(item => items.push(item))
197
-
198
- // for layer
199
- const { $wrap: $layerWrap } = getLayerWrap()
200
- if ($layerWrap) $layerWrap.querySelectorAll<HTMLElement>(`[atk-only-admin-show]`).forEach(item => items.push(item))
201
-
202
- // for sidebar
203
- // TODO: 这个其实应该写在 packages/artalk-sidebar 里面的
204
- const $sidebarEl = document.querySelector<HTMLElement>('.atk-sidebar')
205
- if ($sidebarEl) $sidebarEl.querySelectorAll<HTMLElement>(`[atk-only-admin-show]`).forEach(item => items.push(item))
206
-
207
- items.forEach(($item: HTMLElement) => {
208
- if (this.user.data.isAdmin) $item.classList.remove('atk-hide')
209
- else $item.classList.add('atk-hide')
210
- })
211
- }
212
-
213
- /* 订阅模式 */
214
- public on(name: any, handler: any, scope: any = 'internal') {
215
- this.eventList.push({ name, handler, scope })
111
+ /* Events */
112
+ public on(name: any, handler: any) {
113
+ this.events.on(name, handler)
216
114
  }
217
115
 
218
- public off(name: any, handler: any, scope: any = 'internal') {
219
- this.eventList = this.eventList.filter((evt) => {
220
- if (handler) return !(evt.name === name && evt.handler === handler && evt.scope === scope)
221
- return !(evt.name === name && evt.scope === scope) // 删除全部相同 name event
222
- })
116
+ public off(name: any, handler: any) {
117
+ this.events.off(name, handler)
223
118
  }
224
119
 
225
- public trigger(name: any, payload?: any, scope?: any) {
226
- this.eventList
227
- .filter((evt) => evt.name === name && (scope ? (evt.scope === scope) : true))
228
- .map((evt) => evt.handler)
229
- .forEach((handler) => handler(payload))
120
+ public trigger(name: any, payload?: any) {
121
+ this.events.trigger(name, payload)
230
122
  }
231
123
 
232
124
  /* i18n */
@@ -234,16 +126,19 @@ class Context implements ContextApi {
234
126
  return I18n.t(key, args)
235
127
  }
236
128
 
237
- public setDarkMode(darkMode: boolean): void {
238
- DarkMode.setDarkMode(this, darkMode)
129
+ public setDarkMode(darkMode: boolean|'auto'): void {
130
+ // prevent trigger 'conf-loaded' to improve performance
131
+ // this.updateConf({ ...this.conf, darkMode })
132
+ this.conf.darkMode = darkMode
133
+ this.trigger('dark-mode-changed', darkMode)
239
134
  }
240
135
 
241
136
  public updateConf(nConf: Partial<ArtalkConfig>): void {
242
- this.conf = Utils.mergeDeep(this.conf, nConf)
243
- this.trigger('conf-loaded')
137
+ this.conf = Utils.mergeDeep(this.conf, handelCustomConf(nConf))
138
+ this.trigger('conf-loaded', this.conf)
244
139
  }
245
140
 
246
- public getMarkedInstance() {
141
+ public getMarked() {
247
142
  return marked.getInstance()
248
143
  }
249
144
  }