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
|
@@ -1,35 +0,0 @@
|
|
|
1
|
-
import * as Utils from '@/lib/utils'
|
|
2
|
-
import * as Ui from '@/lib/ui'
|
|
3
|
-
import User from '@/lib/user'
|
|
4
|
-
import $t from '@/i18n'
|
|
5
|
-
|
|
6
|
-
export interface ErrorDialogOptions {
|
|
7
|
-
$err: HTMLElement
|
|
8
|
-
|
|
9
|
-
errMsg: string
|
|
10
|
-
errData?: any
|
|
11
|
-
retryFn?: () => void
|
|
12
|
-
|
|
13
|
-
onOpenSidebar?: () => void
|
|
14
|
-
}
|
|
15
|
-
|
|
16
|
-
export function showErrorDialog(opts: ErrorDialogOptions) {
|
|
17
|
-
const errEl = Utils.createElement(`<span>${opts.errMsg},${$t('listLoadFailMsg')}<br/></span>`)
|
|
18
|
-
|
|
19
|
-
if (opts.retryFn) {
|
|
20
|
-
const $retryBtn = Utils.createElement(`<span style="cursor:pointer;">${$t('listRetry')}</span>`)
|
|
21
|
-
$retryBtn.onclick = () => opts.retryFn && opts.retryFn()
|
|
22
|
-
errEl.appendChild($retryBtn)
|
|
23
|
-
}
|
|
24
|
-
|
|
25
|
-
if (opts.onOpenSidebar) {
|
|
26
|
-
const $openSidebar = Utils.createElement('<span atk-only-admin-show> | <span style="cursor:pointer;">打开控制台</span></span>')
|
|
27
|
-
errEl.appendChild($openSidebar)
|
|
28
|
-
if (!User.data.isAdmin) { // only display if user is admin
|
|
29
|
-
$openSidebar.classList.add('atk-hide')
|
|
30
|
-
}
|
|
31
|
-
$openSidebar.onclick = () => opts.onOpenSidebar && opts.onOpenSidebar()
|
|
32
|
-
}
|
|
33
|
-
|
|
34
|
-
Ui.setError(opts.$err, errEl)
|
|
35
|
-
}
|
|
@@ -1,153 +0,0 @@
|
|
|
1
|
-
import * as Utils from '../lib/utils'
|
|
2
|
-
import * as Ui from '../lib/ui'
|
|
3
|
-
|
|
4
|
-
export interface PaginationOptions {
|
|
5
|
-
/** 每页条数 */
|
|
6
|
-
pageSize: number
|
|
7
|
-
|
|
8
|
-
/** 回调函数 */
|
|
9
|
-
onChange: (offset: number) => void
|
|
10
|
-
}
|
|
11
|
-
|
|
12
|
-
export default class Pagination {
|
|
13
|
-
private opts: PaginationOptions
|
|
14
|
-
public total: number
|
|
15
|
-
public $el: HTMLElement
|
|
16
|
-
public $input: HTMLInputElement
|
|
17
|
-
public inputTimer?: number
|
|
18
|
-
public $prevBtn: HTMLElement
|
|
19
|
-
public $nextBtn: HTMLElement
|
|
20
|
-
|
|
21
|
-
public page: number = 1
|
|
22
|
-
get pageSize(): number {
|
|
23
|
-
return this.opts.pageSize
|
|
24
|
-
}
|
|
25
|
-
get offset(): number {
|
|
26
|
-
return this.pageSize * (this.page - 1)
|
|
27
|
-
}
|
|
28
|
-
get maxPage(): number {
|
|
29
|
-
return Math.ceil(this.total / this.pageSize)
|
|
30
|
-
}
|
|
31
|
-
|
|
32
|
-
public constructor(total: number, opts: PaginationOptions) {
|
|
33
|
-
this.total = total
|
|
34
|
-
this.opts = opts
|
|
35
|
-
|
|
36
|
-
this.$el = Utils.createElement(
|
|
37
|
-
`<div class="atk-pagination-wrap">
|
|
38
|
-
<div class="atk-pagination">
|
|
39
|
-
<div class="atk-btn atk-btn-prev">Prev</div>
|
|
40
|
-
<input type="text" class="atk-input" aria-label="Enter the number of page" />
|
|
41
|
-
<div class="atk-btn atk-btn-next">Next</div>
|
|
42
|
-
</div>
|
|
43
|
-
</div>`)
|
|
44
|
-
this.$input = this.$el.querySelector('.atk-input')!
|
|
45
|
-
this.$input.value = `${this.page}`
|
|
46
|
-
|
|
47
|
-
this.$input.oninput = () => this.input()
|
|
48
|
-
this.$input.onkeydown = (e) => this.keydown(e)
|
|
49
|
-
|
|
50
|
-
this.$prevBtn = this.$el.querySelector('.atk-btn-prev')!
|
|
51
|
-
this.$nextBtn = this.$el.querySelector('.atk-btn-next')!
|
|
52
|
-
|
|
53
|
-
this.$prevBtn.onclick = () => this.prev()
|
|
54
|
-
this.$nextBtn.onclick = () => this.next()
|
|
55
|
-
|
|
56
|
-
this.checkDisabled()
|
|
57
|
-
}
|
|
58
|
-
|
|
59
|
-
public update(offset: number, total: number) {
|
|
60
|
-
this.page = Math.ceil(offset / this.pageSize) + 1
|
|
61
|
-
this.total = total
|
|
62
|
-
|
|
63
|
-
this.setInput(this.page)
|
|
64
|
-
this.checkDisabled()
|
|
65
|
-
}
|
|
66
|
-
|
|
67
|
-
public setInput(page: number) {
|
|
68
|
-
this.$input.value = `${page}`
|
|
69
|
-
}
|
|
70
|
-
|
|
71
|
-
public input(now: boolean = false) {
|
|
72
|
-
window.clearTimeout(this.inputTimer)
|
|
73
|
-
|
|
74
|
-
const value = this.$input.value.trim()
|
|
75
|
-
|
|
76
|
-
const modify = () => {
|
|
77
|
-
if (value === '') { this.setInput(this.page);return }
|
|
78
|
-
let page = Number(value)
|
|
79
|
-
if (Number.isNaN(page)) { this.setInput(this.page);return }
|
|
80
|
-
if (page < 1) { this.setInput(this.page);return }
|
|
81
|
-
if (page > this.maxPage) { this.setInput(this.maxPage);page = this.maxPage }
|
|
82
|
-
this.change(page)
|
|
83
|
-
}
|
|
84
|
-
|
|
85
|
-
// 延迟 800ms 执行
|
|
86
|
-
if (!now) this.inputTimer = window.setTimeout(() => modify(), 800)
|
|
87
|
-
else modify()
|
|
88
|
-
}
|
|
89
|
-
|
|
90
|
-
public prev() {
|
|
91
|
-
const page = this.page - 1
|
|
92
|
-
if (page < 1) { return }
|
|
93
|
-
this.change(page)
|
|
94
|
-
}
|
|
95
|
-
|
|
96
|
-
public next() {
|
|
97
|
-
const page = this.page + 1
|
|
98
|
-
if (page > this.maxPage) { return }
|
|
99
|
-
this.change(page)
|
|
100
|
-
}
|
|
101
|
-
|
|
102
|
-
public getHasMore() {
|
|
103
|
-
return this.page + 1 <= this.maxPage
|
|
104
|
-
}
|
|
105
|
-
|
|
106
|
-
public change(page: number) {
|
|
107
|
-
this.page = page
|
|
108
|
-
this.opts.onChange(this.offset)
|
|
109
|
-
this.setInput(page)
|
|
110
|
-
this.checkDisabled()
|
|
111
|
-
}
|
|
112
|
-
|
|
113
|
-
public checkDisabled() {
|
|
114
|
-
if (this.page + 1 > this.maxPage) {
|
|
115
|
-
this.$nextBtn.classList.add('atk-disabled')
|
|
116
|
-
} else {
|
|
117
|
-
this.$nextBtn.classList.remove('atk-disabled')
|
|
118
|
-
}
|
|
119
|
-
|
|
120
|
-
if (this.page - 1 < 1) {
|
|
121
|
-
this.$prevBtn.classList.add('atk-disabled')
|
|
122
|
-
} else {
|
|
123
|
-
this.$prevBtn.classList.remove('atk-disabled')
|
|
124
|
-
}
|
|
125
|
-
}
|
|
126
|
-
|
|
127
|
-
public keydown(e: KeyboardEvent) {
|
|
128
|
-
const keyCode = e.keyCode || e.which
|
|
129
|
-
|
|
130
|
-
if (keyCode === 38) {
|
|
131
|
-
// 上键
|
|
132
|
-
const page = Number(this.$input.value) + 1
|
|
133
|
-
if (page > this.maxPage) { return }
|
|
134
|
-
this.setInput(page);
|
|
135
|
-
this.input()
|
|
136
|
-
} else if (keyCode === 40) {
|
|
137
|
-
// 下键
|
|
138
|
-
const page = Number(this.$input.value) - 1
|
|
139
|
-
if (page < 1) { return }
|
|
140
|
-
this.setInput(page)
|
|
141
|
-
this.input()
|
|
142
|
-
} else if (keyCode === 13) {
|
|
143
|
-
// 回车
|
|
144
|
-
this.input(true)
|
|
145
|
-
}
|
|
146
|
-
}
|
|
147
|
-
|
|
148
|
-
/** 加载 */
|
|
149
|
-
setLoading (isLoading: boolean) {
|
|
150
|
-
if (isLoading) Ui.showLoading(this.$el)
|
|
151
|
-
else Ui.hideLoading(this.$el)
|
|
152
|
-
}
|
|
153
|
-
}
|
|
@@ -1,92 +0,0 @@
|
|
|
1
|
-
import * as Utils from '../lib/utils'
|
|
2
|
-
|
|
3
|
-
export interface ReadMoreBtnOptions {
|
|
4
|
-
/** 回调函数 */
|
|
5
|
-
onClick: (offset: number) => void
|
|
6
|
-
|
|
7
|
-
pageSize: number
|
|
8
|
-
|
|
9
|
-
text?: string
|
|
10
|
-
}
|
|
11
|
-
|
|
12
|
-
/**
|
|
13
|
-
* 阅读更多按钮
|
|
14
|
-
*/
|
|
15
|
-
export default class ReadMoreBtn {
|
|
16
|
-
public opts: ReadMoreBtnOptions
|
|
17
|
-
public $el: HTMLElement
|
|
18
|
-
private $loading: HTMLElement
|
|
19
|
-
private $text: HTMLElement
|
|
20
|
-
private offset: number = 0
|
|
21
|
-
private total: number = 0
|
|
22
|
-
private origText: string = 'Load More'
|
|
23
|
-
|
|
24
|
-
/** 是否有更多内容 */
|
|
25
|
-
get hasMore() {
|
|
26
|
-
return this.total > (this.offset + this.opts.pageSize)
|
|
27
|
-
}
|
|
28
|
-
|
|
29
|
-
public constructor(opts: ReadMoreBtnOptions) {
|
|
30
|
-
this.opts = opts
|
|
31
|
-
this.origText = this.opts.text || this.origText
|
|
32
|
-
|
|
33
|
-
this.$el = Utils.createElement(
|
|
34
|
-
`<div class="atk-list-read-more" style="display: none;">
|
|
35
|
-
<div class="atk-list-read-more-inner">
|
|
36
|
-
<div class="atk-loading-icon" style="display: none;"></div>
|
|
37
|
-
<span class="atk-text">${this.origText}</span>
|
|
38
|
-
</div>
|
|
39
|
-
</div>`)
|
|
40
|
-
|
|
41
|
-
this.$loading = this.$el.querySelector<HTMLElement>('.atk-loading-icon')!
|
|
42
|
-
this.$text = this.$el.querySelector<HTMLElement>('.atk-text')!
|
|
43
|
-
|
|
44
|
-
this.$el.onclick = () => { this.click() }
|
|
45
|
-
}
|
|
46
|
-
|
|
47
|
-
click() {
|
|
48
|
-
if (this.hasMore) this.opts.onClick(this.offset + this.opts.pageSize)
|
|
49
|
-
this.checkDisabled()
|
|
50
|
-
}
|
|
51
|
-
|
|
52
|
-
/** 显示 */
|
|
53
|
-
show() {
|
|
54
|
-
this.$el.style.display = ''
|
|
55
|
-
}
|
|
56
|
-
|
|
57
|
-
/** 隐藏 */
|
|
58
|
-
hide() {
|
|
59
|
-
this.$el.style.display = 'none'
|
|
60
|
-
}
|
|
61
|
-
|
|
62
|
-
/** 加载 */
|
|
63
|
-
setLoading (isLoading: boolean) {
|
|
64
|
-
this.$loading.style.display = isLoading ? '' : 'none'
|
|
65
|
-
this.$text.style.display = isLoading ? 'none' : ''
|
|
66
|
-
}
|
|
67
|
-
|
|
68
|
-
/** 错误提示 */
|
|
69
|
-
showErr(errMsg: string) {
|
|
70
|
-
this.setLoading(false)
|
|
71
|
-
|
|
72
|
-
this.$text.innerText = errMsg
|
|
73
|
-
this.$el.classList.add('atk-err')
|
|
74
|
-
window.setTimeout(() => {
|
|
75
|
-
this.$text.innerText = this.origText
|
|
76
|
-
this.$el.classList.remove('atk-err')
|
|
77
|
-
}, 2000) // 2s后错误提示复原
|
|
78
|
-
}
|
|
79
|
-
|
|
80
|
-
/** 更新数据 */
|
|
81
|
-
public update(offset: number, total: number) {
|
|
82
|
-
this.offset = offset
|
|
83
|
-
this.total = total
|
|
84
|
-
|
|
85
|
-
this.checkDisabled()
|
|
86
|
-
}
|
|
87
|
-
|
|
88
|
-
public checkDisabled() {
|
|
89
|
-
if (this.hasMore) this.show()
|
|
90
|
-
else this.hide()
|
|
91
|
-
}
|
|
92
|
-
}
|
package/src/config.ts
DELETED
|
@@ -1,119 +0,0 @@
|
|
|
1
|
-
import type { ArtalkConfig, ContextApi } from '~/types'
|
|
2
|
-
import type { ApiOptions } from './api/_options'
|
|
3
|
-
import * as Utils from './lib/utils'
|
|
4
|
-
import Defaults from './defaults'
|
|
5
|
-
|
|
6
|
-
/**
|
|
7
|
-
* Merges the user custom config with the default config
|
|
8
|
-
*
|
|
9
|
-
* @param customConf - The custom config object which is provided by the user
|
|
10
|
-
* @returns The config for Artalk instance creation
|
|
11
|
-
*/
|
|
12
|
-
export function handelCustomConf(customConf: Partial<ArtalkConfig>): ArtalkConfig {
|
|
13
|
-
// 合并默认配置
|
|
14
|
-
const conf: ArtalkConfig = Utils.mergeDeep(Defaults, customConf)
|
|
15
|
-
|
|
16
|
-
// TODO the type of el options may HTMLElement, use it directly instead of from mergeDeep
|
|
17
|
-
if (customConf.el) conf.el = customConf.el
|
|
18
|
-
|
|
19
|
-
// 绑定元素
|
|
20
|
-
if (typeof conf.el === 'string' && !!conf.el) {
|
|
21
|
-
try {
|
|
22
|
-
const findEl = document.querySelector<HTMLElement>(conf.el)
|
|
23
|
-
if (!findEl) throw Error(`Target element "${conf.el}" was not found.`)
|
|
24
|
-
conf.el = findEl
|
|
25
|
-
} catch (e) {
|
|
26
|
-
console.error(e)
|
|
27
|
-
throw new Error('Please check your Artalk `el` config.')
|
|
28
|
-
}
|
|
29
|
-
}
|
|
30
|
-
|
|
31
|
-
// 服务器配置
|
|
32
|
-
conf.server = conf.server.replace(/\/$/, '').replace(/\/api\/?$/, '')
|
|
33
|
-
|
|
34
|
-
// 默认 pageKey
|
|
35
|
-
if (!conf.pageKey) {
|
|
36
|
-
// @link http://bl.ocks.org/abernier/3070589
|
|
37
|
-
conf.pageKey = `${window.location.pathname}`
|
|
38
|
-
}
|
|
39
|
-
|
|
40
|
-
// 默认 pageTitle
|
|
41
|
-
if (!conf.pageTitle) {
|
|
42
|
-
conf.pageTitle = `${document.title}`
|
|
43
|
-
}
|
|
44
|
-
|
|
45
|
-
// 自适应语言
|
|
46
|
-
if (conf.locale === 'auto') {
|
|
47
|
-
conf.locale = navigator.language
|
|
48
|
-
}
|
|
49
|
-
|
|
50
|
-
// flatMode
|
|
51
|
-
if (conf.flatMode === true || Number(conf.nestMax) <= 1)
|
|
52
|
-
conf.flatMode = true
|
|
53
|
-
|
|
54
|
-
// 自动判断启用平铺模式
|
|
55
|
-
if (conf.flatMode === 'auto')
|
|
56
|
-
conf.flatMode = window.matchMedia("(max-width: 768px)").matches
|
|
57
|
-
|
|
58
|
-
return conf
|
|
59
|
-
}
|
|
60
|
-
|
|
61
|
-
/**
|
|
62
|
-
* Handle the config which is provided by the server
|
|
63
|
-
*
|
|
64
|
-
* @param conf - The Server response config for control the frontend of Artalk remotely
|
|
65
|
-
* @returns The config for Artalk instance creation
|
|
66
|
-
*/
|
|
67
|
-
export function handleConfFormServer(conf: Partial<ArtalkConfig>) {
|
|
68
|
-
const DisabledKeys: (keyof ArtalkConfig)[] = [
|
|
69
|
-
'el', 'pageKey', 'pageTitle', 'server', 'site', 'darkMode'
|
|
70
|
-
]
|
|
71
|
-
Object.keys(conf).forEach(k => {
|
|
72
|
-
if (DisabledKeys.includes(k as any)) delete conf[k]
|
|
73
|
-
})
|
|
74
|
-
|
|
75
|
-
// Patch: `emoticons` config string to json
|
|
76
|
-
if (conf.emoticons && typeof conf.emoticons === "string") {
|
|
77
|
-
conf.emoticons = conf.emoticons.trim()
|
|
78
|
-
if (conf.emoticons.startsWith("[") || conf.emoticons.startsWith("{")) {
|
|
79
|
-
conf.emoticons = JSON.parse(conf.emoticons) // pase json
|
|
80
|
-
} else if (conf.emoticons === "false") {
|
|
81
|
-
conf.emoticons = false
|
|
82
|
-
}
|
|
83
|
-
}
|
|
84
|
-
|
|
85
|
-
return conf
|
|
86
|
-
}
|
|
87
|
-
|
|
88
|
-
/**
|
|
89
|
-
* Convert Artalk Config to ApiOptions for Api client
|
|
90
|
-
*
|
|
91
|
-
* @param conf - Artalk config
|
|
92
|
-
* @param ctx - If `ctx` not provided, `checkAdmin` and `checkCaptcha` will be disabled
|
|
93
|
-
* @returns ApiOptions for Api client instance creation
|
|
94
|
-
*/
|
|
95
|
-
export function convertApiOptions(conf: Partial<ArtalkConfig>, ctx?: ContextApi): ApiOptions {
|
|
96
|
-
return {
|
|
97
|
-
baseURL: `${conf.server}/api`,
|
|
98
|
-
siteName: conf.site || '',
|
|
99
|
-
pageKey: conf.pageKey || '',
|
|
100
|
-
pageTitle: conf.pageTitle || '',
|
|
101
|
-
timeout: conf.reqTimeout,
|
|
102
|
-
|
|
103
|
-
onNeedCheckAdmin(payload) {
|
|
104
|
-
ctx?.checkAdmin({
|
|
105
|
-
onSuccess: () => { payload.recall() },
|
|
106
|
-
onCancel: () => { payload.reject() },
|
|
107
|
-
})
|
|
108
|
-
},
|
|
109
|
-
|
|
110
|
-
onNeedCheckCaptcha(payload) {
|
|
111
|
-
ctx?.checkCaptcha({
|
|
112
|
-
imgData: payload.data.imgData,
|
|
113
|
-
iframe: payload.data.iframe,
|
|
114
|
-
onSuccess: () => { payload.recall() },
|
|
115
|
-
onCancel: () => { payload.reject() },
|
|
116
|
-
})
|
|
117
|
-
},
|
|
118
|
-
}
|
|
119
|
-
}
|
package/src/context.ts
DELETED
|
@@ -1,146 +0,0 @@
|
|
|
1
|
-
import type { ArtalkConfig, CommentData, ListFetchParams, ContextApi, EventPayloadMap, SidebarShowPayload } from '~/types'
|
|
2
|
-
import type { TInjectedServices } from './service'
|
|
3
|
-
import Api from './api'
|
|
4
|
-
|
|
5
|
-
import * as Utils from './lib/utils'
|
|
6
|
-
import * as marked from './lib/marked'
|
|
7
|
-
import { CheckerCaptchaPayload, CheckerPayload } from './components/checker'
|
|
8
|
-
|
|
9
|
-
import { DataManager } from './data'
|
|
10
|
-
import * as I18n from './i18n'
|
|
11
|
-
|
|
12
|
-
import EventManager from './lib/event-manager'
|
|
13
|
-
import { convertApiOptions, handelCustomConf } from './config'
|
|
14
|
-
|
|
15
|
-
// Auto dependency injection
|
|
16
|
-
interface Context extends TInjectedServices { }
|
|
17
|
-
|
|
18
|
-
/**
|
|
19
|
-
* Artalk Context
|
|
20
|
-
*/
|
|
21
|
-
class Context implements ContextApi {
|
|
22
|
-
/* 运行参数 */
|
|
23
|
-
public conf: ArtalkConfig
|
|
24
|
-
public data: DataManager
|
|
25
|
-
public $root: HTMLElement
|
|
26
|
-
|
|
27
|
-
/* Event Manager */
|
|
28
|
-
private events = new EventManager<EventPayloadMap>()
|
|
29
|
-
|
|
30
|
-
public constructor(conf: ArtalkConfig, $root?: HTMLElement) {
|
|
31
|
-
this.conf = conf
|
|
32
|
-
|
|
33
|
-
this.$root = $root || document.createElement('div')
|
|
34
|
-
this.$root.classList.add('artalk')
|
|
35
|
-
this.$root.innerHTML = ''
|
|
36
|
-
|
|
37
|
-
this.data = new DataManager(this.events)
|
|
38
|
-
}
|
|
39
|
-
|
|
40
|
-
public inject(depName: string, obj: any) {
|
|
41
|
-
this[depName] = obj
|
|
42
|
-
}
|
|
43
|
-
|
|
44
|
-
public get(depName: string) {
|
|
45
|
-
return this[depName]
|
|
46
|
-
}
|
|
47
|
-
|
|
48
|
-
public getApi() {
|
|
49
|
-
return new Api(convertApiOptions(this.conf, this))
|
|
50
|
-
}
|
|
51
|
-
|
|
52
|
-
public getData() {
|
|
53
|
-
return this.data
|
|
54
|
-
}
|
|
55
|
-
|
|
56
|
-
public replyComment(commentData: CommentData, $comment: HTMLElement): void {
|
|
57
|
-
this.editor.setReply(commentData, $comment)
|
|
58
|
-
}
|
|
59
|
-
|
|
60
|
-
public editComment(commentData: CommentData, $comment: HTMLElement): void {
|
|
61
|
-
this.editor.setEditComment(commentData, $comment)
|
|
62
|
-
}
|
|
63
|
-
|
|
64
|
-
public fetch(params: Partial<ListFetchParams>): void {
|
|
65
|
-
this.data.fetchComments(params)
|
|
66
|
-
}
|
|
67
|
-
|
|
68
|
-
public reload(): void {
|
|
69
|
-
this.data.fetchComments({ offset: 0 })
|
|
70
|
-
}
|
|
71
|
-
|
|
72
|
-
public listGotoFirst(): void {
|
|
73
|
-
this.trigger('list-goto-first')
|
|
74
|
-
}
|
|
75
|
-
|
|
76
|
-
/* 编辑器 */
|
|
77
|
-
public editorShowLoading(): void {
|
|
78
|
-
this.editor.showLoading()
|
|
79
|
-
}
|
|
80
|
-
|
|
81
|
-
public editorHideLoading(): void {
|
|
82
|
-
this.editor.hideLoading()
|
|
83
|
-
}
|
|
84
|
-
|
|
85
|
-
public editorShowNotify(msg, type): void {
|
|
86
|
-
this.editor.showNotify(msg, type)
|
|
87
|
-
}
|
|
88
|
-
|
|
89
|
-
public editorResetState(): void {
|
|
90
|
-
this.editor.resetState()
|
|
91
|
-
}
|
|
92
|
-
|
|
93
|
-
/* 侧边栏 */
|
|
94
|
-
public showSidebar(payload?: SidebarShowPayload): void {
|
|
95
|
-
this.sidebarLayer.show(payload)
|
|
96
|
-
}
|
|
97
|
-
|
|
98
|
-
public hideSidebar(): void {
|
|
99
|
-
this.sidebarLayer.hide()
|
|
100
|
-
}
|
|
101
|
-
|
|
102
|
-
/* 权限检测 */
|
|
103
|
-
public checkAdmin(payload: CheckerPayload): void {
|
|
104
|
-
this.checkerLauncher.checkAdmin(payload)
|
|
105
|
-
}
|
|
106
|
-
|
|
107
|
-
public checkCaptcha(payload: CheckerCaptchaPayload): void {
|
|
108
|
-
this.checkerLauncher.checkCaptcha(payload)
|
|
109
|
-
}
|
|
110
|
-
|
|
111
|
-
/* Events */
|
|
112
|
-
public on(name: any, handler: any) {
|
|
113
|
-
this.events.on(name, handler)
|
|
114
|
-
}
|
|
115
|
-
|
|
116
|
-
public off(name: any, handler: any) {
|
|
117
|
-
this.events.off(name, handler)
|
|
118
|
-
}
|
|
119
|
-
|
|
120
|
-
public trigger(name: any, payload?: any) {
|
|
121
|
-
this.events.trigger(name, payload)
|
|
122
|
-
}
|
|
123
|
-
|
|
124
|
-
/* i18n */
|
|
125
|
-
public $t(key: I18n.I18nKeys, args: {[key: string]: string} = {}): string {
|
|
126
|
-
return I18n.t(key, args)
|
|
127
|
-
}
|
|
128
|
-
|
|
129
|
-
public setDarkMode(darkMode: boolean|'auto'): void {
|
|
130
|
-
// prevent trigger 'conf-loaded' to improve performance
|
|
131
|
-
// this.updateConf({ ...this.conf, darkMode })
|
|
132
|
-
this.conf.darkMode = darkMode
|
|
133
|
-
this.trigger('dark-mode-changed', darkMode)
|
|
134
|
-
}
|
|
135
|
-
|
|
136
|
-
public updateConf(nConf: Partial<ArtalkConfig>): void {
|
|
137
|
-
this.conf = Utils.mergeDeep(this.conf, handelCustomConf(nConf))
|
|
138
|
-
this.trigger('conf-loaded', this.conf)
|
|
139
|
-
}
|
|
140
|
-
|
|
141
|
-
public getMarked() {
|
|
142
|
-
return marked.getInstance()
|
|
143
|
-
}
|
|
144
|
-
}
|
|
145
|
-
|
|
146
|
-
export default Context
|
package/src/data.ts
DELETED
|
@@ -1,110 +0,0 @@
|
|
|
1
|
-
import type { NotifyData, PageData, CommentData, DataManagerApi, ListFetchParams, ListLastFetchData, EventPayloadMap } from '~/types'
|
|
2
|
-
import EventManager from './lib/event-manager'
|
|
3
|
-
|
|
4
|
-
export class DataManager implements DataManagerApi {
|
|
5
|
-
private loading: boolean = false
|
|
6
|
-
private listLastFetch?: ListLastFetchData
|
|
7
|
-
private comments: CommentData[] = [] // Note: 无层级结构 + 无须排列
|
|
8
|
-
private unreads: NotifyData[] = []
|
|
9
|
-
private page?: PageData
|
|
10
|
-
|
|
11
|
-
constructor(
|
|
12
|
-
protected events: EventManager<EventPayloadMap>
|
|
13
|
-
) {}
|
|
14
|
-
|
|
15
|
-
getLoading() {
|
|
16
|
-
return this.loading
|
|
17
|
-
}
|
|
18
|
-
|
|
19
|
-
setLoading(val: boolean) {
|
|
20
|
-
this.loading = val
|
|
21
|
-
}
|
|
22
|
-
|
|
23
|
-
getListLastFetch() {
|
|
24
|
-
return this.listLastFetch
|
|
25
|
-
}
|
|
26
|
-
|
|
27
|
-
setListLastFetch(val: ListLastFetchData) {
|
|
28
|
-
this.listLastFetch = val
|
|
29
|
-
}
|
|
30
|
-
|
|
31
|
-
// -------------------------------------------------------------------
|
|
32
|
-
// Comments
|
|
33
|
-
// -------------------------------------------------------------------
|
|
34
|
-
getComments() {
|
|
35
|
-
return this.comments
|
|
36
|
-
}
|
|
37
|
-
|
|
38
|
-
fetchComments(params: Partial<ListFetchParams>) {
|
|
39
|
-
this.events.trigger('list-fetch', params)
|
|
40
|
-
}
|
|
41
|
-
|
|
42
|
-
findComment(id: number) {
|
|
43
|
-
return this.comments.find(c => c.id === id)
|
|
44
|
-
}
|
|
45
|
-
|
|
46
|
-
clearComments() {
|
|
47
|
-
this.comments = []
|
|
48
|
-
this.events.trigger('list-loaded', this.comments)
|
|
49
|
-
}
|
|
50
|
-
|
|
51
|
-
loadComments(partialComments: CommentData[]) {
|
|
52
|
-
this.events.trigger('list-load', partialComments)
|
|
53
|
-
|
|
54
|
-
this.comments.push(...partialComments)
|
|
55
|
-
|
|
56
|
-
this.events.trigger('list-loaded', this.comments)
|
|
57
|
-
}
|
|
58
|
-
|
|
59
|
-
insertComment(comment: CommentData) {
|
|
60
|
-
this.comments.push(comment)
|
|
61
|
-
|
|
62
|
-
this.events.trigger('comment-inserted', comment)
|
|
63
|
-
this.events.trigger('list-loaded', this.comments) // list-loaded should always keep the last
|
|
64
|
-
}
|
|
65
|
-
|
|
66
|
-
updateComment(comment: CommentData) {
|
|
67
|
-
this.comments = this.comments.map(c => {
|
|
68
|
-
if (c.id === comment.id) return comment
|
|
69
|
-
return c
|
|
70
|
-
})
|
|
71
|
-
|
|
72
|
-
this.events.trigger('comment-updated', comment)
|
|
73
|
-
this.events.trigger('list-loaded', this.comments)
|
|
74
|
-
}
|
|
75
|
-
|
|
76
|
-
deleteComment(id: number) {
|
|
77
|
-
const comment = this.comments.find(c => c.id === id)
|
|
78
|
-
if (!comment) throw new Error(`Comment ${id} not found`)
|
|
79
|
-
this.comments = this.comments.filter(c => c.id !== id)
|
|
80
|
-
|
|
81
|
-
this.events.trigger('comment-deleted', comment)
|
|
82
|
-
this.events.trigger('list-loaded', this.comments)
|
|
83
|
-
}
|
|
84
|
-
|
|
85
|
-
// -------------------------------------------------------------------
|
|
86
|
-
// Unreads
|
|
87
|
-
// -------------------------------------------------------------------
|
|
88
|
-
getUnreads() {
|
|
89
|
-
return this.unreads
|
|
90
|
-
}
|
|
91
|
-
|
|
92
|
-
updateUnreads(unread: NotifyData[]) {
|
|
93
|
-
this.unreads = unread
|
|
94
|
-
|
|
95
|
-
this.events.trigger('unreads-updated', this.unreads)
|
|
96
|
-
}
|
|
97
|
-
|
|
98
|
-
// -------------------------------------------------------------------
|
|
99
|
-
// Page
|
|
100
|
-
// -------------------------------------------------------------------
|
|
101
|
-
getPage() {
|
|
102
|
-
return this.page
|
|
103
|
-
}
|
|
104
|
-
|
|
105
|
-
updatePage(pageData: PageData) {
|
|
106
|
-
this.page = pageData
|
|
107
|
-
|
|
108
|
-
this.events.trigger('page-loaded', pageData)
|
|
109
|
-
}
|
|
110
|
-
}
|