artalk 2.3.3 → 2.4.0
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/dist/Artalk.css +1 -1
- package/dist/Artalk.es.js +3184 -2888
- package/dist/Artalk.iife.js +1 -1
- package/dist/Artalk.js +1 -1
- package/dist/ArtalkLite.css +1 -1
- package/dist/ArtalkLite.es.js +3157 -2887
- package/dist/ArtalkLite.iife.js +1 -1
- package/dist/ArtalkLite.js +1 -1
- package/dist/src/api/admin.d.ts +10 -0
- package/dist/src/api/api-base.d.ts +14 -0
- package/dist/src/api/captcha.d.ts +14 -0
- package/dist/src/api/comment.d.ts +29 -0
- package/dist/src/api/index.d.ts +31 -0
- package/dist/src/api/page.d.ts +22 -0
- package/dist/src/api/request.d.ts +12 -0
- package/dist/src/api/site.d.ts +17 -0
- package/dist/src/api/system.d.ts +13 -0
- package/dist/src/api/upload.d.ts +11 -0
- package/dist/src/api/user.d.ts +28 -0
- package/dist/src/artalk.d.ts +56 -0
- package/dist/src/comment/actions.d.ts +17 -0
- package/dist/src/comment/comment.d.ts +67 -0
- package/dist/src/comment/index.d.ts +2 -0
- package/dist/src/comment/render.d.ts +76 -0
- package/dist/src/components/action-btn.d.ts +52 -0
- package/dist/src/components/dialog.d.ts +18 -0
- package/dist/src/components/pagination.d.ts +30 -0
- package/dist/src/components/read-more-btn.d.ts +33 -0
- package/dist/src/context.d.ts +72 -0
- package/dist/src/defaults.d.ts +3 -0
- package/dist/src/editor/editor.d.ts +84 -0
- package/dist/src/editor/index.d.ts +2 -0
- package/dist/src/editor/plugs/editor-plug.d.ts +26 -0
- package/dist/src/editor/plugs/emoticons-plug.d.ts +36 -0
- package/dist/src/editor/plugs/header-input-plug.d.ts +13 -0
- package/dist/src/editor/plugs/preview-plug.d.ts +10 -0
- package/dist/src/editor/plugs/upload-plug.d.ts +10 -0
- package/dist/src/i18n/en.d.ts +69 -0
- package/dist/src/i18n/index.d.ts +294 -0
- package/dist/src/i18n/zh-CN.d.ts +3 -0
- package/dist/src/layer/index.d.ts +3 -0
- package/dist/src/layer/layer.d.ts +32 -0
- package/dist/src/layer/sidebar-layer.d.ts +20 -0
- package/dist/src/lib/checker/admin-checker.d.ts +3 -0
- package/dist/src/lib/checker/captcha-checker.d.ts +3 -0
- package/dist/src/lib/checker/index.d.ts +42 -0
- package/dist/src/lib/component.d.ts +12 -0
- package/dist/src/lib/detect.d.ts +10 -0
- package/dist/src/lib/stat.d.ts +15 -0
- package/dist/src/lib/ui.d.ts +23 -0
- package/dist/src/lib/user.d.ts +13 -0
- package/dist/src/lib/utils.d.ts +39 -0
- package/dist/src/list/index.d.ts +2 -0
- package/dist/src/list/list-lite.d.ts +63 -0
- package/dist/src/list/list-nest.d.ts +10 -0
- package/dist/src/list/list.d.ts +26 -0
- package/dist/src/main.d.ts +4 -0
- package/dist/types/artalk-config.d.ts +132 -0
- package/dist/types/artalk-data.d.ts +204 -0
- package/dist/types/context.d.ts +146 -0
- package/dist/types/event.d.ts +28 -0
- package/dist/types/global.d.ts +0 -0
- package/dist/types/plug.d.ts +4 -0
- package/index.html +3 -3
- package/package.json +5 -5
- package/src/api/admin.ts +18 -0
- package/src/api/api-base.ts +27 -0
- package/src/api/captcha.ts +24 -0
- package/src/api/comment.ts +84 -0
- package/src/api/index.ts +25 -361
- package/src/api/page.ts +85 -0
- package/src/api/request.ts +12 -8
- package/src/api/site.ts +51 -0
- package/src/api/system.ts +39 -0
- package/src/api/upload.ts +29 -0
- package/src/api/user.ts +75 -0
- package/src/artalk.ts +75 -76
- package/src/comment/actions.ts +3 -3
- package/src/comment/comment.ts +6 -9
- package/src/comment/render.ts +93 -47
- package/src/components/pagination.ts +0 -1
- package/src/context.ts +57 -18
- package/src/editor/editor.ts +111 -18
- package/src/editor/plugs/header-input-plug.ts +1 -1
- package/src/editor/plugs/upload-plug.ts +1 -1
- package/src/i18n/en.ts +3 -0
- package/src/i18n/index.ts +117 -2
- package/src/i18n/zh-CN.ts +4 -1
- package/src/layer/sidebar-layer.ts +1 -3
- package/src/lib/checker/admin-checker.ts +1 -1
- package/src/lib/checker/captcha-checker.ts +3 -3
- package/src/lib/stat.ts +2 -2
- package/src/lib/ui.ts +6 -0
- package/src/list/list-lite.ts +33 -25
- package/src/list/list.ts +3 -4
- package/src/main.ts +3 -0
- package/src/style/comment.less +2 -3
- package/src/style/main.less +6 -0
- package/test/CSRF.html +26 -0
- package/types/artalk-data.d.ts +3 -0
- package/types/context.d.ts +19 -1
- package/types/global.d.ts +0 -2
- package/vite-base.config.ts +9 -5
- package/vite.config.ts +5 -1
- package/types/index.d.ts +0 -3
package/src/api/page.ts
ADDED
|
@@ -0,0 +1,85 @@
|
|
|
1
|
+
import { PageData, CommentData } from '~/types/artalk-data'
|
|
2
|
+
import ApiBase from './api-base'
|
|
3
|
+
|
|
4
|
+
/**
|
|
5
|
+
* 页面 API
|
|
6
|
+
*/
|
|
7
|
+
export default class PageApi extends ApiBase {
|
|
8
|
+
/** 页面 · 获取 */
|
|
9
|
+
public async pageGet(siteName?: string, offset?: number, limit?: number) {
|
|
10
|
+
const params: any = {
|
|
11
|
+
site_name: siteName || '',
|
|
12
|
+
offset: offset || 0,
|
|
13
|
+
limit: limit || 15,
|
|
14
|
+
}
|
|
15
|
+
|
|
16
|
+
const d = await this.POST<any>('/admin/page-get', params)
|
|
17
|
+
return (d as { pages: PageData[], total: number })
|
|
18
|
+
}
|
|
19
|
+
|
|
20
|
+
/** 页面 · 修改 */
|
|
21
|
+
public async pageEdit(data: PageData) {
|
|
22
|
+
const params: any = {
|
|
23
|
+
id: data.id,
|
|
24
|
+
key: data.key,
|
|
25
|
+
title: data.title,
|
|
26
|
+
admin_only: data.admin_only,
|
|
27
|
+
site_name: data.site_name || this.ctx.conf.site,
|
|
28
|
+
}
|
|
29
|
+
|
|
30
|
+
const d = await this.POST<any>('/admin/page-edit', params)
|
|
31
|
+
return (d.page as PageData)
|
|
32
|
+
}
|
|
33
|
+
|
|
34
|
+
/** 页面 · 删除 */
|
|
35
|
+
public pageDel(pageKey: string, siteName?: string) {
|
|
36
|
+
const params: any = {
|
|
37
|
+
key: String(pageKey),
|
|
38
|
+
site_name: siteName || '',
|
|
39
|
+
}
|
|
40
|
+
|
|
41
|
+
return this.POST('/admin/page-del', params)
|
|
42
|
+
}
|
|
43
|
+
|
|
44
|
+
/** 页面 · 数据更新 */
|
|
45
|
+
public async pageFetch(id?: number, siteName?: string, getStatus?: boolean) {
|
|
46
|
+
const params: any = {}
|
|
47
|
+
if (id) params.id = id
|
|
48
|
+
if (siteName) params.site_name = siteName
|
|
49
|
+
if (getStatus) params.get_status = getStatus
|
|
50
|
+
|
|
51
|
+
const d = await this.POST<any>('/admin/page-fetch', params)
|
|
52
|
+
return (d as any)
|
|
53
|
+
}
|
|
54
|
+
|
|
55
|
+
/** PV */
|
|
56
|
+
public async pv() {
|
|
57
|
+
const params: any = {
|
|
58
|
+
site_name: this.ctx.conf.site || '',
|
|
59
|
+
page_key: this.ctx.conf.pageKey || '',
|
|
60
|
+
page_title: this.ctx.conf.pageTitle || ''
|
|
61
|
+
}
|
|
62
|
+
|
|
63
|
+
const p = await this.POST<any>('/pv', params)
|
|
64
|
+
return p.pv as number
|
|
65
|
+
}
|
|
66
|
+
|
|
67
|
+
/** 统计 */
|
|
68
|
+
public async stat(
|
|
69
|
+
type: 'latest_comments'|'latest_pages'|'pv_most_pages'|'comment_most_pages'|
|
|
70
|
+
'page_pv'|'site_pv'|'page_comment'|'site_comment',
|
|
71
|
+
pageKeys?: string|string[],
|
|
72
|
+
limit?: number
|
|
73
|
+
) {
|
|
74
|
+
const params: any = {
|
|
75
|
+
type,
|
|
76
|
+
site_name: this.ctx.conf.site || '',
|
|
77
|
+
}
|
|
78
|
+
|
|
79
|
+
if (pageKeys) params.page_keys = Array.isArray(pageKeys) ? pageKeys.join(',') : pageKeys
|
|
80
|
+
if (limit) params.limit = limit
|
|
81
|
+
|
|
82
|
+
const data = await this.POST<PageData[]|CommentData[]|object|number>(`/stat`, params)
|
|
83
|
+
return data
|
|
84
|
+
}
|
|
85
|
+
}
|
package/src/api/request.ts
CHANGED
|
@@ -9,6 +9,9 @@ export async function Fetch(ctx: Context, input: RequestInfo, init: RequestInit,
|
|
|
9
9
|
init.headers = headers
|
|
10
10
|
}
|
|
11
11
|
|
|
12
|
+
// 跨域请求携带 cookie (无需)
|
|
13
|
+
// init.credentials = 'include'
|
|
14
|
+
|
|
12
15
|
// 请求操作
|
|
13
16
|
const resp = await timeoutFetch(ctx, input, timeout || ctx.conf.reqTimeout || 15000, init)
|
|
14
17
|
|
|
@@ -60,19 +63,20 @@ export async function POST<T>(ctx: Context, url: string, data?: {[key: string]:
|
|
|
60
63
|
const init: RequestInit = {
|
|
61
64
|
method: 'POST',
|
|
62
65
|
}
|
|
63
|
-
|
|
66
|
+
data = { site_name: ctx.conf.site || '', ...(data || {}) } // 总是携带 site_name
|
|
67
|
+
init.body = ToFormData(data)
|
|
64
68
|
|
|
65
69
|
const json = await Fetch(ctx, url, init)
|
|
66
70
|
return ((json.data || {}) as T)
|
|
67
71
|
}
|
|
68
72
|
|
|
69
|
-
/** 公共 GET 请求 */
|
|
70
|
-
export async function GET<T>(ctx: Context, url: string, data?: {[key: string]: any}) {
|
|
71
|
-
|
|
72
|
-
|
|
73
|
-
|
|
74
|
-
|
|
75
|
-
}
|
|
73
|
+
/** 公共 GET 请求 (无 GET 方式 API) */
|
|
74
|
+
// export async function GET<T>(ctx: Context, url: string, data?: {[key: string]: any}) {
|
|
75
|
+
// const json = await Fetch(ctx, url + (data ? (`?${new URLSearchParams(data)}`) : ''), {
|
|
76
|
+
// method: 'GET',
|
|
77
|
+
// })
|
|
78
|
+
// return ((json.data || {}) as T)
|
|
79
|
+
// }
|
|
76
80
|
|
|
77
81
|
/** 对象转 FormData */
|
|
78
82
|
export function ToFormData(object: {[key: string]: any}): FormData {
|
package/src/api/site.ts
ADDED
|
@@ -0,0 +1,51 @@
|
|
|
1
|
+
import { SiteData } from '~/types/artalk-data'
|
|
2
|
+
import ApiBase from './api-base'
|
|
3
|
+
|
|
4
|
+
/**
|
|
5
|
+
* 站点 API
|
|
6
|
+
*/
|
|
7
|
+
export default class SiteApi extends ApiBase {
|
|
8
|
+
/** 站点 · 获取 */
|
|
9
|
+
public async siteGet() {
|
|
10
|
+
const params: any = {}
|
|
11
|
+
|
|
12
|
+
const d = await this.POST<any>('/admin/site-get', params)
|
|
13
|
+
return (d.sites as SiteData[])
|
|
14
|
+
}
|
|
15
|
+
|
|
16
|
+
/** 站点 · 创建 */
|
|
17
|
+
public async siteAdd(name: string, urls: string) {
|
|
18
|
+
const params: any = {
|
|
19
|
+
name, urls,
|
|
20
|
+
site_name: '' // 全局保留字段,当前站点名
|
|
21
|
+
}
|
|
22
|
+
|
|
23
|
+
const d = await this.POST<any>('/admin/site-add', params)
|
|
24
|
+
return (d.site as SiteData)
|
|
25
|
+
}
|
|
26
|
+
|
|
27
|
+
/** 站点 · 修改 */
|
|
28
|
+
public async siteEdit(data: SiteData) {
|
|
29
|
+
const params: any = {
|
|
30
|
+
id: data.id,
|
|
31
|
+
name: data.name || '',
|
|
32
|
+
urls: data.urls || '',
|
|
33
|
+
}
|
|
34
|
+
|
|
35
|
+
const d = await this.POST<any>('/admin/site-edit', params)
|
|
36
|
+
return (d.site as SiteData)
|
|
37
|
+
}
|
|
38
|
+
|
|
39
|
+
/** 站点 · 删除 */
|
|
40
|
+
public siteDel(id: number, delContent = false) {
|
|
41
|
+
const params: any = { id, del_content: delContent }
|
|
42
|
+
|
|
43
|
+
return this.POST('/admin/site-del', params)
|
|
44
|
+
}
|
|
45
|
+
|
|
46
|
+
/** 导出 */
|
|
47
|
+
public async export() {
|
|
48
|
+
const d = await this.Fetch(`/admin/export`, { method: 'POST' }, 0)
|
|
49
|
+
return (d.data?.data || '' as string)
|
|
50
|
+
}
|
|
51
|
+
}
|
|
@@ -0,0 +1,39 @@
|
|
|
1
|
+
import ArtalkConfig from '~/types/artalk-config'
|
|
2
|
+
import ApiBase from './api-base'
|
|
3
|
+
|
|
4
|
+
/**
|
|
5
|
+
* 系统 API
|
|
6
|
+
*/
|
|
7
|
+
export default class SystemApi extends ApiBase {
|
|
8
|
+
/** 获取配置 */
|
|
9
|
+
public async conf() {
|
|
10
|
+
const data = await this.POST<any>(`/conf`)
|
|
11
|
+
const conf = (data.frontend_conf || {}) as ArtalkConfig
|
|
12
|
+
|
|
13
|
+
// Patch: `emoticons` config string to json
|
|
14
|
+
if (conf.emoticons && typeof conf.emoticons === "string") {
|
|
15
|
+
conf.emoticons = conf.emoticons.trim()
|
|
16
|
+
if (conf.emoticons.startsWith("[") || conf.emoticons.startsWith("{")) {
|
|
17
|
+
conf.emoticons = JSON.parse(conf.emoticons) // pase json
|
|
18
|
+
} else if (conf.emoticons === "false") {
|
|
19
|
+
conf.emoticons = false
|
|
20
|
+
}
|
|
21
|
+
}
|
|
22
|
+
|
|
23
|
+
return conf
|
|
24
|
+
}
|
|
25
|
+
|
|
26
|
+
/** 获取配置数据 */
|
|
27
|
+
public async getSettings() {
|
|
28
|
+
const data = await this.POST<string>('/admin/setting-get')
|
|
29
|
+
return data
|
|
30
|
+
}
|
|
31
|
+
|
|
32
|
+
/** 保存配置数据 */
|
|
33
|
+
public async saveSettings(yamlStr: string) {
|
|
34
|
+
const data = await this.POST<boolean>('/admin/setting-save', {
|
|
35
|
+
data: yamlStr,
|
|
36
|
+
})
|
|
37
|
+
return data
|
|
38
|
+
}
|
|
39
|
+
}
|
|
@@ -0,0 +1,29 @@
|
|
|
1
|
+
import { ToFormData } from './request'
|
|
2
|
+
import ApiBase from './api-base'
|
|
3
|
+
|
|
4
|
+
/**
|
|
5
|
+
* 上传 API
|
|
6
|
+
*/
|
|
7
|
+
export default class UploadApi extends ApiBase {
|
|
8
|
+
/** 图片上传 */
|
|
9
|
+
public async imgUpload(file: File) {
|
|
10
|
+
const params: any = {
|
|
11
|
+
name: this.ctx.user.data.nick,
|
|
12
|
+
email: this.ctx.user.data.email,
|
|
13
|
+
page_key: this.ctx.conf.pageKey,
|
|
14
|
+
}
|
|
15
|
+
|
|
16
|
+
if (this.ctx.conf.site) params.site_name = this.ctx.conf.site
|
|
17
|
+
|
|
18
|
+
const form = ToFormData(params)
|
|
19
|
+
form.set('file', file)
|
|
20
|
+
|
|
21
|
+
const init: RequestInit = {
|
|
22
|
+
method: 'POST',
|
|
23
|
+
body: form
|
|
24
|
+
}
|
|
25
|
+
|
|
26
|
+
const json = await this.Fetch('/img-upload', init)
|
|
27
|
+
return ((json.data || {}) as any) as { img_file: string, img_url: string }
|
|
28
|
+
}
|
|
29
|
+
}
|
package/src/api/user.ts
ADDED
|
@@ -0,0 +1,75 @@
|
|
|
1
|
+
import { UserData, NotifyData } from '~/types/artalk-data'
|
|
2
|
+
import ApiBase from './api-base'
|
|
3
|
+
import { ToFormData } from './request'
|
|
4
|
+
|
|
5
|
+
/**
|
|
6
|
+
* 用户 API
|
|
7
|
+
*/
|
|
8
|
+
export default class UserApi extends ApiBase {
|
|
9
|
+
/** 用户 · 登录 */
|
|
10
|
+
public async login(name: string, email: string, password: string) {
|
|
11
|
+
const params: any = {
|
|
12
|
+
name, email, password
|
|
13
|
+
}
|
|
14
|
+
|
|
15
|
+
if (this.ctx.conf.site) params.site_name = this.ctx.conf.site
|
|
16
|
+
|
|
17
|
+
const data = await this.POST<any>('/login', params)
|
|
18
|
+
return (data.token as string)
|
|
19
|
+
}
|
|
20
|
+
|
|
21
|
+
/** 用户 · 获取 */
|
|
22
|
+
public userGet(name: string, email: string) {
|
|
23
|
+
const ctrl = new AbortController()
|
|
24
|
+
const params: any = {
|
|
25
|
+
name, email, site_name: (this.ctx.conf.site || '')
|
|
26
|
+
}
|
|
27
|
+
|
|
28
|
+
const req = this.Fetch(`/user-get`, {
|
|
29
|
+
method: 'POST',
|
|
30
|
+
body: ToFormData(params),
|
|
31
|
+
signal: ctrl.signal,
|
|
32
|
+
}).then((json) => ({
|
|
33
|
+
user: json.data.user as UserData|null,
|
|
34
|
+
is_login: json.data.is_login as boolean,
|
|
35
|
+
unread: (json.data.unread || []) as NotifyData[],
|
|
36
|
+
unread_count: json.data.unread_count || 0,
|
|
37
|
+
}))
|
|
38
|
+
|
|
39
|
+
return {
|
|
40
|
+
req,
|
|
41
|
+
abort: () => { ctrl.abort() },
|
|
42
|
+
}
|
|
43
|
+
}
|
|
44
|
+
|
|
45
|
+
/** 用户 · 登录状态 */
|
|
46
|
+
public async loginStatus() {
|
|
47
|
+
const data = await this.POST<any>('/login-status', {
|
|
48
|
+
name: this.ctx.user.data.nick,
|
|
49
|
+
email: this.ctx.user.data.email
|
|
50
|
+
})
|
|
51
|
+
return (data || { is_login: false, is_admin: false }) as { is_login: boolean, is_admin: boolean }
|
|
52
|
+
}
|
|
53
|
+
|
|
54
|
+
/** 用户 · 注销 */
|
|
55
|
+
public async logout() {
|
|
56
|
+
return this.POST('/logout')
|
|
57
|
+
}
|
|
58
|
+
|
|
59
|
+
/** 已读标记 */
|
|
60
|
+
public markRead(notifyKey: string, readAll = false) {
|
|
61
|
+
const params: any = {
|
|
62
|
+
site_name: this.ctx.conf.site || '',
|
|
63
|
+
notify_key: notifyKey,
|
|
64
|
+
}
|
|
65
|
+
|
|
66
|
+
if (readAll) {
|
|
67
|
+
delete params.notify_key
|
|
68
|
+
params.read_all = true
|
|
69
|
+
params.name = this.ctx.user.data.nick
|
|
70
|
+
params.email = this.ctx.user.data.email
|
|
71
|
+
}
|
|
72
|
+
|
|
73
|
+
return this.POST(`/mark-read`, params)
|
|
74
|
+
}
|
|
75
|
+
}
|
package/src/artalk.ts
CHANGED
|
@@ -6,14 +6,13 @@ import ArtalkPlug from '~/types/plug'
|
|
|
6
6
|
import Context from '~/types/context'
|
|
7
7
|
import ConcreteContext from './context'
|
|
8
8
|
import defaults from './defaults'
|
|
9
|
-
import { internal as internalLocales } from './i18n'
|
|
10
9
|
|
|
11
10
|
import CheckerLauncher from './lib/checker'
|
|
12
11
|
import Editor from './editor'
|
|
13
12
|
import List from './list'
|
|
14
13
|
import SidebarLayer from './layer/sidebar-layer'
|
|
15
14
|
|
|
16
|
-
import Layer
|
|
15
|
+
import Layer from './layer'
|
|
17
16
|
import * as Utils from './lib/utils'
|
|
18
17
|
import * as Ui from './lib/ui'
|
|
19
18
|
import * as Stat from './lib/stat'
|
|
@@ -30,14 +29,14 @@ export default class Artalk {
|
|
|
30
29
|
public ctx!: Context
|
|
31
30
|
public $root!: HTMLElement
|
|
32
31
|
|
|
33
|
-
|
|
34
|
-
|
|
35
|
-
public list!: List
|
|
36
|
-
public sidebarLayer!: SidebarLayer
|
|
32
|
+
/** Plugins (in global scope) */
|
|
33
|
+
protected static Plugins: ArtalkPlug[] = [ Stat.PvCountWidget ]
|
|
37
34
|
|
|
38
|
-
|
|
39
|
-
|
|
40
|
-
|
|
35
|
+
/** Plugins (in a instance scope) */
|
|
36
|
+
protected instancePlugins: ArtalkPlug[] = []
|
|
37
|
+
|
|
38
|
+
/** 禁用的组件 */
|
|
39
|
+
public static DisabledComponents: string[] = []
|
|
41
40
|
|
|
42
41
|
constructor(customConf: Partial<ArtalkConfig>) {
|
|
43
42
|
/* 初始化基本配置 */
|
|
@@ -61,32 +60,52 @@ export default class Artalk {
|
|
|
61
60
|
this.initDarkMode()
|
|
62
61
|
Utils.initMarked(this.ctx)
|
|
63
62
|
|
|
64
|
-
|
|
65
|
-
|
|
66
|
-
|
|
67
|
-
|
|
68
|
-
|
|
69
|
-
|
|
70
|
-
|
|
71
|
-
|
|
72
|
-
|
|
73
|
-
|
|
74
|
-
|
|
75
|
-
|
|
76
|
-
|
|
77
|
-
|
|
78
|
-
|
|
79
|
-
|
|
80
|
-
|
|
81
|
-
|
|
63
|
+
const Components: { [name: string]: () => void } = {
|
|
64
|
+
// CheckerLauncher
|
|
65
|
+
checkerLauncher: () => {
|
|
66
|
+
const checkerLauncher = new CheckerLauncher(this.ctx)
|
|
67
|
+
this.ctx.setCheckerLauncher(checkerLauncher)
|
|
68
|
+
},
|
|
69
|
+
|
|
70
|
+
// 编辑器
|
|
71
|
+
editor: () => {
|
|
72
|
+
const editor = new Editor(this.ctx)
|
|
73
|
+
this.ctx.setEditor(editor)
|
|
74
|
+
this.$root.appendChild(editor.$el)
|
|
75
|
+
},
|
|
76
|
+
|
|
77
|
+
// 评论列表
|
|
78
|
+
list: () => {
|
|
79
|
+
// 评论列表
|
|
80
|
+
const list = new List(this.ctx)
|
|
81
|
+
this.ctx.setList(list)
|
|
82
|
+
this.$root.appendChild(list.$el)
|
|
83
|
+
|
|
84
|
+
// 评论获取
|
|
85
|
+
list.fetchComments(0)
|
|
86
|
+
},
|
|
87
|
+
|
|
88
|
+
// 侧边栏 Layer
|
|
89
|
+
sidebarLayer: () => {
|
|
90
|
+
const sidebarLayer = new SidebarLayer(this.ctx)
|
|
91
|
+
this.ctx.setSidebarLayer(sidebarLayer)
|
|
92
|
+
this.$root.appendChild(sidebarLayer.$el)
|
|
93
|
+
},
|
|
94
|
+
|
|
95
|
+
// 默认事件绑定
|
|
96
|
+
eventsDefault: () => {
|
|
97
|
+
this.initEventBind()
|
|
98
|
+
}
|
|
99
|
+
}
|
|
82
100
|
|
|
83
|
-
//
|
|
84
|
-
|
|
101
|
+
// 组件初始化
|
|
102
|
+
Object.entries(Components).forEach(([name, initComponent]) => {
|
|
103
|
+
if (Artalk.DisabledComponents.includes(name)) return
|
|
85
104
|
|
|
86
|
-
|
|
87
|
-
|
|
105
|
+
initComponent()
|
|
106
|
+
})
|
|
88
107
|
|
|
89
|
-
// 插件初始化
|
|
108
|
+
// 插件初始化 (global scope)
|
|
90
109
|
Artalk.Plugins.forEach(plugin => {
|
|
91
110
|
if (typeof plugin === 'function')
|
|
92
111
|
plugin(this.ctx)
|
|
@@ -94,7 +113,7 @@ export default class Artalk {
|
|
|
94
113
|
}
|
|
95
114
|
|
|
96
115
|
/** 基本配置初始化 */
|
|
97
|
-
|
|
116
|
+
public static HandelBaseConf(customConf: Partial<ArtalkConfig>): ArtalkConfig {
|
|
98
117
|
// 合并默认配置
|
|
99
118
|
const conf: ArtalkConfig = Utils.mergeDeep(Artalk.defaults, customConf)
|
|
100
119
|
|
|
@@ -139,7 +158,7 @@ export default class Artalk {
|
|
|
139
158
|
Ui.showLoading(this.$root)
|
|
140
159
|
let backendConf = {}
|
|
141
160
|
try {
|
|
142
|
-
backendConf = await this.ctx.getApi().conf()
|
|
161
|
+
backendConf = await this.ctx.getApi().system.conf()
|
|
143
162
|
} catch (err) { console.error("Load config from remote err", err) }
|
|
144
163
|
this.ctx.conf = Utils.mergeDeep(this.ctx.conf, backendConf)
|
|
145
164
|
Ui.hideLoading(this.$root)
|
|
@@ -149,8 +168,7 @@ export default class Artalk {
|
|
|
149
168
|
private initEventBind() {
|
|
150
169
|
// 锚点快速跳转评论
|
|
151
170
|
window.addEventListener('hashchange', () => {
|
|
152
|
-
this.
|
|
153
|
-
this.list.checkGoToCommentByUrlHash()
|
|
171
|
+
this.ctx.listHashGotoCheck()
|
|
154
172
|
})
|
|
155
173
|
|
|
156
174
|
// 本地用户数据变更
|
|
@@ -162,20 +180,8 @@ export default class Artalk {
|
|
|
162
180
|
|
|
163
181
|
/** 语言初始化 */
|
|
164
182
|
private initLocale() {
|
|
165
|
-
if (
|
|
166
|
-
|
|
167
|
-
this.conf.locale = ((navigator.languages) ? navigator.languages[0] : navigator.language)
|
|
168
|
-
}
|
|
169
|
-
|
|
170
|
-
this.conf.locale = this.conf.locale.replace(
|
|
171
|
-
/^([a-zA-Z]+)(-[a-zA-Z]+)?$/,
|
|
172
|
-
(_, p1: string, p2: string) => (p1.toLowerCase() + (p2 || '').toUpperCase())
|
|
173
|
-
)
|
|
174
|
-
|
|
175
|
-
if (!internalLocales[this.conf.locale]) { // 语言不存在时,使用 en
|
|
176
|
-
console.log(`Locale "${this.conf.locale}" not found.`)
|
|
177
|
-
this.conf.locale = 'en'
|
|
178
|
-
}
|
|
183
|
+
if (this.conf.locale === 'auto') { // 自适应语言
|
|
184
|
+
this.conf.locale = navigator.language
|
|
179
185
|
}
|
|
180
186
|
}
|
|
181
187
|
|
|
@@ -198,30 +204,6 @@ export default class Artalk {
|
|
|
198
204
|
}
|
|
199
205
|
}
|
|
200
206
|
|
|
201
|
-
/** 设置暗黑模式 */
|
|
202
|
-
public setDarkMode(darkMode: boolean) {
|
|
203
|
-
const darkModeClassName = 'atk-dark-mode'
|
|
204
|
-
|
|
205
|
-
this.ctx.conf.darkMode = darkMode
|
|
206
|
-
this.ctx.trigger('conf-updated')
|
|
207
|
-
|
|
208
|
-
if (this.conf.darkMode) {
|
|
209
|
-
this.$root.classList.add(darkModeClassName)
|
|
210
|
-
} else {
|
|
211
|
-
this.$root.classList.remove(darkModeClassName)
|
|
212
|
-
}
|
|
213
|
-
|
|
214
|
-
// for Layer
|
|
215
|
-
const { $wrap: $layerWrap } = GetLayerWrap(this.ctx)
|
|
216
|
-
if ($layerWrap) {
|
|
217
|
-
if (this.conf.darkMode) {
|
|
218
|
-
$layerWrap.classList.add(darkModeClassName)
|
|
219
|
-
} else {
|
|
220
|
-
$layerWrap.classList.remove(darkModeClassName)
|
|
221
|
-
}
|
|
222
|
-
}
|
|
223
|
-
}
|
|
224
|
-
|
|
225
207
|
/** 监听事件 */
|
|
226
208
|
public on<K extends keyof EventPayloadMap>(name: K, handler: Handler<EventPayloadMap[K]>) {
|
|
227
209
|
this.ctx.on(name, handler, 'external')
|
|
@@ -242,11 +224,28 @@ export default class Artalk {
|
|
|
242
224
|
this.ctx.listReload()
|
|
243
225
|
}
|
|
244
226
|
|
|
245
|
-
/**
|
|
246
|
-
public
|
|
227
|
+
/** 设置暗黑模式 */
|
|
228
|
+
public setDarkMode(darkMode: boolean) {
|
|
229
|
+
this.ctx.setDarkMode(darkMode)
|
|
230
|
+
}
|
|
231
|
+
|
|
232
|
+
/** Use Plugin (specific instance) */
|
|
233
|
+
public use(plugin: ArtalkPlug) {
|
|
234
|
+
this.instancePlugins.push(plugin)
|
|
235
|
+
if (typeof plugin === 'function') plugin(this.ctx)
|
|
236
|
+
}
|
|
237
|
+
|
|
238
|
+
/** Use Plugin (static method for global scope) */
|
|
239
|
+
public static use(plugin: ArtalkPlug) {
|
|
247
240
|
this.Plugins.push(plugin)
|
|
248
241
|
}
|
|
249
242
|
|
|
243
|
+
/** @deprecated Please replace it with lowercase function name `use(...)`. */
|
|
244
|
+
public static Use(plugin: ArtalkPlug) {
|
|
245
|
+
this.use(plugin)
|
|
246
|
+
console.warn('`Use(...)` is deprecated, replace it with lowercase `use(...)`.')
|
|
247
|
+
}
|
|
248
|
+
|
|
250
249
|
/** 装载数量统计元素 */
|
|
251
250
|
public static LoadCountWidget(customConf: Partial<ArtalkConfig>) {
|
|
252
251
|
const conf = this.HandelBaseConf(customConf)
|
package/src/comment/actions.ts
CHANGED
|
@@ -16,7 +16,7 @@ export default class CommentActions {
|
|
|
16
16
|
public vote(type: 'up'|'down') {
|
|
17
17
|
const actionBtn = (type === 'up') ? this.comment.getRender().voteBtnUp : this.comment.getRender().voteBtnDown
|
|
18
18
|
|
|
19
|
-
this.ctx.getApi().vote(this.data.id, `comment_${type}`)
|
|
19
|
+
this.ctx.getApi().comment.vote(this.data.id, `comment_${type}`)
|
|
20
20
|
.then((v) => {
|
|
21
21
|
this.data.vote_up = v.up
|
|
22
22
|
this.data.vote_down = v.down
|
|
@@ -45,7 +45,7 @@ export default class CommentActions {
|
|
|
45
45
|
modify.is_pinned = !modify.is_pinned
|
|
46
46
|
}
|
|
47
47
|
|
|
48
|
-
this.ctx.getApi().commentEdit(modify).then((data) => {
|
|
48
|
+
this.ctx.getApi().comment.commentEdit(modify).then((data) => {
|
|
49
49
|
btnElem.setLoading(false)
|
|
50
50
|
|
|
51
51
|
// 刷新当前 Comment UI
|
|
@@ -64,7 +64,7 @@ export default class CommentActions {
|
|
|
64
64
|
if (btnElem.isLoading) return // 若正在删除中
|
|
65
65
|
|
|
66
66
|
btnElem.setLoading(true, `${this.ctx.$t('deleting')}...`)
|
|
67
|
-
this.ctx.getApi().commentDel(this.data.id, this.data.site_name)
|
|
67
|
+
this.ctx.getApi().comment.commentDel(this.data.id, this.data.site_name)
|
|
68
68
|
.then(() => {
|
|
69
69
|
btnElem.setLoading(false)
|
|
70
70
|
if (this.cConf.onDelete) this.cConf.onDelete(this.comment)
|
package/src/comment/comment.ts
CHANGED
|
@@ -172,16 +172,13 @@ export default class Comment extends Component {
|
|
|
172
172
|
return Utils.timeAgo(new Date(this.data.date), this.ctx)
|
|
173
173
|
}
|
|
174
174
|
|
|
175
|
-
/** 获取用户 UserAgent
|
|
176
|
-
public
|
|
175
|
+
/** 获取用户 UserAgent 信息 */
|
|
176
|
+
public getUserUA() {
|
|
177
177
|
const info = UADetect(this.data.ua)
|
|
178
|
-
return
|
|
179
|
-
|
|
180
|
-
|
|
181
|
-
|
|
182
|
-
public getUserUaOS() {
|
|
183
|
-
const info = UADetect(this.data.ua)
|
|
184
|
-
return `${info.os} ${info.osVersion}`
|
|
178
|
+
return {
|
|
179
|
+
browser: `${info.browser} ${info.version}`,
|
|
180
|
+
os: `${info.os} ${info.osVersion}`
|
|
181
|
+
}
|
|
185
182
|
}
|
|
186
183
|
|
|
187
184
|
/** 获取配置 */
|