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
|
@@ -0,0 +1,172 @@
|
|
|
1
|
+
import '../style/list.less'
|
|
2
|
+
|
|
3
|
+
import Context from '../context'
|
|
4
|
+
import * as Utils from '../lib/utils'
|
|
5
|
+
import * as Ui from '../lib/ui'
|
|
6
|
+
import Api from '../api'
|
|
7
|
+
import ListHTML from './html/list.html?raw'
|
|
8
|
+
import ListLite from './list-lite'
|
|
9
|
+
import { ListData } from '~/types/artalk-data'
|
|
10
|
+
|
|
11
|
+
export default class List extends ListLite {
|
|
12
|
+
private $closeCommentBtn!: HTMLElement
|
|
13
|
+
private $openSidebarBtn!: HTMLElement
|
|
14
|
+
private $unreadBadge!: HTMLElement
|
|
15
|
+
|
|
16
|
+
constructor (ctx: Context) {
|
|
17
|
+
const el = Utils.createElement(ListHTML)
|
|
18
|
+
|
|
19
|
+
super(ctx, el)
|
|
20
|
+
|
|
21
|
+
// 把 listLite $el 变为子元素
|
|
22
|
+
el.querySelector('.atk-list-body')!.append(this.$el)
|
|
23
|
+
this.$el = el
|
|
24
|
+
|
|
25
|
+
// 平铺模式
|
|
26
|
+
let flatMode = false
|
|
27
|
+
if (this.ctx.conf.flatMode === 'auto') {
|
|
28
|
+
if (window.matchMedia("(max-width: 768px)").matches)
|
|
29
|
+
flatMode = true
|
|
30
|
+
} else if (this.ctx.conf.flatMode === true) {
|
|
31
|
+
flatMode = true
|
|
32
|
+
}
|
|
33
|
+
this.flatMode = flatMode
|
|
34
|
+
|
|
35
|
+
// 分页模式
|
|
36
|
+
this.pageMode = this.conf.pagination?.readMore ? 'read-more' : 'pagination'
|
|
37
|
+
|
|
38
|
+
// 操作按钮
|
|
39
|
+
this.initListActionBtn()
|
|
40
|
+
|
|
41
|
+
// copyright
|
|
42
|
+
this.$el.querySelector<HTMLElement>('.atk-copyright')!.innerHTML = `Powered By <a href="https://artalk.js.org" target="_blank" title="Artalk v${ARTALK_VERSION}">Artalk</a>`
|
|
43
|
+
|
|
44
|
+
// event listen
|
|
45
|
+
this.ctx.on('list-reload', () => (this.reqComments(0))) // 刷新评论
|
|
46
|
+
this.ctx.on('list-refresh-ui', () => (this.refreshUI()))
|
|
47
|
+
this.ctx.on('list-import', (data) => (this.importComments(data)))
|
|
48
|
+
this.ctx.on('list-insert', (data) => (this.insertComment(data)))
|
|
49
|
+
this.ctx.on('list-delete', (comment) => (this.deleteComment(comment.id)))
|
|
50
|
+
this.ctx.on('list-update', (updateData) => { updateData(this.data);this.refreshUI() } )
|
|
51
|
+
this.ctx.on('unread-update', (data) => (this.showUnreadBadge(data.notifies?.length || 0)))
|
|
52
|
+
}
|
|
53
|
+
|
|
54
|
+
private initListActionBtn () {
|
|
55
|
+
// 侧边栏呼出按钮
|
|
56
|
+
this.$openSidebarBtn = this.$el.querySelector('[data-action="open-sidebar"]')!
|
|
57
|
+
this.$closeCommentBtn = this.$el.querySelector('[data-action="admin-close-comment"]')!
|
|
58
|
+
this.$unreadBadge = this.$el.querySelector('.atk-unread-badge')!
|
|
59
|
+
|
|
60
|
+
this.$openSidebarBtn.addEventListener('click', () => {
|
|
61
|
+
this.ctx.trigger('sidebar-show')
|
|
62
|
+
})
|
|
63
|
+
|
|
64
|
+
// 关闭评论按钮
|
|
65
|
+
this.$closeCommentBtn.addEventListener('click', () => {
|
|
66
|
+
if (!this.data) return
|
|
67
|
+
|
|
68
|
+
this.data.page.admin_only = !this.data.page.admin_only
|
|
69
|
+
this.adminPageEditSave()
|
|
70
|
+
})
|
|
71
|
+
}
|
|
72
|
+
|
|
73
|
+
/** 刷新界面 */
|
|
74
|
+
public refreshUI () {
|
|
75
|
+
super.refreshUI()
|
|
76
|
+
|
|
77
|
+
this.$el.querySelector<HTMLElement>('.atk-comment-count-num')!.innerText = String(this.commentsCount)
|
|
78
|
+
|
|
79
|
+
// 已输入个人信息
|
|
80
|
+
if (!!this.ctx.user.data.nick && !!this.ctx.user.data.email) {
|
|
81
|
+
this.$openSidebarBtn.classList.remove('atk-hide')
|
|
82
|
+
} else {
|
|
83
|
+
this.$openSidebarBtn.classList.add('atk-hide')
|
|
84
|
+
}
|
|
85
|
+
|
|
86
|
+
// 仅管理员显示控制
|
|
87
|
+
this.ctx.trigger('check-admin-show-el')
|
|
88
|
+
this.$openSidebarBtn.innerText = (!this.ctx.user.data.isAdmin) ? '通知中心' : '控制中心'
|
|
89
|
+
|
|
90
|
+
// 关闭评论
|
|
91
|
+
if (!!this.data && !!this.data.page && this.data.page.admin_only === true) {
|
|
92
|
+
this.ctx.trigger('editor-close')
|
|
93
|
+
this.$closeCommentBtn.innerHTML = '打开评论'
|
|
94
|
+
} else {
|
|
95
|
+
this.ctx.trigger('editor-open')
|
|
96
|
+
this.$closeCommentBtn.innerHTML = '关闭评论'
|
|
97
|
+
}
|
|
98
|
+
}
|
|
99
|
+
|
|
100
|
+
public onLoad(data: ListData, offset: number) {
|
|
101
|
+
super.onLoad(data, offset)
|
|
102
|
+
|
|
103
|
+
// 检测锚点跳转
|
|
104
|
+
this.checkGoToCommentByUrlHash()
|
|
105
|
+
}
|
|
106
|
+
|
|
107
|
+
/** 跳到评论项位置 - 根据 `location.hash` */
|
|
108
|
+
public async checkGoToCommentByUrlHash () {
|
|
109
|
+
let commentId = Number(Utils.getQueryParam('atk_comment')) // same as backend GetReplyLink()
|
|
110
|
+
if (!commentId) {
|
|
111
|
+
const match = window.location.hash.match(/#atk-comment-([0-9]+)/)
|
|
112
|
+
if (!match || !match[1] || Number.isNaN(Number(match[1]))) return
|
|
113
|
+
commentId = Number(match[1])
|
|
114
|
+
}
|
|
115
|
+
if (!commentId) return
|
|
116
|
+
|
|
117
|
+
// 已阅 API
|
|
118
|
+
const notifyKey = Utils.getQueryParam('atk_notify_key')
|
|
119
|
+
if (notifyKey) {
|
|
120
|
+
new Api(this.ctx).markRead(notifyKey)
|
|
121
|
+
.then(() => {
|
|
122
|
+
this.unread = this.unread.filter(o => o.comment_id !== commentId)
|
|
123
|
+
this.ctx.trigger('unread-update', {
|
|
124
|
+
notifies: this.unread
|
|
125
|
+
})
|
|
126
|
+
})
|
|
127
|
+
}
|
|
128
|
+
|
|
129
|
+
const comment = this.findComment(commentId)
|
|
130
|
+
// TODO 若找不到评论的情况
|
|
131
|
+
// if (!comment) { // 若找不到评论
|
|
132
|
+
// if (this.hasMoreComments) { // 阅读更多,并重试
|
|
133
|
+
// await this.reqComments()
|
|
134
|
+
// }
|
|
135
|
+
// }
|
|
136
|
+
|
|
137
|
+
if (!comment) return
|
|
138
|
+
|
|
139
|
+
Ui.scrollIntoView(comment.getEl(), false)
|
|
140
|
+
window.setTimeout(() => {
|
|
141
|
+
comment.getEl().classList.add('atk-flash-once')
|
|
142
|
+
}, 800)
|
|
143
|
+
}
|
|
144
|
+
|
|
145
|
+
/** 管理员设置页面信息 */
|
|
146
|
+
public adminPageEditSave () {
|
|
147
|
+
if (!this.data || !this.data.page) return
|
|
148
|
+
|
|
149
|
+
this.ctx.trigger('editor-show-loading')
|
|
150
|
+
new Api(this.ctx).pageEdit(this.data.page)
|
|
151
|
+
.then((page) => {
|
|
152
|
+
if (this.data)
|
|
153
|
+
this.data.page = { ...page }
|
|
154
|
+
this.refreshUI()
|
|
155
|
+
})
|
|
156
|
+
.catch(err => {
|
|
157
|
+
this.ctx.trigger('editor-notify', { msg: `修改页面数据失败:${err.msg || String(err)}`, type: 'e'})
|
|
158
|
+
})
|
|
159
|
+
.finally(() => {
|
|
160
|
+
this.ctx.trigger('editor-hide-loading')
|
|
161
|
+
})
|
|
162
|
+
}
|
|
163
|
+
|
|
164
|
+
public showUnreadBadge (count: number) {
|
|
165
|
+
if (count > 0) {
|
|
166
|
+
this.$unreadBadge.innerText = `${Number(count || 0)}`
|
|
167
|
+
this.$unreadBadge.style.display = 'block'
|
|
168
|
+
} else {
|
|
169
|
+
this.$unreadBadge.style.display = 'none'
|
|
170
|
+
}
|
|
171
|
+
}
|
|
172
|
+
}
|
|
@@ -0,0 +1,150 @@
|
|
|
1
|
+
import '../style/pagination.less'
|
|
2
|
+
import * as Utils from '../lib/utils'
|
|
3
|
+
import * as Ui from '../lib/ui'
|
|
4
|
+
|
|
5
|
+
export interface PaginationConf {
|
|
6
|
+
/** 每页条数 */
|
|
7
|
+
pageSize?: number
|
|
8
|
+
|
|
9
|
+
/** 回调函数 */
|
|
10
|
+
onChange: (offset: number) => void
|
|
11
|
+
}
|
|
12
|
+
|
|
13
|
+
export default class Pagination {
|
|
14
|
+
private conf: PaginationConf
|
|
15
|
+
public total: number
|
|
16
|
+
public $el: HTMLElement
|
|
17
|
+
public $input: HTMLInputElement
|
|
18
|
+
public inputTimer?: number
|
|
19
|
+
public $prevBtn: HTMLElement
|
|
20
|
+
public $nextBtn: HTMLElement
|
|
21
|
+
|
|
22
|
+
public page: number = 1
|
|
23
|
+
get pageSize(): number {
|
|
24
|
+
return this.conf.pageSize || 15
|
|
25
|
+
}
|
|
26
|
+
get offset(): number {
|
|
27
|
+
return this.pageSize * (this.page - 1)
|
|
28
|
+
}
|
|
29
|
+
get maxPage(): number {
|
|
30
|
+
return Math.ceil(this.total / this.pageSize)
|
|
31
|
+
}
|
|
32
|
+
|
|
33
|
+
public constructor(total: number, conf: PaginationConf) {
|
|
34
|
+
this.total = total
|
|
35
|
+
this.conf = conf
|
|
36
|
+
|
|
37
|
+
this.$el = Utils.createElement(
|
|
38
|
+
`<div class="atk-pagination-wrap">
|
|
39
|
+
<div class="atk-pagination">
|
|
40
|
+
<div class="atk-btn atk-btn-prev">Prev</div>
|
|
41
|
+
<input type="text" class="atk-input" />
|
|
42
|
+
<div class="atk-btn atk-btn-next">Next</div>
|
|
43
|
+
</div>
|
|
44
|
+
</div>`)
|
|
45
|
+
this.$input = this.$el.querySelector('.atk-input')!
|
|
46
|
+
this.$input.value = `${this.page}`
|
|
47
|
+
|
|
48
|
+
this.$input.oninput = () => this.input()
|
|
49
|
+
this.$input.onkeydown = (e) => this.keydown(e)
|
|
50
|
+
|
|
51
|
+
this.$prevBtn = this.$el.querySelector('.atk-btn-prev')!
|
|
52
|
+
this.$nextBtn = this.$el.querySelector('.atk-btn-next')!
|
|
53
|
+
|
|
54
|
+
this.$prevBtn.onclick = () => this.prev()
|
|
55
|
+
this.$nextBtn.onclick = () => this.next()
|
|
56
|
+
|
|
57
|
+
this.checkDisabled()
|
|
58
|
+
}
|
|
59
|
+
|
|
60
|
+
public update(offset: number, total: number) {
|
|
61
|
+
this.page = Math.ceil(offset / this.pageSize) + 1
|
|
62
|
+
this.total = total
|
|
63
|
+
|
|
64
|
+
this.setInput(this.page)
|
|
65
|
+
this.checkDisabled()
|
|
66
|
+
}
|
|
67
|
+
|
|
68
|
+
public setInput(page: number) {
|
|
69
|
+
this.$input.value = `${page}`
|
|
70
|
+
}
|
|
71
|
+
|
|
72
|
+
public input(now: boolean = false) {
|
|
73
|
+
window.clearTimeout(this.inputTimer)
|
|
74
|
+
|
|
75
|
+
const value = this.$input.value.trim()
|
|
76
|
+
|
|
77
|
+
const modify = () => {
|
|
78
|
+
if (value === '') { this.setInput(this.page);return }
|
|
79
|
+
let page = Number(value)
|
|
80
|
+
if (Number.isNaN(page)) { this.setInput(this.page);return }
|
|
81
|
+
if (page < 1) { this.setInput(this.page);return }
|
|
82
|
+
if (page > this.maxPage) { this.setInput(this.maxPage);page = this.maxPage }
|
|
83
|
+
this.change(page)
|
|
84
|
+
}
|
|
85
|
+
|
|
86
|
+
// 延迟 800ms 执行
|
|
87
|
+
if (!now) this.inputTimer = window.setTimeout(() => modify(), 800)
|
|
88
|
+
else modify()
|
|
89
|
+
}
|
|
90
|
+
|
|
91
|
+
public prev() {
|
|
92
|
+
const page = this.page - 1
|
|
93
|
+
if (page < 1) { return }
|
|
94
|
+
this.change(page)
|
|
95
|
+
}
|
|
96
|
+
|
|
97
|
+
public next() {
|
|
98
|
+
const page = this.page + 1
|
|
99
|
+
if (page > this.maxPage) { return }
|
|
100
|
+
this.change(page)
|
|
101
|
+
}
|
|
102
|
+
|
|
103
|
+
public change(page: number) {
|
|
104
|
+
this.page = page
|
|
105
|
+
this.conf.onChange(this.offset)
|
|
106
|
+
this.setInput(page)
|
|
107
|
+
this.checkDisabled()
|
|
108
|
+
}
|
|
109
|
+
|
|
110
|
+
public checkDisabled() {
|
|
111
|
+
if (this.page + 1 > this.maxPage) {
|
|
112
|
+
this.$nextBtn.classList.add('atk-disabled')
|
|
113
|
+
} else {
|
|
114
|
+
this.$nextBtn.classList.remove('atk-disabled')
|
|
115
|
+
}
|
|
116
|
+
|
|
117
|
+
if (this.page - 1 < 1) {
|
|
118
|
+
this.$prevBtn.classList.add('atk-disabled')
|
|
119
|
+
} else {
|
|
120
|
+
this.$prevBtn.classList.remove('atk-disabled')
|
|
121
|
+
}
|
|
122
|
+
}
|
|
123
|
+
|
|
124
|
+
public keydown(e: KeyboardEvent) {
|
|
125
|
+
const keyCode = e.keyCode || e.which
|
|
126
|
+
|
|
127
|
+
if (keyCode === 38) {
|
|
128
|
+
// 上键
|
|
129
|
+
const page = Number(this.$input.value) + 1
|
|
130
|
+
if (page > this.maxPage) { return }
|
|
131
|
+
this.setInput(page);
|
|
132
|
+
this.input()
|
|
133
|
+
} else if (keyCode === 40) {
|
|
134
|
+
// 下键
|
|
135
|
+
const page = Number(this.$input.value) - 1
|
|
136
|
+
if (page < 1) { return }
|
|
137
|
+
this.setInput(page)
|
|
138
|
+
this.input()
|
|
139
|
+
} else if (keyCode === 13) {
|
|
140
|
+
// 回车
|
|
141
|
+
this.input(true)
|
|
142
|
+
}
|
|
143
|
+
}
|
|
144
|
+
|
|
145
|
+
/** 加载 */
|
|
146
|
+
setLoading (isLoading: boolean) {
|
|
147
|
+
if (isLoading) Ui.showLoading(this.$el)
|
|
148
|
+
else Ui.hideLoading(this.$el)
|
|
149
|
+
}
|
|
150
|
+
}
|
|
@@ -0,0 +1,71 @@
|
|
|
1
|
+
import * as Utils from '../lib/utils'
|
|
2
|
+
|
|
3
|
+
export interface ReadMoreBtnConf {
|
|
4
|
+
/** 每页条数 */
|
|
5
|
+
pageSize?: number
|
|
6
|
+
|
|
7
|
+
/** 数据总数 */
|
|
8
|
+
total: number
|
|
9
|
+
|
|
10
|
+
/** 回调函数 */
|
|
11
|
+
onClick: () => void
|
|
12
|
+
}
|
|
13
|
+
|
|
14
|
+
/**
|
|
15
|
+
* 阅读更多按钮
|
|
16
|
+
*/
|
|
17
|
+
export default class ReadMoreBtn {
|
|
18
|
+
public conf: ReadMoreBtnConf
|
|
19
|
+
public $el: HTMLElement
|
|
20
|
+
private $loading: HTMLElement
|
|
21
|
+
private $text: HTMLElement
|
|
22
|
+
|
|
23
|
+
public constructor(conf: ReadMoreBtnConf) {
|
|
24
|
+
this.conf = conf
|
|
25
|
+
|
|
26
|
+
this.$el = Utils.createElement(
|
|
27
|
+
`<div class="atk-list-read-more" style="display: none;">
|
|
28
|
+
<div class="atk-list-read-more-inner">
|
|
29
|
+
<div class="atk-loading-icon" style="display: none;"></div>
|
|
30
|
+
<span class="atk-text">查看更多</span>
|
|
31
|
+
</div>
|
|
32
|
+
</div>`)
|
|
33
|
+
|
|
34
|
+
this.$loading = this.$el.querySelector<HTMLElement>('.atk-loading-icon')!
|
|
35
|
+
this.$text = this.$el.querySelector<HTMLElement>('.atk-text')!
|
|
36
|
+
|
|
37
|
+
this.$el.onclick = () => this.click()
|
|
38
|
+
}
|
|
39
|
+
|
|
40
|
+
click() {
|
|
41
|
+
this.conf.onClick()
|
|
42
|
+
}
|
|
43
|
+
|
|
44
|
+
/** 显示 */
|
|
45
|
+
show() {
|
|
46
|
+
this.$el.style.display = ''
|
|
47
|
+
}
|
|
48
|
+
|
|
49
|
+
/** 隐藏 */
|
|
50
|
+
hide() {
|
|
51
|
+
this.$el.style.display = 'none'
|
|
52
|
+
}
|
|
53
|
+
|
|
54
|
+
/** 加载 */
|
|
55
|
+
setLoading (isLoading: boolean) {
|
|
56
|
+
this.$loading.style.display = isLoading ? '' : 'none'
|
|
57
|
+
this.$text.style.display = isLoading ? 'none' : ''
|
|
58
|
+
}
|
|
59
|
+
|
|
60
|
+
/** 错误提示 */
|
|
61
|
+
showErr(errMsg: string) {
|
|
62
|
+
this.setLoading(false)
|
|
63
|
+
|
|
64
|
+
this.$text.innerText = errMsg
|
|
65
|
+
this.$el.classList.add('atk-err')
|
|
66
|
+
window.setTimeout(() => {
|
|
67
|
+
this.$text.innerText = '查看更多'
|
|
68
|
+
this.$el.classList.remove('atk-err')
|
|
69
|
+
}, 2000) // 2s后错误提示复原
|
|
70
|
+
}
|
|
71
|
+
}
|
|
@@ -0,0 +1,26 @@
|
|
|
1
|
+
import Context from '../context'
|
|
2
|
+
import Component from '../lib/component'
|
|
3
|
+
import * as Utils from '../lib/utils'
|
|
4
|
+
import Comment from './comment'
|
|
5
|
+
|
|
6
|
+
export default class SidebarView extends Component {
|
|
7
|
+
static viewName = ''
|
|
8
|
+
static viewTitle = ''
|
|
9
|
+
static viewAdminOnly = false
|
|
10
|
+
|
|
11
|
+
viewTabs = {}
|
|
12
|
+
viewActiveTab = ''
|
|
13
|
+
|
|
14
|
+
protected $parent: HTMLElement
|
|
15
|
+
|
|
16
|
+
constructor(ctx: Context, $parent: HTMLElement) {
|
|
17
|
+
super(ctx)
|
|
18
|
+
|
|
19
|
+
this.$parent = $parent
|
|
20
|
+
this.$el = Utils.createElement(`<div class="atk-sidebar-view"></div>`)
|
|
21
|
+
}
|
|
22
|
+
|
|
23
|
+
mount(siteName: string) {}
|
|
24
|
+
|
|
25
|
+
switchTab(tab: string, siteName: string): boolean|void {}
|
|
26
|
+
}
|
|
@@ -0,0 +1,66 @@
|
|
|
1
|
+
import Context from '../../context'
|
|
2
|
+
import SidebarView from '../sidebar-view'
|
|
3
|
+
import * as Utils from '../../lib/utils'
|
|
4
|
+
import ListLite from '../list-lite'
|
|
5
|
+
|
|
6
|
+
export default class MessageView extends SidebarView {
|
|
7
|
+
static viewName = 'comments'
|
|
8
|
+
static viewTitle = '评论'
|
|
9
|
+
|
|
10
|
+
viewTabs: any = {}
|
|
11
|
+
viewActiveTab = ''
|
|
12
|
+
|
|
13
|
+
list!: ListLite
|
|
14
|
+
|
|
15
|
+
mount(siteName: string) {
|
|
16
|
+
// tabs
|
|
17
|
+
if (this.ctx.user.data.isAdmin) {
|
|
18
|
+
this.viewTabs = {
|
|
19
|
+
admin_all: '全部',
|
|
20
|
+
admin_pending: '待审',
|
|
21
|
+
all: '个人',
|
|
22
|
+
}
|
|
23
|
+
this.viewActiveTab = 'admin_all'
|
|
24
|
+
} else {
|
|
25
|
+
this.viewTabs = {
|
|
26
|
+
mentions: '提及',
|
|
27
|
+
all: '全部',
|
|
28
|
+
mine: '我的',
|
|
29
|
+
pending: '待审',
|
|
30
|
+
}
|
|
31
|
+
this.viewActiveTab = 'mentions'
|
|
32
|
+
}
|
|
33
|
+
|
|
34
|
+
this.list = new ListLite(this.ctx, this.$el)
|
|
35
|
+
this.list.flatMode = true
|
|
36
|
+
this.list.unreadHighlight = true
|
|
37
|
+
this.list.autoLoadListenerAt = this.$parent
|
|
38
|
+
this.list.pageMode = 'pagination'
|
|
39
|
+
this.list.noCommentText = '<div class="atk-sidebar-no-content">无内容</div>'
|
|
40
|
+
this.list.renderComment = (comment) => {
|
|
41
|
+
comment.setOpenURL(`${comment.data.page_key}#atk-comment-${comment.data.id}`)
|
|
42
|
+
}
|
|
43
|
+
this.list.paramsEditor = (params) => {
|
|
44
|
+
params.site_name = siteName
|
|
45
|
+
}
|
|
46
|
+
|
|
47
|
+
this.$el.innerHTML = ''
|
|
48
|
+
this.$el.append(this.list.$el)
|
|
49
|
+
|
|
50
|
+
this.switchTab(this.viewActiveTab, siteName)
|
|
51
|
+
}
|
|
52
|
+
|
|
53
|
+
switchTab(tab: string, siteName: string): boolean|void {
|
|
54
|
+
//console.log(tab, siteName)
|
|
55
|
+
this.viewActiveTab = tab
|
|
56
|
+
this.list.type = tab as any;
|
|
57
|
+
this.list.isFirstLoad = true
|
|
58
|
+
this.list.paramsEditor = (params) => {
|
|
59
|
+
params.site_name = siteName
|
|
60
|
+
}
|
|
61
|
+
this.list.reqComments()
|
|
62
|
+
|
|
63
|
+
return true
|
|
64
|
+
}
|
|
65
|
+
}
|
|
66
|
+
|
|
@@ -0,0 +1,61 @@
|
|
|
1
|
+
import Api from '~/src/api'
|
|
2
|
+
import Context from '../../context'
|
|
3
|
+
import Component from '../../lib/component'
|
|
4
|
+
import * as Utils from '../../lib/utils'
|
|
5
|
+
import * as Ui from '../../lib/ui'
|
|
6
|
+
import PageList from '../admin/page-list'
|
|
7
|
+
import Comment from '../comment'
|
|
8
|
+
import Pagination, { PaginationConf } from '../pagination'
|
|
9
|
+
import SidebarView from '../sidebar-view'
|
|
10
|
+
|
|
11
|
+
const PAGE_SIZE = 20
|
|
12
|
+
|
|
13
|
+
export default class PagesView extends SidebarView {
|
|
14
|
+
static viewName = 'pages'
|
|
15
|
+
static viewTitle = '页面'
|
|
16
|
+
static viewAdminOnly = true
|
|
17
|
+
|
|
18
|
+
viewTabs = {}
|
|
19
|
+
viewActiveTab = ''
|
|
20
|
+
|
|
21
|
+
pageList!: PageList
|
|
22
|
+
pagination!: Pagination
|
|
23
|
+
|
|
24
|
+
mount(siteName: string) {
|
|
25
|
+
if (!this.pageList) {
|
|
26
|
+
this.pageList = new PageList(this.ctx)
|
|
27
|
+
this.$el.append(this.pageList.$el)
|
|
28
|
+
}
|
|
29
|
+
|
|
30
|
+
this.switchTab(this.viewActiveTab, siteName)
|
|
31
|
+
}
|
|
32
|
+
|
|
33
|
+
switchTab(tab: string, siteName: string): boolean|void {
|
|
34
|
+
this.reqPages(siteName, 0)
|
|
35
|
+
}
|
|
36
|
+
|
|
37
|
+
async reqPages(siteName: string, offset: number) {
|
|
38
|
+
this.pageList.clearAll()
|
|
39
|
+
;(this.$el.parentNode as any)?.scrollTo(0, 0)
|
|
40
|
+
|
|
41
|
+
Ui.showLoading(this.$el)
|
|
42
|
+
|
|
43
|
+
const data = await new Api(this.ctx).pageGet(siteName, offset, PAGE_SIZE)
|
|
44
|
+
this.pageList.importPages(data.pages || [])
|
|
45
|
+
|
|
46
|
+
Ui.hideLoading(this.$el)
|
|
47
|
+
|
|
48
|
+
if (!this.pagination) {
|
|
49
|
+
this.pagination = new Pagination(data.total, {
|
|
50
|
+
pageSize: PAGE_SIZE,
|
|
51
|
+
onChange: (o: number) => {
|
|
52
|
+
this.reqPages(siteName, o)
|
|
53
|
+
}
|
|
54
|
+
})
|
|
55
|
+
|
|
56
|
+
this.$el.append(this.pagination.$el)
|
|
57
|
+
}
|
|
58
|
+
if (this.pagination && offset === 0)
|
|
59
|
+
this.pagination.update(offset, data.total)
|
|
60
|
+
}
|
|
61
|
+
}
|
|
@@ -0,0 +1,21 @@
|
|
|
1
|
+
import Api from '~/src/api'
|
|
2
|
+
import Context from '../../context'
|
|
3
|
+
import Component from '../../lib/component'
|
|
4
|
+
import * as Utils from '../../lib/utils'
|
|
5
|
+
import SiteList from '../admin/site-list'
|
|
6
|
+
import Comment from '../comment'
|
|
7
|
+
import SidebarView from '../sidebar-view'
|
|
8
|
+
|
|
9
|
+
export default class SettingView extends SidebarView {
|
|
10
|
+
static viewName = 'setting'
|
|
11
|
+
static viewTitle = '配置'
|
|
12
|
+
static viewAdminOnly = true
|
|
13
|
+
|
|
14
|
+
viewTabs = {}
|
|
15
|
+
viewActiveTab = ''
|
|
16
|
+
|
|
17
|
+
mount(siteName: string) {
|
|
18
|
+
}
|
|
19
|
+
|
|
20
|
+
switchTab(tab: string, siteName: string) {}
|
|
21
|
+
}
|
|
@@ -0,0 +1,42 @@
|
|
|
1
|
+
import Api from '~/src/api'
|
|
2
|
+
import Context from '../../context'
|
|
3
|
+
import Component from '../../lib/component'
|
|
4
|
+
import * as Utils from '../../lib/utils'
|
|
5
|
+
import SiteList from '../admin/site-list'
|
|
6
|
+
import Comment from '../comment'
|
|
7
|
+
import SidebarView from '../sidebar-view'
|
|
8
|
+
|
|
9
|
+
export default class SitesView extends SidebarView {
|
|
10
|
+
static viewName = 'sites'
|
|
11
|
+
static viewTitle = '站点'
|
|
12
|
+
static viewAdminOnly = true
|
|
13
|
+
|
|
14
|
+
viewTabs = {}
|
|
15
|
+
viewActiveTab = ''
|
|
16
|
+
|
|
17
|
+
siteList!: SiteList
|
|
18
|
+
|
|
19
|
+
constructor(ctx: Context) {
|
|
20
|
+
super(ctx)
|
|
21
|
+
|
|
22
|
+
this.$el = Utils.createElement(`<div class="atk-sidebar-view"></div>`)
|
|
23
|
+
}
|
|
24
|
+
|
|
25
|
+
mount(siteName: string) {
|
|
26
|
+
if (!this.siteList) {
|
|
27
|
+
this.siteList = new SiteList(this.ctx)
|
|
28
|
+
this.$el.append(this.siteList.$el)
|
|
29
|
+
}
|
|
30
|
+
|
|
31
|
+
this.reqSites()
|
|
32
|
+
}
|
|
33
|
+
|
|
34
|
+
switchTab(tab: string, siteName: string) {
|
|
35
|
+
this.reqSites()
|
|
36
|
+
}
|
|
37
|
+
|
|
38
|
+
async reqSites() {
|
|
39
|
+
const sites = await new Api(this.ctx).siteGet()
|
|
40
|
+
this.siteList.loadSites(sites)
|
|
41
|
+
}
|
|
42
|
+
}
|