artalk 2.2.10 → 2.3.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 (73) hide show
  1. package/dist/Artalk.css +1 -1
  2. package/dist/Artalk.es.js +3046 -2342
  3. package/dist/Artalk.iife.js +1 -1
  4. package/dist/Artalk.js +1 -1
  5. package/dist/ArtalkLite.css +1 -0
  6. package/dist/ArtalkLite.es.js +5096 -0
  7. package/dist/ArtalkLite.iife.js +1 -0
  8. package/dist/ArtalkLite.js +1 -0
  9. package/index.html +5 -3
  10. package/package.json +7 -5
  11. package/src/api/index.ts +24 -4
  12. package/src/api/request.ts +50 -81
  13. package/src/artalk.ts +83 -57
  14. package/src/comment/actions.ts +87 -0
  15. package/src/{components/html → comment}/comment.html +1 -1
  16. package/src/comment/comment.ts +191 -0
  17. package/src/comment/index.ts +3 -0
  18. package/src/comment/render.ts +425 -0
  19. package/src/components/action-btn.ts +6 -3
  20. package/src/components/dialog.ts +7 -3
  21. package/src/components/read-more-btn.ts +6 -2
  22. package/src/context.ts +200 -13
  23. package/src/defaults.ts +19 -6
  24. package/src/editor/editor.html +18 -0
  25. package/src/editor/editor.ts +420 -0
  26. package/src/editor/index.ts +3 -0
  27. package/src/editor/plugs/editor-plug.ts +51 -0
  28. package/src/{components/editor-plugs → editor/plugs}/emoticons-plug.less +1 -0
  29. package/src/{components/editor-plugs → editor/plugs}/emoticons-plug.ts +65 -63
  30. package/src/editor/plugs/header-input-plug.ts +79 -0
  31. package/src/{components/editor-plugs → editor/plugs}/preview-plug.less +0 -0
  32. package/src/editor/plugs/preview-plug.ts +40 -0
  33. package/src/editor/plugs/upload-plug.ts +125 -0
  34. package/src/i18n/en.ts +77 -0
  35. package/src/i18n/index.ts +21 -0
  36. package/src/i18n/zh-CN.ts +81 -0
  37. package/src/layer/index.ts +4 -0
  38. package/src/{components → layer}/layer.ts +9 -9
  39. package/src/{components/html → layer}/sidebar-layer.html +0 -0
  40. package/src/{components → layer}/sidebar-layer.ts +17 -46
  41. package/src/lib/checker/admin-checker.ts +7 -6
  42. package/src/lib/checker/captcha-checker.ts +5 -5
  43. package/src/lib/checker/index.ts +22 -17
  44. package/src/lib/component.ts +7 -2
  45. package/src/lib/ui.ts +3 -10
  46. package/src/lib/user.ts +20 -3
  47. package/src/lib/utils.ts +23 -9
  48. package/src/list/index.ts +3 -0
  49. package/src/{components → list}/list-lite.ts +87 -111
  50. package/src/{components → list}/list-nest.ts +0 -0
  51. package/src/{components/html → list}/list.html +3 -6
  52. package/src/{components → list}/list.ts +37 -35
  53. package/src/style/comment.less +23 -10
  54. package/src/style/editor.less +16 -10
  55. package/src/style/list.less +4 -7
  56. package/src/style/main.less +3 -1
  57. package/src/style/pagination.less +1 -1
  58. package/test/ArtalkLite.html +15 -0
  59. package/types/artalk-config.d.ts +52 -31
  60. package/types/context.d.ts +128 -0
  61. package/types/event.d.ts +6 -66
  62. package/types/global.d.ts +1 -0
  63. package/{vite-common.config.ts → vite-base.config.ts} +6 -4
  64. package/vite-demo.config.ts +2 -4
  65. package/vite-lite.config.ts +22 -0
  66. package/vite.config.ts +9 -18
  67. package/src/components/_component.ts.txt +0 -10
  68. package/src/components/comment.ts +0 -605
  69. package/src/components/editor-plugs/_example-plug.ts.txt +0 -29
  70. package/src/components/editor-plugs/editor-plug.ts +0 -20
  71. package/src/components/editor-plugs/preview-plug.ts +0 -48
  72. package/src/components/editor.ts +0 -604
  73. package/src/components/html/editor.html +0 -18
@@ -1,31 +1,28 @@
1
- import { ListData, CommentData, NotifyData, ApiVersionData } from '~/types/artalk-data'
2
- import Context from '../context'
1
+ import { ListData, CommentData, NotifyData } from '~/types/artalk-data'
2
+ import Context from '~/types/context'
3
3
  import Component from '../lib/component'
4
4
  import * as Utils from '../lib/utils'
5
5
  import * as Ui from '../lib/ui'
6
6
  import Api from '../api'
7
- import Comment from './comment'
8
- import Pagination from './pagination'
9
- import ReadMoreBtn from './read-more-btn'
7
+ import Comment from '../comment'
8
+ import Pagination from '../components/pagination'
9
+ import ReadMoreBtn from '../components/read-more-btn'
10
10
  import * as ListNest from './list-nest'
11
11
  import { backendMinVersion } from '../../package.json'
12
12
 
13
13
  export default class ListLite extends Component {
14
14
  protected $commentsWrap: HTMLElement
15
15
 
16
- protected commentList: Comment[] = [] // Note: 无层级结构 + 无须排列
17
- protected get commentDataList() { return this.commentList.map(c => c.data) }
18
-
19
16
  protected data?: ListData
20
17
  protected isLoading: boolean = false
21
18
 
22
- public noCommentText = '无内容' // 无评论时显示
19
+ public noCommentText: string // 无评论时显示
23
20
 
24
21
  /** 平铺模式 */
25
22
  public flatMode = false
26
23
 
27
24
  /** 嵌套模式 */
28
- public nestSortBy: ListNest.SortByType = 'DATE_DESC'
25
+ public nestSortBy!: ListNest.SortByType
29
26
 
30
27
  /** 分页 */
31
28
  public pageMode: 'pagination'|'read-more' = 'pagination'
@@ -56,18 +53,30 @@ export default class ListLite extends Component {
56
53
  this.$commentsWrap = this.$el.querySelector('.atk-list-comments-wrap')!
57
54
 
58
55
  // 评论为空时显示字符
59
- if (ctx.conf.noComment) this.noCommentText = ctx.conf.noComment
56
+ this.noCommentText = ctx.conf.noComment || ctx.$t('noComment')
57
+
58
+ // 嵌套排序方式
59
+ this.nestSortBy = this.ctx.conf.nestSort || 'DATE_ASC'
60
60
 
61
61
  // 评论时间自动更新
62
62
  window.setInterval(() => {
63
63
  this.$el.querySelectorAll<HTMLElement>('[data-atk-comment-date]').forEach(el => {
64
64
  const date = el.getAttribute('data-atk-comment-date')
65
- el.innerText = Utils.timeAgo(new Date(Number(date)))
65
+ el.innerText = Utils.timeAgo(new Date(Number(date)), this.ctx)
66
66
  })
67
67
  }, 30 * 1000) // 30s 更新一次
68
+ }
68
69
 
69
- // 事件监听
70
- this.ctx.on('unread-update', (data) => (this.updateUnread(data.notifies)))
70
+ public getData() {
71
+ return this.data
72
+ }
73
+
74
+ public clearData() {
75
+ this.data = undefined
76
+ }
77
+
78
+ public getCommentsWrapEl() {
79
+ return this.$commentsWrap
71
80
  }
72
81
 
73
82
  /** 评论获取 */
@@ -90,15 +99,15 @@ export default class ListLite extends Component {
90
99
  showLoading()
91
100
 
92
101
  // 事件通知(开始加载评论)
93
- this.ctx.trigger('comments-load')
102
+ this.ctx.trigger('list-load')
94
103
 
95
104
  // 清空评论(加载按钮)
96
- if (this.pageMode === 'read-more' && offset === 0) { this.clearAllComments() }
105
+ if (this.pageMode === 'read-more' && offset === 0) { this.ctx.clearAllComments() }
97
106
 
98
107
  // 请求评论数据
99
108
  let listData: ListData
100
109
  try {
101
- listData = await new Api(this.ctx).get(offset, this.pageSize, this.flatMode, this.paramsEditor)
110
+ listData = await this.ctx.getApi().get(offset, this.pageSize, this.flatMode, this.paramsEditor)
102
111
  } catch (e: any) {
103
112
  this.onError(e.msg || String(e), offset, e.data)
104
113
  throw e
@@ -122,14 +131,14 @@ export default class ListLite extends Component {
122
131
 
123
132
  protected onLoad(data: ListData, offset: number) {
124
133
  // 清空评论(分页条)
125
- if (this.pageMode === 'pagination') { this.clearAllComments() }
134
+ if (this.pageMode === 'pagination') { this.ctx.clearAllComments() }
126
135
 
127
136
  this.data = data
128
137
 
129
138
  // 版本检测
130
139
  const feMinVersion = data.api_version?.fe_min_version || '0.0.0'
131
- if (this.ctx.conf.versionCheck && this.versionCheck('前端', feMinVersion, ARTALK_VERSION)) return
132
- if (this.ctx.conf.versionCheck && this.versionCheck('后端', backendMinVersion, data.api_version?.version)) return
140
+ if (this.ctx.conf.versionCheck && this.versionCheck('frontend', feMinVersion, ARTALK_VERSION)) return
141
+ if (this.ctx.conf.versionCheck && this.versionCheck('backend', backendMinVersion, data.api_version?.version)) return
133
142
 
134
143
  // 图片上传功能
135
144
  if (data.conf && typeof data.conf.img_upload === "boolean") {
@@ -145,8 +154,8 @@ export default class ListLite extends Component {
145
154
  // 加载后事件
146
155
  this.refreshUI()
147
156
 
148
- this.ctx.trigger('unread-update', { notifies: data.unread || [] })
149
- this.ctx.trigger('comments-loaded')
157
+ this.ctx.updateNotifies(data.unread || [])
158
+ this.ctx.trigger('list-loaded')
150
159
  this.ctx.trigger('conf-updated')
151
160
 
152
161
  if (this.onAfterLoad) this.onAfterLoad(data)
@@ -176,11 +185,12 @@ export default class ListLite extends Component {
176
185
  onClick: async (o) => {
177
186
  await this.fetchComments(o)
178
187
  },
188
+ text: this.ctx.$t('loadMore'),
179
189
  })
180
190
  this.$el.append(this.readMoreBtn.$el)
181
191
 
182
192
  // 滚动到底部自动加载
183
- if (this.conf.pagination?.autoLoad) {
193
+ if (this.conf.pagination.autoLoad) {
184
194
  // 添加滚动事件监听
185
195
  const at = this.scrollListenerAt || document
186
196
  if (this.autoLoadScrollEvent) at.removeEventListener('scroll', this.autoLoadScrollEvent) // 解除原有
@@ -207,7 +217,7 @@ export default class ListLite extends Component {
207
217
  pageSize: this.pageSize,
208
218
  onChange: async (o) => {
209
219
  if (this.ctx.conf.editorTravel === true) {
210
- this.ctx.trigger('editor-travel-back') // 防止评论框被吞
220
+ this.ctx.editorTravelBack() // 防止评论框被吞
211
221
  }
212
222
 
213
223
  await this.fetchComments(o)
@@ -234,14 +244,14 @@ export default class ListLite extends Component {
234
244
 
235
245
  // 加载更多按钮显示错误
236
246
  if (offset !== 0 && this.pageMode === 'read-more') {
237
- this.readMoreBtn?.showErr(`获取失败`)
247
+ this.readMoreBtn?.showErr(this.$t('loadFail'))
238
248
  return
239
249
  }
240
250
 
241
251
  // 显示错误对话框
242
- const $err = Utils.createElement(`<span>${msg},无法获取评论列表数据<br/></span>`)
252
+ const $err = Utils.createElement(`<span>${msg},${this.$t('listLoadFailMsg')}<br/></span>`)
243
253
 
244
- const $retryBtn = Utils.createElement('<span style="cursor:pointer;">点击重新获取</span>')
254
+ const $retryBtn = Utils.createElement(`<span style="cursor:pointer;">${this.$t('listRetry')}</span>`)
245
255
  $retryBtn.onclick = () => (this.fetchComments(0))
246
256
  $err.appendChild($retryBtn)
247
257
 
@@ -261,9 +271,9 @@ export default class ListLite extends Component {
261
271
  sidebarView = `sites|${JSON.stringify(viewLoadParam)}`
262
272
  }
263
273
 
264
- adminBtn.onclick = () => (this.ctx.trigger('sidebar-show', {
265
- view: sidebarView
266
- }))
274
+ adminBtn.onclick = () => this.ctx.showSidebar({
275
+ view: sidebarView as any
276
+ })
267
277
 
268
278
  Ui.setError(this.$el, $err)
269
279
  }
@@ -271,7 +281,7 @@ export default class ListLite extends Component {
271
281
  /** 刷新界面 */
272
282
  public refreshUI() {
273
283
  // 无评论
274
- const isNoComment = this.commentList.length <= 0
284
+ const isNoComment = this.ctx.getCommentList().length <= 0
275
285
  let $noComment = this.$commentsWrap.querySelector<HTMLElement>('.atk-list-no-comment')
276
286
 
277
287
  if (isNoComment) {
@@ -285,25 +295,35 @@ export default class ListLite extends Component {
285
295
  }
286
296
 
287
297
  // 仅管理员显示控制
288
- this.ctx.trigger('check-admin-show-el')
298
+ this.ctx.checkAdminShowEl()
299
+ }
300
+
301
+ /** 重新加载列表 */
302
+ public reload() {
303
+ this.fetchComments(0)
289
304
  }
290
305
 
291
306
  /** 创建新评论 */
292
307
  protected createComment(cData: CommentData, ctxData?: CommentData[]) {
293
- if (!ctxData) ctxData = this.commentDataList
308
+ if (!ctxData) ctxData = this.ctx.getCommentDataList()
309
+
310
+ const comment = new Comment(this.ctx, cData, {
311
+ isFlatMode: this.flatMode,
312
+ afterRender: () => {
313
+ if (this.renderComment) this.renderComment(comment)
314
+ },
315
+ onDelete: (c: Comment) => {
316
+ this.ctx.deleteComment(c)
317
+ this.refreshUI()
318
+ },
319
+ replyTo: (cData.rid ? ctxData.find(c => c.id === cData.rid) : undefined)
320
+ })
294
321
 
295
- const comment = new Comment(this.ctx, cData)
296
- comment.flatMode = this.flatMode
297
- comment.afterRender = () => {
298
- if (this.renderComment) this.renderComment(comment)
299
- }
300
- comment.onDelete = (c) => {
301
- this.deleteComment(c)
302
- this.refreshUI()
303
- }
322
+ // 渲染元素
323
+ comment.render()
304
324
 
305
- // 子评论查找回复对象
306
- comment.replyTo = (cData.rid ? ctxData.find(c => c.id === cData.rid) : undefined)
325
+ // 放入 comment 总表中
326
+ this.ctx.getCommentList().push(comment)
307
327
 
308
328
  return comment
309
329
  }
@@ -325,14 +345,10 @@ export default class ListLite extends Component {
325
345
  const rootNodes = ListNest.makeNestCommentNodeList(srcData, this.nestSortBy, this.conf.nestMax)
326
346
  rootNodes.forEach((rootNode: ListNest.CommentNode) => {
327
347
  const rootC = this.createComment(rootNode.comment, srcData)
328
- rootC.render()
329
348
 
330
349
  // 显示并播放渐入动画
331
350
  this.$commentsWrap.appendChild(rootC.getEl())
332
- rootC.playFadeInAnim()
333
-
334
- // 评论放入 comments 总表中
335
- this.commentList.push(rootC)
351
+ rootC.getRender().playFadeAnim()
336
352
 
337
353
  // 加载子评论
338
354
  const that = this
@@ -340,20 +356,17 @@ export default class ListLite extends Component {
340
356
  parentNode.children.forEach((node: ListNest.CommentNode) => {
341
357
  const childD = node.comment
342
358
  const childC = that.createComment(childD, srcData)
343
- childC.render()
344
359
 
345
360
  // 插入到父评论中
346
361
  parentC.putChild(childC)
347
362
 
348
- that.commentList.push(childC)
349
-
350
363
  // 递归加载子评论
351
364
  loadChildren(childC, node)
352
365
  })
353
366
  })(rootC, rootNode)
354
367
 
355
368
  // 限高检测
356
- rootC.checkHeightLimit()
369
+ rootC.getRender().checkHeightLimit()
357
370
  })
358
371
  }
359
372
 
@@ -361,21 +374,17 @@ export default class ListLite extends Component {
361
374
  private putCommentFlatMode(cData: CommentData, ctxData: CommentData[], insertMode: 'append'|'prepend') {
362
375
  if (cData.is_collapsed) cData.is_allow_reply = false
363
376
  const comment = this.createComment(cData, ctxData)
364
- comment.render()
365
-
366
- // 将评论导入 comments 总表中
367
- this.commentList.push(comment)
368
377
 
369
378
  // 可见评论添加到界面
370
379
  // 注:不可见评论用于显示 “引用内容”
371
380
  if (cData.visible) {
372
381
  if (insertMode === 'append') this.$commentsWrap.append(comment.getEl())
373
382
  if (insertMode === 'prepend') this.$commentsWrap.prepend(comment.getEl())
374
- comment.playFadeInAnim()
383
+ comment.getRender().playFadeAnim()
375
384
  }
376
385
 
377
386
  // 平铺评论插入后 · 内容限高检测
378
- comment.checkHeightLimit()
387
+ comment.getRender().checkHeightLimit()
379
388
 
380
389
  return comment
381
390
  }
@@ -388,30 +397,27 @@ export default class ListLite extends Component {
388
397
 
389
398
  if (commentData.rid === 0) {
390
399
  // root评论 新增
391
- comment.render()
392
400
  this.$commentsWrap.prepend(comment.getEl())
393
- this.commentList.push(comment)
394
401
  } else {
395
402
  // 子评论 新增
396
- const parent = this.findComment(commentData.rid)
403
+ const parent = this.ctx.findComment(commentData.rid)
397
404
  if (parent) {
398
- comment.render()
399
405
  parent.putChild(comment, (this.nestSortBy === 'DATE_ASC' ? 'append' : 'prepend'))
400
406
 
401
407
  // 若父评论存在 “子评论部分” 限高,取消限高
402
408
  comment.getParents().forEach((p) => {
403
- if (p.$children) p.heightLimitRemove(p.$children)
409
+ p.getRender().heightLimitRemoveForChildren()
404
410
  })
405
411
  }
406
412
  }
407
413
 
408
- comment.checkHeightLimit()
414
+ comment.getRender().checkHeightLimit()
409
415
 
410
416
  Ui.scrollIntoView(comment.getEl()) // 滚动到可以见
411
- comment.playFadeInAnim() // 播放评论渐出动画
417
+ comment.getRender().playFadeAnim() // 播放评论渐出动画
412
418
  } else {
413
419
  // 平铺模式
414
- const comment = this.putCommentFlatMode(commentData, this.commentDataList, 'prepend')
420
+ const comment = this.putCommentFlatMode(commentData, this.ctx.getCommentDataList(), 'prepend')
415
421
  Ui.scrollIntoView(comment.getEl()) // 滚动到可见
416
422
  }
417
423
 
@@ -420,36 +426,8 @@ export default class ListLite extends Component {
420
426
 
421
427
  // 评论新增后
422
428
  this.refreshUI()
423
- this.ctx.trigger('comments-loaded')
424
- }
425
-
426
- /** 查找评论项 */
427
- protected findComment(id: number): Comment|undefined {
428
- return this.commentList.find(c => c.data.id === id)
429
- }
430
-
431
- /** 删除评论 */
432
- public deleteComment(_comment: number|Comment) {
433
- let comment: Comment
434
- if (typeof _comment === 'number') {
435
- const findComment = this.findComment(_comment)
436
- if (!findComment) throw Error(`未找到评论 ${_comment}`)
437
- comment = findComment
438
- } else comment = _comment
439
-
440
- comment.getEl().remove()
441
- this.commentList.splice(this.commentList.indexOf(comment), 1)
442
-
443
- if (this.data) this.data.total -= 1 // 评论数减 1
444
-
445
- this.refreshUI()
446
- }
447
-
448
- /** 清空所有评论 */
449
- public clearAllComments() {
450
- this.$commentsWrap.innerHTML = ''
451
- this.data = undefined
452
- this.commentList = []
429
+ this.ctx.trigger('list-loaded')
430
+ this.ctx.trigger('list-inserted', commentData)
453
431
  }
454
432
 
455
433
  /** 更新未读数据 */
@@ -458,33 +436,31 @@ export default class ListLite extends Component {
458
436
 
459
437
  // 高亮评论
460
438
  if (this.unreadHighlight === true) {
461
- this.commentList.forEach((comment) => {
462
- const notify = this.unread.find(o => o.comment_id === comment.data.id)
439
+ this.ctx.getCommentList().forEach((comment) => {
440
+ const notify = this.unread.find(o => o.comment_id === comment.getID())
463
441
  if (notify) {
464
- comment.setUnread(true)
465
- comment.setOpenURL(notify.read_link)
466
- comment.openEvt = () => {
467
- this.unread = this.unread.filter(o => o.comment_id !== comment.data.id) // remove
468
- this.ctx.trigger('unread-update', {
469
- notifies: this.unread
470
- })
471
- }
442
+ comment.getRender().setUnread(true)
443
+ comment.getRender().setOpenAction(() => {
444
+ window.open(notify.read_link)
445
+ this.unread = this.unread.filter(o => o.comment_id !== comment.getID()) // remove
446
+ this.ctx.updateNotifies(this.unread)
447
+ })
472
448
  } else {
473
- comment.setUnread(false)
449
+ comment.getRender().setUnread(false)
474
450
  }
475
451
  })
476
452
  }
477
453
  }
478
454
 
479
455
  /** 版本检测 */
480
- public versionCheck(name: '前端'|'后端', needVersion: string, curtVersion: string): boolean {
456
+ public versionCheck(name: 'frontend'|'backend', needVersion: string, curtVersion: string): boolean {
481
457
  const needUpdate = Utils.versionCompare(needVersion, curtVersion) === 1
482
458
  if (needUpdate) {
483
459
  // 需要更新
484
- const errEl = Utils.createElement(`<div>Artalk ${name}版本已过时,请更新以获得完整体验<br/>`
460
+ const errEl = Utils.createElement(`<div>Artalk ${this.$t(name)}版本已过时,请更新以获得完整体验<br/>`
485
461
  + `如果你是管理员,请前往 “<a href="https://artalk.js.org/" target="_blank">官方文档</a>” 获得帮助`
486
462
  + `<br/><br/>`
487
- + `<span style="color: var(--at-color-meta);">当前${name}版本 ${curtVersion},需求版本 >= ${needVersion}</span><br/><br/>`
463
+ + `<span style="color: var(--at-color-meta);">当前${this.$t(name)}版本 ${curtVersion},需求版本 >= ${needVersion}</span><br/><br/>`
488
464
  + `</div>`)
489
465
  const ignoreBtn = Utils.createElement('<span style="cursor:pointer;">忽略</span>')
490
466
  ignoreBtn.onclick = () => {
File without changes
@@ -1,16 +1,13 @@
1
1
  <div class="atk-list">
2
2
  <div class="atk-list-header">
3
3
  <div class="atk-comment-count">
4
- <div class="atk-text">
5
- <span class="atk-comment-count-num">0</span>
6
- 条评论
7
- </div>
4
+ <div class="atk-text"></div>
8
5
  </div>
9
6
  <div class="atk-right-action">
10
- <span data-action="admin-close-comment" class="atk-hide" atk-only-admin-show>关闭评论</span>
7
+ <span data-action="admin-close-comment" class="atk-hide" atk-only-admin-show></span>
11
8
  <span data-action="open-sidebar" class="atk-hide atk-on">
12
9
  <span class="atk-unread-badge" style="display: none;"></span>
13
- <div class="atk-text">通知中心</div>
10
+ <div class="atk-text"></div>
14
11
  </span>
15
12
  </div>
16
13
  </div>
@@ -1,11 +1,11 @@
1
1
  import '../style/list.less'
2
2
 
3
- import { ListData } from '~/types/artalk-data'
4
- import Context from '../context'
3
+ import { ListData, NotifyData } from '~/types/artalk-data'
4
+ import Context from '~/types/context'
5
5
  import * as Utils from '../lib/utils'
6
6
  import * as Ui from '../lib/ui'
7
7
  import Api from '../api'
8
- import ListHTML from './html/list.html?raw'
8
+ import ListHTML from './list.html?raw'
9
9
  import ListLite from './list-lite'
10
10
 
11
11
  export default class List extends ListLite {
@@ -13,6 +13,7 @@ export default class List extends ListLite {
13
13
  private $openSidebarBtn!: HTMLElement
14
14
  private $unreadBadge!: HTMLElement
15
15
  private $commentCount!: HTMLElement
16
+ private $commentCountNum!: HTMLElement
16
17
  private $dropdownWrap?: HTMLElement
17
18
 
18
19
  constructor (ctx: Context) {
@@ -35,14 +36,18 @@ export default class List extends ListLite {
35
36
  this.flatMode = flatMode
36
37
 
37
38
  // 分页模式
38
- this.pageMode = this.conf.pagination?.readMore ? 'read-more' : 'pagination'
39
- this.pageSize = this.conf.pagination?.pageSize || 20
39
+ this.pageMode = this.conf.pagination.readMore ? 'read-more' : 'pagination'
40
+ this.pageSize = this.conf.pagination.pageSize || 20
40
41
  this.repositionAt = this.$el
41
42
 
42
43
  // 操作按钮
43
44
  this.initListActionBtn()
44
45
 
45
46
  this.$commentCount = this.$el.querySelector('.atk-comment-count')!
47
+ this.$commentCount.innerHTML = this.$t('counter', {
48
+ count: '<span class="atk-comment-count-num">0</span>',
49
+ })
50
+ this.$commentCountNum = this.$commentCount.querySelector('.atk-comment-count-num')!
46
51
 
47
52
  // 评论列表排序 Dropdown 下拉选择层
48
53
  if (this.ctx.conf.listSort) {
@@ -53,13 +58,6 @@ export default class List extends ListLite {
53
58
  this.$el.querySelector<HTMLElement>('.atk-copyright')!.innerHTML = `Powered By <a href="https://artalk.js.org" target="_blank" title="Artalk v${ARTALK_VERSION}">Artalk</a>`
54
59
 
55
60
  // event listen
56
- this.ctx.on('list-reload', () => (this.fetchComments(0))) // 刷新评论
57
- this.ctx.on('list-refresh-ui', () => (this.refreshUI()))
58
- this.ctx.on('list-import', (data) => (this.importComments(data)))
59
- this.ctx.on('list-insert', (data) => (this.insertComment(data)))
60
- this.ctx.on('list-delete', (comment) => (this.deleteComment(comment.id)))
61
- this.ctx.on('list-update', (updateData) => { updateData(this.data);this.refreshUI() } )
62
- this.ctx.on('unread-update', (data) => (this.showUnreadBadge(data.notifies?.length || 0)))
63
61
  }
64
62
 
65
63
  private initListActionBtn() {
@@ -69,7 +67,7 @@ export default class List extends ListLite {
69
67
  this.$unreadBadge = this.$el.querySelector('.atk-unread-badge')!
70
68
 
71
69
  this.$openSidebarBtn.addEventListener('click', () => {
72
- this.ctx.trigger('sidebar-show')
70
+ this.ctx.showSidebar()
73
71
  })
74
72
 
75
73
  // 关闭评论按钮
@@ -85,7 +83,7 @@ export default class List extends ListLite {
85
83
  public refreshUI() {
86
84
  super.refreshUI()
87
85
 
88
- this.$el.querySelector<HTMLElement>('.atk-comment-count-num')!.innerText = String(Number(this.data?.total) || 0)
86
+ this.$commentCountNum.innerText = String(Number(this.data?.total) || 0)
89
87
 
90
88
  // 已输入个人信息
91
89
  if (!!this.ctx.user.data.nick && !!this.ctx.user.data.email) {
@@ -95,16 +93,17 @@ export default class List extends ListLite {
95
93
  }
96
94
 
97
95
  // 仅管理员显示控制
98
- this.ctx.trigger('check-admin-show-el')
99
- this.$openSidebarBtn.querySelector<HTMLElement>('.atk-text')!.innerText = (!this.ctx.user.data.isAdmin) ? '通知中心' : '控制中心'
96
+ this.ctx.checkAdminShowEl()
97
+ this.$openSidebarBtn.querySelector<HTMLElement>('.atk-text')!
98
+ .innerText = (!this.ctx.user.data.isAdmin) ? this.$t('msgCenter') : this.$t('ctrlCenter')
100
99
 
101
100
  // 关闭评论
102
101
  if (!!this.data && !!this.data.page && this.data.page.admin_only === true) {
103
- this.ctx.trigger('editor-close')
104
- this.$closeCommentBtn.innerHTML = '打开评论'
102
+ this.ctx.editorClose()
103
+ this.$closeCommentBtn.innerHTML = this.$t('openComment')
105
104
  } else {
106
- this.ctx.trigger('editor-open')
107
- this.$closeCommentBtn.innerHTML = '关闭评论'
105
+ this.ctx.editorOpen()
106
+ this.$closeCommentBtn.innerHTML = this.$t('closeComment')
108
107
  }
109
108
  }
110
109
 
@@ -116,7 +115,7 @@ export default class List extends ListLite {
116
115
 
117
116
  // 防止评论框被吞
118
117
  if (this.ctx.conf.editorTravel === true) {
119
- this.ctx.trigger('editor-travel-back')
118
+ this.ctx.editorTravelBack()
120
119
  }
121
120
  }
122
121
 
@@ -133,7 +132,7 @@ export default class List extends ListLite {
133
132
  }
134
133
  if (!commentId) return
135
134
 
136
- const comment = this.findComment(commentId)
135
+ const comment = this.ctx.findComment(commentId)
137
136
  if (!comment) { // 若找不到评论
138
137
  // 自动翻页
139
138
  if (this.readMoreBtn) this.readMoreBtn.click()
@@ -144,18 +143,16 @@ export default class List extends ListLite {
144
143
  // 已阅 API
145
144
  const notifyKey = Utils.getQueryParam('atk_notify_key')
146
145
  if (notifyKey) {
147
- new Api(this.ctx).markRead(notifyKey)
146
+ this.ctx.getApi().markRead(notifyKey)
148
147
  .then(() => {
149
148
  this.unread = this.unread.filter(o => o.comment_id !== commentId)
150
- this.ctx.trigger('unread-update', {
151
- notifies: this.unread
152
- })
149
+ this.updateUnread(this.unread)
153
150
  })
154
151
  }
155
152
 
156
153
  // 若父评论存在 “子评论部分” 限高,取消限高
157
154
  comment.getParents().forEach((p) => {
158
- if (p.$children) p.heightLimitRemove(p.$children)
155
+ p.getRender().heightLimitRemoveForChildren()
159
156
  })
160
157
 
161
158
  const goTo = () => {
@@ -177,18 +174,18 @@ export default class List extends ListLite {
177
174
  public adminPageEditSave () {
178
175
  if (!this.data || !this.data.page) return
179
176
 
180
- this.ctx.trigger('editor-show-loading')
181
- new Api(this.ctx).pageEdit(this.data.page)
177
+ this.ctx.editorShowLoading()
178
+ this.ctx.getApi().pageEdit(this.data.page)
182
179
  .then((page) => {
183
180
  if (this.data)
184
181
  this.data.page = { ...page }
185
182
  this.refreshUI()
186
183
  })
187
184
  .catch(err => {
188
- this.ctx.trigger('editor-notify', { msg: `修改页面数据失败:${err.msg || String(err)}`, type: 'e'})
185
+ this.ctx.editorShowNotify(`${this.$t('editFail')}: ${err.msg || String(err)}`, 'e')
189
186
  })
190
187
  .finally(() => {
191
- this.ctx.trigger('editor-hide-loading')
188
+ this.ctx.editorHideLoading()
192
189
  })
193
190
  }
194
191
 
@@ -216,10 +213,10 @@ export default class List extends ListLite {
216
213
 
217
214
  // 下拉列表
218
215
  const dropdownList = [
219
- ['最新', () => { reloadUseParamsEditor(p => { p.sort_by = 'date_desc' }) }],
220
- ['最热', () => { reloadUseParamsEditor(p => { p.sort_by = 'vote' }) }],
221
- ['最早', () => { reloadUseParamsEditor(p => { p.sort_by = 'date_asc' }) }],
222
- ['作者', () => { reloadUseParamsEditor(p => { p.view_only_admin = true }) }],
216
+ [this.$t('sortLatest'), () => { reloadUseParamsEditor(p => { p.sort_by = 'date_desc' }) }],
217
+ [this.$t('sortBest'), () => { reloadUseParamsEditor(p => { p.sort_by = 'vote' }) }],
218
+ [this.$t('sortOldest'), () => { reloadUseParamsEditor(p => { p.sort_by = 'date_asc' }) }],
219
+ [this.$t('sortAuthor'), () => { reloadUseParamsEditor(p => { p.view_only_admin = true }) }],
223
220
  ]
224
221
 
225
222
  // 列表项点击事件
@@ -254,4 +251,9 @@ export default class List extends ListLite {
254
251
 
255
252
  this.$dropdownWrap.append($dropdown)
256
253
  }
254
+
255
+ public updateUnread(notifies: NotifyData[]): void {
256
+ super.updateUnread(notifies)
257
+ this.showUnreadBadge(notifies?.length || 0)
258
+ }
257
259
  }