artalk 2.1.3 → 2.1.4
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 +285 -323
- package/dist/Artalk.iife.js +1 -1
- package/dist/Artalk.js +1 -1
- package/package.json +6 -9
- package/src/api/index.ts +2 -3
- package/src/artalk.ts +2 -2
- package/src/components/action-btn.ts +1 -1
- package/src/components/comment.ts +88 -3
- package/src/components/editor-plugs/emoticons-plug.less +21 -11
- package/src/components/editor-plugs/emoticons-plug.ts +18 -18
- package/src/components/editor-plugs/preview-plug.less +1 -1
- package/src/components/editor.ts +15 -20
- package/src/components/html/comment.html +6 -13
- package/src/components/html/editor.html +8 -9
- package/src/components/html/list.html +1 -1
- package/src/components/list-lite.ts +203 -299
- package/src/components/list.ts +11 -9
- package/src/components/pagination.ts +2 -2
- package/src/components/read-more-btn.ts +27 -4
- package/src/components/sidebar-views/comments-view.ts +4 -5
- package/src/defaults.ts +1 -1
- package/src/lib/utils.ts +2 -1
- package/src/style/_color.less +19 -23
- package/src/style/_extend.less +3 -3
- package/src/style/_variables.less +0 -24
- package/src/style/comment.less +191 -197
- package/src/style/editor.less +69 -94
- package/src/style/item-text-editor.less +2 -2
- package/src/style/list.less +13 -13
- package/src/style/main.less +31 -31
- package/src/style/page-list.less +4 -4
- package/src/style/pagination.less +6 -6
- package/src/style/sidebar.less +35 -35
- package/src/style/site-list.less +13 -13
- package/types/artalk-data.d.ts +2 -2
|
@@ -9,50 +9,45 @@ import Pagination from './pagination'
|
|
|
9
9
|
import ReadMoreBtn from './read-more-btn'
|
|
10
10
|
|
|
11
11
|
export default class ListLite extends Component {
|
|
12
|
-
|
|
12
|
+
protected $commentsWrap: HTMLElement
|
|
13
|
+
protected comments: Comment[] = []
|
|
13
14
|
|
|
14
|
-
|
|
15
|
-
|
|
15
|
+
protected data?: ListData
|
|
16
|
+
protected isLoading: boolean = false
|
|
16
17
|
|
|
17
|
-
public
|
|
18
|
-
private pageSize: number = 15 // 每次请求获取量
|
|
19
|
-
private offset: number = 0
|
|
20
|
-
public type?: 'all'|'mentions'|'mine'|'pending'
|
|
18
|
+
public noCommentText = '无内容' // 无评论时显示
|
|
21
19
|
|
|
22
|
-
|
|
23
|
-
public
|
|
24
|
-
public paramsEditor?: (params: any) => void
|
|
25
|
-
public onAfterLoad?: (data: ListData) => void
|
|
20
|
+
/** 平铺模式 */
|
|
21
|
+
public flatMode = false
|
|
26
22
|
|
|
27
|
-
|
|
28
|
-
public
|
|
23
|
+
/** 分页 */
|
|
24
|
+
public pageMode: 'pagination'|'read-more' = 'pagination'
|
|
25
|
+
public pageSize: number = 20 // 每次请求获取量
|
|
26
|
+
public scrollListenerAt?: HTMLElement // 监听指定元素上的滚动
|
|
27
|
+
public repositionAt?: HTMLElement // 翻页归位到指定元素
|
|
29
28
|
|
|
30
|
-
|
|
29
|
+
protected pagination?: Pagination // 分页条
|
|
30
|
+
protected readMoreBtn?: ReadMoreBtn // 阅读更多
|
|
31
|
+
protected autoLoadScrollEvent?: any // 自动加载滚动事件
|
|
31
32
|
|
|
32
|
-
public
|
|
33
|
-
public
|
|
34
|
-
public
|
|
35
|
-
public autoLoadScrollEvent?: any
|
|
36
|
-
public autoLoadListenerAt?: HTMLElement
|
|
33
|
+
public renderComment?: (comment: Comment) => void
|
|
34
|
+
public paramsEditor?: (params: any) => void
|
|
35
|
+
public onAfterLoad?: (data: ListData) => void
|
|
37
36
|
|
|
38
|
-
|
|
39
|
-
|
|
37
|
+
// 未读标记
|
|
38
|
+
protected unread: NotifyData[] = []
|
|
39
|
+
public unreadHighlight?: boolean // 高亮未读
|
|
40
40
|
|
|
41
|
-
constructor (ctx: Context
|
|
41
|
+
constructor (ctx: Context) {
|
|
42
42
|
super(ctx)
|
|
43
43
|
|
|
44
|
-
|
|
44
|
+
// 初始化元素
|
|
45
45
|
this.$el = Utils.createElement(
|
|
46
46
|
`<div class="atk-list-lite">
|
|
47
47
|
<div class="atk-list-comments-wrap"></div>
|
|
48
48
|
</div>`)
|
|
49
49
|
this.$commentsWrap = this.$el.querySelector('.atk-list-comments-wrap')!
|
|
50
50
|
|
|
51
|
-
// 查看更多
|
|
52
|
-
this.pageSize = this.conf.pagination ? (this.conf.pagination.pageSize || this.pageSize) : this.pageSize
|
|
53
|
-
|
|
54
|
-
this.noCommentText = this.conf.noComment || '无评论'
|
|
55
|
-
|
|
56
51
|
// 评论时间自动更新
|
|
57
52
|
window.setInterval(() => {
|
|
58
53
|
this.$el.querySelectorAll<HTMLElement>('[data-atk-comment-date]').forEach(el => {
|
|
@@ -61,13 +56,15 @@ export default class ListLite extends Component {
|
|
|
61
56
|
})
|
|
62
57
|
}, 30 * 1000) // 30s 更新一次
|
|
63
58
|
|
|
59
|
+
// 事件监听
|
|
64
60
|
this.ctx.on('unread-update', (data) => (this.updateUnread(data.notifies)))
|
|
65
61
|
}
|
|
66
62
|
|
|
67
|
-
|
|
68
|
-
|
|
63
|
+
/** 评论获取 */
|
|
64
|
+
public async fetchComments(offset: number) {
|
|
65
|
+
if (this.isLoading) return
|
|
69
66
|
|
|
70
|
-
//
|
|
67
|
+
// 加载动画
|
|
71
68
|
const showLoading = () => {
|
|
72
69
|
this.isLoading = true
|
|
73
70
|
if (offset === 0) Ui.showLoading(this.$el)
|
|
@@ -80,184 +77,186 @@ export default class ListLite extends Component {
|
|
|
80
77
|
else if (this.pageMode === 'read-more') this.readMoreBtn!.setLoading(false)
|
|
81
78
|
else if (this.pageMode === 'pagination') this.pagination!.setLoading(false)
|
|
82
79
|
}
|
|
83
|
-
|
|
84
80
|
showLoading()
|
|
81
|
+
|
|
82
|
+
// 事件通知(开始加载评论)
|
|
85
83
|
this.ctx.trigger('comments-load')
|
|
86
84
|
|
|
85
|
+
// 清空评论(加载按钮)
|
|
86
|
+
if (this.pageMode === 'read-more' && offset === 0) { this.clearAllComments() }
|
|
87
|
+
|
|
88
|
+
// 请求评论数据
|
|
87
89
|
let listData: ListData
|
|
88
90
|
try {
|
|
89
|
-
listData = await new Api(this.ctx).get(offset, this.
|
|
91
|
+
listData = await new Api(this.ctx).get(offset, this.pageSize, this.flatMode, this.paramsEditor)
|
|
90
92
|
} catch (e: any) {
|
|
91
|
-
this.onError(e.msg || String(e))
|
|
93
|
+
this.onError(e.msg || String(e), offset)
|
|
92
94
|
throw e
|
|
93
95
|
} finally {
|
|
94
96
|
hideLoading()
|
|
95
97
|
}
|
|
96
98
|
|
|
97
|
-
//
|
|
98
|
-
|
|
99
|
-
const needUpdate = this.apiVersionCheck(listData.api_version || {})
|
|
100
|
-
if (needUpdate) return
|
|
101
|
-
}
|
|
102
|
-
|
|
103
|
-
// load data
|
|
104
|
-
this.offset = offset
|
|
99
|
+
// 清除原有错误
|
|
100
|
+
Ui.setError(this.$el, null)
|
|
105
101
|
|
|
102
|
+
// 装载数据
|
|
106
103
|
try {
|
|
107
104
|
this.onLoad(listData, offset)
|
|
108
|
-
|
|
109
|
-
if (this.onAfterLoad) {
|
|
110
|
-
this.onAfterLoad(listData)
|
|
111
|
-
}
|
|
112
105
|
} catch (e: any) {
|
|
113
|
-
this.onError(String(e))
|
|
106
|
+
this.onError(String(e), offset)
|
|
114
107
|
throw e
|
|
115
108
|
} finally {
|
|
116
109
|
hideLoading()
|
|
117
110
|
}
|
|
118
111
|
}
|
|
119
112
|
|
|
120
|
-
|
|
121
|
-
|
|
122
|
-
|
|
123
|
-
if (this.pageMode === 'pagination') {
|
|
124
|
-
this.clearAllComments()
|
|
125
|
-
}
|
|
113
|
+
protected onLoad(data: ListData, offset: number) {
|
|
114
|
+
// 清空评论(分页条)
|
|
115
|
+
if (this.pageMode === 'pagination') { this.clearAllComments() }
|
|
126
116
|
|
|
127
117
|
this.data = data
|
|
118
|
+
|
|
119
|
+
// 版本检测
|
|
120
|
+
if (this.ctx.conf.versionCheck && this.versionCheck(data.api_version)) return
|
|
121
|
+
|
|
122
|
+
// 导入数据
|
|
128
123
|
this.importComments(data.comments)
|
|
129
124
|
|
|
130
|
-
//
|
|
131
|
-
|
|
132
|
-
this.onLoadInit()
|
|
133
|
-
}
|
|
125
|
+
// 分页方式
|
|
126
|
+
this.refreshPagination(offset, (this.flatMode ? data.total : data.total_roots)) // 初始化
|
|
134
127
|
|
|
135
|
-
|
|
136
|
-
|
|
137
|
-
}
|
|
138
|
-
if (this.pageMode === 'read-more') {
|
|
139
|
-
if (this.hasMoreComments) this.readMoreBtn!.show()
|
|
140
|
-
else this.readMoreBtn!.hide()
|
|
141
|
-
}
|
|
128
|
+
// 加载后事件
|
|
129
|
+
this.refreshUI()
|
|
142
130
|
|
|
143
131
|
this.ctx.trigger('unread-update', { notifies: data.unread || [] })
|
|
132
|
+
this.ctx.trigger('comments-loaded')
|
|
144
133
|
|
|
145
|
-
this.
|
|
134
|
+
if (this.onAfterLoad) this.onAfterLoad(data)
|
|
146
135
|
}
|
|
147
136
|
|
|
148
|
-
/**
|
|
149
|
-
|
|
150
|
-
|
|
151
|
-
|
|
152
|
-
|
|
137
|
+
/** 分页模式 */
|
|
138
|
+
private refreshPagination(offset: number, total: number) {
|
|
139
|
+
const modePagination = (this.pageMode === 'pagination')
|
|
140
|
+
const modeReadMoreBtn = (this.pageMode === 'read-more')
|
|
141
|
+
const initialized = (modePagination) ? !!this.pagination : !!this.readMoreBtn
|
|
142
|
+
|
|
143
|
+
// 初始化
|
|
144
|
+
if (!initialized) {
|
|
145
|
+
this.initPagination()
|
|
153
146
|
}
|
|
154
147
|
|
|
148
|
+
// 更新
|
|
149
|
+
if (modePagination) this.pagination!.update(offset, total)
|
|
150
|
+
if (modeReadMoreBtn) this.readMoreBtn!.update(offset, total)
|
|
151
|
+
}
|
|
152
|
+
|
|
153
|
+
private initPagination() {
|
|
154
|
+
// 加载更多按钮
|
|
155
155
|
if (this.pageMode === 'read-more') {
|
|
156
|
-
|
|
157
|
-
|
|
158
|
-
onClick: async () => {
|
|
159
|
-
|
|
160
|
-
await this.reqComments(offset)
|
|
156
|
+
this.readMoreBtn = new ReadMoreBtn({
|
|
157
|
+
pageSize: this.pageSize,
|
|
158
|
+
onClick: async (o) => {
|
|
159
|
+
await this.fetchComments(o)
|
|
161
160
|
},
|
|
162
161
|
})
|
|
163
|
-
|
|
164
|
-
else this.$el.append(readMoreBtn.$el)
|
|
165
|
-
this.readMoreBtn = readMoreBtn
|
|
162
|
+
this.$el.append(this.readMoreBtn.$el)
|
|
166
163
|
|
|
167
164
|
// 滚动到底部自动加载
|
|
168
165
|
if (this.conf.pagination?.autoLoad) {
|
|
166
|
+
// 添加滚动事件监听
|
|
167
|
+
const at = this.scrollListenerAt || document
|
|
168
|
+
if (this.autoLoadScrollEvent) at.removeEventListener('scroll', this.autoLoadScrollEvent) // 解除原有
|
|
169
169
|
this.autoLoadScrollEvent = () => {
|
|
170
170
|
if (this.pageMode !== 'read-more') return
|
|
171
|
-
if (!this.
|
|
171
|
+
if (!this.readMoreBtn) return
|
|
172
|
+
|
|
173
|
+
if (!this.readMoreBtn.hasMore) return
|
|
172
174
|
if (this.isLoading) return
|
|
173
175
|
|
|
174
176
|
const $target = this.$el.querySelector<HTMLElement>('.atk-list-comments-wrap > .atk-comment-wrap:nth-last-child(3)') // 获取倒数第3个评论元素
|
|
175
177
|
if (!$target) return
|
|
176
|
-
if (Ui.isVisible($target, this.
|
|
177
|
-
//
|
|
178
|
-
this.readMoreBtn!.click()
|
|
178
|
+
if (Ui.isVisible($target, this.scrollListenerAt)) {
|
|
179
|
+
this.readMoreBtn.click() // 自动点击加载更多按钮
|
|
179
180
|
}
|
|
180
181
|
}
|
|
181
|
-
const at = this.autoLoadListenerAt || document
|
|
182
182
|
at.addEventListener('scroll', this.autoLoadScrollEvent)
|
|
183
183
|
}
|
|
184
|
-
}
|
|
185
|
-
|
|
186
|
-
|
|
184
|
+
}
|
|
185
|
+
|
|
186
|
+
// 分页条
|
|
187
|
+
if (this.pageMode === 'pagination') {
|
|
188
|
+
this.pagination = new Pagination((!this.flatMode ? this.data!.total_roots : this.data!.total), {
|
|
187
189
|
pageSize: this.pageSize,
|
|
188
|
-
onChange: async (
|
|
190
|
+
onChange: async (o) => {
|
|
189
191
|
if (this.ctx.conf.editorTravel === true) {
|
|
190
192
|
this.ctx.trigger('editor-travel-back') // 防止评论框被吞
|
|
191
193
|
}
|
|
192
194
|
|
|
193
|
-
await this.
|
|
195
|
+
await this.fetchComments(o)
|
|
196
|
+
|
|
194
197
|
// 滚动到第一个评论的位置
|
|
195
|
-
if (this
|
|
196
|
-
|
|
197
|
-
if (!this.autoLoadListenerAt && this.$parent) {
|
|
198
|
-
topPos = Utils.getOffset(this.$parent).top
|
|
199
|
-
}
|
|
200
|
-
const at = this.autoLoadListenerAt || window
|
|
198
|
+
if (this.repositionAt) {
|
|
199
|
+
const at = this.scrollListenerAt || window
|
|
201
200
|
at.scroll({
|
|
202
|
-
top:
|
|
201
|
+
top: this.repositionAt ? Utils.getOffset(this.repositionAt).top : 0,
|
|
203
202
|
left: 0,
|
|
204
203
|
})
|
|
205
204
|
}
|
|
206
205
|
}
|
|
207
206
|
})
|
|
208
|
-
|
|
209
|
-
|
|
210
|
-
this.pagination = pagination
|
|
207
|
+
|
|
208
|
+
this.$el.append(this.pagination.$el)
|
|
211
209
|
}
|
|
212
210
|
}
|
|
213
211
|
|
|
214
|
-
|
|
212
|
+
/** 错误处理 */
|
|
213
|
+
protected onError(msg: any, offset: number) {
|
|
215
214
|
msg = String(msg)
|
|
216
215
|
console.error(msg)
|
|
217
|
-
|
|
218
|
-
|
|
219
|
-
|
|
220
|
-
retryBtn.onclick = () => {
|
|
221
|
-
this.reqComments(this.offset)
|
|
222
|
-
}
|
|
223
|
-
errEl.appendChild(retryBtn)
|
|
224
|
-
const adminBtn = Utils.createElement('<span atk-only-admin-show> | <span style="cursor:pointer;">打开控制台</span></span>')
|
|
225
|
-
adminBtn.onclick = () => {
|
|
226
|
-
this.ctx.trigger('sidebar-show')
|
|
227
|
-
}
|
|
228
|
-
if (!this.ctx.user.data.isAdmin) {
|
|
229
|
-
adminBtn.classList.add('atk-hide')
|
|
230
|
-
}
|
|
231
|
-
errEl.appendChild(adminBtn)
|
|
232
|
-
Ui.setError(this.$el, errEl)
|
|
233
|
-
} else {
|
|
216
|
+
|
|
217
|
+
// 加载更多按钮显示错误
|
|
218
|
+
if (offset !== 0 && this.pageMode === 'read-more') {
|
|
234
219
|
this.readMoreBtn?.showErr(`获取失败`)
|
|
220
|
+
return
|
|
235
221
|
}
|
|
222
|
+
|
|
223
|
+
// 显示错误对话框
|
|
224
|
+
const $err = Utils.createElement(`<span>${msg},无法获取评论列表数据<br/></span>`)
|
|
225
|
+
|
|
226
|
+
const $retryBtn = Utils.createElement('<span style="cursor:pointer;">点击重新获取</span>')
|
|
227
|
+
$retryBtn.onclick = () => (this.fetchComments(0))
|
|
228
|
+
$err.appendChild($retryBtn)
|
|
229
|
+
|
|
230
|
+
const adminBtn = Utils.createElement('<span atk-only-admin-show> | <span style="cursor:pointer;">打开控制台</span></span>')
|
|
231
|
+
adminBtn.onclick = () => (this.ctx.trigger('sidebar-show'))
|
|
232
|
+
if (!this.ctx.user.data.isAdmin) adminBtn.classList.add('atk-hide')
|
|
233
|
+
$err.appendChild(adminBtn)
|
|
234
|
+
|
|
235
|
+
Ui.setError(this.$el, $err)
|
|
236
236
|
}
|
|
237
237
|
|
|
238
238
|
/** 刷新界面 */
|
|
239
239
|
public refreshUI() {
|
|
240
|
-
//
|
|
241
|
-
const
|
|
242
|
-
let
|
|
243
|
-
|
|
244
|
-
if (
|
|
245
|
-
if (
|
|
246
|
-
|
|
247
|
-
this
|
|
248
|
-
|
|
240
|
+
// 无评论
|
|
241
|
+
const isNoComment = this.comments.length <= 0
|
|
242
|
+
let $noComment = this.$commentsWrap.querySelector<HTMLElement>('.atk-list-no-comment')
|
|
243
|
+
|
|
244
|
+
if (isNoComment) {
|
|
245
|
+
if (!$noComment) {
|
|
246
|
+
$noComment = Utils.createElement('<div class="atk-list-no-comment"></div>')
|
|
247
|
+
$noComment.innerHTML = this.noCommentText
|
|
248
|
+
this.$commentsWrap.appendChild($noComment)
|
|
249
249
|
}
|
|
250
|
+
} else {
|
|
251
|
+
$noComment?.remove()
|
|
250
252
|
}
|
|
251
253
|
|
|
252
|
-
if (!noComment && noCommentEl)
|
|
253
|
-
noCommentEl.remove()
|
|
254
|
-
|
|
255
254
|
// 仅管理员显示控制
|
|
256
255
|
this.ctx.trigger('check-admin-show-el')
|
|
257
256
|
}
|
|
258
257
|
|
|
259
258
|
/** 创建新评论 */
|
|
260
|
-
|
|
259
|
+
protected createComment(data: CommentData) {
|
|
261
260
|
const comment = new Comment(this.ctx, data)
|
|
262
261
|
comment.afterRender = () => {
|
|
263
262
|
if (this.renderComment) this.renderComment(comment)
|
|
@@ -271,216 +270,126 @@ export default class ListLite extends Component {
|
|
|
271
270
|
}
|
|
272
271
|
|
|
273
272
|
/** 导入评论 · 通过请求数据 */
|
|
274
|
-
public importComments(
|
|
275
|
-
|
|
276
|
-
|
|
277
|
-
|
|
278
|
-
|
|
273
|
+
public importComments(srcData: CommentData[]) {
|
|
274
|
+
if (this.flatMode) {
|
|
275
|
+
srcData.forEach((commentData: CommentData) => {
|
|
276
|
+
this.putCommentFlatMode(commentData, srcData, 'append')
|
|
277
|
+
})
|
|
278
|
+
} else {
|
|
279
|
+
this.importCommentsNesting(srcData)
|
|
280
|
+
}
|
|
281
|
+
}
|
|
279
282
|
|
|
280
|
-
|
|
281
|
-
|
|
282
|
-
|
|
283
|
+
// 导入评论 · 嵌套模式
|
|
284
|
+
private importCommentsNesting(srcData: CommentData[]) {
|
|
285
|
+
// 查找并导入所有子评论
|
|
286
|
+
const loadChildren = (parentC: Comment) => {
|
|
287
|
+
const children = srcData.filter(o => o.rid === parentC.data.id)
|
|
288
|
+
children.forEach((childData: CommentData) => {
|
|
289
|
+
const childC = this.createComment(childData)
|
|
283
290
|
childC.render()
|
|
291
|
+
|
|
292
|
+
// 插入到父评论中
|
|
284
293
|
parentC.putChild(childC)
|
|
285
|
-
|
|
294
|
+
|
|
295
|
+
// 递归加载子评论
|
|
296
|
+
loadChildren(childC)
|
|
286
297
|
})
|
|
287
298
|
}
|
|
288
299
|
|
|
289
|
-
//
|
|
290
|
-
|
|
291
|
-
|
|
292
|
-
|
|
293
|
-
|
|
294
|
-
rootComment.render()
|
|
295
|
-
this.comments.push(rootComment) // 将评论导入 comments 总表中
|
|
300
|
+
// 遍历 root 评论
|
|
301
|
+
const rootComments = srcData.filter((o) => o.rid === 0)
|
|
302
|
+
rootComments.forEach((rootData: CommentData) => {
|
|
303
|
+
const rootC = this.createComment(rootData)
|
|
304
|
+
rootC.render()
|
|
296
305
|
|
|
297
|
-
|
|
298
|
-
|
|
306
|
+
// 显示并播放渐入动画
|
|
307
|
+
this.$commentsWrap.appendChild(rootC.getEl())
|
|
308
|
+
rootC.playFadeInAnim()
|
|
299
309
|
|
|
300
|
-
|
|
301
|
-
|
|
302
|
-
} else {
|
|
303
|
-
// 平铺模式
|
|
304
|
-
rawData.forEach((commentData: CommentData) => {
|
|
305
|
-
this.putCommentFlatMode(commentData, rawData, 'append')
|
|
306
|
-
})
|
|
307
|
-
}
|
|
310
|
+
// 评论放入 comments 总表中
|
|
311
|
+
this.comments.push(rootC)
|
|
308
312
|
|
|
309
|
-
|
|
310
|
-
|
|
311
|
-
})
|
|
313
|
+
// 加载子评论
|
|
314
|
+
loadChildren(rootC)
|
|
312
315
|
|
|
313
|
-
|
|
314
|
-
|
|
316
|
+
// 限高检测
|
|
317
|
+
rootC.checkHeightLimit()
|
|
318
|
+
})
|
|
315
319
|
}
|
|
316
320
|
|
|
317
321
|
/** 导入评论 · 平铺模式 */
|
|
318
|
-
private putCommentFlatMode(
|
|
319
|
-
if (
|
|
320
|
-
const comment = this.createComment(
|
|
321
|
-
if (
|
|
322
|
-
const rComment =
|
|
322
|
+
private putCommentFlatMode(cData: CommentData, srcData: CommentData[], insertMode: 'append'|'prepend') {
|
|
323
|
+
if (cData.is_collapsed) cData.is_allow_reply = false
|
|
324
|
+
const comment = this.createComment(cData)
|
|
325
|
+
if (cData.rid !== 0) {
|
|
326
|
+
const rComment = srcData.find(o => o.id === cData.rid)
|
|
323
327
|
if (rComment) comment.replyTo = rComment
|
|
324
328
|
}
|
|
325
329
|
comment.render()
|
|
326
330
|
|
|
327
331
|
// 将评论导入 comments 总表中
|
|
328
|
-
if (insertMode === 'append')
|
|
329
|
-
|
|
330
|
-
|
|
331
|
-
|
|
332
|
-
|
|
333
|
-
|
|
334
|
-
|
|
335
|
-
if (insertMode === '
|
|
336
|
-
this.$commentsWrap.appendChild(comment.getEl())
|
|
337
|
-
} else {
|
|
338
|
-
this.$commentsWrap.prepend(comment.getEl())
|
|
339
|
-
}
|
|
332
|
+
if (insertMode === 'append') this.comments.push(comment)
|
|
333
|
+
if (insertMode === 'prepend') this.comments.unshift(comment)
|
|
334
|
+
|
|
335
|
+
// 可见评论添加到界面
|
|
336
|
+
// 注:不可见评论用于显示 “引用内容”
|
|
337
|
+
if (cData.visible) {
|
|
338
|
+
if (insertMode === 'append') this.$commentsWrap.append(comment.getEl())
|
|
339
|
+
if (insertMode === 'prepend') this.$commentsWrap.prepend(comment.getEl())
|
|
340
340
|
comment.playFadeInAnim()
|
|
341
341
|
}
|
|
342
342
|
|
|
343
|
-
|
|
343
|
+
// 平铺评论插入后 · 内容限高检测
|
|
344
|
+
comment.checkHeightLimit()
|
|
344
345
|
|
|
345
346
|
return comment
|
|
346
347
|
}
|
|
347
348
|
|
|
348
|
-
/**
|
|
349
|
+
/** 新增评论 · 首部添加 */
|
|
349
350
|
public insertComment(commentData: CommentData) {
|
|
350
351
|
if (!this.flatMode) {
|
|
352
|
+
// 嵌套模式
|
|
351
353
|
const comment = this.createComment(commentData)
|
|
352
354
|
comment.render()
|
|
353
355
|
|
|
354
356
|
if (commentData.rid === 0) {
|
|
357
|
+
// root评论 新增
|
|
355
358
|
this.$commentsWrap.prepend(comment.getEl())
|
|
356
359
|
this.comments.unshift(comment)
|
|
357
|
-
this.checkMoreHide(comment)
|
|
358
360
|
} else {
|
|
359
|
-
// 子评论
|
|
361
|
+
// 子评论 新增
|
|
360
362
|
const parent = this.findComment(commentData.rid)
|
|
361
363
|
if (parent) {
|
|
362
364
|
parent.putChild(comment)
|
|
363
|
-
|
|
364
|
-
|
|
365
|
-
|
|
365
|
+
|
|
366
|
+
// 若父评论存在 “子评论部分” 限高,取消限高
|
|
367
|
+
comment.getParents().forEach((p) => {
|
|
368
|
+
if (p.$children) p.heightLimitRemove(p.$children)
|
|
366
369
|
})
|
|
367
370
|
}
|
|
368
371
|
}
|
|
369
372
|
|
|
373
|
+
comment.checkHeightLimit()
|
|
374
|
+
|
|
370
375
|
Ui.scrollIntoView(comment.getEl()) // 滚动到可以见
|
|
371
376
|
comment.playFadeInAnim() // 播放评论渐出动画
|
|
372
377
|
} else {
|
|
378
|
+
// 平铺模式
|
|
373
379
|
const comment = this.putCommentFlatMode(commentData, this.comments.map(c => c.data), 'prepend')
|
|
374
|
-
Ui.scrollIntoView(comment.getEl()) //
|
|
375
|
-
}
|
|
376
|
-
|
|
377
|
-
if (this.data) this.data.total += 1 // 评论数增加 1
|
|
378
|
-
this.refreshUI() // 更新 list 界面
|
|
379
|
-
this.ctx.trigger('comments-loaded')
|
|
380
|
-
}
|
|
381
|
-
|
|
382
|
-
checkMoreHide(c: Comment) {
|
|
383
|
-
const check = () => {
|
|
384
|
-
// 子评论内容过多隐藏
|
|
385
|
-
this.checkMoreHideEl(c, 'children')
|
|
386
|
-
|
|
387
|
-
// 评论内容过多隐藏
|
|
388
|
-
this.checkMoreHideEl(c, 'content')
|
|
389
|
-
|
|
390
|
-
// 平铺模式回复内容
|
|
391
|
-
if (c.$replyTo) this.checkMoreHideEl(c, 'replyTo')
|
|
392
|
-
}
|
|
393
|
-
|
|
394
|
-
// 执行检测
|
|
395
|
-
check()
|
|
396
|
-
|
|
397
|
-
// 图片加载完后再检测一次
|
|
398
|
-
if (c.$content.querySelectorAll('img').length) {
|
|
399
|
-
Utils.onImagesLoaded(c.$content, () => {
|
|
400
|
-
check()
|
|
401
|
-
})
|
|
380
|
+
Ui.scrollIntoView(comment.getEl()) // 滚动到可见
|
|
402
381
|
}
|
|
403
|
-
}
|
|
404
382
|
|
|
405
|
-
|
|
406
|
-
|
|
407
|
-
const childrenH = this.ctx.conf.heightLimit?.children
|
|
408
|
-
const contentH = this.ctx.conf.heightLimit?.content
|
|
409
|
-
|
|
410
|
-
if (area === 'children' && (!childrenH)) return
|
|
411
|
-
if ((area === 'content' || area === 'replyTo') && (!contentH)) return
|
|
412
|
-
|
|
413
|
-
// 限高
|
|
414
|
-
if (area === 'children') allowHeight = childrenH || 300
|
|
415
|
-
else allowHeight = contentH || 200
|
|
416
|
-
|
|
417
|
-
// target 准备
|
|
418
|
-
let $target!: HTMLElement
|
|
419
|
-
if (area === 'children') $target = comment.$children!
|
|
420
|
-
else if (area === 'content') $target = comment.$content!
|
|
421
|
-
else if (area === 'replyTo') $target = comment.$replyTo!
|
|
422
|
-
if (!$target) return
|
|
423
|
-
|
|
424
|
-
// 阅读更多按钮
|
|
425
|
-
let $hideMoreOpenBtn = $target.querySelector<HTMLElement>('.atk-more-hide-open-btn')
|
|
426
|
-
|
|
427
|
-
const removeHideMore = () => {
|
|
428
|
-
$target.classList.remove('atk-comment-more-hide')
|
|
429
|
-
if ($hideMoreOpenBtn) $hideMoreOpenBtn.remove()
|
|
430
|
-
$target.style.height = ''
|
|
431
|
-
$target.style.overflow = ''
|
|
432
|
-
}
|
|
383
|
+
// 评论数增加 1
|
|
384
|
+
if (this.data) this.data.total += 1
|
|
433
385
|
|
|
434
|
-
|
|
435
|
-
|
|
436
|
-
|
|
437
|
-
$target.style.height = `${allowHeight}px`
|
|
438
|
-
$target.style.overflow = 'hidden'
|
|
439
|
-
if (!$hideMoreOpenBtn) {
|
|
440
|
-
$hideMoreOpenBtn = Utils.createElement(`<div class="atk-more-hide-open-btn">阅读更多</span>`)
|
|
441
|
-
$hideMoreOpenBtn.onclick = (e) => {
|
|
442
|
-
e.stopPropagation()
|
|
443
|
-
removeHideMore()
|
|
444
|
-
// 阅读更多过后,再检查隐藏
|
|
445
|
-
if (comment.getIsRoot()) {
|
|
446
|
-
const children = comment.getChildren()
|
|
447
|
-
if (children.length > 1) {
|
|
448
|
-
this.eachComment(children, (c) => {
|
|
449
|
-
this.checkMoreHideEl(c, 'content', contentH || 200)
|
|
450
|
-
})
|
|
451
|
-
}
|
|
452
|
-
}
|
|
453
|
-
}
|
|
454
|
-
$target.append($hideMoreOpenBtn)
|
|
455
|
-
}
|
|
456
|
-
}
|
|
457
|
-
}
|
|
458
|
-
|
|
459
|
-
public removeHideMore($target: HTMLElement) {
|
|
460
|
-
const $hideMoreOpenBtn = $target.querySelector<HTMLElement>('.atk-more-hide-open-btn')
|
|
461
|
-
$target.classList.remove('atk-comment-more-hide')
|
|
462
|
-
if ($hideMoreOpenBtn) $hideMoreOpenBtn.remove()
|
|
463
|
-
$target.style.height = ''
|
|
464
|
-
$target.style.overflow = ''
|
|
465
|
-
}
|
|
466
|
-
|
|
467
|
-
/** 获取评论总数 (包括子评论) */
|
|
468
|
-
get commentsCount(): number {
|
|
469
|
-
return Number(this.data?.total) || 0
|
|
470
|
-
}
|
|
471
|
-
|
|
472
|
-
get parentCommentsCount() {
|
|
473
|
-
return Number(this.data?.total_parents) || 0
|
|
474
|
-
}
|
|
475
|
-
|
|
476
|
-
/** 是否还有更多的评论 */
|
|
477
|
-
get hasMoreComments(): boolean {
|
|
478
|
-
if (!this.data) return false
|
|
479
|
-
return (!this.flatMode ? this.data.total_parents : this.data.total) > (this.offset + this.pageSize)
|
|
386
|
+
// 评论新增后
|
|
387
|
+
this.refreshUI()
|
|
388
|
+
this.ctx.trigger('comments-loaded')
|
|
480
389
|
}
|
|
481
390
|
|
|
482
391
|
/** 遍历操作 Comment (包括子评论) */
|
|
483
|
-
|
|
392
|
+
protected eachComment(commentList: Comment[], action: (comment: Comment, levelList: Comment[]) => boolean|void) {
|
|
484
393
|
if (commentList.length === 0) return
|
|
485
394
|
commentList.every((item) => {
|
|
486
395
|
if (action(item, commentList) === false) return false
|
|
@@ -490,7 +399,7 @@ export default class ListLite extends Component {
|
|
|
490
399
|
}
|
|
491
400
|
|
|
492
401
|
/** 查找评论项 */
|
|
493
|
-
|
|
402
|
+
protected findComment(id: number, src?: Comment[]): Comment|null {
|
|
494
403
|
if (!src) src = this.comments
|
|
495
404
|
let comment: Comment|null = null
|
|
496
405
|
this.eachComment(src, (item) => {
|
|
@@ -504,13 +413,6 @@ export default class ListLite extends Component {
|
|
|
504
413
|
return comment
|
|
505
414
|
}
|
|
506
415
|
|
|
507
|
-
/** 获取评论总数 */
|
|
508
|
-
public getCommentCount(): number {
|
|
509
|
-
let count = 0
|
|
510
|
-
this.eachComment(this.comments, () => { count++ })
|
|
511
|
-
return count
|
|
512
|
-
}
|
|
513
|
-
|
|
514
416
|
/** 删除评论 */
|
|
515
417
|
public deleteComment(comment: number|Comment) {
|
|
516
418
|
let findComment: Comment|null
|
|
@@ -540,11 +442,12 @@ export default class ListLite extends Component {
|
|
|
540
442
|
this.comments = []
|
|
541
443
|
}
|
|
542
444
|
|
|
445
|
+
/** 更新未读数据 */
|
|
543
446
|
public updateUnread(notifies: NotifyData[]) {
|
|
544
447
|
this.unread = notifies
|
|
545
448
|
|
|
546
449
|
// 高亮评论
|
|
547
|
-
if (this.unreadHighlight) {
|
|
450
|
+
if (this.unreadHighlight === true) {
|
|
548
451
|
this.eachComment(this.comments, (comment) => {
|
|
549
452
|
const notify = this.unread.find(o => o.comment_id === comment.data.id)
|
|
550
453
|
if (notify) {
|
|
@@ -563,7 +466,8 @@ export default class ListLite extends Component {
|
|
|
563
466
|
}
|
|
564
467
|
}
|
|
565
468
|
|
|
566
|
-
|
|
469
|
+
/** 前端版本检测 */
|
|
470
|
+
public versionCheck(versionData: ApiVersionData): boolean {
|
|
567
471
|
const needVersion = versionData?.fe_min_version || '0.0.0'
|
|
568
472
|
const needUpdate = Utils.versionCompare(needVersion, ARTALK_VERSION) === 1
|
|
569
473
|
if (needUpdate) {
|
|
@@ -577,7 +481,7 @@ export default class ListLite extends Component {
|
|
|
577
481
|
ignoreBtn.onclick = () => {
|
|
578
482
|
Ui.setError(this.ctx, null)
|
|
579
483
|
this.ctx.conf.versionCheck = false
|
|
580
|
-
this.
|
|
484
|
+
this.fetchComments(0)
|
|
581
485
|
}
|
|
582
486
|
errEl.append(ignoreBtn)
|
|
583
487
|
Ui.setError(this.ctx, errEl, '<span class="atk-warn-title">Artalk Warn</span>')
|