artalk 2.7.0 → 2.7.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.
- package/README.md +1 -1
- package/dist/Artalk.css +1 -1
- package/dist/Artalk.es.js +209 -188
- package/dist/Artalk.es.js.map +1 -0
- package/dist/Artalk.iife.js +2 -1
- package/dist/Artalk.iife.js.map +1 -0
- package/dist/Artalk.js +2 -1
- package/dist/Artalk.js.map +1 -0
- package/dist/ArtalkLite.css +1 -1
- package/dist/ArtalkLite.es.js +209 -188
- package/dist/ArtalkLite.es.js.map +1 -0
- package/dist/ArtalkLite.iife.js +2 -1
- package/dist/ArtalkLite.iife.js.map +1 -0
- package/dist/ArtalkLite.js +2 -1
- package/dist/ArtalkLite.js.map +1 -0
- package/dist/i18n/jp.js +1 -1
- package/dist/i18n/zh-TW.js +1 -1
- package/dist/src/api/_base.d.ts +7 -0
- package/dist/src/api/_options.d.ts +5 -0
- package/dist/src/artalk.d.ts +0 -2
- package/dist/src/components/checker/index.d.ts +2 -0
- package/dist/src/i18n/en.d.ts +4 -0
- package/dist/src/i18n/external.d.ts +4 -0
- package/dist/src/i18n/index.d.ts +12 -0
- package/dist/src/i18n/jp.d.ts +4 -0
- package/dist/src/i18n/zh-TW.d.ts +4 -0
- package/dist/src/lib/user.d.ts +8 -6
- package/dist/src/main.d.ts +3 -0
- package/dist/src/plugins/editor/_kit.d.ts +7 -1
- package/dist/src/service.d.ts +2 -8
- package/dist/types/event.d.ts +1 -1
- package/package.json +43 -17
- package/dist/src/components/dark-mode.d.ts +0 -2
- package/src/api/_base.ts +0 -18
- package/src/api/_options.ts +0 -25
- package/src/api/_request.ts +0 -104
- package/src/api/admin.ts +0 -18
- package/src/api/captcha.ts +0 -24
- package/src/api/comment.ts +0 -84
- package/src/api/index.ts +0 -29
- package/src/api/page.ts +0 -83
- package/src/api/site.ts +0 -51
- package/src/api/system.ts +0 -49
- package/src/api/upload.ts +0 -28
- package/src/api/user.ts +0 -132
- package/src/artalk.ts +0 -119
- package/src/comment/actions.ts +0 -83
- package/src/comment/comment.html +0 -18
- package/src/comment/comment.ts +0 -192
- package/src/comment/height-limit.ts +0 -100
- package/src/comment/index.ts +0 -3
- package/src/comment/render.ts +0 -150
- package/src/comment/renders/actions.ts +0 -114
- package/src/comment/renders/avatar.ts +0 -22
- package/src/comment/renders/content.ts +0 -39
- package/src/comment/renders/header.ts +0 -84
- package/src/comment/renders/index.ts +0 -19
- package/src/comment/renders/pending.ts +0 -12
- package/src/comment/renders/reply-at.ts +0 -16
- package/src/comment/renders/reply-to.ts +0 -24
- package/src/components/action-btn.ts +0 -170
- package/src/components/checker/admin.ts +0 -37
- package/src/components/checker/captcha-renders.ts +0 -69
- package/src/components/checker/captcha.ts +0 -26
- package/src/components/checker/index.ts +0 -192
- package/src/components/dark-mode.ts +0 -30
- package/src/components/dialog.ts +0 -62
- package/src/components/error-dialog.ts +0 -35
- package/src/components/pagination.ts +0 -153
- package/src/components/read-more-btn.ts +0 -92
- package/src/config.ts +0 -119
- package/src/context.ts +0 -146
- package/src/data.ts +0 -110
- package/src/defaults.ts +0 -61
- package/src/editor/editor.html +0 -18
- package/src/editor/editor.ts +0 -114
- package/src/editor/state.ts +0 -52
- package/src/editor/ui.ts +0 -36
- package/src/i18n/en.ts +0 -81
- package/src/i18n/external.ts +0 -10
- package/src/i18n/index.ts +0 -67
- package/src/i18n/jp.ts +0 -83
- package/src/i18n/zh-CN.ts +0 -85
- package/src/i18n/zh-TW.ts +0 -83
- package/src/layer/index.ts +0 -4
- package/src/layer/layer-manager.ts +0 -32
- package/src/layer/layer.ts +0 -39
- package/src/layer/scrollbar-helper.ts +0 -24
- package/src/layer/sidebar-layer.html +0 -8
- package/src/layer/sidebar-layer.ts +0 -155
- package/src/layer/wrap.ts +0 -77
- package/src/lib/component.ts +0 -12
- package/src/lib/detect.ts +0 -222
- package/src/lib/event-manager.ts +0 -47
- package/src/lib/highlight.ts +0 -5
- package/src/lib/marked-renderer.ts +0 -32
- package/src/lib/marked.ts +0 -72
- package/src/lib/sanitizer.ts +0 -57
- package/src/lib/ui.ts +0 -193
- package/src/lib/user.ts +0 -55
- package/src/lib/utils.ts +0 -236
- package/src/list/comment.ts +0 -20
- package/src/list/layout.ts +0 -120
- package/src/list/list.html +0 -20
- package/src/list/list.ts +0 -79
- package/src/list/nest.ts +0 -66
- package/src/list/page.ts +0 -97
- package/src/list/paginator/index.ts +0 -25
- package/src/list/paginator/read-more.ts +0 -67
- package/src/list/paginator/up-down.ts +0 -51
- package/src/main.ts +0 -5
- package/src/plugins/admin-only-elem.ts +0 -40
- package/src/plugins/conf-remoter.ts +0 -54
- package/src/plugins/dark-mode.ts +0 -12
- package/src/plugins/editor/_kit.ts +0 -57
- package/src/plugins/editor/_plug.ts +0 -60
- package/src/plugins/editor/_sample.ts +0 -8
- package/src/plugins/editor/closable.ts +0 -44
- package/src/plugins/editor/emoticons.scss +0 -72
- package/src/plugins/editor/emoticons.ts +0 -293
- package/src/plugins/editor/header-event.ts +0 -35
- package/src/plugins/editor/header-link.ts +0 -31
- package/src/plugins/editor/header-user.ts +0 -98
- package/src/plugins/editor/index.ts +0 -40
- package/src/plugins/editor/local-storage.ts +0 -36
- package/src/plugins/editor/mover.ts +0 -29
- package/src/plugins/editor/preview.scss +0 -7
- package/src/plugins/editor/preview.ts +0 -41
- package/src/plugins/editor/state-edit.ts +0 -116
- package/src/plugins/editor/state-reply.ts +0 -91
- package/src/plugins/editor/submit-add.ts +0 -33
- package/src/plugins/editor/submit-btn.ts +0 -25
- package/src/plugins/editor/submit.ts +0 -73
- package/src/plugins/editor/textarea.ts +0 -55
- package/src/plugins/editor/upload.ts +0 -145
- package/src/plugins/editor-kit.ts +0 -161
- package/src/plugins/index.ts +0 -16
- package/src/plugins/list/copyright.ts +0 -16
- package/src/plugins/list/count.ts +0 -31
- package/src/plugins/list/dropdown.ts +0 -95
- package/src/plugins/list/error-dialog.ts +0 -22
- package/src/plugins/list/fetch.ts +0 -64
- package/src/plugins/list/goto-first.ts +0 -23
- package/src/plugins/list/goto.ts +0 -72
- package/src/plugins/list/index.ts +0 -25
- package/src/plugins/list/loading.ts +0 -17
- package/src/plugins/list/no-comment.ts +0 -25
- package/src/plugins/list/reach-bottom.ts +0 -46
- package/src/plugins/list/sidebar-btn.ts +0 -39
- package/src/plugins/list/time-ticking.ts +0 -22
- package/src/plugins/list/unread-badge.ts +0 -26
- package/src/plugins/list/unread.ts +0 -38
- package/src/plugins/list/with-editor.ts +0 -59
- package/src/plugins/markdown.ts +0 -10
- package/src/plugins/stat.ts +0 -79
- package/src/plugins/version-check.ts +0 -37
- package/src/service.ts +0 -91
- package/src/style/_color.scss +0 -41
- package/src/style/_extend.scss +0 -20
- package/src/style/_variables.scss +0 -3
- package/src/style/comment.scss +0 -360
- package/src/style/editor.scss +0 -194
- package/src/style/list.scss +0 -212
- package/src/style/main.scss +0 -486
- package/src/style/pagination.scss +0 -58
- package/src/style/sidebar-layer.scss +0 -92
- package/types/config.ts +0 -153
- package/types/context.ts +0 -84
- package/types/data.ts +0 -271
- package/types/editor.ts +0 -95
- package/types/event.ts +0 -40
- package/types/global.d.ts +0 -1
- package/types/index.ts +0 -7
- package/types/plugin.ts +0 -3
- package/types/sidebar.ts +0 -3
package/src/list/layout.ts
DELETED
|
@@ -1,120 +0,0 @@
|
|
|
1
|
-
import type { CommentData } from '~/types'
|
|
2
|
-
import * as Ui from '@/lib/ui'
|
|
3
|
-
import Comment from '../comment/comment'
|
|
4
|
-
import * as ListNest from './nest'
|
|
5
|
-
|
|
6
|
-
export interface LayoutOptions {
|
|
7
|
-
$commentsWrap: HTMLElement
|
|
8
|
-
nestSortBy: ListNest.SortByType
|
|
9
|
-
nestMax: number
|
|
10
|
-
flatMode: boolean
|
|
11
|
-
|
|
12
|
-
createCommentNode(comment: CommentData, ctxComments: CommentData[]): Comment
|
|
13
|
-
findCommentNode(id: number): Comment|undefined
|
|
14
|
-
getCommentDataList(): CommentData[]
|
|
15
|
-
}
|
|
16
|
-
|
|
17
|
-
export default class ListLayout {
|
|
18
|
-
constructor(private options: LayoutOptions) {}
|
|
19
|
-
|
|
20
|
-
// TODO refactor `if syntax` to strategy pattern
|
|
21
|
-
import(comments: CommentData[]) {
|
|
22
|
-
if (this.options.flatMode) {
|
|
23
|
-
comments.forEach((commentData: CommentData) => {
|
|
24
|
-
this.putCommentFlatMode(commentData, comments, 'append')
|
|
25
|
-
})
|
|
26
|
-
} else {
|
|
27
|
-
this.importCommentsNestMode(comments)
|
|
28
|
-
}
|
|
29
|
-
}
|
|
30
|
-
|
|
31
|
-
insert(comment: CommentData) {
|
|
32
|
-
if (!this.options.flatMode) {
|
|
33
|
-
this.insertCommentNest(comment)
|
|
34
|
-
} else {
|
|
35
|
-
this.insertCommentFlatMode(comment)
|
|
36
|
-
}
|
|
37
|
-
}
|
|
38
|
-
|
|
39
|
-
// 导入评论 · 嵌套模式
|
|
40
|
-
private importCommentsNestMode(srcData: CommentData[]) {
|
|
41
|
-
// 遍历 root 评论
|
|
42
|
-
const rootNodes = ListNest.makeNestCommentNodeList(srcData, this.options.nestSortBy, this.options.nestMax)
|
|
43
|
-
rootNodes.forEach((rootNode: ListNest.CommentNode) => {
|
|
44
|
-
const rootC = this.options.createCommentNode(rootNode.comment, srcData)
|
|
45
|
-
|
|
46
|
-
// 显示并播放渐入动画
|
|
47
|
-
this.options.$commentsWrap?.appendChild(rootC.getEl())
|
|
48
|
-
rootC.getRender().playFadeAnim()
|
|
49
|
-
|
|
50
|
-
// 加载子评论
|
|
51
|
-
const loadChildren = (parentC: Comment, parentNode: ListNest.CommentNode) => {
|
|
52
|
-
parentNode.children.forEach((node: ListNest.CommentNode) => {
|
|
53
|
-
const childD = node.comment
|
|
54
|
-
const childC = this.options.createCommentNode(childD, srcData)
|
|
55
|
-
|
|
56
|
-
// 插入到父评论中
|
|
57
|
-
parentC.putChild(childC)
|
|
58
|
-
|
|
59
|
-
// 递归加载子评论
|
|
60
|
-
loadChildren(childC, node)
|
|
61
|
-
})
|
|
62
|
-
}
|
|
63
|
-
loadChildren(rootC, rootNode)
|
|
64
|
-
|
|
65
|
-
// 限高检测
|
|
66
|
-
rootC.getRender().checkHeightLimit()
|
|
67
|
-
})
|
|
68
|
-
}
|
|
69
|
-
|
|
70
|
-
/** 导入评论 · 平铺模式 */
|
|
71
|
-
private putCommentFlatMode(cData: CommentData, ctxData: CommentData[], insertMode: 'append'|'prepend') {
|
|
72
|
-
if (cData.is_collapsed) cData.is_allow_reply = false
|
|
73
|
-
const comment = this.options.createCommentNode(cData, ctxData)
|
|
74
|
-
|
|
75
|
-
// 可见评论添加到界面
|
|
76
|
-
// 注:不可见评论用于显示 “引用内容”
|
|
77
|
-
if (cData.visible) {
|
|
78
|
-
if (insertMode === 'append') this.options.$commentsWrap?.append(comment.getEl())
|
|
79
|
-
if (insertMode === 'prepend') this.options.$commentsWrap?.prepend(comment.getEl())
|
|
80
|
-
comment.getRender().playFadeAnim()
|
|
81
|
-
}
|
|
82
|
-
|
|
83
|
-
// 平铺评论插入后 · 内容限高检测
|
|
84
|
-
comment.getRender().checkHeightLimit()
|
|
85
|
-
|
|
86
|
-
return comment
|
|
87
|
-
}
|
|
88
|
-
|
|
89
|
-
private insertCommentNest(commentData: CommentData) {
|
|
90
|
-
// 嵌套模式
|
|
91
|
-
const comment = this.options.createCommentNode(commentData, this.options.getCommentDataList())
|
|
92
|
-
|
|
93
|
-
if (commentData.rid === 0) {
|
|
94
|
-
// root评论 新增
|
|
95
|
-
this.options.$commentsWrap?.prepend(comment.getEl())
|
|
96
|
-
} else {
|
|
97
|
-
// 子评论 新增
|
|
98
|
-
const parent = this.options.findCommentNode(commentData.rid)
|
|
99
|
-
if (parent) {
|
|
100
|
-
parent.putChild(comment, (this.options.nestSortBy === 'DATE_ASC' ? 'append' : 'prepend'))
|
|
101
|
-
|
|
102
|
-
// 若父评论存在 “子评论部分” 限高,取消限高
|
|
103
|
-
comment.getParents().forEach((p) => {
|
|
104
|
-
p.getRender().heightLimitRemoveForChildren()
|
|
105
|
-
})
|
|
106
|
-
}
|
|
107
|
-
}
|
|
108
|
-
|
|
109
|
-
comment.getRender().checkHeightLimit()
|
|
110
|
-
|
|
111
|
-
Ui.scrollIntoView(comment.getEl()) // 滚动到可以见
|
|
112
|
-
comment.getRender().playFadeAnim() // 播放评论渐出动画
|
|
113
|
-
}
|
|
114
|
-
|
|
115
|
-
private insertCommentFlatMode(commentData: CommentData) {
|
|
116
|
-
// 平铺模式
|
|
117
|
-
const comment = this.putCommentFlatMode(commentData, this.options.getCommentDataList(), 'prepend')
|
|
118
|
-
Ui.scrollIntoView(comment.getEl()) // 滚动到可见
|
|
119
|
-
}
|
|
120
|
-
}
|
package/src/list/list.html
DELETED
|
@@ -1,20 +0,0 @@
|
|
|
1
|
-
<div class="atk-list">
|
|
2
|
-
<div class="atk-list-header">
|
|
3
|
-
<div class="atk-comment-count">
|
|
4
|
-
<div class="atk-text"></div>
|
|
5
|
-
</div>
|
|
6
|
-
<div class="atk-right-action">
|
|
7
|
-
<span data-action="admin-close-comment" class="atk-hide" atk-only-admin-show></span>
|
|
8
|
-
<span data-action="open-sidebar" class="atk-hide atk-on">
|
|
9
|
-
<span class="atk-unread-badge" style="display: none;"></span>
|
|
10
|
-
<div class="atk-text"></div>
|
|
11
|
-
</span>
|
|
12
|
-
</div>
|
|
13
|
-
</div>
|
|
14
|
-
<div class="atk-list-body">
|
|
15
|
-
<div class="atk-list-comments-wrap"></div>
|
|
16
|
-
</div>
|
|
17
|
-
<div class="atk-list-footer">
|
|
18
|
-
<div class="atk-copyright"></div>
|
|
19
|
-
</div>
|
|
20
|
-
</div>
|
package/src/list/list.ts
DELETED
|
@@ -1,79 +0,0 @@
|
|
|
1
|
-
import type { ContextApi } from '~/types'
|
|
2
|
-
import Component from '../lib/component'
|
|
3
|
-
import * as Utils from '../lib/utils'
|
|
4
|
-
import CommentNode from '../comment/comment'
|
|
5
|
-
import ListHTML from './list.html?raw'
|
|
6
|
-
import ListLayout from './layout'
|
|
7
|
-
import { createComment as createCommentNode } from './comment'
|
|
8
|
-
import { initListPaginatorFunc } from './page'
|
|
9
|
-
|
|
10
|
-
export default class List extends Component {
|
|
11
|
-
/** 列表评论集区域元素 */
|
|
12
|
-
$commentsWrap!: HTMLElement
|
|
13
|
-
public getCommentsWrapEl() { return this.$commentsWrap }
|
|
14
|
-
|
|
15
|
-
protected commentNodes: CommentNode[] = []
|
|
16
|
-
getCommentNodes() { return this.commentNodes }
|
|
17
|
-
|
|
18
|
-
constructor (ctx: ContextApi) {
|
|
19
|
-
super(ctx)
|
|
20
|
-
|
|
21
|
-
// Init base element
|
|
22
|
-
this.$el = Utils.createElement(ListHTML)
|
|
23
|
-
this.$commentsWrap = this.$el.querySelector('.atk-list-comments-wrap')!
|
|
24
|
-
|
|
25
|
-
// Init paginator
|
|
26
|
-
initListPaginatorFunc(ctx)
|
|
27
|
-
|
|
28
|
-
// Bind events
|
|
29
|
-
this.initCrudEvents()
|
|
30
|
-
}
|
|
31
|
-
|
|
32
|
-
getListLayout() {
|
|
33
|
-
return new ListLayout({
|
|
34
|
-
$commentsWrap: this.$commentsWrap,
|
|
35
|
-
nestSortBy: this.ctx.conf.nestSort,
|
|
36
|
-
nestMax: this.ctx.conf.nestMax,
|
|
37
|
-
flatMode: this.ctx.conf.flatMode as boolean,
|
|
38
|
-
// flatMode must be boolean because it had been handled when Artalk.init
|
|
39
|
-
createCommentNode: (d, c) => {
|
|
40
|
-
const node = createCommentNode(this.ctx, d, c)
|
|
41
|
-
this.commentNodes.push(node)
|
|
42
|
-
return node
|
|
43
|
-
},
|
|
44
|
-
findCommentNode: (id) => this.commentNodes.find(c => c.getID() === id),
|
|
45
|
-
getCommentDataList: () => this.ctx.getData().getComments(),
|
|
46
|
-
})
|
|
47
|
-
}
|
|
48
|
-
|
|
49
|
-
private initCrudEvents() {
|
|
50
|
-
this.ctx.on('list-load', (comments) => {
|
|
51
|
-
// 导入数据
|
|
52
|
-
this.getListLayout().import(comments)
|
|
53
|
-
})
|
|
54
|
-
|
|
55
|
-
this.ctx.on('list-loaded', (comments) => {
|
|
56
|
-
if (comments.length === 0) this.$commentsWrap.innerHTML = ''
|
|
57
|
-
})
|
|
58
|
-
|
|
59
|
-
// When comment insert
|
|
60
|
-
this.ctx.on('comment-inserted', (comment) => {
|
|
61
|
-
this.getListLayout().insert(comment)
|
|
62
|
-
})
|
|
63
|
-
|
|
64
|
-
// When comment delete
|
|
65
|
-
this.ctx.on('comment-deleted', (comment) => {
|
|
66
|
-
const node = this.commentNodes.find(c => c.getID() === comment.id)
|
|
67
|
-
if (!node) { console.error(`comment node id=${comment.id} not found`);return }
|
|
68
|
-
node.getEl().remove()
|
|
69
|
-
this.commentNodes = this.commentNodes.filter(c => c.getID() !== comment.id)
|
|
70
|
-
// TODO remove child nodes
|
|
71
|
-
})
|
|
72
|
-
|
|
73
|
-
// When comment update
|
|
74
|
-
this.ctx.on('comment-updated', (comment) => {
|
|
75
|
-
const node = this.commentNodes.find(c => c.getID() === comment.id)
|
|
76
|
-
node && node.setData(comment)
|
|
77
|
-
})
|
|
78
|
-
}
|
|
79
|
-
}
|
package/src/list/nest.ts
DELETED
|
@@ -1,66 +0,0 @@
|
|
|
1
|
-
import type { CommentData } from '~/types'
|
|
2
|
-
|
|
3
|
-
export type CommentNode = {
|
|
4
|
-
id: number
|
|
5
|
-
comment: CommentData
|
|
6
|
-
children: CommentNode[]
|
|
7
|
-
parent?: CommentNode
|
|
8
|
-
level: number
|
|
9
|
-
}
|
|
10
|
-
|
|
11
|
-
export type SortByType = 'DATE_DESC'|'DATE_ASC'|'SRC_INDEX'|'VOTE_UP_DESC'
|
|
12
|
-
|
|
13
|
-
// 构建树状结构列表
|
|
14
|
-
export function makeNestCommentNodeList(srcData: CommentData[], sortBy: SortByType = 'DATE_DESC', nestMax = 2) {
|
|
15
|
-
const nodeList: CommentNode[] = []
|
|
16
|
-
|
|
17
|
-
const roots = srcData.filter((o) => o.rid === 0)
|
|
18
|
-
roots.forEach((root: CommentData) => {
|
|
19
|
-
const rootNode: CommentNode = {
|
|
20
|
-
id: root.id,
|
|
21
|
-
comment: root,
|
|
22
|
-
children: [],
|
|
23
|
-
level: 1,
|
|
24
|
-
}
|
|
25
|
-
|
|
26
|
-
rootNode.parent = rootNode
|
|
27
|
-
nodeList.push(rootNode)
|
|
28
|
-
|
|
29
|
-
;(function loadChildren(parentNode: CommentNode) {
|
|
30
|
-
const children = srcData.filter((o) => o.rid === parentNode.id)
|
|
31
|
-
if (children.length === 0) return
|
|
32
|
-
if (parentNode.level >= nestMax) parentNode = parentNode.parent!
|
|
33
|
-
children.forEach((child: CommentData) => {
|
|
34
|
-
const childNode: CommentNode = {
|
|
35
|
-
id: child.id,
|
|
36
|
-
comment: child,
|
|
37
|
-
children: [],
|
|
38
|
-
parent: parentNode,
|
|
39
|
-
level: parentNode.level + 1,
|
|
40
|
-
}
|
|
41
|
-
|
|
42
|
-
parentNode.children.push(childNode)
|
|
43
|
-
loadChildren(childNode)
|
|
44
|
-
})
|
|
45
|
-
})(rootNode)
|
|
46
|
-
})
|
|
47
|
-
|
|
48
|
-
// 排序
|
|
49
|
-
const sortFunc = (a: CommentNode, b: CommentNode): number => {
|
|
50
|
-
let v = a.id - b.id
|
|
51
|
-
if (sortBy === 'DATE_ASC') v = +new Date(a.comment.date) - +new Date(b.comment.date)
|
|
52
|
-
else if (sortBy === 'DATE_DESC') v = +new Date(b.comment.date) - +new Date(a.comment.date)
|
|
53
|
-
else if (sortBy === 'SRC_INDEX') v = srcData.indexOf(a.comment) - srcData.indexOf(b.comment)
|
|
54
|
-
else if (sortBy === 'VOTE_UP_DESC') v = b.comment.vote_up - a.comment.vote_up
|
|
55
|
-
return v
|
|
56
|
-
}
|
|
57
|
-
|
|
58
|
-
(function sortLevels(nodes: CommentNode[]) {
|
|
59
|
-
nodes.forEach((node) => {
|
|
60
|
-
node.children = node.children.sort(sortFunc)
|
|
61
|
-
sortLevels(node.children)
|
|
62
|
-
})
|
|
63
|
-
})(nodeList)
|
|
64
|
-
|
|
65
|
-
return nodeList
|
|
66
|
-
}
|
package/src/list/page.ts
DELETED
|
@@ -1,97 +0,0 @@
|
|
|
1
|
-
import type { ArtalkConfig, ContextApi } from '~/types'
|
|
2
|
-
import $t from '@/i18n'
|
|
3
|
-
import { Paginator } from './paginator'
|
|
4
|
-
import ReadMorePaginator from './paginator/read-more'
|
|
5
|
-
import UpDownPaginator from './paginator/up-down'
|
|
6
|
-
|
|
7
|
-
function createPaginatorByConf(conf: ArtalkConfig): Paginator {
|
|
8
|
-
if (conf.pagination.readMore) return new ReadMorePaginator()
|
|
9
|
-
return new UpDownPaginator()
|
|
10
|
-
}
|
|
11
|
-
|
|
12
|
-
function getPageDataByLastData(ctx: ContextApi): { offset: number, total: number } {
|
|
13
|
-
const last = ctx.getData().getListLastFetch()
|
|
14
|
-
const r = { offset: 0, total: 0 }
|
|
15
|
-
if (!last) return r
|
|
16
|
-
|
|
17
|
-
r.offset = last.params.offset
|
|
18
|
-
if (last.data) r.total = last.params.flatMode ? last.data.total : last.data.total_roots
|
|
19
|
-
|
|
20
|
-
return r
|
|
21
|
-
}
|
|
22
|
-
|
|
23
|
-
export const initListPaginatorFunc = (ctx: ContextApi) => {
|
|
24
|
-
let paginator: Paginator|null = null
|
|
25
|
-
|
|
26
|
-
// Init paginator when conf loaded
|
|
27
|
-
ctx.on('conf-loaded', (conf) => {
|
|
28
|
-
const list = ctx.get('list')
|
|
29
|
-
|
|
30
|
-
if (paginator) paginator.dispose() // if had been init, dispose it
|
|
31
|
-
|
|
32
|
-
// create paginator instance
|
|
33
|
-
paginator = createPaginatorByConf(conf)
|
|
34
|
-
|
|
35
|
-
// create paginator dom
|
|
36
|
-
const { offset, total } = getPageDataByLastData(ctx)
|
|
37
|
-
const $paginator = paginator.create({
|
|
38
|
-
ctx, pageSize: conf.pagination.pageSize, total,
|
|
39
|
-
|
|
40
|
-
readMoreAutoLoad: conf.pagination.autoLoad,
|
|
41
|
-
})
|
|
42
|
-
|
|
43
|
-
// mount paginator dom
|
|
44
|
-
list.$commentsWrap.after($paginator)
|
|
45
|
-
|
|
46
|
-
// update paginator info
|
|
47
|
-
paginator?.update(offset, total)
|
|
48
|
-
})
|
|
49
|
-
|
|
50
|
-
// When list loaded
|
|
51
|
-
ctx.on('list-loaded', (comments) => {
|
|
52
|
-
// update paginator info
|
|
53
|
-
const { offset, total } = getPageDataByLastData(ctx)
|
|
54
|
-
paginator?.update(offset, total)
|
|
55
|
-
})
|
|
56
|
-
|
|
57
|
-
// When list fetch
|
|
58
|
-
ctx.on('list-fetch', (params) => {
|
|
59
|
-
// if clear comments when fetch new page data
|
|
60
|
-
if (ctx.getData().getComments().length > 0 && paginator?.getIsClearComments(params)) {
|
|
61
|
-
ctx.getData().clearComments()
|
|
62
|
-
}
|
|
63
|
-
})
|
|
64
|
-
|
|
65
|
-
// When list error
|
|
66
|
-
ctx.on('list-error', () => {
|
|
67
|
-
paginator?.showErr?.($t('loadFail'))
|
|
68
|
-
})
|
|
69
|
-
|
|
70
|
-
// List goto auto next page when comment not found
|
|
71
|
-
const autoSwitchPageForFindComment = (commentID: number) => {
|
|
72
|
-
const comment = ctx.getData().findComment(commentID)
|
|
73
|
-
if (!!comment || !paginator?.getHasMore()) return
|
|
74
|
-
|
|
75
|
-
// wait for list loaded
|
|
76
|
-
ctx.on('list-loaded', () => {
|
|
77
|
-
autoSwitchPageForFindComment(commentID) // recursive, until comment found or no more page
|
|
78
|
-
}, { once: true })
|
|
79
|
-
|
|
80
|
-
// TODO 自动范围改为直接跳转到计算后的页面
|
|
81
|
-
setTimeout(() => {
|
|
82
|
-
paginator?.next()
|
|
83
|
-
}, 80)
|
|
84
|
-
}
|
|
85
|
-
|
|
86
|
-
ctx.on('list-goto', (commentID) => {
|
|
87
|
-
autoSwitchPageForFindComment(commentID)
|
|
88
|
-
})
|
|
89
|
-
|
|
90
|
-
// loading
|
|
91
|
-
ctx.on('list-fetch', (params) => {
|
|
92
|
-
paginator?.setLoading(true)
|
|
93
|
-
})
|
|
94
|
-
ctx.on('list-fetched', ({ params }) => {
|
|
95
|
-
paginator?.setLoading(false)
|
|
96
|
-
})
|
|
97
|
-
}
|
|
@@ -1,25 +0,0 @@
|
|
|
1
|
-
import type { ContextApi, ListFetchParams } from '~/types'
|
|
2
|
-
import UpDownPaginator from './up-down'
|
|
3
|
-
import ReadMorePaginator from './read-more'
|
|
4
|
-
|
|
5
|
-
export interface IPgHolderOpt {
|
|
6
|
-
ctx: ContextApi
|
|
7
|
-
total: number
|
|
8
|
-
pageSize: number
|
|
9
|
-
|
|
10
|
-
readMoreAutoLoad?: boolean
|
|
11
|
-
}
|
|
12
|
-
|
|
13
|
-
export interface Paginator {
|
|
14
|
-
create(opts: IPgHolderOpt): HTMLElement
|
|
15
|
-
setLoading(val: boolean): void
|
|
16
|
-
update(offset: number, total: number): void
|
|
17
|
-
next(): void
|
|
18
|
-
showErr?(msg: string): void
|
|
19
|
-
getHasMore(): boolean
|
|
20
|
-
/** Clear comments when fetch new page data */
|
|
21
|
-
getIsClearComments(params: Partial<ListFetchParams>): boolean
|
|
22
|
-
dispose(): void
|
|
23
|
-
}
|
|
24
|
-
|
|
25
|
-
export default { UpDownPaginator, ReadMorePaginator }
|
|
@@ -1,67 +0,0 @@
|
|
|
1
|
-
import type { ListFetchParams } from '~/types'
|
|
2
|
-
import ReadMoreBtn from '@/components/read-more-btn'
|
|
3
|
-
import $t from '@/i18n'
|
|
4
|
-
import type { Paginator, IPgHolderOpt } from '.'
|
|
5
|
-
|
|
6
|
-
/**
|
|
7
|
-
* 阅读更多形式的分页
|
|
8
|
-
*/
|
|
9
|
-
export default class ReadMorePaginator implements Paginator {
|
|
10
|
-
private instance!: ReadMoreBtn
|
|
11
|
-
private onReachedBottom: (() => void) | null = null
|
|
12
|
-
private opt!: IPgHolderOpt
|
|
13
|
-
|
|
14
|
-
create(opt: IPgHolderOpt) {
|
|
15
|
-
this.opt = opt
|
|
16
|
-
|
|
17
|
-
this.instance = new ReadMoreBtn({
|
|
18
|
-
pageSize: opt.pageSize,
|
|
19
|
-
onClick: async (o) => {
|
|
20
|
-
opt.ctx.fetch({
|
|
21
|
-
offset: o,
|
|
22
|
-
})
|
|
23
|
-
},
|
|
24
|
-
text: $t('loadMore'),
|
|
25
|
-
})
|
|
26
|
-
|
|
27
|
-
// 滚动到底部自动加载
|
|
28
|
-
if (opt.readMoreAutoLoad) {
|
|
29
|
-
this.onReachedBottom = () => {
|
|
30
|
-
if (!this.instance.hasMore || this.opt.ctx.getData().getLoading()) return
|
|
31
|
-
this.instance.click()
|
|
32
|
-
}
|
|
33
|
-
this.opt.ctx.on('list-reach-bottom', this.onReachedBottom)
|
|
34
|
-
}
|
|
35
|
-
|
|
36
|
-
return this.instance.$el
|
|
37
|
-
}
|
|
38
|
-
|
|
39
|
-
setLoading(val: boolean) {
|
|
40
|
-
this.instance.setLoading(val)
|
|
41
|
-
}
|
|
42
|
-
|
|
43
|
-
update(offset: number, total: number) {
|
|
44
|
-
this.instance.update(offset, total)
|
|
45
|
-
}
|
|
46
|
-
|
|
47
|
-
showErr(msg: string) {
|
|
48
|
-
this.instance.showErr(msg)
|
|
49
|
-
}
|
|
50
|
-
|
|
51
|
-
next() {
|
|
52
|
-
this.instance.click()
|
|
53
|
-
}
|
|
54
|
-
|
|
55
|
-
getHasMore(): boolean {
|
|
56
|
-
return this.instance.hasMore
|
|
57
|
-
}
|
|
58
|
-
|
|
59
|
-
getIsClearComments(params: Partial<ListFetchParams>): boolean {
|
|
60
|
-
return params.offset === 0
|
|
61
|
-
}
|
|
62
|
-
|
|
63
|
-
dispose(): void {
|
|
64
|
-
this.onReachedBottom && this.opt.ctx.off('list-reach-bottom', this.onReachedBottom)
|
|
65
|
-
this.instance.$el.remove()
|
|
66
|
-
}
|
|
67
|
-
}
|
|
@@ -1,51 +0,0 @@
|
|
|
1
|
-
import PaginationComponent from '@/components/pagination'
|
|
2
|
-
import type { Paginator, IPgHolderOpt } from '.'
|
|
3
|
-
|
|
4
|
-
/**
|
|
5
|
-
* 翻页形式的分页
|
|
6
|
-
*/
|
|
7
|
-
export default class UpDownPaginator implements Paginator {
|
|
8
|
-
private instance!: PaginationComponent
|
|
9
|
-
|
|
10
|
-
create(opt: IPgHolderOpt) {
|
|
11
|
-
this.instance = new PaginationComponent(opt.total, {
|
|
12
|
-
pageSize: opt.pageSize,
|
|
13
|
-
onChange: async (o) => {
|
|
14
|
-
opt.ctx.editorResetState() // 防止评论框被吞
|
|
15
|
-
|
|
16
|
-
opt.ctx.fetch({
|
|
17
|
-
offset: o,
|
|
18
|
-
onSuccess: () => {
|
|
19
|
-
opt.ctx.listGotoFirst()
|
|
20
|
-
}
|
|
21
|
-
})
|
|
22
|
-
}
|
|
23
|
-
})
|
|
24
|
-
|
|
25
|
-
return this.instance.$el
|
|
26
|
-
}
|
|
27
|
-
|
|
28
|
-
setLoading(val: boolean) {
|
|
29
|
-
this.instance.setLoading(val)
|
|
30
|
-
}
|
|
31
|
-
|
|
32
|
-
update(offset: number, total: number) {
|
|
33
|
-
this.instance.update(offset, total)
|
|
34
|
-
}
|
|
35
|
-
|
|
36
|
-
next() {
|
|
37
|
-
this.instance.next()
|
|
38
|
-
}
|
|
39
|
-
|
|
40
|
-
getHasMore(): boolean {
|
|
41
|
-
return this.instance.getHasMore()
|
|
42
|
-
}
|
|
43
|
-
|
|
44
|
-
getIsClearComments(): boolean {
|
|
45
|
-
return true
|
|
46
|
-
}
|
|
47
|
-
|
|
48
|
-
dispose(): void {
|
|
49
|
-
this.instance.$el.remove()
|
|
50
|
-
}
|
|
51
|
-
}
|
package/src/main.ts
DELETED
|
@@ -1,40 +0,0 @@
|
|
|
1
|
-
import type { ArtalkPlugin } from '~/types'
|
|
2
|
-
|
|
3
|
-
export const AdminOnlyElem: ArtalkPlugin = (ctx) => {
|
|
4
|
-
const scanApply = () => {
|
|
5
|
-
applyAdminOnlyEls(ctx.get('user').data.isAdmin, getAdminOnlyEls({
|
|
6
|
-
$root: ctx.$root
|
|
7
|
-
}))
|
|
8
|
-
}
|
|
9
|
-
|
|
10
|
-
ctx.on('list-loaded', () => {
|
|
11
|
-
scanApply()
|
|
12
|
-
})
|
|
13
|
-
|
|
14
|
-
ctx.on('user-changed', (user) => {
|
|
15
|
-
scanApply()
|
|
16
|
-
})
|
|
17
|
-
}
|
|
18
|
-
|
|
19
|
-
function getAdminOnlyEls(opts: { $root: HTMLElement }): HTMLElement[] {
|
|
20
|
-
const els: HTMLElement[] = []
|
|
21
|
-
|
|
22
|
-
// elements in $root
|
|
23
|
-
opts.$root.querySelectorAll<HTMLElement>(`[atk-only-admin-show]`).forEach(item => els.push(item))
|
|
24
|
-
|
|
25
|
-
// TODO provide a Artalk.conf hook to set whitelist of admin-only elements,
|
|
26
|
-
// and move following code to that hook (move into packages/artalk-sidebar)
|
|
27
|
-
|
|
28
|
-
// elements in sidebar
|
|
29
|
-
const $sidebarEl = document.querySelector<HTMLElement>('.atk-sidebar')
|
|
30
|
-
if ($sidebarEl) $sidebarEl.querySelectorAll<HTMLElement>(`[atk-only-admin-show]`).forEach(item => els.push(item))
|
|
31
|
-
|
|
32
|
-
return els
|
|
33
|
-
}
|
|
34
|
-
|
|
35
|
-
function applyAdminOnlyEls(isAdmin: boolean, els: HTMLElement[]) {
|
|
36
|
-
els.forEach(($item: HTMLElement) => {
|
|
37
|
-
if (isAdmin) $item.classList.remove('atk-hide')
|
|
38
|
-
else $item.classList.add('atk-hide')
|
|
39
|
-
})
|
|
40
|
-
}
|
|
@@ -1,54 +0,0 @@
|
|
|
1
|
-
import type { ArtalkConfig, ArtalkPlugin, ContextApi } from '~/types'
|
|
2
|
-
import { handleConfFormServer } from '@/config'
|
|
3
|
-
import { showErrorDialog } from '../components/error-dialog'
|
|
4
|
-
|
|
5
|
-
export const ConfRemoter: ArtalkPlugin = (ctx) => {
|
|
6
|
-
ctx.on('inited', () => {
|
|
7
|
-
loadConf(ctx)
|
|
8
|
-
})
|
|
9
|
-
}
|
|
10
|
-
|
|
11
|
-
function loadConf(ctx: ContextApi) {
|
|
12
|
-
ctx.getApi().system.conf().then((data) => {
|
|
13
|
-
let conf: Partial<ArtalkConfig> = {
|
|
14
|
-
apiVersion: data.version.version, // version info
|
|
15
|
-
}
|
|
16
|
-
|
|
17
|
-
// reference conf from backend
|
|
18
|
-
if (ctx.conf.useBackendConf) {
|
|
19
|
-
if (!data.frontend_conf) throw new Error('The remote backend does not respond to the frontend conf, but `useBackendConf` conf is enabled')
|
|
20
|
-
conf = { ...conf, ...handleConfFormServer(data.frontend_conf) }
|
|
21
|
-
}
|
|
22
|
-
|
|
23
|
-
// apply conf modifier
|
|
24
|
-
ctx.conf.remoteConfModifier && ctx.conf.remoteConfModifier(conf)
|
|
25
|
-
|
|
26
|
-
ctx.updateConf(conf)
|
|
27
|
-
}).catch((err) => {
|
|
28
|
-
ctx.updateConf({})
|
|
29
|
-
|
|
30
|
-
let sidebarOpenView = ''
|
|
31
|
-
|
|
32
|
-
// if response err_no_site, modify the sidebar open view to create site
|
|
33
|
-
if (err.data?.err_no_site) {
|
|
34
|
-
const viewLoadParam = { create_name: ctx.conf.site, create_urls: `${window.location.protocol}//${window.location.host}` }
|
|
35
|
-
sidebarOpenView = `sites|${JSON.stringify(viewLoadParam)}`
|
|
36
|
-
}
|
|
37
|
-
|
|
38
|
-
showErrorDialog({
|
|
39
|
-
$err: ctx.get('list').$el,
|
|
40
|
-
errMsg: err.msg || String(err),
|
|
41
|
-
errData: err.data,
|
|
42
|
-
retryFn: () => loadConf(ctx),
|
|
43
|
-
onOpenSidebar:() => ctx.showSidebar({
|
|
44
|
-
view: sidebarOpenView as any
|
|
45
|
-
})
|
|
46
|
-
})
|
|
47
|
-
|
|
48
|
-
throw err
|
|
49
|
-
}).then(() => {
|
|
50
|
-
// 评论获取
|
|
51
|
-
if (ctx.conf.remoteConfModifier) return // only auto fetch when no remoteConfModifier
|
|
52
|
-
ctx.fetch({ offset: 0 })
|
|
53
|
-
}).catch(() => {})
|
|
54
|
-
}
|
package/src/plugins/dark-mode.ts
DELETED
|
@@ -1,12 +0,0 @@
|
|
|
1
|
-
import type { ArtalkPlugin } from '~/types'
|
|
2
|
-
import { applyDarkMode } from '@/components/dark-mode'
|
|
3
|
-
|
|
4
|
-
export const DarkMode: ArtalkPlugin = (ctx) => {
|
|
5
|
-
const sync = () => {
|
|
6
|
-
applyDarkMode([ctx.$root, ctx.get('layerManager').getEl()], ctx.conf.darkMode)
|
|
7
|
-
}
|
|
8
|
-
|
|
9
|
-
ctx.on('inited', () => sync())
|
|
10
|
-
ctx.on('conf-loaded', () => sync())
|
|
11
|
-
ctx.on('dark-mode-changed', () => sync())
|
|
12
|
-
}
|