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.
- package/dist/Artalk.css +1 -1
- package/dist/Artalk.es.js +3046 -2342
- package/dist/Artalk.iife.js +1 -1
- package/dist/Artalk.js +1 -1
- package/dist/ArtalkLite.css +1 -0
- package/dist/ArtalkLite.es.js +5096 -0
- package/dist/ArtalkLite.iife.js +1 -0
- package/dist/ArtalkLite.js +1 -0
- package/index.html +5 -3
- package/package.json +7 -5
- package/src/api/index.ts +24 -4
- package/src/api/request.ts +50 -81
- package/src/artalk.ts +83 -57
- package/src/comment/actions.ts +87 -0
- package/src/{components/html → comment}/comment.html +1 -1
- package/src/comment/comment.ts +191 -0
- package/src/comment/index.ts +3 -0
- package/src/comment/render.ts +425 -0
- package/src/components/action-btn.ts +6 -3
- package/src/components/dialog.ts +7 -3
- package/src/components/read-more-btn.ts +6 -2
- package/src/context.ts +200 -13
- package/src/defaults.ts +19 -6
- package/src/editor/editor.html +18 -0
- package/src/editor/editor.ts +420 -0
- package/src/editor/index.ts +3 -0
- package/src/editor/plugs/editor-plug.ts +51 -0
- package/src/{components/editor-plugs → editor/plugs}/emoticons-plug.less +1 -0
- package/src/{components/editor-plugs → editor/plugs}/emoticons-plug.ts +65 -63
- package/src/editor/plugs/header-input-plug.ts +79 -0
- package/src/{components/editor-plugs → editor/plugs}/preview-plug.less +0 -0
- package/src/editor/plugs/preview-plug.ts +40 -0
- package/src/editor/plugs/upload-plug.ts +125 -0
- package/src/i18n/en.ts +77 -0
- package/src/i18n/index.ts +21 -0
- package/src/i18n/zh-CN.ts +81 -0
- package/src/layer/index.ts +4 -0
- package/src/{components → layer}/layer.ts +9 -9
- package/src/{components/html → layer}/sidebar-layer.html +0 -0
- package/src/{components → layer}/sidebar-layer.ts +17 -46
- package/src/lib/checker/admin-checker.ts +7 -6
- package/src/lib/checker/captcha-checker.ts +5 -5
- package/src/lib/checker/index.ts +22 -17
- package/src/lib/component.ts +7 -2
- package/src/lib/ui.ts +3 -10
- package/src/lib/user.ts +20 -3
- package/src/lib/utils.ts +23 -9
- package/src/list/index.ts +3 -0
- package/src/{components → list}/list-lite.ts +87 -111
- package/src/{components → list}/list-nest.ts +0 -0
- package/src/{components/html → list}/list.html +3 -6
- package/src/{components → list}/list.ts +37 -35
- package/src/style/comment.less +23 -10
- package/src/style/editor.less +16 -10
- package/src/style/list.less +4 -7
- package/src/style/main.less +3 -1
- package/src/style/pagination.less +1 -1
- package/test/ArtalkLite.html +15 -0
- package/types/artalk-config.d.ts +52 -31
- package/types/context.d.ts +128 -0
- package/types/event.d.ts +6 -66
- package/types/global.d.ts +1 -0
- package/{vite-common.config.ts → vite-base.config.ts} +6 -4
- package/vite-demo.config.ts +2 -4
- package/vite-lite.config.ts +22 -0
- package/vite.config.ts +9 -18
- package/src/components/_component.ts.txt +0 -10
- package/src/components/comment.ts +0 -605
- package/src/components/editor-plugs/_example-plug.ts.txt +0 -29
- package/src/components/editor-plugs/editor-plug.ts +0 -20
- package/src/components/editor-plugs/preview-plug.ts +0 -48
- package/src/components/editor.ts +0 -604
- package/src/components/html/editor.html +0 -18
|
@@ -1,31 +1,28 @@
|
|
|
1
|
-
import { ListData, CommentData, NotifyData
|
|
2
|
-
import Context from '
|
|
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 '
|
|
8
|
-
import Pagination from '
|
|
9
|
-
import ReadMoreBtn from '
|
|
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
|
|
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
|
-
|
|
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
|
-
|
|
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('
|
|
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
|
|
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('
|
|
132
|
-
if (this.ctx.conf.versionCheck && this.versionCheck('
|
|
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.
|
|
149
|
-
this.ctx.trigger('
|
|
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
|
|
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.
|
|
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}
|
|
252
|
+
const $err = Utils.createElement(`<span>${msg},${this.$t('listLoadFailMsg')}<br/></span>`)
|
|
243
253
|
|
|
244
|
-
const $retryBtn = Utils.createElement(
|
|
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 = () =>
|
|
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.
|
|
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.
|
|
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.
|
|
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
|
-
|
|
296
|
-
comment.
|
|
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
|
-
|
|
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.
|
|
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.
|
|
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
|
-
|
|
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.
|
|
417
|
+
comment.getRender().playFadeAnim() // 播放评论渐出动画
|
|
412
418
|
} else {
|
|
413
419
|
// 平铺模式
|
|
414
|
-
const comment = this.putCommentFlatMode(commentData, this.
|
|
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('
|
|
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.
|
|
462
|
-
const notify = this.unread.find(o => o.comment_id === comment.
|
|
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.
|
|
466
|
-
|
|
467
|
-
this.unread = this.unread.filter(o => o.comment_id !== comment.
|
|
468
|
-
this.ctx.
|
|
469
|
-
|
|
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: '
|
|
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
|
|
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"
|
|
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 '
|
|
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 './
|
|
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
|
|
39
|
-
this.pageSize = this.conf.pagination
|
|
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.
|
|
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.$
|
|
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.
|
|
99
|
-
this.$openSidebarBtn.querySelector<HTMLElement>('.atk-text')
|
|
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.
|
|
104
|
-
this.$closeCommentBtn.innerHTML = '
|
|
102
|
+
this.ctx.editorClose()
|
|
103
|
+
this.$closeCommentBtn.innerHTML = this.$t('openComment')
|
|
105
104
|
} else {
|
|
106
|
-
this.ctx.
|
|
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.
|
|
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
|
-
|
|
146
|
+
this.ctx.getApi().markRead(notifyKey)
|
|
148
147
|
.then(() => {
|
|
149
148
|
this.unread = this.unread.filter(o => o.comment_id !== commentId)
|
|
150
|
-
this.
|
|
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
|
-
|
|
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.
|
|
181
|
-
|
|
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.
|
|
185
|
+
this.ctx.editorShowNotify(`${this.$t('editFail')}: ${err.msg || String(err)}`, 'e')
|
|
189
186
|
})
|
|
190
187
|
.finally(() => {
|
|
191
|
-
this.ctx.
|
|
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
|
-
['
|
|
220
|
-
['
|
|
221
|
-
['
|
|
222
|
-
['
|
|
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
|
}
|