artalk 2.2.6 → 2.2.9
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 +282 -121
- package/dist/Artalk.iife.js +1 -1
- package/dist/Artalk.js +1 -1
- package/index.html +10 -8
- package/package.json +2 -2
- package/src/api/index.ts +33 -1
- package/src/artalk.ts +40 -12
- package/src/components/comment.ts +54 -22
- package/src/components/editor-plugs/emoticons-plug.ts +2 -2
- package/src/components/editor-plugs/preview-plug.ts +1 -1
- package/src/components/editor.ts +16 -3
- package/src/components/list-lite.ts +64 -78
- package/src/components/list-nest.ts +66 -0
- package/src/components/list.ts +37 -17
- package/src/components/pagination.ts +1 -1
- package/src/components/sidebar-layer.ts +2 -2
- package/src/context.ts +1 -1
- package/src/defaults.ts +3 -1
- package/src/lib/checker/index.ts +1 -1
- package/src/lib/utils.ts +30 -0
- package/src/style/_color.less +2 -2
- package/src/style/comment.less +21 -0
- package/types/artalk-config.d.ts +5 -2
package/index.html
CHANGED
|
@@ -1,5 +1,5 @@
|
|
|
1
1
|
<!DOCTYPE html>
|
|
2
|
-
<html>
|
|
2
|
+
<html lang="zh-CN">
|
|
3
3
|
<head>
|
|
4
4
|
<meta charset="UTF-8">
|
|
5
5
|
<title>Artalk DEMO</title>
|
|
@@ -16,7 +16,8 @@
|
|
|
16
16
|
.title > a:hover { margin-left:0 }
|
|
17
17
|
.title > a > span { opacity:0 }
|
|
18
18
|
.title > a:hover>span { opacity:1 }
|
|
19
|
-
.desc { font-size:12px;color:#
|
|
19
|
+
.desc { font-size:12px;color:#697182 }
|
|
20
|
+
body.dark-mode .desc { color:#848da3 }
|
|
20
21
|
.social { margin-top:20px }
|
|
21
22
|
.social > a:not(:last-child) { margin-right:2px }
|
|
22
23
|
@media only screen and (max-width: 768px) {
|
|
@@ -26,7 +27,7 @@
|
|
|
26
27
|
}
|
|
27
28
|
.float-btn { user-select: none;bottom: 25px;display: block;cursor: pointer;text-align: center;width: 60px;height: 37px;line-height: 37px;font-size: 13px;color: #757e91;background: #fff;opacity: 0.8;border-radius: 4px;border: 1px solid #eceff2;position: fixed; }
|
|
28
29
|
.to-night { z-index: 99999;left: 25px;background: #1e2223;color: #fff; }
|
|
29
|
-
body.dark-mode .to-night { background: #
|
|
30
|
+
body.dark-mode .to-night { background: #006fd9;border: 1px solid #2d3235;color: #fff; }
|
|
30
31
|
.to-top { right: 25px; }
|
|
31
32
|
</style>
|
|
32
33
|
<!--<link rel="stylesheet"
|
|
@@ -45,11 +46,11 @@
|
|
|
45
46
|
<div class="title"><a href="https://github.com/ArtalkJS/Artalk" target="_blank"><span>『 </span>Artalk<span> 』</span></a></div>
|
|
46
47
|
<div class="desc">一款简洁的自托管评论系统 <span id="ArtalkPV"></span></div>
|
|
47
48
|
<div class="social">
|
|
48
|
-
<a href="https://www.npmjs.com/package/artalk" target="_blank"><img src="https://img.shields.io/npm/v/artalk.svg?style=flat-square"></a>
|
|
49
|
-
<a href="https://www.npmjs.com/package/artalk" target="_blank"><img src="https://img.shields.io/npm/dt/artalk.svg?style=flat-square"></a>
|
|
50
|
-
<a href="https://github.com/ArtalkJS/Artalk/commits/master" target="_blank"><img src="https://img.shields.io/github/last-commit/ArtalkJS/Artalk?style=flat-square"></a>
|
|
51
|
-
<a href="https://github.com/ArtalkJS/Artalk/blob/master/LICENSE" target="_blank"><img src="https://img.shields.io/github/license/ArtalkJS/Artalk.svg?style=flat-square"></a>
|
|
52
|
-
<a href="https://github.com/ArtalkJS/Artalk" target="_blank"><img src="https://img.shields.io/github/stars/ArtalkJS/Artalk?style=flat-square"></a>
|
|
49
|
+
<a href="https://www.npmjs.com/package/artalk" aria-label="npm package version" target="_blank"><img src="https://img.shields.io/npm/v/artalk.svg?style=flat-square"></a>
|
|
50
|
+
<a href="https://www.npmjs.com/package/artalk" aria-label="npm package download number" target="_blank"><img src="https://img.shields.io/npm/dt/artalk.svg?style=flat-square"></a>
|
|
51
|
+
<a href="https://github.com/ArtalkJS/Artalk/commits/master" aria-label="last commit" target="_blank"><img src="https://img.shields.io/github/last-commit/ArtalkJS/Artalk?style=flat-square"></a>
|
|
52
|
+
<a href="https://github.com/ArtalkJS/Artalk/blob/master/LICENSE" aria-label="open source license" target="_blank"><img src="https://img.shields.io/github/license/ArtalkJS/Artalk.svg?style=flat-square"></a>
|
|
53
|
+
<a href="https://github.com/ArtalkJS/Artalk" aria-label="GitHub star number" target="_blank"><img src="https://img.shields.io/github/stars/ArtalkJS/Artalk?style=flat-square"></a>
|
|
53
54
|
</div>
|
|
54
55
|
</div>
|
|
55
56
|
<div class="card atk-fade-in">
|
|
@@ -66,6 +67,7 @@
|
|
|
66
67
|
pageTitle: 'Artalk Home',
|
|
67
68
|
server: (import.meta.env.MODE === 'development') ? 'http://localhost:23366' : 'https://artalk.qwqaq.com',
|
|
68
69
|
site: 'ArtalkDemo',
|
|
70
|
+
//useBackendConf: true,
|
|
69
71
|
});
|
|
70
72
|
|
|
71
73
|
window.artalk = artalk;
|
package/package.json
CHANGED
package/src/api/index.ts
CHANGED
|
@@ -1,5 +1,6 @@
|
|
|
1
|
-
import Context from '../context'
|
|
2
1
|
import { CommentData, ListData, UserData, PageData, SiteData, NotifyData } from '~/types/artalk-data'
|
|
2
|
+
import ArtalkConfig from '~/types/artalk-config'
|
|
3
|
+
import Context from '../context'
|
|
3
4
|
import { Fetch, ToFormData, POST, GET } from './request'
|
|
4
5
|
import * as Utils from '../lib/utils'
|
|
5
6
|
|
|
@@ -294,7 +295,22 @@ export default class Api {
|
|
|
294
295
|
|
|
295
296
|
const json = await Fetch(this.ctx, `${this.baseURL}/img-upload`, init)
|
|
296
297
|
return ((json.data || {}) as any) as { img_file: string, img_url: string }
|
|
298
|
+
}
|
|
297
299
|
|
|
300
|
+
/** 获取配置 */
|
|
301
|
+
public async conf() {
|
|
302
|
+
const data = await POST<any>(this.ctx, `${this.baseURL}/conf`)
|
|
303
|
+
const conf = (data.frontend_conf || {}) as ArtalkConfig
|
|
304
|
+
|
|
305
|
+
// Patch: `emoticons` config string to json
|
|
306
|
+
if (conf.emoticons && typeof conf.emoticons === "string") {
|
|
307
|
+
conf.emoticons = conf.emoticons.trim()
|
|
308
|
+
if (conf.emoticons.startsWith("[") || conf.emoticons.startsWith("{")) {
|
|
309
|
+
conf.emoticons = JSON.parse(conf.emoticons) // pase json
|
|
310
|
+
}
|
|
311
|
+
}
|
|
312
|
+
|
|
313
|
+
return conf
|
|
298
314
|
}
|
|
299
315
|
|
|
300
316
|
// ============================
|
|
@@ -318,4 +334,20 @@ export default class Api {
|
|
|
318
334
|
const data = await POST<any>(this.ctx, `${this.baseURL}/captcha/status`)
|
|
319
335
|
return (data || { is_pass: false }) as { is_pass: boolean }
|
|
320
336
|
}
|
|
337
|
+
|
|
338
|
+
// ============================
|
|
339
|
+
// 管理员缓存操作
|
|
340
|
+
// ============================
|
|
341
|
+
|
|
342
|
+
/** 缓存清除 */
|
|
343
|
+
public cacheFlushAll() {
|
|
344
|
+
const params: any = { flush_all: true }
|
|
345
|
+
return POST(this.ctx, `${this.baseURL}/admin/cache-flush`, params)
|
|
346
|
+
}
|
|
347
|
+
|
|
348
|
+
/** 缓存预热 */
|
|
349
|
+
public cacheWarmUp() {
|
|
350
|
+
const params: any = {}
|
|
351
|
+
return POST(this.ctx, `${this.baseURL}/admin/cache-warm`, params)
|
|
352
|
+
}
|
|
321
353
|
}
|
package/src/artalk.ts
CHANGED
|
@@ -1,7 +1,8 @@
|
|
|
1
1
|
import './style/main.less'
|
|
2
2
|
|
|
3
|
-
import Context from './context'
|
|
4
3
|
import ArtalkConfig from '~/types/artalk-config'
|
|
4
|
+
import { EventPayloadMap, Handler } from '~/types/event'
|
|
5
|
+
import Context from './context'
|
|
5
6
|
import defaults from './defaults'
|
|
6
7
|
|
|
7
8
|
import CheckerLauncher from './lib/checker'
|
|
@@ -10,9 +11,9 @@ import List from './components/list'
|
|
|
10
11
|
import SidebarLayer from './components/sidebar-layer'
|
|
11
12
|
|
|
12
13
|
import Layer, { GetLayerWrap } from './components/layer'
|
|
13
|
-
import { EventPayloadMap, Handler } from '~/types/event'
|
|
14
14
|
import Api from './api'
|
|
15
15
|
import * as Utils from './lib/utils'
|
|
16
|
+
import * as Ui from './lib/ui'
|
|
16
17
|
|
|
17
18
|
/**
|
|
18
19
|
* Artalk
|
|
@@ -21,18 +22,18 @@ import * as Utils from './lib/utils'
|
|
|
21
22
|
export default class Artalk {
|
|
22
23
|
public static readonly defaults: ArtalkConfig = defaults
|
|
23
24
|
|
|
24
|
-
public ctx
|
|
25
|
-
public conf
|
|
26
|
-
public $root
|
|
25
|
+
public ctx!: Context
|
|
26
|
+
public conf!: ArtalkConfig
|
|
27
|
+
public $root!: HTMLElement
|
|
27
28
|
|
|
28
|
-
public checkerLauncher
|
|
29
|
-
public editor
|
|
30
|
-
public list
|
|
31
|
-
public sidebarLayer
|
|
29
|
+
public checkerLauncher!: CheckerLauncher
|
|
30
|
+
public editor!: Editor
|
|
31
|
+
public list!: List
|
|
32
|
+
public sidebarLayer!: SidebarLayer
|
|
32
33
|
|
|
33
34
|
constructor (customConf: ArtalkConfig) {
|
|
34
35
|
// 配置
|
|
35
|
-
this.conf =
|
|
36
|
+
this.conf = Utils.mergeDeep(Artalk.defaults, customConf)
|
|
36
37
|
this.conf.server = this.conf.server.replace(/\/$/, '').replace(/\/api\/?$/, '')
|
|
37
38
|
|
|
38
39
|
// 默认 pageKey
|
|
@@ -66,10 +67,25 @@ export default class Artalk {
|
|
|
66
67
|
// 界面初始化
|
|
67
68
|
this.$root.classList.add('artalk')
|
|
68
69
|
this.$root.innerHTML = ''
|
|
69
|
-
this.initLayer()
|
|
70
|
-
this.initDarkMode()
|
|
71
70
|
|
|
71
|
+
// 初始化组件
|
|
72
|
+
if (this.conf.useBackendConf) {
|
|
73
|
+
// 复用后端的配置
|
|
74
|
+
// @ts-ignore
|
|
75
|
+
return (async () => {
|
|
76
|
+
await this.loadConfRemote()
|
|
77
|
+
this.initCore()
|
|
78
|
+
return this // Promise<Artalk>
|
|
79
|
+
})()
|
|
80
|
+
}
|
|
81
|
+
|
|
82
|
+
this.initCore()
|
|
83
|
+
}
|
|
84
|
+
|
|
85
|
+
private initCore() {
|
|
72
86
|
// 组件初始化
|
|
87
|
+
this.initLayer()
|
|
88
|
+
this.initDarkMode()
|
|
73
89
|
this.checkerLauncher = new CheckerLauncher(this.ctx)
|
|
74
90
|
Utils.initMarked(this.ctx) // 初始化 marked
|
|
75
91
|
|
|
@@ -102,10 +118,22 @@ export default class Artalk {
|
|
|
102
118
|
})
|
|
103
119
|
}
|
|
104
120
|
|
|
121
|
+
/** 获取远程配置 */
|
|
122
|
+
private async loadConfRemote() {
|
|
123
|
+
Ui.showLoading(this.$root)
|
|
124
|
+
let backendConf = {}
|
|
125
|
+
try {
|
|
126
|
+
backendConf = await (new Api(this.ctx)).conf()
|
|
127
|
+
} catch (err) { console.error("配置远程获取失败", err) }
|
|
128
|
+
this.ctx.conf = Utils.mergeDeep(this.ctx.conf, backendConf)
|
|
129
|
+
Ui.hideLoading(this.$root)
|
|
130
|
+
}
|
|
131
|
+
|
|
105
132
|
/** 事件绑定 · 初始化 */
|
|
106
133
|
private initEventBind() {
|
|
107
134
|
// 锚点快速跳转评论
|
|
108
135
|
window.addEventListener('hashchange', () => {
|
|
136
|
+
this.list.goToCommentDelay = false
|
|
109
137
|
this.list.checkGoToCommentByUrlHash()
|
|
110
138
|
})
|
|
111
139
|
|
|
@@ -1,11 +1,11 @@
|
|
|
1
1
|
import '../style/comment.less'
|
|
2
2
|
|
|
3
|
+
import { CommentData } from '~/types/artalk-data'
|
|
3
4
|
import Context from '../context'
|
|
4
5
|
import Component from '../lib/component'
|
|
5
6
|
import * as Utils from '../lib/utils'
|
|
6
7
|
import * as Ui from '../lib/ui'
|
|
7
8
|
import UADetect from '../lib/detect'
|
|
8
|
-
import { CommentData } from '~/types/artalk-data'
|
|
9
9
|
import CommentHTML from './html/comment.html?raw'
|
|
10
10
|
import Api from '../api'
|
|
11
11
|
import ActionBtn from './action-btn'
|
|
@@ -15,6 +15,7 @@ export default class Comment extends Component {
|
|
|
15
15
|
|
|
16
16
|
public $main!: HTMLElement
|
|
17
17
|
public $header!: HTMLElement
|
|
18
|
+
public $headerNick!: HTMLElement
|
|
18
19
|
public $body!: HTMLElement
|
|
19
20
|
public $content!: HTMLElement
|
|
20
21
|
public $children!: HTMLElement|null
|
|
@@ -23,12 +24,15 @@ export default class Comment extends Component {
|
|
|
23
24
|
public voteBtnDown?: ActionBtn
|
|
24
25
|
|
|
25
26
|
public parent: Comment|null
|
|
26
|
-
public
|
|
27
|
-
private
|
|
28
|
-
|
|
27
|
+
public nestCurt: number
|
|
28
|
+
private nestMax: number // 最大嵌套层数
|
|
29
|
+
private children: Comment[] = []
|
|
30
|
+
|
|
31
|
+
public flatMode: boolean = false
|
|
32
|
+
public replyTo?: CommentData // 回复对象
|
|
29
33
|
|
|
30
|
-
public replyTo?:
|
|
31
|
-
public $
|
|
34
|
+
public $replyTo?: HTMLElement // 回复评论内容 (平铺下显示)
|
|
35
|
+
public $replyAt?: HTMLElement // 回复 AT(层级嵌套下显示)
|
|
32
36
|
|
|
33
37
|
public afterRender?: () => void
|
|
34
38
|
|
|
@@ -43,13 +47,13 @@ export default class Comment extends Component {
|
|
|
43
47
|
super(ctx)
|
|
44
48
|
|
|
45
49
|
// 最大嵌套数
|
|
46
|
-
this.
|
|
50
|
+
this.nestMax = ctx.conf.nestMax || 3
|
|
47
51
|
|
|
48
52
|
this.data = { ...data }
|
|
49
53
|
this.data.date = this.data.date.replace(/-/g, '/') // 解决 Safari 日期解析 NaN 问题
|
|
50
54
|
|
|
51
55
|
this.parent = null
|
|
52
|
-
this.
|
|
56
|
+
this.nestCurt = 1 // 现在已嵌套 n 层
|
|
53
57
|
}
|
|
54
58
|
|
|
55
59
|
/** 渲染 UI */
|
|
@@ -70,6 +74,7 @@ export default class Comment extends Component {
|
|
|
70
74
|
this.renderAvatar()
|
|
71
75
|
this.renderHeader()
|
|
72
76
|
this.renderContent()
|
|
77
|
+
this.renderReplyAt()
|
|
73
78
|
this.renderReplyTo()
|
|
74
79
|
this.renderPending()
|
|
75
80
|
this.renderActionBtn()
|
|
@@ -117,14 +122,14 @@ export default class Comment extends Component {
|
|
|
117
122
|
}
|
|
118
123
|
|
|
119
124
|
private renderHeader() {
|
|
120
|
-
|
|
125
|
+
this.$headerNick = this.$el.querySelector<HTMLElement>('.atk-nick')!
|
|
121
126
|
if (this.data.link) {
|
|
122
127
|
const $nickA = Utils.createElement<HTMLLinkElement>('<a target="_blank" rel="noreferrer noopener nofollow"></a>')
|
|
123
128
|
$nickA.innerText = this.data.nick
|
|
124
129
|
$nickA.href = this.data.link
|
|
125
|
-
|
|
130
|
+
this.$headerNick.append($nickA)
|
|
126
131
|
} else {
|
|
127
|
-
|
|
132
|
+
this.$headerNick.innerText = this.data.nick
|
|
128
133
|
}
|
|
129
134
|
|
|
130
135
|
const $badge = this.$el.querySelector<HTMLElement>('.atk-badge')!
|
|
@@ -138,7 +143,7 @@ export default class Comment extends Component {
|
|
|
138
143
|
|
|
139
144
|
if (this.data.is_pinned) {
|
|
140
145
|
const $pinnedBadge = Utils.createElement(`<span class="atk-item atk-pinned-badge">置顶</span>`) // 置顶徽章
|
|
141
|
-
|
|
146
|
+
this.$headerNick.insertAdjacentElement('afterend', $pinnedBadge)
|
|
142
147
|
}
|
|
143
148
|
|
|
144
149
|
const $date = this.$el.querySelector<HTMLElement>('.atk-date')!
|
|
@@ -189,8 +194,22 @@ export default class Comment extends Component {
|
|
|
189
194
|
})
|
|
190
195
|
}
|
|
191
196
|
|
|
197
|
+
// 层级嵌套模式显示 At
|
|
198
|
+
private renderReplyAt() {
|
|
199
|
+
if (this.flatMode || this.data.rid === 0) return // not 平铺模式 或 根评论
|
|
200
|
+
if (this.$replyAt) return // not 关闭显示 或 已经显示
|
|
201
|
+
if (!this.replyTo) return
|
|
202
|
+
|
|
203
|
+
this.$replyAt = Utils.createElement(`<span class="atk-item atk-reply-at"><span class="atk-arrow"></span><span class="atk-nick"></span></span>`)
|
|
204
|
+
this.$replyAt.querySelector<HTMLElement>('.atk-nick')!.innerText = `${this.replyTo.nick}`
|
|
205
|
+
this.$replyAt.onclick = () => { this.goToReplyComment() }
|
|
206
|
+
|
|
207
|
+
this.$headerNick.insertAdjacentElement('afterend', this.$replyAt)
|
|
208
|
+
}
|
|
209
|
+
|
|
192
210
|
// 回复的对象
|
|
193
211
|
private renderReplyTo() {
|
|
212
|
+
if (!this.flatMode) return // 仅平铺模式显示
|
|
194
213
|
if (!this.replyTo) return
|
|
195
214
|
|
|
196
215
|
this.$replyTo = Utils.createElement(`
|
|
@@ -198,13 +217,23 @@ export default class Comment extends Component {
|
|
|
198
217
|
<div class="atk-meta">回复 <span class="atk-nick"></span>:</div>
|
|
199
218
|
<div class="atk-content"></div>
|
|
200
219
|
</div>`)
|
|
201
|
-
this.$replyTo.querySelector<HTMLElement>('.atk-nick')
|
|
220
|
+
const $nick = this.$replyTo.querySelector<HTMLElement>('.atk-nick')!
|
|
221
|
+
$nick.innerText = `@${this.replyTo.nick}`
|
|
222
|
+
$nick.onclick = () => { this.goToReplyComment() }
|
|
202
223
|
let replyContent = Utils.marked(this.ctx, this.replyTo.content)
|
|
203
224
|
if (this.replyTo.is_collapsed) replyContent = '[已折叠]'
|
|
204
225
|
this.$replyTo.querySelector<HTMLElement>('.atk-content')!.innerHTML = replyContent
|
|
205
226
|
this.$body.prepend(this.$replyTo)
|
|
206
227
|
}
|
|
207
228
|
|
|
229
|
+
public goToReplyComment() {
|
|
230
|
+
const origHash = window.location.hash
|
|
231
|
+
const modifyHash = `#atk-comment-${this.data.rid}`
|
|
232
|
+
|
|
233
|
+
window.location.hash = modifyHash
|
|
234
|
+
if (modifyHash === origHash) window.dispatchEvent(new Event('hashchange')) // 强制触发事件
|
|
235
|
+
}
|
|
236
|
+
|
|
208
237
|
// 待审核状态
|
|
209
238
|
private renderPending() {
|
|
210
239
|
if (!this.data.is_pending) return
|
|
@@ -324,30 +353,33 @@ export default class Comment extends Component {
|
|
|
324
353
|
return this.children
|
|
325
354
|
}
|
|
326
355
|
|
|
327
|
-
putChild(childC: Comment) {
|
|
356
|
+
putChild(childC: Comment, insertMode: 'append'|'prepend' = 'append') {
|
|
328
357
|
childC.parent = this
|
|
329
|
-
childC.
|
|
358
|
+
childC.nestCurt = this.nestCurt + 1 // 嵌套层数 +1
|
|
330
359
|
this.children.push(childC)
|
|
331
360
|
|
|
332
|
-
this.getChildrenEl()
|
|
361
|
+
const $children = this.getChildrenEl()
|
|
362
|
+
if (insertMode === 'append') $children.append(childC.getEl())
|
|
363
|
+
else if (insertMode === 'prepend') $children.prepend(childC.getEl())
|
|
364
|
+
|
|
333
365
|
childC.playFadeInAnim()
|
|
334
366
|
|
|
335
367
|
// 内容限高
|
|
336
368
|
childC.checkHeightLimitArea('content')
|
|
337
369
|
}
|
|
338
370
|
|
|
339
|
-
getChildrenEl() {
|
|
340
|
-
if (this.$children
|
|
341
|
-
// console.log(this.
|
|
342
|
-
if (this.
|
|
371
|
+
getChildrenEl(): HTMLElement {
|
|
372
|
+
if (!this.$children) {
|
|
373
|
+
// console.log(this.nestCurt)
|
|
374
|
+
if (this.nestCurt < this.nestMax) {
|
|
343
375
|
this.$children = Utils.createElement('<div class="atk-comment-children"></div>')
|
|
344
|
-
this.$main.
|
|
376
|
+
this.$main.append(this.$children)
|
|
345
377
|
} else if (this.parent) {
|
|
346
378
|
this.$children = this.parent.getChildrenEl()
|
|
347
379
|
}
|
|
348
380
|
}
|
|
349
381
|
|
|
350
|
-
return this.$children
|
|
382
|
+
return this.$children!
|
|
351
383
|
}
|
|
352
384
|
|
|
353
385
|
getParent() {
|
|
@@ -1,10 +1,10 @@
|
|
|
1
1
|
import './emoticons-plug.less'
|
|
2
2
|
|
|
3
|
-
import Editor from '../editor'
|
|
4
|
-
import EditorPlug from './editor-plug'
|
|
5
3
|
import * as Utils from '~/src/lib/utils'
|
|
6
4
|
import * as Ui from '~/src/lib/ui'
|
|
7
5
|
import { EmoticonListData, EmoticonGrpData } from '~/types/artalk-data'
|
|
6
|
+
import EditorPlug from './editor-plug'
|
|
7
|
+
import Editor from '../editor'
|
|
8
8
|
|
|
9
9
|
type OwOFormatType = {
|
|
10
10
|
[key: string] : {
|
|
@@ -1,8 +1,8 @@
|
|
|
1
1
|
import './preview-plug.less'
|
|
2
2
|
|
|
3
|
+
import * as Utils from '~/src/lib/utils'
|
|
3
4
|
import Editor from '../editor'
|
|
4
5
|
import EditorPlug from './editor-plug'
|
|
5
|
-
import * as Utils from '~/src/lib/utils'
|
|
6
6
|
|
|
7
7
|
export default class PreviewPlug extends EditorPlug {
|
|
8
8
|
$el!: HTMLElement
|
package/src/components/editor.ts
CHANGED
|
@@ -1,5 +1,6 @@
|
|
|
1
1
|
import '../style/editor.less'
|
|
2
2
|
|
|
3
|
+
import { CommentData } from '~/types/artalk-data'
|
|
3
4
|
import Context from '../context'
|
|
4
5
|
import Component from '../lib/component'
|
|
5
6
|
import * as Utils from '../lib/utils'
|
|
@@ -8,7 +9,6 @@ import EditorHTML from './html/editor.html?raw'
|
|
|
8
9
|
|
|
9
10
|
import EmoticonsPlug from './editor-plugs/emoticons-plug'
|
|
10
11
|
import PreviewPlug from './editor-plugs/preview-plug'
|
|
11
|
-
import { CommentData } from '~/types/artalk-data'
|
|
12
12
|
import Api from '../api'
|
|
13
13
|
|
|
14
14
|
export default class Editor extends Component {
|
|
@@ -85,9 +85,22 @@ export default class Editor extends Component {
|
|
|
85
85
|
if (inputEl && inputEl instanceof HTMLInputElement) {
|
|
86
86
|
inputEl.value = this.user.data[field] || ''
|
|
87
87
|
// 绑定事件
|
|
88
|
-
inputEl.addEventListener('input', () => this.
|
|
88
|
+
inputEl.addEventListener('input', () => this.onHeaderInput(field, inputEl))
|
|
89
89
|
}
|
|
90
90
|
})
|
|
91
|
+
|
|
92
|
+
// Link URL 自动补全协议
|
|
93
|
+
const $linkInput = this.getInputEl('link')
|
|
94
|
+
if ($linkInput) {
|
|
95
|
+
$linkInput.addEventListener('change', () => {
|
|
96
|
+
const link = $linkInput.value.trim()
|
|
97
|
+
if (!!link && !/^(http|https):\/\//.test(link)) {
|
|
98
|
+
$linkInput.value = `https://${link}`
|
|
99
|
+
this.user.data.link = $linkInput.value
|
|
100
|
+
this.saveUser()
|
|
101
|
+
}
|
|
102
|
+
})
|
|
103
|
+
}
|
|
91
104
|
}
|
|
92
105
|
|
|
93
106
|
getInputEl (field: string) {
|
|
@@ -101,7 +114,7 @@ export default class Editor extends Component {
|
|
|
101
114
|
}
|
|
102
115
|
|
|
103
116
|
/** header 输入框内容变化事件 */
|
|
104
|
-
|
|
117
|
+
onHeaderInput(field: string, inputEl: HTMLInputElement) {
|
|
105
118
|
this.user.data[field] = inputEl.value.trim()
|
|
106
119
|
|
|
107
120
|
// 若修改的是 nick or email
|