artalk 2.2.12 → 2.3.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/dist/Artalk.css +1 -1
- package/dist/Artalk.es.js +1535 -1175
- package/dist/Artalk.iife.js +1 -1
- package/dist/Artalk.js +1 -1
- package/dist/ArtalkLite.css +1 -0
- package/dist/ArtalkLite.es.js +5123 -0
- package/dist/ArtalkLite.iife.js +1 -0
- package/dist/ArtalkLite.js +1 -0
- package/index.html +2 -2
- package/package.json +6 -5
- package/src/api/index.ts +20 -1
- package/src/api/request.ts +7 -7
- package/src/artalk.ts +117 -121
- package/src/comment/actions.ts +86 -0
- package/src/{components/html → comment}/comment.html +1 -1
- package/src/comment/comment.ts +191 -0
- package/src/comment/index.ts +3 -0
- package/src/comment/render.ts +425 -0
- package/src/components/action-btn.ts +6 -3
- package/src/components/dialog.ts +7 -3
- package/src/components/read-more-btn.ts +6 -2
- package/src/context.ts +204 -13
- package/src/defaults.ts +16 -5
- package/src/editor/editor.html +18 -0
- package/src/editor/editor.ts +419 -0
- package/src/editor/index.ts +3 -0
- package/src/editor/plugs/editor-plug.ts +51 -0
- package/src/{components/editor-plugs → editor/plugs}/emoticons-plug.less +2 -1
- package/src/{components/editor-plugs → editor/plugs}/emoticons-plug.ts +65 -63
- package/src/editor/plugs/header-input-plug.ts +78 -0
- package/src/{components/editor-plugs → editor/plugs}/preview-plug.less +0 -0
- package/src/editor/plugs/preview-plug.ts +40 -0
- package/src/editor/plugs/upload-plug.ts +124 -0
- package/src/i18n/en.ts +78 -0
- package/src/i18n/index.ts +21 -0
- package/src/i18n/zh-CN.ts +82 -0
- package/src/layer/index.ts +4 -0
- package/src/{components → layer}/layer.ts +9 -9
- package/src/{components/html → layer}/sidebar-layer.html +0 -0
- package/src/{components → layer}/sidebar-layer.ts +17 -47
- package/src/lib/checker/admin-checker.ts +7 -7
- package/src/lib/checker/captcha-checker.ts +5 -6
- package/src/lib/checker/index.ts +22 -17
- package/src/lib/component.ts +7 -2
- package/src/lib/stat.ts +63 -0
- package/src/lib/ui.ts +6 -12
- package/src/lib/user.ts +20 -3
- package/src/lib/utils.ts +23 -9
- package/src/list/index.ts +3 -0
- package/src/{components → list}/list-lite.ts +80 -100
- package/src/{components → list}/list-nest.ts +0 -0
- package/src/{components/html → list}/list.html +3 -6
- package/src/{components → list}/list.ts +44 -42
- package/src/style/_variables.less +1 -2
- package/src/style/comment.less +26 -13
- package/src/style/editor.less +22 -14
- package/src/style/list.less +6 -9
- package/src/style/main.less +9 -8
- package/src/style/pagination.less +1 -1
- package/test/ArtalkCount.html +16 -0
- package/test/ArtalkI18n.html +15 -0
- package/test/ArtalkLite.html +15 -0
- package/types/artalk-config.d.ts +50 -32
- package/types/context.d.ts +128 -0
- package/types/event.d.ts +6 -66
- package/types/global.d.ts +1 -0
- package/types/plug.d.ts +4 -0
- package/{vite-common.config.ts → vite-base.config.ts} +6 -4
- package/vite-demo.config.ts +2 -4
- package/vite-lite.config.ts +22 -0
- package/vite.config.ts +9 -12
- package/src/components/_component.ts.txt +0 -10
- package/src/components/comment.ts +0 -605
- package/src/components/editor-plugs/_example-plug.ts.txt +0 -29
- package/src/components/editor-plugs/editor-plug.ts +0 -20
- package/src/components/editor-plugs/preview-plug.ts +0 -48
- package/src/components/editor.ts +0 -607
- package/src/components/html/editor.html +0 -18
|
@@ -5,6 +5,8 @@ export interface ReadMoreBtnConf {
|
|
|
5
5
|
onClick: (offset: number) => void
|
|
6
6
|
|
|
7
7
|
pageSize: number
|
|
8
|
+
|
|
9
|
+
text?: string
|
|
8
10
|
}
|
|
9
11
|
|
|
10
12
|
/**
|
|
@@ -17,6 +19,7 @@ export default class ReadMoreBtn {
|
|
|
17
19
|
private $text: HTMLElement
|
|
18
20
|
private offset: number = 0
|
|
19
21
|
private total: number = 0
|
|
22
|
+
private origText: string = 'Load More'
|
|
20
23
|
|
|
21
24
|
/** 是否有更多内容 */
|
|
22
25
|
get hasMore() {
|
|
@@ -25,12 +28,13 @@ export default class ReadMoreBtn {
|
|
|
25
28
|
|
|
26
29
|
public constructor(conf: ReadMoreBtnConf) {
|
|
27
30
|
this.conf = conf
|
|
31
|
+
this.origText = this.conf.text || this.origText
|
|
28
32
|
|
|
29
33
|
this.$el = Utils.createElement(
|
|
30
34
|
`<div class="atk-list-read-more" style="display: none;">
|
|
31
35
|
<div class="atk-list-read-more-inner">
|
|
32
36
|
<div class="atk-loading-icon" style="display: none;"></div>
|
|
33
|
-
<span class="atk-text"
|
|
37
|
+
<span class="atk-text">${this.origText}</span>
|
|
34
38
|
</div>
|
|
35
39
|
</div>`)
|
|
36
40
|
|
|
@@ -68,7 +72,7 @@ export default class ReadMoreBtn {
|
|
|
68
72
|
this.$text.innerText = errMsg
|
|
69
73
|
this.$el.classList.add('atk-err')
|
|
70
74
|
window.setTimeout(() => {
|
|
71
|
-
this.$text.innerText =
|
|
75
|
+
this.$text.innerText = this.origText
|
|
72
76
|
this.$el.classList.remove('atk-err')
|
|
73
77
|
}, 2000) // 2s后错误提示复原
|
|
74
78
|
}
|
package/src/context.ts
CHANGED
|
@@ -1,46 +1,237 @@
|
|
|
1
1
|
import { marked as libMarked } from 'marked'
|
|
2
2
|
import ArtalkConfig from '~/types/artalk-config'
|
|
3
|
-
import {
|
|
3
|
+
import { CommentData, NotifyData } from '~/types/artalk-data'
|
|
4
|
+
import { Event } from '~/types/event'
|
|
5
|
+
import { internal as internalLocales, I18n } from './i18n'
|
|
4
6
|
import User from './lib/user'
|
|
7
|
+
import ContextApi from '../types/context'
|
|
8
|
+
import Editor from './editor'
|
|
9
|
+
import Comment from './comment'
|
|
10
|
+
import ListLite from './list/list-lite'
|
|
11
|
+
import SidebarLayer, { SidebarShowPayload } from './layer/sidebar-layer'
|
|
12
|
+
import CheckerLauncher, { CheckerCaptchaPayload, CheckerPayload } from './lib/checker'
|
|
13
|
+
import Layer, { GetLayerWrap } from './layer'
|
|
14
|
+
import Api from './api'
|
|
5
15
|
|
|
6
16
|
/**
|
|
7
17
|
* Artalk Context
|
|
8
18
|
*/
|
|
9
|
-
export default class Context {
|
|
19
|
+
export default class Context implements ContextApi {
|
|
20
|
+
/* 持有同事类 */
|
|
21
|
+
private api!: Api
|
|
22
|
+
private editor!: Editor
|
|
23
|
+
private list!: ListLite
|
|
24
|
+
private sidebarLayer!: SidebarLayer
|
|
25
|
+
private checkerLauncher!: CheckerLauncher
|
|
26
|
+
|
|
27
|
+
/* 运行参数 */
|
|
10
28
|
public cid: number // Context 唯一标识
|
|
11
|
-
public $root: HTMLElement
|
|
12
29
|
public conf: ArtalkConfig
|
|
13
30
|
public user: User
|
|
31
|
+
public $root: HTMLElement
|
|
32
|
+
public markedInstance?: typeof libMarked
|
|
33
|
+
public markedReplacers: ((raw: string) => string)[] = []
|
|
34
|
+
|
|
35
|
+
private commentList: Comment[] = [] // Note: 无层级结构 + 无须排列
|
|
14
36
|
|
|
37
|
+
/* 订阅者模式 */
|
|
15
38
|
private eventList: Event[] = []
|
|
16
39
|
|
|
17
|
-
public constructor
|
|
40
|
+
public constructor(conf: ArtalkConfig, $root?: HTMLElement) {
|
|
18
41
|
this.cid = +new Date()
|
|
19
|
-
this.$root = rootEl
|
|
20
42
|
this.conf = conf
|
|
21
|
-
this.user = new User(this
|
|
43
|
+
this.user = new User(this)
|
|
22
44
|
|
|
45
|
+
this.$root = $root || document.createElement('div')
|
|
23
46
|
this.$root.setAttribute('atk-run-id', this.cid.toString())
|
|
47
|
+
this.$root.classList.add('artalk')
|
|
48
|
+
this.$root.innerHTML = ''
|
|
49
|
+
|
|
50
|
+
this.api = new Api(this)
|
|
51
|
+
}
|
|
52
|
+
|
|
53
|
+
/* 设置持有的同事类 */
|
|
54
|
+
public setApi(api: Api): void {
|
|
55
|
+
this.api = api
|
|
56
|
+
}
|
|
57
|
+
|
|
58
|
+
public setEditor(editor: Editor): void {
|
|
59
|
+
this.editor = editor
|
|
60
|
+
}
|
|
61
|
+
|
|
62
|
+
public setList(list: ListLite): void {
|
|
63
|
+
this.list = list
|
|
64
|
+
}
|
|
65
|
+
|
|
66
|
+
public setSidebarLayer(sidebarLayer: SidebarLayer): void {
|
|
67
|
+
this.sidebarLayer = sidebarLayer
|
|
68
|
+
}
|
|
69
|
+
|
|
70
|
+
public setCheckerLauncher(checkerLauncher: CheckerLauncher): void {
|
|
71
|
+
this.checkerLauncher = checkerLauncher
|
|
72
|
+
}
|
|
73
|
+
|
|
74
|
+
public getApi() {
|
|
75
|
+
return this.api
|
|
76
|
+
}
|
|
77
|
+
|
|
78
|
+
/* 评论操作 */
|
|
79
|
+
public getCommentList() {
|
|
80
|
+
return this.commentList
|
|
81
|
+
}
|
|
82
|
+
|
|
83
|
+
public getCommentDataList() {
|
|
84
|
+
return this.commentList.map(c => c.getData())
|
|
85
|
+
}
|
|
86
|
+
|
|
87
|
+
public findComment(id: number): Comment|undefined {
|
|
88
|
+
return this.commentList.find(c => c.getData().id === id)
|
|
89
|
+
}
|
|
90
|
+
|
|
91
|
+
public deleteComment(_comment: number|Comment) {
|
|
92
|
+
let comment: Comment
|
|
93
|
+
if (typeof _comment === 'number') {
|
|
94
|
+
const findComment = this.findComment(_comment)
|
|
95
|
+
if (!findComment) throw Error(`Comment ${_comment} cannot be found`)
|
|
96
|
+
comment = findComment
|
|
97
|
+
} else comment = _comment
|
|
98
|
+
|
|
99
|
+
comment.getEl().remove()
|
|
100
|
+
this.commentList.splice(this.commentList.indexOf(comment), 1)
|
|
101
|
+
|
|
102
|
+
const listData = this.list.getData()
|
|
103
|
+
if (listData) listData.total -= 1 // 评论数减 1
|
|
104
|
+
|
|
105
|
+
this.list.refreshUI()
|
|
106
|
+
}
|
|
107
|
+
|
|
108
|
+
public clearAllComments() {
|
|
109
|
+
this.list.getCommentsWrapEl().innerHTML = ''
|
|
110
|
+
this.list.clearData()
|
|
111
|
+
this.commentList = []
|
|
112
|
+
}
|
|
113
|
+
|
|
114
|
+
public insertComment(commentData: CommentData) {
|
|
115
|
+
this.list.insertComment(commentData)
|
|
116
|
+
}
|
|
117
|
+
|
|
118
|
+
public replyComment(commentData: CommentData, $comment: HTMLElement, scroll?: boolean): void {
|
|
119
|
+
this.editor.setReply(commentData, $comment, scroll)
|
|
120
|
+
}
|
|
121
|
+
|
|
122
|
+
public cancelReplyComment(): void {
|
|
123
|
+
this.editor.cancelReply()
|
|
124
|
+
}
|
|
125
|
+
|
|
126
|
+
public updateNotifies(notifies: NotifyData[]): void {
|
|
127
|
+
this.list.updateUnread(notifies)
|
|
128
|
+
}
|
|
129
|
+
|
|
130
|
+
/* 评论列表 */
|
|
131
|
+
public listReload(): void {
|
|
132
|
+
this.list.reload()
|
|
133
|
+
}
|
|
134
|
+
|
|
135
|
+
public listRefreshUI(): void {
|
|
136
|
+
this.list.refreshUI()
|
|
137
|
+
}
|
|
138
|
+
|
|
139
|
+
/* 编辑器 */
|
|
140
|
+
public editorOpen(): void {
|
|
141
|
+
this.editor.open()
|
|
142
|
+
}
|
|
143
|
+
|
|
144
|
+
public editorClose(): void {
|
|
145
|
+
this.editor.close()
|
|
146
|
+
}
|
|
147
|
+
|
|
148
|
+
public editorShowLoading(): void {
|
|
149
|
+
this.editor.showLoading()
|
|
150
|
+
}
|
|
151
|
+
|
|
152
|
+
public editorHideLoading(): void {
|
|
153
|
+
this.editor.hideLoading()
|
|
154
|
+
}
|
|
155
|
+
|
|
156
|
+
public editorShowNotify(msg, type): void {
|
|
157
|
+
this.editor.showNotify(msg, type)
|
|
158
|
+
}
|
|
159
|
+
|
|
160
|
+
public editorTravel($el: HTMLElement): void {
|
|
161
|
+
this.editor.travel($el)
|
|
162
|
+
}
|
|
163
|
+
|
|
164
|
+
public editorTravelBack(): void {
|
|
165
|
+
this.editor.travelBack()
|
|
24
166
|
}
|
|
25
167
|
|
|
26
|
-
|
|
27
|
-
|
|
168
|
+
/* 侧边栏 */
|
|
169
|
+
public showSidebar(payload?: SidebarShowPayload): void {
|
|
170
|
+
this.sidebarLayer.show(payload)
|
|
28
171
|
}
|
|
29
172
|
|
|
30
|
-
public
|
|
173
|
+
public hideSidebar(): void {
|
|
174
|
+
this.sidebarLayer.hide()
|
|
175
|
+
}
|
|
176
|
+
|
|
177
|
+
/* 权限检测 */
|
|
178
|
+
public checkAdmin(payload: CheckerPayload): void {
|
|
179
|
+
this.checkerLauncher.checkAdmin(payload)
|
|
180
|
+
}
|
|
181
|
+
|
|
182
|
+
public checkCaptcha(payload: CheckerCaptchaPayload): void {
|
|
183
|
+
this.checkerLauncher.checkCaptcha(payload)
|
|
184
|
+
}
|
|
185
|
+
|
|
186
|
+
public checkAdminShowEl() {
|
|
187
|
+
const items: HTMLElement[] = []
|
|
188
|
+
|
|
189
|
+
this.$root.querySelectorAll<HTMLElement>(`[atk-only-admin-show]`).forEach(item => items.push(item))
|
|
190
|
+
|
|
191
|
+
// for layer
|
|
192
|
+
const { $wrap: $layerWrap } = GetLayerWrap(this)
|
|
193
|
+
if ($layerWrap) $layerWrap.querySelectorAll<HTMLElement>(`[atk-only-admin-show]`).forEach(item => items.push(item))
|
|
194
|
+
|
|
195
|
+
// for sidebar
|
|
196
|
+
// TODO: 这个其实应该写在 packages/artalk-sidebar 里面的
|
|
197
|
+
const $sidebarEl = document.querySelector<HTMLElement>('.atk-sidebar')
|
|
198
|
+
if ($sidebarEl) $sidebarEl.querySelectorAll<HTMLElement>(`[atk-only-admin-show]`).forEach(item => items.push(item))
|
|
199
|
+
|
|
200
|
+
items.forEach(($item: HTMLElement) => {
|
|
201
|
+
if (this.user.data.isAdmin) $item.classList.remove('atk-hide')
|
|
202
|
+
else $item.classList.add('atk-hide')
|
|
203
|
+
})
|
|
204
|
+
}
|
|
205
|
+
|
|
206
|
+
/* 订阅模式 */
|
|
207
|
+
public on(name: any, handler: any, scope: any = 'internal') {
|
|
208
|
+
this.eventList.push({ name, handler, scope })
|
|
209
|
+
}
|
|
210
|
+
|
|
211
|
+
public off(name: any, handler: any, scope: any = 'internal') {
|
|
31
212
|
this.eventList = this.eventList.filter((evt) => {
|
|
32
213
|
if (handler) return !(evt.name === name && evt.handler === handler && evt.scope === scope)
|
|
33
214
|
return !(evt.name === name && evt.scope === scope) // 删除全部相同 name event
|
|
34
215
|
})
|
|
35
216
|
}
|
|
36
217
|
|
|
37
|
-
public trigger
|
|
218
|
+
public trigger(name: any, payload?: any, scope?: any) {
|
|
38
219
|
this.eventList
|
|
39
220
|
.filter((evt) => evt.name === name && (scope ? (evt.scope === scope) : true))
|
|
40
221
|
.map((evt) => evt.handler)
|
|
41
|
-
.forEach((handler) => handler(payload
|
|
222
|
+
.forEach((handler) => handler(payload))
|
|
42
223
|
}
|
|
43
224
|
|
|
44
|
-
|
|
45
|
-
public
|
|
225
|
+
/* i18n */
|
|
226
|
+
public $t(key: keyof I18n, args: {[key: string]: string} = {}): string {
|
|
227
|
+
let locales = this.conf.locale
|
|
228
|
+
if (typeof locales === 'string') {
|
|
229
|
+
locales = internalLocales[locales]
|
|
230
|
+
}
|
|
231
|
+
|
|
232
|
+
let str = locales?.[key] || key
|
|
233
|
+
str = str.replace(/\{\s*(\w+?)\s*\}/g, (_, token) => args[token] || '')
|
|
234
|
+
|
|
235
|
+
return str
|
|
236
|
+
}
|
|
46
237
|
}
|
package/src/defaults.ts
CHANGED
|
@@ -1,15 +1,16 @@
|
|
|
1
|
-
import ArtalkConfig from "~/types/artalk-config"
|
|
1
|
+
import ArtalkConfig from "~/types/artalk-config"
|
|
2
2
|
|
|
3
3
|
const defaults: ArtalkConfig = {
|
|
4
4
|
el: '',
|
|
5
5
|
pageKey: '',
|
|
6
|
+
pageTitle: '',
|
|
6
7
|
server: '',
|
|
7
8
|
site: '',
|
|
8
9
|
|
|
9
|
-
placeholder: '
|
|
10
|
-
noComment: '
|
|
11
|
-
sendBtn: '
|
|
12
|
-
darkMode:
|
|
10
|
+
placeholder: '',
|
|
11
|
+
noComment: '',
|
|
12
|
+
sendBtn: '',
|
|
13
|
+
darkMode: false,
|
|
13
14
|
editorTravel: true,
|
|
14
15
|
|
|
15
16
|
flatMode: 'auto',
|
|
@@ -22,6 +23,8 @@ const defaults: ArtalkConfig = {
|
|
|
22
23
|
voteDown: false,
|
|
23
24
|
uaBadge: true,
|
|
24
25
|
listSort: true,
|
|
26
|
+
preview: true,
|
|
27
|
+
countEl: '#ArtalkCount',
|
|
25
28
|
pvEl: '#ArtalkPV',
|
|
26
29
|
|
|
27
30
|
gravatar: {
|
|
@@ -44,6 +47,14 @@ const defaults: ArtalkConfig = {
|
|
|
44
47
|
reqTimeout: 15000,
|
|
45
48
|
versionCheck: true,
|
|
46
49
|
useBackendConf: false,
|
|
50
|
+
|
|
51
|
+
locale: 'zh-CN',
|
|
52
|
+
}
|
|
53
|
+
|
|
54
|
+
if (ARTALK_LITE) {
|
|
55
|
+
defaults.vote = false
|
|
56
|
+
defaults.uaBadge = false
|
|
57
|
+
defaults.emoticons = false
|
|
47
58
|
}
|
|
48
59
|
|
|
49
60
|
export default defaults
|
|
@@ -0,0 +1,18 @@
|
|
|
1
|
+
<div class="atk-main-editor">
|
|
2
|
+
<div class="atk-header">
|
|
3
|
+
<input name="nick" class="atk-nick" type="text" required="required">
|
|
4
|
+
<input name="email" class="atk-email" type="email" required="required">
|
|
5
|
+
<input name="link" class="atk-link" type="url">
|
|
6
|
+
</div>
|
|
7
|
+
<div class="atk-textarea-wrap">
|
|
8
|
+
<textarea class="atk-textarea"></textarea>
|
|
9
|
+
</div>
|
|
10
|
+
<div class="atk-plug-panel-wrap" style="display: none;"></div>
|
|
11
|
+
<div class="atk-bottom">
|
|
12
|
+
<div class="atk-item atk-plug-btn-wrap"></div>
|
|
13
|
+
<div class="atk-item">
|
|
14
|
+
<button type="button" class="atk-send-btn"></button>
|
|
15
|
+
</div>
|
|
16
|
+
</div>
|
|
17
|
+
<div class="atk-notify-wrap"></div>
|
|
18
|
+
</div>
|