artalk 2.4.4 → 2.5.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/README.md +27 -0
- package/dist/Artalk.css +1 -1
- package/dist/Artalk.es.js +4872 -4072
- package/dist/Artalk.iife.js +1 -1
- package/dist/Artalk.js +1 -1
- package/dist/ArtalkLite.css +1 -1
- package/dist/ArtalkLite.es.js +2468 -1779
- 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 +15 -29
- package/dist/src/editor/edit-mode.d.ts +9 -0
- package/dist/src/editor/editor-ui.d.ts +25 -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/index.d.ts +11 -7
- 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 +18 -10
- package/dist/src/lib/dark-mode.d.ts +4 -0
- package/dist/src/lib/marked.d.ts +9 -0
- 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 +7 -0
- 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 +40 -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 +11 -17
- package/dist/types/global.d.ts +1 -0
- package/package.json +6 -7
- package/src/api/system.ts +3 -12
- package/src/artalk.ts +101 -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 +31 -86
- package/src/defaults.ts +1 -0
- package/src/editor/edit-mode.ts +102 -0
- package/src/editor/editor.ts +100 -395
- package/src/editor/funcs.ts +96 -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 +5 -5
- 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 +10 -13
- package/src/editor/reply.ts +62 -0
- package/src/editor/submit.ts +98 -0
- package/src/editor/ui.ts +36 -0
- package/src/i18n/index.ts +21 -10
- package/src/layer/index.ts +2 -2
- package/src/layer/layer.ts +4 -4
- package/src/layer/sidebar-layer.ts +2 -1
- package/src/lib/checker/admin.ts +36 -0
- package/src/lib/checker/captcha-renders.ts +68 -0
- package/src/lib/checker/captcha.ts +26 -0
- package/src/lib/checker/index.ts +38 -20
- package/src/lib/dark-mode.ts +48 -0
- package/src/lib/marked.ts +133 -0
- package/src/lib/utils.ts +1 -123
- package/src/list/list-lite.ts +59 -162
- package/src/list/list-ui.ts +80 -0
- package/src/list/list.ts +16 -8
- 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 +55 -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} +8 -6
- 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 +11 -17
- 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,97 @@
|
|
|
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 initEditorFuncs from './funcs'
|
|
8
|
+
import { render, EditorUI } from './ui'
|
|
9
|
+
import { PlugManager } from './plug-manager'
|
|
10
|
+
import { Mover } from './mover'
|
|
11
|
+
import { ReplyManager } from './reply'
|
|
12
|
+
import { EditModeManager } from './edit-mode'
|
|
13
|
+
import { SubmitManager } from './submit'
|
|
14
14
|
|
|
15
15
|
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
|
-
}
|
|
16
|
+
/** 界面 */
|
|
17
|
+
private ui: EditorUI
|
|
18
|
+
public getUI() { return this.ui }
|
|
25
19
|
|
|
26
|
-
|
|
27
|
-
|
|
28
|
-
public
|
|
29
|
-
public
|
|
30
|
-
public $notifyWrap: HTMLElement
|
|
20
|
+
/** 插件管理器 */
|
|
21
|
+
private plugs?: PlugManager
|
|
22
|
+
public getPlugs() { return this.plugs }
|
|
23
|
+
public setPlugs(p: PlugManager) { this.plugs = p }
|
|
31
24
|
|
|
32
|
-
|
|
33
|
-
private
|
|
25
|
+
/** 评论框移动 */
|
|
26
|
+
private mover?: Mover
|
|
27
|
+
public setMover(m: Mover) { this.mover = m }
|
|
34
28
|
|
|
35
29
|
/** 回复评论 */
|
|
36
|
-
private
|
|
37
|
-
|
|
38
|
-
public
|
|
30
|
+
private reply?: ReplyManager
|
|
31
|
+
public setReplyManager(m: ReplyManager) { this.reply = m }
|
|
32
|
+
public getReplyManager() { return this.reply }
|
|
33
|
+
public get isReplyMode() { return !!this.reply?.comment }
|
|
39
34
|
|
|
40
35
|
/** 编辑评论 */
|
|
41
|
-
private
|
|
42
|
-
|
|
43
|
-
public get isEditMode() { return this.
|
|
36
|
+
private editMode?: EditModeManager
|
|
37
|
+
public setEditModeManager(m: EditModeManager) { this.editMode = m }
|
|
38
|
+
public get isEditMode() { return !!this.editMode?.comment }
|
|
44
39
|
|
|
45
|
-
/**
|
|
46
|
-
private
|
|
47
|
-
public
|
|
48
|
-
|
|
49
|
-
public $plugPanelWrap: HTMLElement
|
|
50
|
-
public $plugBtnWrap: HTMLElement
|
|
40
|
+
/** 提交评论 */
|
|
41
|
+
private submitManager?: SubmitManager
|
|
42
|
+
public setSubmitManager(m: SubmitManager) { this.submitManager = m }
|
|
43
|
+
public getSubmitManager() { return this.submitManager }
|
|
51
44
|
|
|
52
45
|
public constructor(ctx: Context) {
|
|
53
46
|
super(ctx)
|
|
54
47
|
|
|
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')!
|
|
48
|
+
// init editor ui
|
|
49
|
+
this.ui = render()
|
|
50
|
+
this.$el = this.ui.$el
|
|
67
51
|
|
|
68
|
-
|
|
69
|
-
this.$plugPanelWrap = this.$el.querySelector('.atk-plug-panel-wrap')!
|
|
70
|
-
|
|
71
|
-
// 监听事件
|
|
52
|
+
// event listen
|
|
72
53
|
this.ctx.on('conf-loaded', () => {
|
|
73
|
-
//
|
|
74
|
-
this.initLocalStorage()
|
|
75
|
-
this.initHeader()
|
|
76
|
-
this.initTextarea()
|
|
77
|
-
this.initSubmitBtn()
|
|
78
|
-
this.initPlugs()
|
|
54
|
+
initEditorFuncs(this) // init editor funcs
|
|
79
55
|
})
|
|
80
56
|
}
|
|
81
57
|
|
|
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()))
|
|
58
|
+
public getHeaderInputEls() {
|
|
59
|
+
return { nick: this.ui.$nick, email: this.ui.$email, link: this.ui.$link }
|
|
90
60
|
}
|
|
91
61
|
|
|
92
|
-
|
|
62
|
+
public saveToLocalStorage() {
|
|
93
63
|
window.localStorage.setItem('ArtalkContent', this.getContentOriginal().trim())
|
|
94
64
|
}
|
|
95
65
|
|
|
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()))
|
|
66
|
+
public refreshSendBtnText() {
|
|
67
|
+
if (this.isEditMode) this.ui.$submitBtn.innerText = this.$t('save')
|
|
68
|
+
else this.ui.$submitBtn.innerText = this.ctx.conf.sendBtn || this.$t('send')
|
|
147
69
|
}
|
|
148
70
|
|
|
149
71
|
/** 最终用于 submit 的数据 */
|
|
150
72
|
public getFinalContent() {
|
|
151
73
|
let content = this.getContentOriginal()
|
|
152
74
|
|
|
153
|
-
//
|
|
154
|
-
if (this.
|
|
155
|
-
content = (this.plugList.emoticons as EmoticonsPlug).transEmoticonImageText(content)
|
|
156
|
-
}
|
|
75
|
+
// plug hook: final content transformer
|
|
76
|
+
if (this.plugs) content = this.plugs.getTransformedContent(content)
|
|
157
77
|
|
|
158
78
|
return content
|
|
159
79
|
}
|
|
160
80
|
|
|
161
81
|
public getContentOriginal() {
|
|
162
|
-
return this.$textarea.value || '' // Tip: !!"0" === true
|
|
82
|
+
return this.ui.$textarea.value || '' // Tip: !!"0" === true
|
|
163
83
|
}
|
|
164
84
|
|
|
165
85
|
public getContentMarked() {
|
|
166
|
-
return
|
|
86
|
+
return marked(this.ctx, this.getFinalContent())
|
|
167
87
|
}
|
|
168
88
|
|
|
169
89
|
public setContent(val: string) {
|
|
170
|
-
this.$textarea.value = val
|
|
90
|
+
this.ui.$textarea.value = val
|
|
171
91
|
this.saveToLocalStorage()
|
|
172
|
-
|
|
173
|
-
|
|
174
|
-
|
|
92
|
+
|
|
93
|
+
// plug hook: content updated
|
|
94
|
+
if (this.plugs) this.plugs.triggerContentUpdatedEvt(val)
|
|
175
95
|
|
|
176
96
|
// 延迟执行防止无效
|
|
177
97
|
window.setTimeout(() => {
|
|
@@ -181,333 +101,118 @@ export default class Editor extends Component {
|
|
|
181
101
|
|
|
182
102
|
public insertContent(val: string) {
|
|
183
103
|
if ((document as any).selection) {
|
|
184
|
-
this.$textarea.focus();
|
|
104
|
+
this.ui.$textarea.focus();
|
|
185
105
|
(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
|
|
106
|
+
this.ui.$textarea.focus()
|
|
107
|
+
} else if (this.ui.$textarea.selectionStart || this.ui.$textarea.selectionStart === 0) {
|
|
108
|
+
const sStart = this.ui.$textarea.selectionStart
|
|
109
|
+
const sEnd = this.ui.$textarea.selectionEnd
|
|
110
|
+
const sT = this.ui.$textarea.scrollTop
|
|
111
|
+
this.setContent(this.ui.$textarea.value.substring(0, sStart) + val + this.ui.$textarea.value.substring(sEnd, this.ui.$textarea.value.length))
|
|
112
|
+
this.ui.$textarea.focus()
|
|
113
|
+
this.ui.$textarea.selectionStart = sStart + val.length
|
|
114
|
+
this.ui.$textarea.selectionEnd = sStart + val.length
|
|
115
|
+
this.ui.$textarea.scrollTop = sT
|
|
196
116
|
} else {
|
|
197
|
-
this.$textarea.focus()
|
|
198
|
-
this.$textarea.value += val
|
|
117
|
+
this.ui.$textarea.focus()
|
|
118
|
+
this.ui.$textarea.value += val
|
|
199
119
|
}
|
|
200
120
|
}
|
|
201
121
|
|
|
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`
|
|
122
|
+
public adjustTextareaHeight() {
|
|
123
|
+
const diff = this.ui.$textarea.offsetHeight - this.ui.$textarea.clientHeight
|
|
124
|
+
this.ui.$textarea.style.height = '0px' // it's a magic. 若不加此行,内容减少,高度回不去
|
|
125
|
+
this.ui.$textarea.style.height = `${this.ui.$textarea.scrollHeight + diff}px`
|
|
206
126
|
}
|
|
207
127
|
|
|
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
|
-
}
|
|
128
|
+
public focus() {
|
|
129
|
+
this.ui.$textarea.focus()
|
|
130
|
+
}
|
|
226
131
|
|
|
227
|
-
|
|
132
|
+
public reset() {
|
|
133
|
+
this.setContent('')
|
|
134
|
+
this.cancelReply()
|
|
135
|
+
this.cancelEditComment()
|
|
136
|
+
}
|
|
228
137
|
|
|
229
|
-
|
|
138
|
+
/** 设置回复评论 */
|
|
139
|
+
public setReply(commentData: CommentData, $comment: HTMLElement, scroll = true) {
|
|
140
|
+
this.reply?.setReply(commentData, $comment, scroll)
|
|
230
141
|
}
|
|
231
142
|
|
|
232
143
|
/** 取消回复评论 */
|
|
233
144
|
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
|
-
}
|
|
145
|
+
this.reply?.cancelReply()
|
|
243
146
|
}
|
|
244
147
|
|
|
245
148
|
/** 设置编辑评论 */
|
|
246
149
|
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()
|
|
150
|
+
this.editMode?.setEdit(commentData, $comment)
|
|
271
151
|
}
|
|
272
152
|
|
|
273
153
|
/** 取消编辑评论 */
|
|
274
154
|
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
|
|
155
|
+
this.editMode?.cancelEdit()
|
|
290
156
|
}
|
|
291
157
|
|
|
292
158
|
public showNotify(msg: string, type: "i"|"s"|"w"|"e") {
|
|
293
|
-
Ui.showNotify(this.$notifyWrap, msg, type)
|
|
159
|
+
Ui.showNotify(this.ui.$notifyWrap, msg, type)
|
|
294
160
|
}
|
|
295
161
|
|
|
296
162
|
public showLoading() {
|
|
297
|
-
Ui.showLoading(this.$el)
|
|
163
|
+
Ui.showLoading(this.ui.$el)
|
|
298
164
|
}
|
|
299
165
|
|
|
300
166
|
public hideLoading() {
|
|
301
|
-
Ui.hideLoading(this.$el)
|
|
167
|
+
Ui.hideLoading(this.ui.$el)
|
|
302
168
|
}
|
|
303
169
|
|
|
304
170
|
/** 点击评论提交按钮事件 */
|
|
305
171
|
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
|
-
}
|
|
172
|
+
if (!this.submitManager) return
|
|
173
|
+
await this.submitManager.do()
|
|
379
174
|
}
|
|
380
175
|
|
|
381
176
|
/** 关闭评论 */
|
|
382
177
|
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>`))
|
|
178
|
+
if (!this.ui.$textareaWrap.querySelector('.atk-comment-closed'))
|
|
179
|
+
this.ui.$textareaWrap.prepend(Utils.createElement(`<div class="atk-comment-closed">${this.$t('onlyAdminCanReply')}</div>`))
|
|
385
180
|
|
|
386
|
-
if (!this.user.data.isAdmin) {
|
|
387
|
-
this.$textarea.style.display = 'none'
|
|
181
|
+
if (!this.ctx.user.data.isAdmin) {
|
|
182
|
+
this.ui.$textarea.style.display = 'none'
|
|
388
183
|
this.closePlugPanel()
|
|
389
|
-
this.$bottom.style.display = 'none'
|
|
184
|
+
this.ui.$bottom.style.display = 'none'
|
|
390
185
|
} else {
|
|
391
186
|
// 管理员一直打开评论
|
|
392
|
-
this.$textarea.style.display = ''
|
|
393
|
-
this.$bottom.style.display = ''
|
|
187
|
+
this.ui.$textarea.style.display = ''
|
|
188
|
+
this.ui.$bottom.style.display = ''
|
|
394
189
|
}
|
|
395
190
|
}
|
|
396
191
|
|
|
397
192
|
/** 打开评论 */
|
|
398
193
|
public open() {
|
|
399
|
-
this.$textareaWrap.querySelector('.atk-comment-closed')?.remove()
|
|
400
|
-
this.$textarea.style.display = ''
|
|
401
|
-
this.$bottom.style.display = ''
|
|
194
|
+
this.ui.$textareaWrap.querySelector('.atk-comment-closed')?.remove()
|
|
195
|
+
this.ui.$textarea.style.display = ''
|
|
196
|
+
this.ui.$bottom.style.display = ''
|
|
402
197
|
}
|
|
403
198
|
|
|
404
199
|
/** 移动评论框到置顶元素之后 */
|
|
405
200
|
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') // 添加渐入动画
|
|
201
|
+
this.mover?.move($afterEl)
|
|
415
202
|
}
|
|
416
203
|
|
|
417
204
|
/** 评论框归位 */
|
|
418
205
|
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
|
-
})
|
|
206
|
+
this.mover?.back()
|
|
480
207
|
}
|
|
481
208
|
|
|
482
209
|
/** 展开插件面板 */
|
|
483
210
|
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
|
|
211
|
+
this.plugs?.openPlugPanel(plugName)
|
|
499
212
|
}
|
|
500
213
|
|
|
501
214
|
/** 收起插件面板 */
|
|
502
215
|
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
|
|
216
|
+
this.plugs?.closePlugPanel()
|
|
512
217
|
}
|
|
513
218
|
}
|