artalk 2.2.12 → 2.3.2

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 (78) hide show
  1. package/dist/Artalk.css +1 -1
  2. package/dist/Artalk.es.js +1535 -1175
  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 +5123 -0
  7. package/dist/ArtalkLite.iife.js +1 -0
  8. package/dist/ArtalkLite.js +1 -0
  9. package/index.html +2 -2
  10. package/package.json +6 -5
  11. package/src/api/index.ts +20 -1
  12. package/src/api/request.ts +7 -7
  13. package/src/artalk.ts +117 -121
  14. package/src/comment/actions.ts +86 -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 +204 -13
  23. package/src/defaults.ts +16 -5
  24. package/src/editor/editor.html +18 -0
  25. package/src/editor/editor.ts +419 -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 +2 -1
  29. package/src/{components/editor-plugs → editor/plugs}/emoticons-plug.ts +65 -63
  30. package/src/editor/plugs/header-input-plug.ts +78 -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 +124 -0
  34. package/src/i18n/en.ts +78 -0
  35. package/src/i18n/index.ts +21 -0
  36. package/src/i18n/zh-CN.ts +82 -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 -47
  41. package/src/lib/checker/admin-checker.ts +7 -7
  42. package/src/lib/checker/captcha-checker.ts +5 -6
  43. package/src/lib/checker/index.ts +22 -17
  44. package/src/lib/component.ts +7 -2
  45. package/src/lib/stat.ts +63 -0
  46. package/src/lib/ui.ts +6 -12
  47. package/src/lib/user.ts +20 -3
  48. package/src/lib/utils.ts +23 -9
  49. package/src/list/index.ts +3 -0
  50. package/src/{components → list}/list-lite.ts +80 -100
  51. package/src/{components → list}/list-nest.ts +0 -0
  52. package/src/{components/html → list}/list.html +3 -6
  53. package/src/{components → list}/list.ts +44 -42
  54. package/src/style/_variables.less +1 -2
  55. package/src/style/comment.less +26 -13
  56. package/src/style/editor.less +22 -14
  57. package/src/style/list.less +6 -9
  58. package/src/style/main.less +9 -8
  59. package/src/style/pagination.less +1 -1
  60. package/test/ArtalkCount.html +16 -0
  61. package/test/ArtalkI18n.html +15 -0
  62. package/test/ArtalkLite.html +15 -0
  63. package/types/artalk-config.d.ts +50 -32
  64. package/types/context.d.ts +128 -0
  65. package/types/event.d.ts +6 -66
  66. package/types/global.d.ts +1 -0
  67. package/types/plug.d.ts +4 -0
  68. package/{vite-common.config.ts → vite-base.config.ts} +6 -4
  69. package/vite-demo.config.ts +2 -4
  70. package/vite-lite.config.ts +22 -0
  71. package/vite.config.ts +9 -12
  72. package/src/components/_component.ts.txt +0 -10
  73. package/src/components/comment.ts +0 -605
  74. package/src/components/editor-plugs/_example-plug.ts.txt +0 -29
  75. package/src/components/editor-plugs/editor-plug.ts +0 -20
  76. package/src/components/editor-plugs/preview-plug.ts +0 -48
  77. package/src/components/editor.ts +0 -607
  78. package/src/components/html/editor.html +0 -18
@@ -1,25 +1,21 @@
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
- import Api from '../api'
7
- import Comment from './comment'
8
- import Pagination from './pagination'
9
- import ReadMoreBtn from './read-more-btn'
6
+ import Comment from '../comment'
7
+ import Pagination from '../components/pagination'
8
+ import ReadMoreBtn from '../components/read-more-btn'
10
9
  import * as ListNest from './list-nest'
11
10
  import { backendMinVersion } from '../../package.json'
12
11
 
13
12
  export default class ListLite extends Component {
14
13
  protected $commentsWrap: HTMLElement
15
14
 
16
- protected commentList: Comment[] = [] // Note: 无层级结构 + 无须排列
17
- protected get commentDataList() { return this.commentList.map(c => c.data) }
18
-
19
15
  protected data?: ListData
20
16
  protected isLoading: boolean = false
21
17
 
22
- public noCommentText = '无内容' // 无评论时显示
18
+ public noCommentText: string // 无评论时显示
23
19
 
24
20
  /** 平铺模式 */
25
21
  public flatMode = false
@@ -56,7 +52,7 @@ export default class ListLite extends Component {
56
52
  this.$commentsWrap = this.$el.querySelector('.atk-list-comments-wrap')!
57
53
 
58
54
  // 评论为空时显示字符
59
- if (ctx.conf.noComment) this.noCommentText = ctx.conf.noComment
55
+ this.noCommentText = ctx.conf.noComment || ctx.$t('noComment')
60
56
 
61
57
  // 嵌套排序方式
62
58
  this.nestSortBy = this.ctx.conf.nestSort || 'DATE_ASC'
@@ -65,12 +61,21 @@ export default class ListLite extends Component {
65
61
  window.setInterval(() => {
66
62
  this.$el.querySelectorAll<HTMLElement>('[data-atk-comment-date]').forEach(el => {
67
63
  const date = el.getAttribute('data-atk-comment-date')
68
- el.innerText = Utils.timeAgo(new Date(Number(date)))
64
+ el.innerText = Utils.timeAgo(new Date(Number(date)), this.ctx)
69
65
  })
70
66
  }, 30 * 1000) // 30s 更新一次
67
+ }
68
+
69
+ public getData() {
70
+ return this.data
71
+ }
71
72
 
72
- // 事件监听
73
- this.ctx.on('unread-update', (data) => (this.updateUnread(data.notifies)))
73
+ public clearData() {
74
+ this.data = undefined
75
+ }
76
+
77
+ public getCommentsWrapEl() {
78
+ return this.$commentsWrap
74
79
  }
75
80
 
76
81
  /** 评论获取 */
@@ -93,15 +98,15 @@ export default class ListLite extends Component {
93
98
  showLoading()
94
99
 
95
100
  // 事件通知(开始加载评论)
96
- this.ctx.trigger('comments-load')
101
+ this.ctx.trigger('list-load')
97
102
 
98
103
  // 清空评论(加载按钮)
99
- if (this.pageMode === 'read-more' && offset === 0) { this.clearAllComments() }
104
+ if (this.pageMode === 'read-more' && offset === 0) { this.ctx.clearAllComments() }
100
105
 
101
106
  // 请求评论数据
102
107
  let listData: ListData
103
108
  try {
104
- listData = await new Api(this.ctx).get(offset, this.pageSize, this.flatMode, this.paramsEditor)
109
+ listData = await this.ctx.getApi().get(offset, this.pageSize, this.flatMode, this.paramsEditor)
105
110
  } catch (e: any) {
106
111
  this.onError(e.msg || String(e), offset, e.data)
107
112
  throw e
@@ -125,14 +130,14 @@ export default class ListLite extends Component {
125
130
 
126
131
  protected onLoad(data: ListData, offset: number) {
127
132
  // 清空评论(分页条)
128
- if (this.pageMode === 'pagination') { this.clearAllComments() }
133
+ if (this.pageMode === 'pagination') { this.ctx.clearAllComments() }
129
134
 
130
135
  this.data = data
131
136
 
132
137
  // 版本检测
133
138
  const feMinVersion = data.api_version?.fe_min_version || '0.0.0'
134
- if (this.ctx.conf.versionCheck && this.versionCheck('前端', feMinVersion, ARTALK_VERSION)) return
135
- if (this.ctx.conf.versionCheck && this.versionCheck('后端', backendMinVersion, data.api_version?.version)) return
139
+ if (this.ctx.conf.versionCheck && this.versionCheck('frontend', feMinVersion, ARTALK_VERSION)) return
140
+ if (this.ctx.conf.versionCheck && this.versionCheck('backend', backendMinVersion, data.api_version?.version)) return
136
141
 
137
142
  // 图片上传功能
138
143
  if (data.conf && typeof data.conf.img_upload === "boolean") {
@@ -148,8 +153,8 @@ export default class ListLite extends Component {
148
153
  // 加载后事件
149
154
  this.refreshUI()
150
155
 
151
- this.ctx.trigger('unread-update', { notifies: data.unread || [] })
152
- this.ctx.trigger('comments-loaded')
156
+ this.ctx.updateNotifies(data.unread || [])
157
+ this.ctx.trigger('list-loaded')
153
158
  this.ctx.trigger('conf-updated')
154
159
 
155
160
  if (this.onAfterLoad) this.onAfterLoad(data)
@@ -179,11 +184,12 @@ export default class ListLite extends Component {
179
184
  onClick: async (o) => {
180
185
  await this.fetchComments(o)
181
186
  },
187
+ text: this.ctx.$t('loadMore'),
182
188
  })
183
189
  this.$el.append(this.readMoreBtn.$el)
184
190
 
185
191
  // 滚动到底部自动加载
186
- if (this.conf.pagination?.autoLoad) {
192
+ if (this.conf.pagination.autoLoad) {
187
193
  // 添加滚动事件监听
188
194
  const at = this.scrollListenerAt || document
189
195
  if (this.autoLoadScrollEvent) at.removeEventListener('scroll', this.autoLoadScrollEvent) // 解除原有
@@ -210,7 +216,7 @@ export default class ListLite extends Component {
210
216
  pageSize: this.pageSize,
211
217
  onChange: async (o) => {
212
218
  if (this.ctx.conf.editorTravel === true) {
213
- this.ctx.trigger('editor-travel-back') // 防止评论框被吞
219
+ this.ctx.editorTravelBack() // 防止评论框被吞
214
220
  }
215
221
 
216
222
  await this.fetchComments(o)
@@ -237,14 +243,14 @@ export default class ListLite extends Component {
237
243
 
238
244
  // 加载更多按钮显示错误
239
245
  if (offset !== 0 && this.pageMode === 'read-more') {
240
- this.readMoreBtn?.showErr(`获取失败`)
246
+ this.readMoreBtn?.showErr(this.$t('loadFail'))
241
247
  return
242
248
  }
243
249
 
244
250
  // 显示错误对话框
245
- const $err = Utils.createElement(`<span>${msg},无法获取评论列表数据<br/></span>`)
251
+ const $err = Utils.createElement(`<span>${msg},${this.$t('listLoadFailMsg')}<br/></span>`)
246
252
 
247
- const $retryBtn = Utils.createElement('<span style="cursor:pointer;">点击重新获取</span>')
253
+ const $retryBtn = Utils.createElement(`<span style="cursor:pointer;">${this.$t('listRetry')}</span>`)
248
254
  $retryBtn.onclick = () => (this.fetchComments(0))
249
255
  $err.appendChild($retryBtn)
250
256
 
@@ -264,9 +270,9 @@ export default class ListLite extends Component {
264
270
  sidebarView = `sites|${JSON.stringify(viewLoadParam)}`
265
271
  }
266
272
 
267
- adminBtn.onclick = () => (this.ctx.trigger('sidebar-show', {
268
- view: sidebarView
269
- }))
273
+ adminBtn.onclick = () => this.ctx.showSidebar({
274
+ view: sidebarView as any
275
+ })
270
276
 
271
277
  Ui.setError(this.$el, $err)
272
278
  }
@@ -274,7 +280,7 @@ export default class ListLite extends Component {
274
280
  /** 刷新界面 */
275
281
  public refreshUI() {
276
282
  // 无评论
277
- const isNoComment = this.commentList.length <= 0
283
+ const isNoComment = this.ctx.getCommentList().length <= 0
278
284
  let $noComment = this.$commentsWrap.querySelector<HTMLElement>('.atk-list-no-comment')
279
285
 
280
286
  if (isNoComment) {
@@ -288,31 +294,35 @@ export default class ListLite extends Component {
288
294
  }
289
295
 
290
296
  // 仅管理员显示控制
291
- this.ctx.trigger('check-admin-show-el')
297
+ this.ctx.checkAdminShowEl()
298
+ }
299
+
300
+ /** 重新加载列表 */
301
+ public reload() {
302
+ this.fetchComments(0)
292
303
  }
293
304
 
294
305
  /** 创建新评论 */
295
306
  protected createComment(cData: CommentData, ctxData?: CommentData[]) {
296
- if (!ctxData) ctxData = this.commentDataList
297
-
298
- const comment = new Comment(this.ctx, cData)
299
- comment.flatMode = this.flatMode
300
- comment.afterRender = () => {
301
- if (this.renderComment) this.renderComment(comment)
302
- }
303
- comment.onDelete = (c) => {
304
- this.deleteComment(c)
305
- this.refreshUI()
306
- }
307
-
308
- // 子评论查找回复对象
309
- comment.replyTo = (cData.rid ? ctxData.find(c => c.id === cData.rid) : undefined)
307
+ if (!ctxData) ctxData = this.ctx.getCommentDataList()
308
+
309
+ const comment = new Comment(this.ctx, cData, {
310
+ isFlatMode: this.flatMode,
311
+ afterRender: () => {
312
+ if (this.renderComment) this.renderComment(comment)
313
+ },
314
+ onDelete: (c: Comment) => {
315
+ this.ctx.deleteComment(c)
316
+ this.refreshUI()
317
+ },
318
+ replyTo: (cData.rid ? ctxData.find(c => c.id === cData.rid) : undefined)
319
+ })
310
320
 
311
321
  // 渲染元素
312
322
  comment.render()
313
323
 
314
324
  // 放入 comment 总表中
315
- this.commentList.push(comment)
325
+ this.ctx.getCommentList().push(comment)
316
326
 
317
327
  return comment
318
328
  }
@@ -337,7 +347,7 @@ export default class ListLite extends Component {
337
347
 
338
348
  // 显示并播放渐入动画
339
349
  this.$commentsWrap.appendChild(rootC.getEl())
340
- rootC.playFadeInAnim()
350
+ rootC.getRender().playFadeAnim()
341
351
 
342
352
  // 加载子评论
343
353
  const that = this
@@ -355,7 +365,7 @@ export default class ListLite extends Component {
355
365
  })(rootC, rootNode)
356
366
 
357
367
  // 限高检测
358
- rootC.checkHeightLimit()
368
+ rootC.getRender().checkHeightLimit()
359
369
  })
360
370
  }
361
371
 
@@ -369,11 +379,11 @@ export default class ListLite extends Component {
369
379
  if (cData.visible) {
370
380
  if (insertMode === 'append') this.$commentsWrap.append(comment.getEl())
371
381
  if (insertMode === 'prepend') this.$commentsWrap.prepend(comment.getEl())
372
- comment.playFadeInAnim()
382
+ comment.getRender().playFadeAnim()
373
383
  }
374
384
 
375
385
  // 平铺评论插入后 · 内容限高检测
376
- comment.checkHeightLimit()
386
+ comment.getRender().checkHeightLimit()
377
387
 
378
388
  return comment
379
389
  }
@@ -389,24 +399,24 @@ export default class ListLite extends Component {
389
399
  this.$commentsWrap.prepend(comment.getEl())
390
400
  } else {
391
401
  // 子评论 新增
392
- const parent = this.findComment(commentData.rid)
402
+ const parent = this.ctx.findComment(commentData.rid)
393
403
  if (parent) {
394
404
  parent.putChild(comment, (this.nestSortBy === 'DATE_ASC' ? 'append' : 'prepend'))
395
405
 
396
406
  // 若父评论存在 “子评论部分” 限高,取消限高
397
407
  comment.getParents().forEach((p) => {
398
- if (p.$children) p.heightLimitRemove(p.$children)
408
+ p.getRender().heightLimitRemoveForChildren()
399
409
  })
400
410
  }
401
411
  }
402
412
 
403
- comment.checkHeightLimit()
413
+ comment.getRender().checkHeightLimit()
404
414
 
405
415
  Ui.scrollIntoView(comment.getEl()) // 滚动到可以见
406
- comment.playFadeInAnim() // 播放评论渐出动画
416
+ comment.getRender().playFadeAnim() // 播放评论渐出动画
407
417
  } else {
408
418
  // 平铺模式
409
- const comment = this.putCommentFlatMode(commentData, this.commentDataList, 'prepend')
419
+ const comment = this.putCommentFlatMode(commentData, this.ctx.getCommentDataList(), 'prepend')
410
420
  Ui.scrollIntoView(comment.getEl()) // 滚动到可见
411
421
  }
412
422
 
@@ -415,36 +425,8 @@ export default class ListLite extends Component {
415
425
 
416
426
  // 评论新增后
417
427
  this.refreshUI()
418
- this.ctx.trigger('comments-loaded')
419
- }
420
-
421
- /** 查找评论项 */
422
- protected findComment(id: number): Comment|undefined {
423
- return this.commentList.find(c => c.data.id === id)
424
- }
425
-
426
- /** 删除评论 */
427
- public deleteComment(_comment: number|Comment) {
428
- let comment: Comment
429
- if (typeof _comment === 'number') {
430
- const findComment = this.findComment(_comment)
431
- if (!findComment) throw Error(`未找到评论 ${_comment}`)
432
- comment = findComment
433
- } else comment = _comment
434
-
435
- comment.getEl().remove()
436
- this.commentList.splice(this.commentList.indexOf(comment), 1)
437
-
438
- if (this.data) this.data.total -= 1 // 评论数减 1
439
-
440
- this.refreshUI()
441
- }
442
-
443
- /** 清空所有评论 */
444
- public clearAllComments() {
445
- this.$commentsWrap.innerHTML = ''
446
- this.data = undefined
447
- this.commentList = []
428
+ this.ctx.trigger('list-loaded')
429
+ this.ctx.trigger('list-inserted', commentData)
448
430
  }
449
431
 
450
432
  /** 更新未读数据 */
@@ -453,33 +435,31 @@ export default class ListLite extends Component {
453
435
 
454
436
  // 高亮评论
455
437
  if (this.unreadHighlight === true) {
456
- this.commentList.forEach((comment) => {
457
- const notify = this.unread.find(o => o.comment_id === comment.data.id)
438
+ this.ctx.getCommentList().forEach((comment) => {
439
+ const notify = this.unread.find(o => o.comment_id === comment.getID())
458
440
  if (notify) {
459
- comment.setUnread(true)
460
- comment.setOpenURL(notify.read_link)
461
- comment.openEvt = () => {
462
- this.unread = this.unread.filter(o => o.comment_id !== comment.data.id) // remove
463
- this.ctx.trigger('unread-update', {
464
- notifies: this.unread
465
- })
466
- }
441
+ comment.getRender().setUnread(true)
442
+ comment.getRender().setOpenAction(() => {
443
+ window.open(notify.read_link)
444
+ this.unread = this.unread.filter(o => o.comment_id !== comment.getID()) // remove
445
+ this.ctx.updateNotifies(this.unread)
446
+ })
467
447
  } else {
468
- comment.setUnread(false)
448
+ comment.getRender().setUnread(false)
469
449
  }
470
450
  })
471
451
  }
472
452
  }
473
453
 
474
454
  /** 版本检测 */
475
- public versionCheck(name: '前端'|'后端', needVersion: string, curtVersion: string): boolean {
455
+ public versionCheck(name: 'frontend'|'backend', needVersion: string, curtVersion: string): boolean {
476
456
  const needUpdate = Utils.versionCompare(needVersion, curtVersion) === 1
477
457
  if (needUpdate) {
478
458
  // 需要更新
479
- const errEl = Utils.createElement(`<div>Artalk ${name}版本已过时,请更新以获得完整体验<br/>`
459
+ const errEl = Utils.createElement(`<div>Artalk ${this.$t(name)}版本已过时,请更新以获得完整体验<br/>`
480
460
  + `如果你是管理员,请前往 “<a href="https://artalk.js.org/" target="_blank">官方文档</a>” 获得帮助`
481
461
  + `<br/><br/>`
482
- + `<span style="color: var(--at-color-meta);">当前${name}版本 ${curtVersion},需求版本 >= ${needVersion}</span><br/><br/>`
462
+ + `<span style="color: var(--at-color-meta);">当前${this.$t(name)}版本 ${curtVersion},需求版本 >= ${needVersion}</span><br/><br/>`
483
463
  + `</div>`)
484
464
  const ignoreBtn = Utils.createElement('<span style="cursor:pointer;">忽略</span>')
485
465
  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,10 @@
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
- import Api from '../api'
8
- import ListHTML from './html/list.html?raw'
7
+ import ListHTML from './list.html?raw'
9
8
  import ListLite from './list-lite'
10
9
 
11
10
  export default class List extends ListLite {
@@ -13,6 +12,7 @@ export default class List extends ListLite {
13
12
  private $openSidebarBtn!: HTMLElement
14
13
  private $unreadBadge!: HTMLElement
15
14
  private $commentCount!: HTMLElement
15
+ private $commentCountNum!: HTMLElement
16
16
  private $dropdownWrap?: HTMLElement
17
17
 
18
18
  constructor (ctx: Context) {
@@ -25,24 +25,29 @@ export default class List extends ListLite {
25
25
  this.$el = el
26
26
 
27
27
  // 平铺模式
28
- let flatMode = false
29
- if (this.ctx.conf.flatMode === 'auto') {
28
+ if (this.ctx.conf.flatMode === true) {
29
+ this.flatMode = true // 遵循配置总是开启平铺模式
30
+ } else if (this.conf.nestMax && this.conf.nestMax <= 1) {
31
+ this.flatMode = true // 嵌套层数值无效时,强制开启平铺模式
32
+ } else if (this.ctx.conf.flatMode === 'auto') {
33
+ // 自动判断启用平铺模式
30
34
  if (window.matchMedia("(max-width: 768px)").matches)
31
- flatMode = true
32
- } else if (this.ctx.conf.flatMode === true) {
33
- flatMode = true
35
+ this.flatMode = true
34
36
  }
35
- 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
  }
@@ -1,4 +1,3 @@
1
- @font-family: "Helvetica Neue", "PingFangSC-Light", "Hiragino Sans GB", "Microsoft YaHei", "WenQuanYi Micro Hei", sans-serif;
2
1
  @font-size: 14px;
3
2
  @line-height: 1.6em;
4
- @block-radius: 4px;
3
+ @block-radius: 6px;