artalk 2.4.4 → 2.5.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 +27 -0
- package/dist/Artalk.css +1 -1
- package/dist/Artalk.es.js +7066 -6256
- package/dist/Artalk.iife.js +1 -1
- package/dist/Artalk.js +1 -1
- package/dist/ArtalkLite.css +1 -1
- package/dist/ArtalkLite.es.js +5095 -4396
- package/dist/ArtalkLite.iife.js +1 -1
- package/dist/ArtalkLite.js +1 -1
- package/dist/i18n/jp.js +1 -1
- package/dist/i18n/zh-TW.js +1 -1
- package/dist/src/api/index.d.ts +2 -2
- package/dist/src/api/system.d.ts +5 -2
- package/dist/src/artalk.d.ts +42 -34
- package/dist/src/comment/comment.d.ts +2 -2
- package/dist/src/comment/height-limit.d.ts +30 -0
- package/dist/src/comment/render-ctx.d.ts +23 -0
- package/dist/src/comment/render.d.ts +2 -50
- package/dist/src/comment/renders/actions.d.ts +5 -0
- package/dist/src/comment/renders/avatar.d.ts +5 -0
- package/dist/src/comment/renders/content.d.ts +5 -0
- package/dist/src/comment/renders/header.d.ts +5 -0
- package/dist/src/comment/renders/index.d.ts +2 -0
- package/dist/src/comment/renders/pending.d.ts +5 -0
- package/dist/src/comment/renders/reply-at.d.ts +5 -0
- package/dist/src/comment/renders/reply-to.d.ts +5 -0
- package/dist/src/components/dialog.d.ts +1 -1
- package/dist/src/config.d.ts +8 -0
- package/dist/src/context.d.ts +16 -29
- package/dist/src/editor/edit-mode.d.ts +9 -0
- package/dist/src/editor/editor.d.ts +37 -45
- package/dist/src/editor/funcs.d.ts +2 -0
- package/dist/src/editor/mover.d.ts +8 -0
- package/dist/src/editor/plug-manager.d.ts +17 -0
- package/dist/src/editor/plugs/editor-plug.d.ts +13 -1
- package/dist/src/editor/reply.d.ts +9 -0
- package/dist/src/editor/submit.d.ts +16 -0
- package/dist/src/editor/ui.d.ts +25 -0
- package/dist/src/i18n/external.d.ts +70 -0
- package/dist/src/i18n/index.d.ts +11 -75
- package/dist/src/layer/index.d.ts +2 -2
- package/dist/src/layer/layer.d.ts +1 -1
- package/dist/src/lib/checker/captcha-renders.d.ts +5 -0
- package/dist/src/lib/checker/index.d.ts +16 -10
- package/dist/src/lib/dark-mode.d.ts +4 -0
- package/dist/src/lib/marked.d.ts +9 -0
- package/dist/src/lib/user.d.ts +6 -3
- package/dist/src/lib/utils.d.ts +1 -5
- package/dist/src/list/list-lite.d.ts +15 -11
- package/dist/src/list/list-nest.d.ts +2 -2
- package/dist/src/list/list-ui.d.ts +16 -0
- package/dist/src/list/list.d.ts +0 -1
- package/dist/src/list/paginator/adaptors/index.d.ts +12 -0
- package/dist/src/list/paginator/adaptors/pagination.d.ts +9 -0
- package/dist/src/list/paginator/adaptors/read-more.d.ts +10 -0
- package/dist/src/list/paginator/holder.d.ts +16 -0
- package/dist/src/list/paginator/index.d.ts +10 -0
- package/dist/src/service.d.ts +46 -0
- package/dist/types/artalk-config.d.ts +5 -2
- package/dist/types/artalk-data.d.ts +3 -3
- package/dist/types/context.d.ts +13 -20
- package/dist/types/global.d.ts +1 -0
- package/package.json +6 -7
- package/src/api/comment.ts +7 -7
- package/src/api/page.ts +0 -2
- package/src/api/request.ts +6 -4
- package/src/api/system.ts +3 -12
- package/src/api/upload.ts +3 -4
- package/src/api/user.ts +6 -8
- package/src/artalk.ts +103 -158
- package/src/comment/comment.ts +7 -6
- package/src/comment/height-limit.ts +100 -0
- package/src/comment/render-ctx.ts +30 -0
- package/src/comment/render.ts +31 -375
- package/src/comment/renders/actions.ts +114 -0
- package/src/comment/renders/avatar.ts +22 -0
- package/src/comment/renders/content.ts +39 -0
- package/src/comment/renders/header.ts +84 -0
- package/src/comment/renders/index.ts +19 -0
- package/src/comment/renders/pending.ts +12 -0
- package/src/comment/renders/reply-at.ts +16 -0
- package/src/comment/renders/reply-to.ts +24 -0
- package/src/config.ts +65 -0
- package/src/context.ts +33 -86
- package/src/defaults.ts +1 -0
- package/src/editor/edit-mode.ts +103 -0
- package/src/editor/editor.ts +101 -395
- package/src/editor/funcs.ts +97 -0
- package/src/editor/mover.ts +43 -0
- package/src/editor/plug-manager.ts +172 -0
- package/src/editor/plugs/editor-plug.ts +20 -2
- package/src/editor/plugs/{emoticons-plug.less → emoticons-plug.scss} +5 -4
- package/src/editor/plugs/emoticons-plug.ts +2 -1
- package/src/editor/plugs/header-input-plug.ts +11 -10
- package/src/editor/plugs/{preview-plug.less → preview-plug.scss} +1 -1
- package/src/editor/plugs/preview-plug.ts +8 -4
- package/src/editor/plugs/upload-plug.ts +12 -14
- package/src/editor/reply.ts +62 -0
- package/src/editor/submit.ts +99 -0
- package/src/editor/ui.ts +36 -0
- package/src/i18n/external.ts +10 -0
- package/src/i18n/index.ts +22 -19
- package/src/i18n/jp.ts +1 -1
- package/src/i18n/zh-TW.ts +1 -1
- package/src/layer/index.ts +2 -2
- package/src/layer/layer.ts +4 -4
- package/src/layer/sidebar-layer.ts +4 -2
- package/src/lib/checker/admin.ts +37 -0
- package/src/lib/checker/captcha-renders.ts +68 -0
- package/src/lib/checker/captcha.ts +26 -0
- package/src/lib/checker/index.ts +36 -20
- package/src/lib/dark-mode.ts +48 -0
- package/src/lib/marked.ts +133 -0
- package/src/lib/user.ts +13 -7
- package/src/lib/utils.ts +1 -123
- package/src/list/list-lite.ts +59 -162
- package/src/list/list-ui.ts +137 -0
- package/src/list/list.ts +33 -60
- package/src/list/paginator/adaptors/index.ts +21 -0
- package/src/list/paginator/adaptors/pagination.ts +42 -0
- package/src/list/paginator/adaptors/read-more.ts +56 -0
- package/src/list/paginator/holder.ts +56 -0
- package/src/list/paginator/index.ts +13 -0
- package/src/service.ts +118 -0
- package/src/style/{_color.less → _color.scss} +3 -3
- package/src/style/{_extend.less → _extend.scss} +1 -1
- package/src/style/_variables.scss +3 -0
- package/src/style/{comment.less → comment.scss} +36 -12
- package/src/style/{editor.less → editor.scss} +11 -11
- package/src/style/{list.less → list.scss} +12 -10
- package/src/style/{main.less → main.scss} +24 -23
- package/src/style/{sidebar-layer.less → sidebar-layer.scss} +8 -8
- package/types/artalk-config.d.ts +5 -2
- package/types/artalk-data.d.ts +3 -3
- package/types/context.d.ts +13 -20
- package/types/global.d.ts +1 -0
- package/CNAME +0 -1
- package/LICENSE +0 -165
- package/index.html +0 -157
- package/postcss.config.js +0 -5
- package/scripts/build-i18n.mjs +0 -46
- package/src/lib/checker/admin-checker.ts +0 -36
- package/src/lib/checker/captcha-checker.ts +0 -84
- package/src/style/_variables.less +0 -3
- package/test/ArtalkCount.html +0 -16
- package/test/ArtalkI18n.html +0 -16
- package/test/ArtalkLite.html +0 -15
- package/test/CSRF.html +0 -26
- package/tsconfig.json +0 -12
- package/vite-base.config.ts +0 -21
- package/vite-demo.config.ts +0 -12
- package/vite-lite.config.ts +0 -22
- package/vite.config.ts +0 -27
- /package/dist/src/lib/checker/{admin-checker.d.ts → admin.d.ts} +0 -0
- /package/dist/src/lib/checker/{captcha-checker.d.ts → captcha.d.ts} +0 -0
- /package/src/style/{pagination.less → pagination.scss} +0 -0
package/src/editor/editor.ts
CHANGED
|
@@ -1,177 +1,98 @@
|
|
|
1
|
-
import { CommentData } from '~/types/artalk-data'
|
|
2
|
-
import Context from '~/types/context'
|
|
1
|
+
import type { CommentData } from '~/types/artalk-data'
|
|
2
|
+
import type Context from '~/types/context'
|
|
3
3
|
import Component from '../lib/component'
|
|
4
4
|
import * as Utils from '../lib/utils'
|
|
5
5
|
import * as Ui from '../lib/ui'
|
|
6
|
-
|
|
7
|
-
import
|
|
8
|
-
|
|
9
|
-
import
|
|
10
|
-
import
|
|
11
|
-
import
|
|
12
|
-
import
|
|
13
|
-
import
|
|
6
|
+
import marked from '../lib/marked'
|
|
7
|
+
import User from '../lib/user'
|
|
8
|
+
import initEditorFuncs from './funcs'
|
|
9
|
+
import { render, EditorUI } from './ui'
|
|
10
|
+
import { PlugManager } from './plug-manager'
|
|
11
|
+
import { Mover } from './mover'
|
|
12
|
+
import { ReplyManager } from './reply'
|
|
13
|
+
import { EditModeManager } from './edit-mode'
|
|
14
|
+
import { SubmitManager } from './submit'
|
|
14
15
|
|
|
15
16
|
export default class Editor extends Component {
|
|
16
|
-
|
|
17
|
-
|
|
18
|
-
public
|
|
19
|
-
public $nick: HTMLInputElement
|
|
20
|
-
public $email: HTMLInputElement
|
|
21
|
-
public $link: HTMLInputElement
|
|
22
|
-
public get $inputs() {
|
|
23
|
-
return { nick: this.$nick, email: this.$email, link: this.$link }
|
|
24
|
-
}
|
|
17
|
+
/** 界面 */
|
|
18
|
+
private ui: EditorUI
|
|
19
|
+
public getUI() { return this.ui }
|
|
25
20
|
|
|
26
|
-
|
|
27
|
-
|
|
28
|
-
public
|
|
29
|
-
public
|
|
30
|
-
public $notifyWrap: HTMLElement
|
|
21
|
+
/** 插件管理器 */
|
|
22
|
+
private plugs?: PlugManager
|
|
23
|
+
public getPlugs() { return this.plugs }
|
|
24
|
+
public setPlugs(p: PlugManager) { this.plugs = p }
|
|
31
25
|
|
|
32
|
-
|
|
33
|
-
private
|
|
26
|
+
/** 评论框移动 */
|
|
27
|
+
private mover?: Mover
|
|
28
|
+
public setMover(m: Mover) { this.mover = m }
|
|
34
29
|
|
|
35
30
|
/** 回复评论 */
|
|
36
|
-
private
|
|
37
|
-
|
|
38
|
-
public
|
|
31
|
+
private reply?: ReplyManager
|
|
32
|
+
public setReplyManager(m: ReplyManager) { this.reply = m }
|
|
33
|
+
public getReplyManager() { return this.reply }
|
|
34
|
+
public get isReplyMode() { return !!this.reply?.comment }
|
|
39
35
|
|
|
40
36
|
/** 编辑评论 */
|
|
41
|
-
private
|
|
42
|
-
|
|
43
|
-
public get isEditMode() { return this.
|
|
37
|
+
private editMode?: EditModeManager
|
|
38
|
+
public setEditModeManager(m: EditModeManager) { this.editMode = m }
|
|
39
|
+
public get isEditMode() { return !!this.editMode?.comment }
|
|
44
40
|
|
|
45
|
-
/**
|
|
46
|
-
private
|
|
47
|
-
public
|
|
48
|
-
|
|
49
|
-
public $plugPanelWrap: HTMLElement
|
|
50
|
-
public $plugBtnWrap: HTMLElement
|
|
41
|
+
/** 提交评论 */
|
|
42
|
+
private submitManager?: SubmitManager
|
|
43
|
+
public setSubmitManager(m: SubmitManager) { this.submitManager = m }
|
|
44
|
+
public getSubmitManager() { return this.submitManager }
|
|
51
45
|
|
|
52
46
|
public constructor(ctx: Context) {
|
|
53
47
|
super(ctx)
|
|
54
48
|
|
|
55
|
-
|
|
56
|
-
|
|
57
|
-
this.$
|
|
58
|
-
this.$nick = this.$header.querySelector('[name="nick"]')!
|
|
59
|
-
this.$email = this.$header.querySelector('[name="email"]')!
|
|
60
|
-
this.$link = this.$header.querySelector('[name="link"]')!
|
|
61
|
-
|
|
62
|
-
this.$textareaWrap = this.$el.querySelector('.atk-textarea-wrap')!
|
|
63
|
-
this.$textarea = this.$el.querySelector('.atk-textarea')!
|
|
64
|
-
this.$bottom = this.$el.querySelector('.atk-bottom')!
|
|
65
|
-
this.$submitBtn = this.$el.querySelector('.atk-send-btn')!
|
|
66
|
-
this.$notifyWrap = this.$el.querySelector('.atk-notify-wrap')!
|
|
49
|
+
// init editor ui
|
|
50
|
+
this.ui = render()
|
|
51
|
+
this.$el = this.ui.$el
|
|
67
52
|
|
|
68
|
-
|
|
69
|
-
this.$plugPanelWrap = this.$el.querySelector('.atk-plug-panel-wrap')!
|
|
70
|
-
|
|
71
|
-
// 监听事件
|
|
53
|
+
// event listen
|
|
72
54
|
this.ctx.on('conf-loaded', () => {
|
|
73
|
-
//
|
|
74
|
-
this.initLocalStorage()
|
|
75
|
-
this.initHeader()
|
|
76
|
-
this.initTextarea()
|
|
77
|
-
this.initSubmitBtn()
|
|
78
|
-
this.initPlugs()
|
|
55
|
+
initEditorFuncs(this) // init editor funcs
|
|
79
56
|
})
|
|
80
57
|
}
|
|
81
58
|
|
|
82
|
-
|
|
83
|
-
|
|
84
|
-
if (localContent.trim() !== '') {
|
|
85
|
-
this.showNotify(this.$t('restoredMsg'), 'i')
|
|
86
|
-
this.setContent(localContent)
|
|
87
|
-
}
|
|
88
|
-
|
|
89
|
-
this.$textarea.addEventListener('input', () => (this.saveToLocalStorage()))
|
|
59
|
+
public getHeaderInputEls() {
|
|
60
|
+
return { nick: this.ui.$nick, email: this.ui.$email, link: this.ui.$link }
|
|
90
61
|
}
|
|
91
62
|
|
|
92
|
-
|
|
63
|
+
public saveToLocalStorage() {
|
|
93
64
|
window.localStorage.setItem('ArtalkContent', this.getContentOriginal().trim())
|
|
94
65
|
}
|
|
95
66
|
|
|
96
|
-
|
|
97
|
-
|
|
98
|
-
|
|
99
|
-
$input.addEventListener('input', () => this.onHeaderInput(key, $input))
|
|
100
|
-
|
|
101
|
-
// 设置 Placeholder
|
|
102
|
-
$input.placeholder = `${this.$t(key as any)}`
|
|
103
|
-
})
|
|
104
|
-
}
|
|
105
|
-
|
|
106
|
-
private onHeaderInput(key: string, $input: HTMLInputElement) {
|
|
107
|
-
if (this.isEditMode) return // 评论编辑模式,不修改个人信息
|
|
108
|
-
|
|
109
|
-
this.user.update({
|
|
110
|
-
[key]: $input.value.trim()
|
|
111
|
-
})
|
|
112
|
-
|
|
113
|
-
// 插件监听事件响应
|
|
114
|
-
Object.entries(this.plugList).forEach(([plugName, plug]) => {
|
|
115
|
-
if (plug.onHeaderInput) plug.onHeaderInput(key, $input)
|
|
116
|
-
})
|
|
117
|
-
}
|
|
118
|
-
|
|
119
|
-
private initTextarea() {
|
|
120
|
-
// 占位符
|
|
121
|
-
this.$textarea.placeholder = this.ctx.conf.placeholder || this.$t('placeholder')
|
|
122
|
-
|
|
123
|
-
// 修复按下 Tab 输入的内容
|
|
124
|
-
this.$textarea.addEventListener('keydown', (e) => {
|
|
125
|
-
const keyCode = e.keyCode || e.which
|
|
126
|
-
|
|
127
|
-
if (keyCode === 9) {
|
|
128
|
-
e.preventDefault()
|
|
129
|
-
this.insertContent('\t')
|
|
130
|
-
}
|
|
131
|
-
})
|
|
132
|
-
|
|
133
|
-
// 输入框高度随内容而变化
|
|
134
|
-
this.$textarea.addEventListener('input', () => {
|
|
135
|
-
this.adjustTextareaHeight()
|
|
136
|
-
})
|
|
137
|
-
}
|
|
138
|
-
|
|
139
|
-
private refreshSendBtnText() {
|
|
140
|
-
if (this.isEditMode) this.$submitBtn.innerText = this.$t('save')
|
|
141
|
-
else this.$submitBtn.innerText = this.ctx.conf.sendBtn || this.$t('send')
|
|
142
|
-
}
|
|
143
|
-
|
|
144
|
-
private initSubmitBtn() {
|
|
145
|
-
this.refreshSendBtnText()
|
|
146
|
-
this.$submitBtn.addEventListener('click', () => (this.submit()))
|
|
67
|
+
public refreshSendBtnText() {
|
|
68
|
+
if (this.isEditMode) this.ui.$submitBtn.innerText = this.$t('save')
|
|
69
|
+
else this.ui.$submitBtn.innerText = this.ctx.conf.sendBtn || this.$t('send')
|
|
147
70
|
}
|
|
148
71
|
|
|
149
72
|
/** 最终用于 submit 的数据 */
|
|
150
73
|
public getFinalContent() {
|
|
151
74
|
let content = this.getContentOriginal()
|
|
152
75
|
|
|
153
|
-
//
|
|
154
|
-
if (this.
|
|
155
|
-
content = (this.plugList.emoticons as EmoticonsPlug).transEmoticonImageText(content)
|
|
156
|
-
}
|
|
76
|
+
// plug hook: final content transformer
|
|
77
|
+
if (this.plugs) content = this.plugs.getTransformedContent(content)
|
|
157
78
|
|
|
158
79
|
return content
|
|
159
80
|
}
|
|
160
81
|
|
|
161
82
|
public getContentOriginal() {
|
|
162
|
-
return this.$textarea.value || '' // Tip: !!"0" === true
|
|
83
|
+
return this.ui.$textarea.value || '' // Tip: !!"0" === true
|
|
163
84
|
}
|
|
164
85
|
|
|
165
86
|
public getContentMarked() {
|
|
166
|
-
return
|
|
87
|
+
return marked(this.ctx, this.getFinalContent())
|
|
167
88
|
}
|
|
168
89
|
|
|
169
90
|
public setContent(val: string) {
|
|
170
|
-
this.$textarea.value = val
|
|
91
|
+
this.ui.$textarea.value = val
|
|
171
92
|
this.saveToLocalStorage()
|
|
172
|
-
|
|
173
|
-
|
|
174
|
-
|
|
93
|
+
|
|
94
|
+
// plug hook: content updated
|
|
95
|
+
if (this.plugs) this.plugs.triggerContentUpdatedEvt(val)
|
|
175
96
|
|
|
176
97
|
// 延迟执行防止无效
|
|
177
98
|
window.setTimeout(() => {
|
|
@@ -181,333 +102,118 @@ export default class Editor extends Component {
|
|
|
181
102
|
|
|
182
103
|
public insertContent(val: string) {
|
|
183
104
|
if ((document as any).selection) {
|
|
184
|
-
this.$textarea.focus();
|
|
105
|
+
this.ui.$textarea.focus();
|
|
185
106
|
(document as any).selection.createRange().text = val
|
|
186
|
-
this.$textarea.focus()
|
|
187
|
-
} else if (this.$textarea.selectionStart || this.$textarea.selectionStart === 0) {
|
|
188
|
-
const sStart = this.$textarea.selectionStart
|
|
189
|
-
const sEnd = this.$textarea.selectionEnd
|
|
190
|
-
const sT = this.$textarea.scrollTop
|
|
191
|
-
this.setContent(this.$textarea.value.substring(0, sStart) + val + this.$textarea.value.substring(sEnd, this.$textarea.value.length))
|
|
192
|
-
this.$textarea.focus()
|
|
193
|
-
this.$textarea.selectionStart = sStart + val.length
|
|
194
|
-
this.$textarea.selectionEnd = sStart + val.length
|
|
195
|
-
this.$textarea.scrollTop = sT
|
|
107
|
+
this.ui.$textarea.focus()
|
|
108
|
+
} else if (this.ui.$textarea.selectionStart || this.ui.$textarea.selectionStart === 0) {
|
|
109
|
+
const sStart = this.ui.$textarea.selectionStart
|
|
110
|
+
const sEnd = this.ui.$textarea.selectionEnd
|
|
111
|
+
const sT = this.ui.$textarea.scrollTop
|
|
112
|
+
this.setContent(this.ui.$textarea.value.substring(0, sStart) + val + this.ui.$textarea.value.substring(sEnd, this.ui.$textarea.value.length))
|
|
113
|
+
this.ui.$textarea.focus()
|
|
114
|
+
this.ui.$textarea.selectionStart = sStart + val.length
|
|
115
|
+
this.ui.$textarea.selectionEnd = sStart + val.length
|
|
116
|
+
this.ui.$textarea.scrollTop = sT
|
|
196
117
|
} else {
|
|
197
|
-
this.$textarea.focus()
|
|
198
|
-
this.$textarea.value += val
|
|
118
|
+
this.ui.$textarea.focus()
|
|
119
|
+
this.ui.$textarea.value += val
|
|
199
120
|
}
|
|
200
121
|
}
|
|
201
122
|
|
|
202
|
-
|
|
203
|
-
const diff = this.$textarea.offsetHeight - this.$textarea.clientHeight
|
|
204
|
-
this.$textarea.style.height = '0px' // it's a magic. 若不加此行,内容减少,高度回不去
|
|
205
|
-
this.$textarea.style.height = `${this.$textarea.scrollHeight + diff}px`
|
|
123
|
+
public adjustTextareaHeight() {
|
|
124
|
+
const diff = this.ui.$textarea.offsetHeight - this.ui.$textarea.clientHeight
|
|
125
|
+
this.ui.$textarea.style.height = '0px' // it's a magic. 若不加此行,内容减少,高度回不去
|
|
126
|
+
this.ui.$textarea.style.height = `${this.ui.$textarea.scrollHeight + diff}px`
|
|
206
127
|
}
|
|
207
128
|
|
|
208
|
-
|
|
209
|
-
|
|
210
|
-
|
|
211
|
-
if (this.isReplyMode) this.cancelReply()
|
|
212
|
-
|
|
213
|
-
if (this.$sendReply === null) {
|
|
214
|
-
this.$sendReply = Utils.createElement(`<div class="atk-send-reply">${this.$t('reply')} <span class="atk-text"></span><span class="atk-cancel">×</span></div>`);
|
|
215
|
-
this.$sendReply.querySelector<HTMLElement>('.atk-text')!.innerText = `@${commentData.nick}`
|
|
216
|
-
this.$sendReply.addEventListener('click', () => {
|
|
217
|
-
this.cancelReply()
|
|
218
|
-
})
|
|
219
|
-
this.$textareaWrap.append(this.$sendReply)
|
|
220
|
-
}
|
|
221
|
-
this.replyComment = commentData
|
|
222
|
-
|
|
223
|
-
if (this.ctx.conf.editorTravel === true) {
|
|
224
|
-
this.travel($comment)
|
|
225
|
-
}
|
|
129
|
+
public focus() {
|
|
130
|
+
this.ui.$textarea.focus()
|
|
131
|
+
}
|
|
226
132
|
|
|
227
|
-
|
|
133
|
+
public reset() {
|
|
134
|
+
this.setContent('')
|
|
135
|
+
this.cancelReply()
|
|
136
|
+
this.cancelEditComment()
|
|
137
|
+
}
|
|
228
138
|
|
|
229
|
-
|
|
139
|
+
/** 设置回复评论 */
|
|
140
|
+
public setReply(commentData: CommentData, $comment: HTMLElement, scroll = true) {
|
|
141
|
+
this.reply?.setReply(commentData, $comment, scroll)
|
|
230
142
|
}
|
|
231
143
|
|
|
232
144
|
/** 取消回复评论 */
|
|
233
145
|
public cancelReply() {
|
|
234
|
-
|
|
235
|
-
this.$sendReply.remove()
|
|
236
|
-
this.$sendReply = null
|
|
237
|
-
}
|
|
238
|
-
this.replyComment = null
|
|
239
|
-
|
|
240
|
-
if (this.ctx.conf.editorTravel === true) {
|
|
241
|
-
this.travelBack()
|
|
242
|
-
}
|
|
146
|
+
this.reply?.cancelReply()
|
|
243
147
|
}
|
|
244
148
|
|
|
245
149
|
/** 设置编辑评论 */
|
|
246
150
|
public setEditComment(commentData: CommentData, $comment: HTMLElement) {
|
|
247
|
-
|
|
248
|
-
if (this.isReplyMode) this.cancelReply()
|
|
249
|
-
|
|
250
|
-
if (this.$editCancelBtn === null) {
|
|
251
|
-
this.$editCancelBtn = Utils.createElement(`<div class="atk-send-reply">${this.$t('editCancel')}<span class="atk-cancel">×</span></div>`);
|
|
252
|
-
this.$editCancelBtn.onclick = () => {
|
|
253
|
-
this.cancelEditComment()
|
|
254
|
-
}
|
|
255
|
-
this.$textareaWrap.append(this.$editCancelBtn)
|
|
256
|
-
}
|
|
257
|
-
this.editComment = commentData
|
|
258
|
-
|
|
259
|
-
this.$header.style.display = 'none' // TODO 暂时隐藏
|
|
260
|
-
|
|
261
|
-
this.travel($comment)
|
|
262
|
-
|
|
263
|
-
this.$nick.value = commentData.nick
|
|
264
|
-
this.$email.value = commentData.email || ''
|
|
265
|
-
this.$link.value = commentData.link
|
|
266
|
-
|
|
267
|
-
this.setContent(commentData.content)
|
|
268
|
-
this.$textarea.focus()
|
|
269
|
-
|
|
270
|
-
this.refreshSendBtnText()
|
|
151
|
+
this.editMode?.setEdit(commentData, $comment)
|
|
271
152
|
}
|
|
272
153
|
|
|
273
154
|
/** 取消编辑评论 */
|
|
274
155
|
public cancelEditComment() {
|
|
275
|
-
|
|
276
|
-
this.$editCancelBtn.remove()
|
|
277
|
-
this.$editCancelBtn = null
|
|
278
|
-
}
|
|
279
|
-
|
|
280
|
-
this.editComment = null
|
|
281
|
-
this.travelBack()
|
|
282
|
-
|
|
283
|
-
this.$nick.value = this.user.data.nick
|
|
284
|
-
this.$email.value = this.user.data.email
|
|
285
|
-
this.$link.value = this.user.data.link
|
|
286
|
-
|
|
287
|
-
this.setContent('')
|
|
288
|
-
this.refreshSendBtnText()
|
|
289
|
-
this.$header.style.display = '' // TODO
|
|
156
|
+
this.editMode?.cancelEdit()
|
|
290
157
|
}
|
|
291
158
|
|
|
292
159
|
public showNotify(msg: string, type: "i"|"s"|"w"|"e") {
|
|
293
|
-
Ui.showNotify(this.$notifyWrap, msg, type)
|
|
160
|
+
Ui.showNotify(this.ui.$notifyWrap, msg, type)
|
|
294
161
|
}
|
|
295
162
|
|
|
296
163
|
public showLoading() {
|
|
297
|
-
Ui.showLoading(this.$el)
|
|
164
|
+
Ui.showLoading(this.ui.$el)
|
|
298
165
|
}
|
|
299
166
|
|
|
300
167
|
public hideLoading() {
|
|
301
|
-
Ui.hideLoading(this.$el)
|
|
168
|
+
Ui.hideLoading(this.ui.$el)
|
|
302
169
|
}
|
|
303
170
|
|
|
304
171
|
/** 点击评论提交按钮事件 */
|
|
305
172
|
public async submit() {
|
|
306
|
-
if (this.
|
|
307
|
-
|
|
308
|
-
return
|
|
309
|
-
}
|
|
310
|
-
|
|
311
|
-
this.ctx.trigger('editor-submit')
|
|
312
|
-
|
|
313
|
-
this.showLoading()
|
|
314
|
-
|
|
315
|
-
if (!this.isEditMode) {
|
|
316
|
-
await this.submitAdd()
|
|
317
|
-
} else {
|
|
318
|
-
await this.submitEdit()
|
|
319
|
-
}
|
|
320
|
-
|
|
321
|
-
this.hideLoading()
|
|
322
|
-
}
|
|
323
|
-
|
|
324
|
-
/** 创建评论 */
|
|
325
|
-
public async submitAdd() {
|
|
326
|
-
try {
|
|
327
|
-
const nComment = await this.ctx.getApi().comment.add({
|
|
328
|
-
content: this.getFinalContent(),
|
|
329
|
-
nick: this.user.data.nick,
|
|
330
|
-
email: this.user.data.email,
|
|
331
|
-
link: this.user.data.link,
|
|
332
|
-
rid: (this.replyComment === null) ? 0 : this.replyComment.id,
|
|
333
|
-
page_key: (this.replyComment === null) ? this.ctx.conf.pageKey : this.replyComment.page_key,
|
|
334
|
-
page_title: (this.replyComment === null) ? this.ctx.conf.pageTitle : undefined,
|
|
335
|
-
site_name: (this.replyComment === null) ? this.ctx.conf.site : this.replyComment.site_name
|
|
336
|
-
})
|
|
337
|
-
|
|
338
|
-
// 回复不同页面的评论
|
|
339
|
-
if (this.replyComment !== null && this.replyComment.page_key !== this.ctx.conf.pageKey) {
|
|
340
|
-
window.open(`${this.replyComment.page_url}#atk-comment-${nComment.id}`)
|
|
341
|
-
}
|
|
342
|
-
|
|
343
|
-
this.ctx.insertComment(nComment)
|
|
344
|
-
|
|
345
|
-
// 复原编辑器
|
|
346
|
-
this.setContent('')
|
|
347
|
-
this.cancelReply()
|
|
348
|
-
|
|
349
|
-
this.ctx.trigger('editor-submitted')
|
|
350
|
-
} catch (err: any) {
|
|
351
|
-
console.error(err)
|
|
352
|
-
this.showNotify(`${this.$t('commentFail')},${err.msg || String(err)}`, 'e')
|
|
353
|
-
}
|
|
354
|
-
}
|
|
355
|
-
|
|
356
|
-
/** 修改评论 */
|
|
357
|
-
public async submitEdit() {
|
|
358
|
-
try {
|
|
359
|
-
const saveData = {
|
|
360
|
-
content: this.getFinalContent(),
|
|
361
|
-
nick: this.$nick.value,
|
|
362
|
-
email: this.$email.value,
|
|
363
|
-
link: this.$link.value,
|
|
364
|
-
}
|
|
365
|
-
const nComment = await this.ctx.getApi().comment.commentEdit({
|
|
366
|
-
...this.editComment, ...saveData
|
|
367
|
-
})
|
|
368
|
-
this.ctx.updateComment(nComment)
|
|
369
|
-
|
|
370
|
-
// 复原编辑器
|
|
371
|
-
this.setContent('')
|
|
372
|
-
this.cancelEditComment()
|
|
373
|
-
|
|
374
|
-
this.ctx.trigger('editor-submitted')
|
|
375
|
-
} catch (err: any) {
|
|
376
|
-
console.error(err)
|
|
377
|
-
this.showNotify(`${this.$t('commentFail')},${err.msg || String(err)}`, 'e')
|
|
378
|
-
}
|
|
173
|
+
if (!this.submitManager) return
|
|
174
|
+
await this.submitManager.do()
|
|
379
175
|
}
|
|
380
176
|
|
|
381
177
|
/** 关闭评论 */
|
|
382
178
|
public close() {
|
|
383
|
-
if (!this.$textareaWrap.querySelector('.atk-comment-closed'))
|
|
384
|
-
this.$textareaWrap.prepend(Utils.createElement(`<div class="atk-comment-closed">${this.$t('onlyAdminCanReply')}</div>`))
|
|
179
|
+
if (!this.ui.$textareaWrap.querySelector('.atk-comment-closed'))
|
|
180
|
+
this.ui.$textareaWrap.prepend(Utils.createElement(`<div class="atk-comment-closed">${this.$t('onlyAdminCanReply')}</div>`))
|
|
385
181
|
|
|
386
|
-
if (!
|
|
387
|
-
this.$textarea.style.display = 'none'
|
|
182
|
+
if (!User.data.isAdmin) {
|
|
183
|
+
this.ui.$textarea.style.display = 'none'
|
|
388
184
|
this.closePlugPanel()
|
|
389
|
-
this.$bottom.style.display = 'none'
|
|
185
|
+
this.ui.$bottom.style.display = 'none'
|
|
390
186
|
} else {
|
|
391
187
|
// 管理员一直打开评论
|
|
392
|
-
this.$textarea.style.display = ''
|
|
393
|
-
this.$bottom.style.display = ''
|
|
188
|
+
this.ui.$textarea.style.display = ''
|
|
189
|
+
this.ui.$bottom.style.display = ''
|
|
394
190
|
}
|
|
395
191
|
}
|
|
396
192
|
|
|
397
193
|
/** 打开评论 */
|
|
398
194
|
public open() {
|
|
399
|
-
this.$textareaWrap.querySelector('.atk-comment-closed')?.remove()
|
|
400
|
-
this.$textarea.style.display = ''
|
|
401
|
-
this.$bottom.style.display = ''
|
|
195
|
+
this.ui.$textareaWrap.querySelector('.atk-comment-closed')?.remove()
|
|
196
|
+
this.ui.$textarea.style.display = ''
|
|
197
|
+
this.ui.$bottom.style.display = ''
|
|
402
198
|
}
|
|
403
199
|
|
|
404
200
|
/** 移动评论框到置顶元素之后 */
|
|
405
201
|
public travel($afterEl: HTMLElement) {
|
|
406
|
-
|
|
407
|
-
this.isTraveling = true
|
|
408
|
-
this.$el.after(Utils.createElement('<div class="atk-editor-travel-placeholder"></div>'))
|
|
409
|
-
|
|
410
|
-
const $travelPlace = Utils.createElement('<div></div>')
|
|
411
|
-
$afterEl.after($travelPlace)
|
|
412
|
-
$travelPlace.replaceWith(this.$el)
|
|
413
|
-
|
|
414
|
-
this.$el.classList.add('atk-fade-in') // 添加渐入动画
|
|
202
|
+
this.mover?.move($afterEl)
|
|
415
203
|
}
|
|
416
204
|
|
|
417
205
|
/** 评论框归位 */
|
|
418
206
|
public travelBack() {
|
|
419
|
-
|
|
420
|
-
this.isTraveling = false
|
|
421
|
-
this.ctx.$root.querySelector('.atk-editor-travel-placeholder')?.replaceWith(this.$el)
|
|
422
|
-
|
|
423
|
-
// 取消回复
|
|
424
|
-
if (this.replyComment !== null) this.cancelReply()
|
|
425
|
-
}
|
|
426
|
-
|
|
427
|
-
/** 插件初始化 */
|
|
428
|
-
private initPlugs() {
|
|
429
|
-
this.plugList = {}
|
|
430
|
-
this.$plugPanelWrap.innerHTML = ''
|
|
431
|
-
this.$plugPanelWrap.style.display = 'none'
|
|
432
|
-
this.openedPlugName = null
|
|
433
|
-
this.$plugBtnWrap.innerHTML = ''
|
|
434
|
-
|
|
435
|
-
const disabledPlugs: string[] = []
|
|
436
|
-
if (!this.conf.imgUpload) disabledPlugs.push('upload')
|
|
437
|
-
if (!this.conf.emoticons) disabledPlugs.push('emoticons')
|
|
438
|
-
if (!this.conf.preview) disabledPlugs.push('preview')
|
|
439
|
-
|
|
440
|
-
// 初始化 Editor 插件
|
|
441
|
-
this.ENABLED_PLUGS.forEach((Plug) => {
|
|
442
|
-
const plugName = Plug.Name
|
|
443
|
-
|
|
444
|
-
// 禁用的插件
|
|
445
|
-
if (disabledPlugs.includes(plugName)) return
|
|
446
|
-
|
|
447
|
-
// 插件对象实例化
|
|
448
|
-
const plug = new Plug(this)
|
|
449
|
-
this.plugList[plugName] = plug
|
|
450
|
-
|
|
451
|
-
// 插件按钮
|
|
452
|
-
const $btn = plug.getBtn()
|
|
453
|
-
if ($btn) {
|
|
454
|
-
this.$plugBtnWrap.appendChild($btn)
|
|
455
|
-
$btn.onclick = $btn.onclick || (() => {
|
|
456
|
-
// 其他按钮去除 Active
|
|
457
|
-
this.$plugBtnWrap.querySelectorAll('.active').forEach(item => item.classList.remove('active'))
|
|
458
|
-
|
|
459
|
-
// 若点击已打开的,则关闭打开的面板
|
|
460
|
-
if (plugName === this.openedPlugName) {
|
|
461
|
-
this.closePlugPanel()
|
|
462
|
-
return
|
|
463
|
-
}
|
|
464
|
-
|
|
465
|
-
this.openPlugPanel(plugName)
|
|
466
|
-
|
|
467
|
-
// 当前按钮添加 Active
|
|
468
|
-
$btn.classList.add('active')
|
|
469
|
-
})
|
|
470
|
-
|
|
471
|
-
// 插件面板初始化
|
|
472
|
-
const $panel = plug.getPanel()
|
|
473
|
-
if ($panel) {
|
|
474
|
-
$panel.setAttribute('data-plug-name', plugName)
|
|
475
|
-
$panel.style.display = 'none'
|
|
476
|
-
this.$plugPanelWrap.appendChild($panel)
|
|
477
|
-
}
|
|
478
|
-
}
|
|
479
|
-
})
|
|
207
|
+
this.mover?.back()
|
|
480
208
|
}
|
|
481
209
|
|
|
482
210
|
/** 展开插件面板 */
|
|
483
211
|
public openPlugPanel(plugName: string) {
|
|
484
|
-
|
|
485
|
-
const plugPanel = plug.getPanel()
|
|
486
|
-
if (!plugPanel) return
|
|
487
|
-
|
|
488
|
-
if (aPlugName === plugName) {
|
|
489
|
-
plugPanel.style.display = ''
|
|
490
|
-
if (plug.onPanelShow) plug.onPanelShow()
|
|
491
|
-
} else {
|
|
492
|
-
plugPanel.style.display = 'none'
|
|
493
|
-
if (plug.onPanelHide) plug.onPanelHide()
|
|
494
|
-
}
|
|
495
|
-
})
|
|
496
|
-
|
|
497
|
-
this.$plugPanelWrap.style.display = ''
|
|
498
|
-
this.openedPlugName = plugName
|
|
212
|
+
this.plugs?.openPlugPanel(plugName)
|
|
499
213
|
}
|
|
500
214
|
|
|
501
215
|
/** 收起插件面板 */
|
|
502
216
|
public closePlugPanel() {
|
|
503
|
-
|
|
504
|
-
|
|
505
|
-
const plug = this.plugList[this.openedPlugName]
|
|
506
|
-
if (!plug) return
|
|
507
|
-
|
|
508
|
-
if (plug.onPanelHide) plug.onPanelHide()
|
|
509
|
-
|
|
510
|
-
this.$plugPanelWrap.style.display = 'none'
|
|
511
|
-
this.openedPlugName = null
|
|
217
|
+
this.plugs?.closePlugPanel()
|
|
512
218
|
}
|
|
513
219
|
}
|