artalk 2.0.4 → 2.1.1
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/README.md +7 -60
- package/dist/Artalk.css +1 -1
- package/dist/Artalk.es.js +5996 -1
- package/dist/Artalk.iife.js +266 -1
- package/dist/Artalk.js +266 -1
- package/package.json +3 -4
- package/src/api/index.ts +269 -0
- package/src/api/request.ts +125 -0
- package/src/artalk.ts +153 -0
- package/src/components/_component.ts.txt +10 -0
- package/src/components/action-btn.ts +169 -0
- package/src/components/admin/page-list.ts +194 -0
- package/src/components/admin/site-list-floater.ts +98 -0
- package/src/components/admin/site-list.ts +289 -0
- package/src/components/comment.ts +478 -0
- package/src/components/dialog.ts +63 -0
- package/src/components/editor-plugs/{_ExamplePlug.ts.txt → _example-plug.ts.txt} +0 -0
- package/src/components/editor-plugs/{EditorPlug.ts → editor-plug.ts} +3 -3
- package/src/components/editor-plugs/{EmoticonsPlug.less → emoticons-plug.less} +0 -0
- package/src/components/editor-plugs/{EmoticonsPlug.ts → emoticons-plug.ts} +9 -9
- package/src/components/editor-plugs/{PreviewPlug.less → preview-plug.less} +0 -0
- package/src/components/editor-plugs/{PreviewPlug.ts → preview-plug.ts} +10 -10
- package/src/components/{Editor.ts → editor.ts} +104 -102
- package/src/components/html/comment.html +2 -6
- package/src/components/html/list.html +0 -1
- package/src/components/html/sidebar.html +18 -4
- package/src/components/item-text-editor.ts +136 -0
- package/src/components/layer.ts +135 -0
- package/src/components/list-lite.ts +507 -0
- package/src/components/list.ts +172 -0
- package/src/components/pagination.ts +150 -0
- package/src/components/read-more-btn.ts +71 -0
- package/src/components/sidebar-view.ts +26 -0
- package/src/components/sidebar-views/comments-view.ts +66 -0
- package/src/components/sidebar-views/pages-view.ts +61 -0
- package/src/components/sidebar-views/setting-view.ts +21 -0
- package/src/components/sidebar-views/sites-view.ts +42 -0
- package/src/components/sidebar-views/transfer-view.ts +218 -0
- package/src/components/sidebar.ts +288 -0
- package/src/context.ts +42 -0
- package/src/default-conf.ts +42 -0
- package/src/lib/checker/admin-checker.ts +33 -0
- package/src/lib/checker/captcha-checker.ts +38 -0
- package/src/lib/checker/index.ts +134 -0
- package/src/lib/component.ts +3 -3
- package/src/lib/md5.js +6 -0
- package/src/lib/ui.ts +64 -74
- package/src/lib/user.ts +2 -8
- package/src/lib/utils.ts +30 -11
- package/src/main.ts +1 -1
- package/src/style/_color.less +8 -2
- package/src/style/_extend.less +81 -0
- package/src/style/_variables.less +3 -0
- package/src/style/comment.less +60 -24
- package/src/style/editor.less +3 -0
- package/src/style/item-text-editor.less +35 -0
- package/src/style/list.less +51 -32
- package/src/style/main.less +75 -1
- package/src/style/page-list.less +50 -0
- package/src/style/pagination.less +58 -0
- package/src/style/sidebar.less +274 -199
- package/src/style/site-list.less +208 -0
- package/tsconfig.json +27 -0
- package/types/artalk-config.d.ts +68 -51
- package/types/artalk-data.d.ts +38 -1
- package/types/event.d.ts +73 -0
- package/types/index.d.ts +1 -6
- package/.github/workflows/npm.yml +0 -31
- package/.github/workflows/pages.yml +0 -30
- package/dist/src/Event.d.ts +0 -59
- package/dist/types/artalk-config.d.ts +0 -79
- package/dist/types/artalk-data.d.ts +0 -153
- package/dist/types/global.d.ts +0 -1
- package/dist/types/index.d.ts +0 -8
- package/dist/types/vite-env.d.ts +0 -1
- package/example/pjax/res1.html +0 -41
- package/example/pjax/res2.html +0 -41
- package/src/Artalk.ts +0 -160
- package/src/Constant.ts +0 -6
- package/src/Context.ts +0 -34
- package/src/Event.d.ts +0 -59
- package/src/components/Comment.ts +0 -402
- package/src/components/Layer.ts +0 -138
- package/src/components/List.ts +0 -162
- package/src/components/ListLite.ts +0 -407
- package/src/components/Sidebar.ts +0 -141
- package/src/components/sidebar-views/AdminView.ts +0 -523
- package/src/components/sidebar-views/MessageView.ts +0 -48
- package/src/components/sidebar-views/SidebarView.ts +0 -24
- package/src/lib/api.ts +0 -380
- package/src/lib/checker.ts +0 -164
|
@@ -1,407 +0,0 @@
|
|
|
1
|
-
import Context from '../Context'
|
|
2
|
-
import Component from '../lib/component'
|
|
3
|
-
import * as Utils from '../lib/utils'
|
|
4
|
-
import * as Ui from '../lib/ui'
|
|
5
|
-
import Api from '../lib/api'
|
|
6
|
-
import Comment from './Comment'
|
|
7
|
-
import { ListData, CommentData, NotifyData } from '~/types/artalk-data'
|
|
8
|
-
|
|
9
|
-
export default class ListLite extends Component {
|
|
10
|
-
public el: HTMLElement
|
|
11
|
-
private commentsWrapEl: HTMLElement
|
|
12
|
-
public comments: Comment[] = []
|
|
13
|
-
|
|
14
|
-
public data?: ListData
|
|
15
|
-
private pageSize: number = 15 // 每次请求获取量
|
|
16
|
-
private offset: number = 0
|
|
17
|
-
public type?: 'all'|'mentions'|'mine'|'pending'
|
|
18
|
-
|
|
19
|
-
private readMoreEl: HTMLElement
|
|
20
|
-
private readMoreLoadingEl: HTMLElement
|
|
21
|
-
private readMoreTextEl: HTMLElement
|
|
22
|
-
|
|
23
|
-
public noCommentText: string
|
|
24
|
-
public renderComment?: (comment: Comment) => void
|
|
25
|
-
public paramsEditor?: (params: any) => void
|
|
26
|
-
public onAfterLoad?: (data: ListData) => void
|
|
27
|
-
|
|
28
|
-
private isLoading: boolean = false
|
|
29
|
-
public isFirstLoad = true
|
|
30
|
-
|
|
31
|
-
public flatMode = false
|
|
32
|
-
|
|
33
|
-
public unread: NotifyData[] = []
|
|
34
|
-
public unreadHighlight = false
|
|
35
|
-
|
|
36
|
-
constructor (ctx: Context) {
|
|
37
|
-
super(ctx)
|
|
38
|
-
|
|
39
|
-
this.el = Utils.createElement(`
|
|
40
|
-
<div class="atk-list-lite">
|
|
41
|
-
<div class="atk-list-comments-wrap"></div>
|
|
42
|
-
<div class="atk-list-read-more" style="display: none;">
|
|
43
|
-
<div class="atk-loading-icon" style="display: none;"></div>
|
|
44
|
-
<span class="atk-text">查看更多</span>
|
|
45
|
-
</div>
|
|
46
|
-
</div>
|
|
47
|
-
`)
|
|
48
|
-
this.commentsWrapEl = this.el.querySelector('.atk-list-comments-wrap')!
|
|
49
|
-
|
|
50
|
-
// 查看更多
|
|
51
|
-
this.pageSize = this.conf.readMore ? (this.conf.readMore.pageSize || this.pageSize) : this.pageSize
|
|
52
|
-
this.readMoreEl = this.el.querySelector('.atk-list-read-more')!
|
|
53
|
-
this.readMoreLoadingEl = this.readMoreEl.querySelector('.atk-loading-icon')!
|
|
54
|
-
this.readMoreTextEl = this.readMoreEl.querySelector('.atk-text')!
|
|
55
|
-
this.readMoreEl.addEventListener('click', () => {
|
|
56
|
-
this.readMore()
|
|
57
|
-
})
|
|
58
|
-
|
|
59
|
-
this.noCommentText = this.conf.noComment || '无评论'
|
|
60
|
-
|
|
61
|
-
// 评论时间自动更新
|
|
62
|
-
setInterval(() => {
|
|
63
|
-
this.el.querySelectorAll<HTMLElement>('[data-atk-comment-date]').forEach(el => {
|
|
64
|
-
const date = el.getAttribute('data-atk-comment-date')
|
|
65
|
-
el.innerText = Utils.timeAgo(new Date(Number(date)))
|
|
66
|
-
})
|
|
67
|
-
}, 30 * 1000) // 30s 更新一次
|
|
68
|
-
|
|
69
|
-
this.ctx.addEventListener('unread-update', (data) => (this.updateUnread(data.notifies)))
|
|
70
|
-
}
|
|
71
|
-
|
|
72
|
-
public async reqComments(offset: number = 0) {
|
|
73
|
-
if (offset === 0) {
|
|
74
|
-
this.clearComments()
|
|
75
|
-
}
|
|
76
|
-
|
|
77
|
-
// set loading
|
|
78
|
-
this.isLoading = true
|
|
79
|
-
if (offset === 0) Ui.showLoading(this.el)
|
|
80
|
-
else this.readMoreBtnSetLoading(true)
|
|
81
|
-
|
|
82
|
-
const hideLoading = () => {
|
|
83
|
-
// hide loading
|
|
84
|
-
this.isLoading = false
|
|
85
|
-
if (offset === 0) Ui.hideLoading(this.el)
|
|
86
|
-
else this.readMoreBtnSetLoading(false)
|
|
87
|
-
}
|
|
88
|
-
|
|
89
|
-
let listData: ListData
|
|
90
|
-
try {
|
|
91
|
-
listData = await new Api(this.ctx).get(offset, this.type, this.paramsEditor)
|
|
92
|
-
} catch (e: any) {
|
|
93
|
-
this.onError(e.msg || String(e))
|
|
94
|
-
throw e
|
|
95
|
-
} finally {
|
|
96
|
-
hideLoading()
|
|
97
|
-
}
|
|
98
|
-
|
|
99
|
-
// load data
|
|
100
|
-
this.offset = offset
|
|
101
|
-
|
|
102
|
-
try {
|
|
103
|
-
this.onLoad(listData)
|
|
104
|
-
|
|
105
|
-
if (this.onAfterLoad) {
|
|
106
|
-
this.onAfterLoad(listData)
|
|
107
|
-
}
|
|
108
|
-
} catch (e: any) {
|
|
109
|
-
this.onError(String(e))
|
|
110
|
-
throw e
|
|
111
|
-
} finally {
|
|
112
|
-
hideLoading()
|
|
113
|
-
}
|
|
114
|
-
}
|
|
115
|
-
|
|
116
|
-
public onLoad (data: ListData) {
|
|
117
|
-
this.data = data
|
|
118
|
-
Ui.setError(this.el, null)
|
|
119
|
-
this.importComments(data.comments)
|
|
120
|
-
|
|
121
|
-
// 查看更多按钮
|
|
122
|
-
if (this.hasMoreComments) {
|
|
123
|
-
this.showReadMoreBtn()
|
|
124
|
-
} else {
|
|
125
|
-
this.hideReadMoreBtn()
|
|
126
|
-
}
|
|
127
|
-
|
|
128
|
-
// 滚动到底部自动加载
|
|
129
|
-
if (this.isFirstLoad && this.hasMoreComments) {
|
|
130
|
-
this.initScrollBottomAutoLoad()
|
|
131
|
-
}
|
|
132
|
-
|
|
133
|
-
this.ctx.dispatchEvent('unread-update', { notifies: data.unread || [] })
|
|
134
|
-
|
|
135
|
-
this.isFirstLoad = false
|
|
136
|
-
}
|
|
137
|
-
|
|
138
|
-
public onError (msg: any) {
|
|
139
|
-
msg = String(msg)
|
|
140
|
-
console.error(msg)
|
|
141
|
-
if (this.isFirstLoad) {
|
|
142
|
-
const errEl = Utils.createElement(`<span>${msg},无法获取评论列表数据<br/></span>`)
|
|
143
|
-
const retryBtn = Utils.createElement('<span style="cursor:pointer;">点击重新获取</span>')
|
|
144
|
-
retryBtn.onclick = () => {
|
|
145
|
-
this.reqComments(0)
|
|
146
|
-
}
|
|
147
|
-
errEl.appendChild(retryBtn)
|
|
148
|
-
const adminBtn = Utils.createElement('<span atk-only-admin-show> | <span style="cursor:pointer;">打开控制台</span></span>')
|
|
149
|
-
adminBtn.onclick = () => {
|
|
150
|
-
this.ctx.dispatchEvent('sidebar-show', { viewName: 'admin' })
|
|
151
|
-
}
|
|
152
|
-
if (!this.ctx.user.data.isAdmin) {
|
|
153
|
-
adminBtn.classList.add('atk-hide')
|
|
154
|
-
}
|
|
155
|
-
errEl.appendChild(adminBtn)
|
|
156
|
-
Ui.setError(this.el, errEl)
|
|
157
|
-
} else {
|
|
158
|
-
this.readMoreBtnShowErr(`${msg} 获取失败`)
|
|
159
|
-
}
|
|
160
|
-
}
|
|
161
|
-
|
|
162
|
-
public createComment(data: CommentData) {
|
|
163
|
-
const comment = new Comment(this.ctx, data)
|
|
164
|
-
comment.afterRender = () => {
|
|
165
|
-
if (this.renderComment) this.renderComment(comment)
|
|
166
|
-
}
|
|
167
|
-
comment.onDelete = (c) => {
|
|
168
|
-
this.deleteComment(c)
|
|
169
|
-
this.refreshUI()
|
|
170
|
-
}
|
|
171
|
-
|
|
172
|
-
return comment
|
|
173
|
-
}
|
|
174
|
-
|
|
175
|
-
/** 导入评论 - 通过请求数据 */
|
|
176
|
-
public importComments (rawData: CommentData[]) {
|
|
177
|
-
// 查找并导入所有子评论
|
|
178
|
-
const queryImportChildren = (parentC: Comment) => {
|
|
179
|
-
const children = rawData.filter(o => o.rid === parentC.data.id)
|
|
180
|
-
if (children.length === 0) return
|
|
181
|
-
|
|
182
|
-
children.forEach((itemData: CommentData) => {
|
|
183
|
-
itemData.is_allow_reply = parentC.data.is_allow_reply
|
|
184
|
-
const childC = this.createComment(itemData)
|
|
185
|
-
childC.renderElem()
|
|
186
|
-
parentC.putChild(childC)
|
|
187
|
-
queryImportChildren(childC) // 递归
|
|
188
|
-
})
|
|
189
|
-
}
|
|
190
|
-
|
|
191
|
-
// 开始处理 rawData
|
|
192
|
-
if (!this.flatMode) {
|
|
193
|
-
rawData.filter((o) => o.rid === 0).forEach((rootCommentData: CommentData) => {
|
|
194
|
-
if (rootCommentData.is_collapsed) rootCommentData.is_allow_reply = false
|
|
195
|
-
const rootComment = this.createComment(rootCommentData)
|
|
196
|
-
rootComment.renderElem()
|
|
197
|
-
this.comments.push(rootComment) // 将评论导入 comments 总表中
|
|
198
|
-
|
|
199
|
-
this.commentsWrapEl.appendChild(rootComment.getEl())
|
|
200
|
-
rootComment.playFadeInAnim()
|
|
201
|
-
|
|
202
|
-
queryImportChildren(rootComment)
|
|
203
|
-
})
|
|
204
|
-
} else {
|
|
205
|
-
rawData.forEach((commentData: CommentData) => {
|
|
206
|
-
if (commentData.is_collapsed) commentData.is_allow_reply = false
|
|
207
|
-
const comment = this.createComment(commentData)
|
|
208
|
-
if (commentData.rid !== 0) {
|
|
209
|
-
const rComment = rawData.find(o => o.id === commentData.rid)
|
|
210
|
-
if (rComment) comment.replyTo = rComment
|
|
211
|
-
}
|
|
212
|
-
comment.renderElem()
|
|
213
|
-
|
|
214
|
-
this.comments.push(comment) // 将评论导入 comments 总表中
|
|
215
|
-
|
|
216
|
-
if (commentData.visible) {
|
|
217
|
-
this.commentsWrapEl.appendChild(comment.getEl())
|
|
218
|
-
comment.playFadeInAnim()
|
|
219
|
-
}
|
|
220
|
-
})
|
|
221
|
-
}
|
|
222
|
-
|
|
223
|
-
this.refreshUI()
|
|
224
|
-
}
|
|
225
|
-
|
|
226
|
-
public insertComment (commentData: CommentData) {
|
|
227
|
-
const comment = this.createComment(commentData)
|
|
228
|
-
comment.renderElem()
|
|
229
|
-
|
|
230
|
-
if (commentData.rid !== 0) {
|
|
231
|
-
this.findComment(commentData.rid)?.putChild(comment)
|
|
232
|
-
} else {
|
|
233
|
-
this.commentsWrapEl.prepend(comment.getEl())
|
|
234
|
-
this.comments.unshift(comment)
|
|
235
|
-
}
|
|
236
|
-
|
|
237
|
-
Ui.scrollIntoView(comment.getEl()) // 滚动到可以见
|
|
238
|
-
comment.playFadeInAnim() // 播放评论渐出动画
|
|
239
|
-
if (this.data) this.data.total += 1 // 评论数增加 1
|
|
240
|
-
this.refreshUI() // 更新 list 界面
|
|
241
|
-
}
|
|
242
|
-
|
|
243
|
-
/** 刷新界面 */
|
|
244
|
-
public refreshUI () {
|
|
245
|
-
// 评论为空界面
|
|
246
|
-
const noComment = this.comments.length <= 0
|
|
247
|
-
let noCommentEl = this.commentsWrapEl.querySelector<HTMLElement>('.atk-list-no-comment')
|
|
248
|
-
|
|
249
|
-
if (noComment) {
|
|
250
|
-
if (!noCommentEl) {
|
|
251
|
-
noCommentEl = Utils.createElement('<div class="atk-list-no-comment"></div>')
|
|
252
|
-
this.commentsWrapEl.appendChild(noCommentEl)
|
|
253
|
-
noCommentEl.innerHTML = this.noCommentText
|
|
254
|
-
}
|
|
255
|
-
}
|
|
256
|
-
|
|
257
|
-
if (!noComment && noCommentEl)
|
|
258
|
-
noCommentEl.remove()
|
|
259
|
-
|
|
260
|
-
// 仅管理员显示控制
|
|
261
|
-
this.ctx.dispatchEvent('check-admin-show-el')
|
|
262
|
-
}
|
|
263
|
-
|
|
264
|
-
/** 获取评论总数 (包括子评论) */
|
|
265
|
-
public getListCommentCount (): number {
|
|
266
|
-
if (!this.data || !this.data.total) return 0
|
|
267
|
-
return Number(this.data.total || '0')
|
|
268
|
-
}
|
|
269
|
-
|
|
270
|
-
/** 是否还有更多的评论 */
|
|
271
|
-
get hasMoreComments (): boolean {
|
|
272
|
-
if (!this.data) return false
|
|
273
|
-
return this.data.total_parents > (this.offset + this.pageSize)
|
|
274
|
-
}
|
|
275
|
-
|
|
276
|
-
/** 阅读更多操作 */
|
|
277
|
-
async readMore () {
|
|
278
|
-
const offset = this.offset + this.pageSize
|
|
279
|
-
await this.reqComments(offset)
|
|
280
|
-
}
|
|
281
|
-
|
|
282
|
-
/** 阅读更多按钮 - 显示 */
|
|
283
|
-
showReadMoreBtn () {
|
|
284
|
-
this.readMoreEl.style.display = ''
|
|
285
|
-
}
|
|
286
|
-
|
|
287
|
-
/** 阅读更多按钮 - 隐藏 */
|
|
288
|
-
hideReadMoreBtn () {
|
|
289
|
-
this.readMoreEl.style.display = 'none'
|
|
290
|
-
}
|
|
291
|
-
|
|
292
|
-
/** 阅读更多按钮 - 显示加载 */
|
|
293
|
-
readMoreBtnSetLoading (isLoading: boolean) {
|
|
294
|
-
this.readMoreLoadingEl.style.display = isLoading ? '' : 'none'
|
|
295
|
-
this.readMoreTextEl.style.display = isLoading ? 'none' : ''
|
|
296
|
-
}
|
|
297
|
-
|
|
298
|
-
/** 阅读更多按钮 - 显示错误 */
|
|
299
|
-
readMoreBtnShowErr (errMsg: string) {
|
|
300
|
-
this.readMoreBtnSetLoading(false)
|
|
301
|
-
|
|
302
|
-
const readMoreTextOrg = this.readMoreTextEl.innerText
|
|
303
|
-
this.readMoreTextEl.innerText = errMsg
|
|
304
|
-
this.readMoreEl.classList.add('atk-err')
|
|
305
|
-
setTimeout(() => {
|
|
306
|
-
this.readMoreTextEl.innerText = readMoreTextOrg
|
|
307
|
-
this.readMoreEl.classList.remove('atk-err')
|
|
308
|
-
}, 2000) // 2s后错误提示复原
|
|
309
|
-
}
|
|
310
|
-
|
|
311
|
-
/** 初始化滚动到底部自动查看更多(若开启) */
|
|
312
|
-
initScrollBottomAutoLoad () {
|
|
313
|
-
if (!this.conf.readMore) return
|
|
314
|
-
if (!this.conf.readMore.autoLoad) return
|
|
315
|
-
|
|
316
|
-
document.addEventListener('scroll', () => {
|
|
317
|
-
const targetEl = this.el.querySelector<HTMLElement>('.atk-list-comments-wrap > .atk-comment-wrap:nth-last-child(3)') // 获取倒数第3个评论元素
|
|
318
|
-
if (!targetEl) return
|
|
319
|
-
if (!this.hasMoreComments) return
|
|
320
|
-
if (this.isLoading) return
|
|
321
|
-
if (Ui.isVisible(targetEl)) {
|
|
322
|
-
// 加载更多
|
|
323
|
-
this.readMore()
|
|
324
|
-
}
|
|
325
|
-
})
|
|
326
|
-
}
|
|
327
|
-
|
|
328
|
-
/** 遍历操作 Comment (包括子评论) */
|
|
329
|
-
public eachComment (commentList: Comment[], action: (comment: Comment, levelList: Comment[]) => boolean|void) {
|
|
330
|
-
if (commentList.length === 0) return
|
|
331
|
-
commentList.every((item) => {
|
|
332
|
-
if (action(item, commentList) === false) return false
|
|
333
|
-
this.eachComment(item.getChildren(), action)
|
|
334
|
-
return true
|
|
335
|
-
})
|
|
336
|
-
}
|
|
337
|
-
|
|
338
|
-
/** 查找评论项 */
|
|
339
|
-
public findComment (id: number, src?: Comment[]): Comment|null {
|
|
340
|
-
if (!src) src = this.comments
|
|
341
|
-
let comment: Comment|null = null
|
|
342
|
-
this.eachComment(src, (item) => {
|
|
343
|
-
if (item.data.id === id) {
|
|
344
|
-
comment = item
|
|
345
|
-
return false
|
|
346
|
-
}
|
|
347
|
-
return true
|
|
348
|
-
})
|
|
349
|
-
|
|
350
|
-
return comment
|
|
351
|
-
}
|
|
352
|
-
|
|
353
|
-
/** 获取评论总数 */
|
|
354
|
-
public getCommentCount (): number {
|
|
355
|
-
let count = 0
|
|
356
|
-
this.eachComment(this.comments, () => { count++ })
|
|
357
|
-
return count
|
|
358
|
-
}
|
|
359
|
-
|
|
360
|
-
/** 删除评论 */
|
|
361
|
-
public deleteComment (comment: number|Comment) {
|
|
362
|
-
let findComment: Comment|null
|
|
363
|
-
if (typeof comment === 'number') {
|
|
364
|
-
findComment = this.findComment(comment)
|
|
365
|
-
if (!findComment) throw Error(`未找到评论 ${comment}`)
|
|
366
|
-
} else findComment = comment
|
|
367
|
-
|
|
368
|
-
findComment.getEl().remove()
|
|
369
|
-
this.eachComment(this.comments, (item, levelList) => {
|
|
370
|
-
if (item === findComment) {
|
|
371
|
-
levelList.splice(levelList.indexOf(item), 1)
|
|
372
|
-
return false
|
|
373
|
-
}
|
|
374
|
-
return true
|
|
375
|
-
})
|
|
376
|
-
}
|
|
377
|
-
|
|
378
|
-
/** 清空所有评论 */
|
|
379
|
-
public clearComments () {
|
|
380
|
-
this.commentsWrapEl.innerHTML = ''
|
|
381
|
-
this.data = undefined
|
|
382
|
-
this.comments = []
|
|
383
|
-
}
|
|
384
|
-
|
|
385
|
-
public updateUnread(notifies: NotifyData[]) {
|
|
386
|
-
this.unread = notifies
|
|
387
|
-
|
|
388
|
-
// 高亮评论
|
|
389
|
-
if (this.unreadHighlight) {
|
|
390
|
-
this.eachComment(this.comments, (comment) => {
|
|
391
|
-
const notify = this.unread.find(o => o.comment_id === comment.data.id)
|
|
392
|
-
if (notify) {
|
|
393
|
-
comment.setUnread(true)
|
|
394
|
-
comment.setOpenURL(notify.read_link)
|
|
395
|
-
comment.openEvt = () => {
|
|
396
|
-
this.unread = this.unread.filter(o => o.comment_id !== comment.data.id) // remove
|
|
397
|
-
this.ctx.dispatchEvent('unread-update', {
|
|
398
|
-
notifies: this.unread
|
|
399
|
-
})
|
|
400
|
-
}
|
|
401
|
-
} else {
|
|
402
|
-
comment.setUnread(false)
|
|
403
|
-
}
|
|
404
|
-
})
|
|
405
|
-
}
|
|
406
|
-
}
|
|
407
|
-
}
|
|
@@ -1,141 +0,0 @@
|
|
|
1
|
-
import '../style/sidebar.less'
|
|
2
|
-
|
|
3
|
-
import Context from '../Context'
|
|
4
|
-
import Component from '../lib/component'
|
|
5
|
-
import * as Utils from '../lib/utils'
|
|
6
|
-
import * as Ui from '../lib/ui'
|
|
7
|
-
import Comment from './Comment'
|
|
8
|
-
import SidebarHTML from './html/sidebar.html?raw'
|
|
9
|
-
import BuildLayer, { Layer } from './Layer'
|
|
10
|
-
|
|
11
|
-
import SidebarView from './sidebar-views/SidebarView'
|
|
12
|
-
import MessageView from './sidebar-views/MessageView'
|
|
13
|
-
import AdminView from './sidebar-views/AdminView'
|
|
14
|
-
|
|
15
|
-
export default class Sidebar extends Component {
|
|
16
|
-
public el: HTMLElement
|
|
17
|
-
public layer?: Layer
|
|
18
|
-
public actionsEl: HTMLElement
|
|
19
|
-
public contentEl: HTMLElement
|
|
20
|
-
public titleWrapEl: HTMLElement
|
|
21
|
-
|
|
22
|
-
public view?: SidebarView
|
|
23
|
-
public action?: string
|
|
24
|
-
private isFirstShow = true
|
|
25
|
-
|
|
26
|
-
public viewInstances: {[name: string]: SidebarView} = {}
|
|
27
|
-
public registerViews: (typeof SidebarView)[] = [
|
|
28
|
-
MessageView, AdminView,
|
|
29
|
-
]
|
|
30
|
-
|
|
31
|
-
constructor (ctx: Context) {
|
|
32
|
-
super(ctx)
|
|
33
|
-
|
|
34
|
-
// initial elements
|
|
35
|
-
this.el = Utils.createElement(SidebarHTML)
|
|
36
|
-
this.contentEl = this.el.querySelector('.atk-sidebar-content')!
|
|
37
|
-
this.titleWrapEl = this.el.querySelector('.atk-sidebar-title-wrap')!
|
|
38
|
-
this.actionsEl = this.el.querySelector('.atk-sidebar-actions')!
|
|
39
|
-
|
|
40
|
-
this.el.querySelector('.atk-sidebar-close')!.addEventListener('click', () => {
|
|
41
|
-
this.hide()
|
|
42
|
-
})
|
|
43
|
-
|
|
44
|
-
// event
|
|
45
|
-
this.ctx.addEventListener('sidebar-show', (payload) => (this.show(payload?.viewName)))
|
|
46
|
-
this.ctx.addEventListener('sidebar-hide', () => (this.hide()))
|
|
47
|
-
|
|
48
|
-
// titles
|
|
49
|
-
this.registerViews.forEach(View => {
|
|
50
|
-
const viewInstance = new View(this.ctx)
|
|
51
|
-
this.viewInstances[viewInstance.name] = viewInstance
|
|
52
|
-
viewInstance.el.classList.add(`atk-sidebar-view-${viewInstance.name}`)
|
|
53
|
-
|
|
54
|
-
const titleEl = Utils.createElement(`
|
|
55
|
-
<span class="atk-title-item" data-name="${viewInstance.name}">${viewInstance.title}</span>
|
|
56
|
-
`)
|
|
57
|
-
if (viewInstance.adminOnly) {
|
|
58
|
-
titleEl.setAttribute('atk-only-admin-show', '')
|
|
59
|
-
if (!this.ctx.user.data.isAdmin)
|
|
60
|
-
titleEl.classList.add('atk-hide')
|
|
61
|
-
}
|
|
62
|
-
this.titleWrapEl.append(titleEl)
|
|
63
|
-
|
|
64
|
-
// title click
|
|
65
|
-
titleEl.addEventListener('click', () => { this.switchView(viewInstance) })
|
|
66
|
-
})
|
|
67
|
-
}
|
|
68
|
-
|
|
69
|
-
show (viewName?: string) {
|
|
70
|
-
this.el.style.transform = '' // 动画清除,防止二次打开失效
|
|
71
|
-
|
|
72
|
-
this.layer = BuildLayer(this.ctx, 'sidebar', this.el)
|
|
73
|
-
this.layer.show()
|
|
74
|
-
this.contentEl.scrollTo(0, 0)
|
|
75
|
-
|
|
76
|
-
setTimeout(() => {
|
|
77
|
-
this.el.style.transform = 'translate(0, 0)' // 执行动画
|
|
78
|
-
}, 20)
|
|
79
|
-
|
|
80
|
-
if (viewName) {
|
|
81
|
-
this.switchViewByName(viewName) // 打开指定 view
|
|
82
|
-
}
|
|
83
|
-
|
|
84
|
-
if (this.isFirstShow) {
|
|
85
|
-
if (!viewName) this.switchViewByName('message') // 打开默认 view
|
|
86
|
-
this.isFirstShow = false
|
|
87
|
-
}
|
|
88
|
-
}
|
|
89
|
-
|
|
90
|
-
hide () {
|
|
91
|
-
this.el.style.transform = ''
|
|
92
|
-
this.layer?.dispose() // 用完即销毁
|
|
93
|
-
}
|
|
94
|
-
|
|
95
|
-
switchViewByName (viewName: string) {
|
|
96
|
-
if (!this.viewInstances[viewName]) {
|
|
97
|
-
console.error(`未找到 view: ${viewName}`)
|
|
98
|
-
return
|
|
99
|
-
}
|
|
100
|
-
|
|
101
|
-
this.switchView(this.viewInstances[viewName])
|
|
102
|
-
}
|
|
103
|
-
|
|
104
|
-
switchView (view: SidebarView) {
|
|
105
|
-
this.view = view
|
|
106
|
-
|
|
107
|
-
// focus title
|
|
108
|
-
const titleEl = this.titleWrapEl.querySelector<HTMLElement>(`[data-name=${view.name}]`)!
|
|
109
|
-
this.titleWrapEl.querySelector<HTMLElement>('.atk-active')!.innerText = view.title
|
|
110
|
-
this.titleWrapEl.querySelectorAll<HTMLElement>('.atk-title-item').forEach((item) => {
|
|
111
|
-
if (!item.classList.contains('atk-active'))
|
|
112
|
-
item.style.display = ''
|
|
113
|
-
})
|
|
114
|
-
titleEl.style.display = 'none'
|
|
115
|
-
|
|
116
|
-
// init view ui
|
|
117
|
-
view.init()
|
|
118
|
-
this.contentEl.innerHTML = ''
|
|
119
|
-
this.contentEl.append(view.el)
|
|
120
|
-
|
|
121
|
-
// actions
|
|
122
|
-
this.actionsEl.innerHTML = ''
|
|
123
|
-
Object.entries(view.actions).forEach(([name, label]) => {
|
|
124
|
-
const actionItemEl = Utils.createElement(`<span class="atk-action-item">${label}</span>`)
|
|
125
|
-
this.actionsEl.append(actionItemEl)
|
|
126
|
-
|
|
127
|
-
if (view.activeAction === name) actionItemEl.classList.add('atk-active')
|
|
128
|
-
|
|
129
|
-
// action click
|
|
130
|
-
actionItemEl.addEventListener('click', () => {
|
|
131
|
-
view.switch(name)
|
|
132
|
-
view.activeAction = name
|
|
133
|
-
|
|
134
|
-
this.actionsEl.querySelectorAll('.atk-active').forEach((item) => {
|
|
135
|
-
item.classList.remove('atk-active')
|
|
136
|
-
})
|
|
137
|
-
actionItemEl.classList.add('atk-active')
|
|
138
|
-
})
|
|
139
|
-
})
|
|
140
|
-
}
|
|
141
|
-
}
|