artalk 2.7.0 → 2.7.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/README.md +1 -1
- package/dist/Artalk.css +1 -1
- package/dist/Artalk.es.js +209 -188
- package/dist/Artalk.es.js.map +1 -0
- package/dist/Artalk.iife.js +2 -1
- package/dist/Artalk.iife.js.map +1 -0
- package/dist/Artalk.js +2 -1
- package/dist/Artalk.js.map +1 -0
- package/dist/ArtalkLite.css +1 -1
- package/dist/ArtalkLite.es.js +209 -188
- package/dist/ArtalkLite.es.js.map +1 -0
- package/dist/ArtalkLite.iife.js +2 -1
- package/dist/ArtalkLite.iife.js.map +1 -0
- package/dist/ArtalkLite.js +2 -1
- package/dist/ArtalkLite.js.map +1 -0
- package/dist/i18n/jp.js +1 -1
- package/dist/i18n/zh-TW.js +1 -1
- package/dist/src/api/_base.d.ts +7 -0
- package/dist/src/api/_options.d.ts +5 -0
- package/dist/src/artalk.d.ts +0 -2
- package/dist/src/components/checker/index.d.ts +2 -0
- package/dist/src/i18n/en.d.ts +4 -0
- package/dist/src/i18n/external.d.ts +4 -0
- package/dist/src/i18n/index.d.ts +12 -0
- package/dist/src/i18n/jp.d.ts +4 -0
- package/dist/src/i18n/zh-TW.d.ts +4 -0
- package/dist/src/lib/user.d.ts +8 -6
- package/dist/src/main.d.ts +3 -0
- package/dist/src/plugins/editor/_kit.d.ts +7 -1
- package/dist/src/service.d.ts +2 -8
- package/dist/types/event.d.ts +1 -1
- package/package.json +43 -17
- package/dist/src/components/dark-mode.d.ts +0 -2
- package/src/api/_base.ts +0 -18
- package/src/api/_options.ts +0 -25
- package/src/api/_request.ts +0 -104
- package/src/api/admin.ts +0 -18
- package/src/api/captcha.ts +0 -24
- package/src/api/comment.ts +0 -84
- package/src/api/index.ts +0 -29
- package/src/api/page.ts +0 -83
- package/src/api/site.ts +0 -51
- package/src/api/system.ts +0 -49
- package/src/api/upload.ts +0 -28
- package/src/api/user.ts +0 -132
- package/src/artalk.ts +0 -119
- package/src/comment/actions.ts +0 -83
- package/src/comment/comment.html +0 -18
- package/src/comment/comment.ts +0 -192
- package/src/comment/height-limit.ts +0 -100
- package/src/comment/index.ts +0 -3
- package/src/comment/render.ts +0 -150
- package/src/comment/renders/actions.ts +0 -114
- package/src/comment/renders/avatar.ts +0 -22
- package/src/comment/renders/content.ts +0 -39
- package/src/comment/renders/header.ts +0 -84
- package/src/comment/renders/index.ts +0 -19
- package/src/comment/renders/pending.ts +0 -12
- package/src/comment/renders/reply-at.ts +0 -16
- package/src/comment/renders/reply-to.ts +0 -24
- package/src/components/action-btn.ts +0 -170
- package/src/components/checker/admin.ts +0 -37
- package/src/components/checker/captcha-renders.ts +0 -69
- package/src/components/checker/captcha.ts +0 -26
- package/src/components/checker/index.ts +0 -192
- package/src/components/dark-mode.ts +0 -30
- package/src/components/dialog.ts +0 -62
- package/src/components/error-dialog.ts +0 -35
- package/src/components/pagination.ts +0 -153
- package/src/components/read-more-btn.ts +0 -92
- package/src/config.ts +0 -119
- package/src/context.ts +0 -146
- package/src/data.ts +0 -110
- package/src/defaults.ts +0 -61
- package/src/editor/editor.html +0 -18
- package/src/editor/editor.ts +0 -114
- package/src/editor/state.ts +0 -52
- package/src/editor/ui.ts +0 -36
- package/src/i18n/en.ts +0 -81
- package/src/i18n/external.ts +0 -10
- package/src/i18n/index.ts +0 -67
- package/src/i18n/jp.ts +0 -83
- package/src/i18n/zh-CN.ts +0 -85
- package/src/i18n/zh-TW.ts +0 -83
- package/src/layer/index.ts +0 -4
- package/src/layer/layer-manager.ts +0 -32
- package/src/layer/layer.ts +0 -39
- package/src/layer/scrollbar-helper.ts +0 -24
- package/src/layer/sidebar-layer.html +0 -8
- package/src/layer/sidebar-layer.ts +0 -155
- package/src/layer/wrap.ts +0 -77
- package/src/lib/component.ts +0 -12
- package/src/lib/detect.ts +0 -222
- package/src/lib/event-manager.ts +0 -47
- package/src/lib/highlight.ts +0 -5
- package/src/lib/marked-renderer.ts +0 -32
- package/src/lib/marked.ts +0 -72
- package/src/lib/sanitizer.ts +0 -57
- package/src/lib/ui.ts +0 -193
- package/src/lib/user.ts +0 -55
- package/src/lib/utils.ts +0 -236
- package/src/list/comment.ts +0 -20
- package/src/list/layout.ts +0 -120
- package/src/list/list.html +0 -20
- package/src/list/list.ts +0 -79
- package/src/list/nest.ts +0 -66
- package/src/list/page.ts +0 -97
- package/src/list/paginator/index.ts +0 -25
- package/src/list/paginator/read-more.ts +0 -67
- package/src/list/paginator/up-down.ts +0 -51
- package/src/main.ts +0 -5
- package/src/plugins/admin-only-elem.ts +0 -40
- package/src/plugins/conf-remoter.ts +0 -54
- package/src/plugins/dark-mode.ts +0 -12
- package/src/plugins/editor/_kit.ts +0 -57
- package/src/plugins/editor/_plug.ts +0 -60
- package/src/plugins/editor/_sample.ts +0 -8
- package/src/plugins/editor/closable.ts +0 -44
- package/src/plugins/editor/emoticons.scss +0 -72
- package/src/plugins/editor/emoticons.ts +0 -293
- package/src/plugins/editor/header-event.ts +0 -35
- package/src/plugins/editor/header-link.ts +0 -31
- package/src/plugins/editor/header-user.ts +0 -98
- package/src/plugins/editor/index.ts +0 -40
- package/src/plugins/editor/local-storage.ts +0 -36
- package/src/plugins/editor/mover.ts +0 -29
- package/src/plugins/editor/preview.scss +0 -7
- package/src/plugins/editor/preview.ts +0 -41
- package/src/plugins/editor/state-edit.ts +0 -116
- package/src/plugins/editor/state-reply.ts +0 -91
- package/src/plugins/editor/submit-add.ts +0 -33
- package/src/plugins/editor/submit-btn.ts +0 -25
- package/src/plugins/editor/submit.ts +0 -73
- package/src/plugins/editor/textarea.ts +0 -55
- package/src/plugins/editor/upload.ts +0 -145
- package/src/plugins/editor-kit.ts +0 -161
- package/src/plugins/index.ts +0 -16
- package/src/plugins/list/copyright.ts +0 -16
- package/src/plugins/list/count.ts +0 -31
- package/src/plugins/list/dropdown.ts +0 -95
- package/src/plugins/list/error-dialog.ts +0 -22
- package/src/plugins/list/fetch.ts +0 -64
- package/src/plugins/list/goto-first.ts +0 -23
- package/src/plugins/list/goto.ts +0 -72
- package/src/plugins/list/index.ts +0 -25
- package/src/plugins/list/loading.ts +0 -17
- package/src/plugins/list/no-comment.ts +0 -25
- package/src/plugins/list/reach-bottom.ts +0 -46
- package/src/plugins/list/sidebar-btn.ts +0 -39
- package/src/plugins/list/time-ticking.ts +0 -22
- package/src/plugins/list/unread-badge.ts +0 -26
- package/src/plugins/list/unread.ts +0 -38
- package/src/plugins/list/with-editor.ts +0 -59
- package/src/plugins/markdown.ts +0 -10
- package/src/plugins/stat.ts +0 -79
- package/src/plugins/version-check.ts +0 -37
- package/src/service.ts +0 -91
- package/src/style/_color.scss +0 -41
- package/src/style/_extend.scss +0 -20
- package/src/style/_variables.scss +0 -3
- package/src/style/comment.scss +0 -360
- package/src/style/editor.scss +0 -194
- package/src/style/list.scss +0 -212
- package/src/style/main.scss +0 -486
- package/src/style/pagination.scss +0 -58
- package/src/style/sidebar-layer.scss +0 -92
- package/types/config.ts +0 -153
- package/types/context.ts +0 -84
- package/types/data.ts +0 -271
- package/types/editor.ts +0 -95
- package/types/event.ts +0 -40
- package/types/global.d.ts +0 -1
- package/types/index.ts +0 -7
- package/types/plugin.ts +0 -3
- package/types/sidebar.ts +0 -3
|
@@ -1,19 +0,0 @@
|
|
|
1
|
-
import type Render from '../render'
|
|
2
|
-
import Avatar from './avatar'
|
|
3
|
-
import Header from './header'
|
|
4
|
-
import Content from './content'
|
|
5
|
-
import ReplyAt from './reply-at'
|
|
6
|
-
import ReplyTo from './reply-to'
|
|
7
|
-
import Pending from './pending'
|
|
8
|
-
import Actions from './actions'
|
|
9
|
-
|
|
10
|
-
const Renders = {
|
|
11
|
-
Avatar, Header, Content, ReplyAt,
|
|
12
|
-
ReplyTo, Pending, Actions
|
|
13
|
-
}
|
|
14
|
-
|
|
15
|
-
export default function loadRenders(r: Render) {
|
|
16
|
-
Object.entries(Renders).forEach(([ name, render ]) => {
|
|
17
|
-
render(r)
|
|
18
|
-
})
|
|
19
|
-
}
|
|
@@ -1,12 +0,0 @@
|
|
|
1
|
-
import * as Utils from '../../lib/utils'
|
|
2
|
-
import type Render from '../render'
|
|
3
|
-
|
|
4
|
-
/**
|
|
5
|
-
* 待审核状态界面
|
|
6
|
-
*/
|
|
7
|
-
export default function renderPending(r: Render) {
|
|
8
|
-
if (!r.data.is_pending) return
|
|
9
|
-
|
|
10
|
-
const pendingEl = Utils.createElement(`<div class="atk-pending">${r.ctx.$t('pendingMsg')}</div>`)
|
|
11
|
-
r.$body.prepend(pendingEl)
|
|
12
|
-
}
|
|
@@ -1,16 +0,0 @@
|
|
|
1
|
-
import * as Utils from '../../lib/utils'
|
|
2
|
-
import type Render from '../render'
|
|
3
|
-
|
|
4
|
-
/**
|
|
5
|
-
* 层级嵌套模式显示 AT 界面
|
|
6
|
-
*/
|
|
7
|
-
export default function renderReplyAt(r: Render) {
|
|
8
|
-
if (r.cConf.isFlatMode || r.data.rid === 0) return // not 平铺模式 或 根评论
|
|
9
|
-
if (!r.cConf.replyTo) return
|
|
10
|
-
|
|
11
|
-
r.$replyAt = Utils.createElement(`<span class="atk-item atk-reply-at"><span class="atk-arrow"></span><span class="atk-nick"></span></span>`)
|
|
12
|
-
r.$replyAt.querySelector<HTMLElement>('.atk-nick')!.innerText = `${r.cConf.replyTo.nick}`
|
|
13
|
-
r.$replyAt.onclick = () => { r.comment.getActions().goToReplyComment() }
|
|
14
|
-
|
|
15
|
-
r.$headerBadgeWrap.insertAdjacentElement('afterend', r.$replyAt)
|
|
16
|
-
}
|
|
@@ -1,24 +0,0 @@
|
|
|
1
|
-
import * as Utils from '../../lib/utils'
|
|
2
|
-
import marked from '../../lib/marked'
|
|
3
|
-
import type Render from '../render'
|
|
4
|
-
|
|
5
|
-
/**
|
|
6
|
-
* 回复的对象界面
|
|
7
|
-
*/
|
|
8
|
-
export default function renderReplyTo(r: Render) {
|
|
9
|
-
if (!r.cConf.isFlatMode) return // 仅平铺模式显示
|
|
10
|
-
if (!r.cConf.replyTo) return
|
|
11
|
-
|
|
12
|
-
r.$replyTo = Utils.createElement(`
|
|
13
|
-
<div class="atk-reply-to">
|
|
14
|
-
<div class="atk-meta">${r.ctx.$t('reply')} <span class="atk-nick"></span>:</div>
|
|
15
|
-
<div class="atk-content"></div>
|
|
16
|
-
</div>`)
|
|
17
|
-
const $nick = r.$replyTo.querySelector<HTMLElement>('.atk-nick')!
|
|
18
|
-
$nick.innerText = `@${r.cConf.replyTo.nick}`
|
|
19
|
-
$nick.onclick = () => { r.comment.getActions().goToReplyComment() }
|
|
20
|
-
let replyContent = marked(r.cConf.replyTo.content)
|
|
21
|
-
if (r.cConf.replyTo.is_collapsed) replyContent = `[${Utils.htmlEncode(r.ctx.$t('collapsed'))}]`
|
|
22
|
-
r.$replyTo.querySelector<HTMLElement>('.atk-content')!.innerHTML = replyContent
|
|
23
|
-
r.$body.prepend(r.$replyTo)
|
|
24
|
-
}
|
|
@@ -1,170 +0,0 @@
|
|
|
1
|
-
import $t from '@/i18n'
|
|
2
|
-
import * as Utils from '../lib/utils'
|
|
3
|
-
|
|
4
|
-
interface ActionBtnOptions {
|
|
5
|
-
/** 按钮文字 (动态/静态) */
|
|
6
|
-
text: (() => string) | string
|
|
7
|
-
|
|
8
|
-
/** 仅管理员可用 */
|
|
9
|
-
adminOnly?: boolean
|
|
10
|
-
|
|
11
|
-
/** 确认操作 */
|
|
12
|
-
confirm?: boolean
|
|
13
|
-
|
|
14
|
-
/** 确认时提示文字 */
|
|
15
|
-
confirmText?: string
|
|
16
|
-
}
|
|
17
|
-
|
|
18
|
-
/**
|
|
19
|
-
* 通用操作按钮
|
|
20
|
-
*/
|
|
21
|
-
export default class ActionBtn {
|
|
22
|
-
private opts: ActionBtnOptions
|
|
23
|
-
public $el: HTMLElement
|
|
24
|
-
|
|
25
|
-
public isLoading = false // 正在加载
|
|
26
|
-
|
|
27
|
-
public msgRecTimer?: number // 消息显示复原定时器
|
|
28
|
-
public msgRecTimerFunc?: Function // 消息显示复原操作
|
|
29
|
-
public get isMessaging() { return !!this.msgRecTimer } // 消息正在显示
|
|
30
|
-
|
|
31
|
-
public isConfirming = false // 正在确认
|
|
32
|
-
public confirmRecTimer?: number // 确认消息复原定时器
|
|
33
|
-
|
|
34
|
-
/** 构造函数 */
|
|
35
|
-
constructor(opts: ActionBtnOptions|string|(() => string)) {
|
|
36
|
-
this.$el = Utils.createElement(`<span class="atk-common-action-btn"></span>`)
|
|
37
|
-
|
|
38
|
-
this.opts = (typeof opts !== 'object') ? ({ text: opts }) : opts
|
|
39
|
-
this.$el.innerText = this.getText()
|
|
40
|
-
|
|
41
|
-
// 仅管理员可操作
|
|
42
|
-
if (this.opts.adminOnly) this.$el.setAttribute('atk-only-admin-show', '')
|
|
43
|
-
}
|
|
44
|
-
|
|
45
|
-
/** 将按钮装载到指定元素 */
|
|
46
|
-
public appendTo(dom: HTMLElement) {
|
|
47
|
-
dom.append(this.$el)
|
|
48
|
-
return this
|
|
49
|
-
}
|
|
50
|
-
|
|
51
|
-
/** 获取按钮文字(动态/静态) */
|
|
52
|
-
private getText() {
|
|
53
|
-
return (typeof this.opts.text === 'string') ? this.opts.text : this.opts.text()
|
|
54
|
-
}
|
|
55
|
-
|
|
56
|
-
/** 设置点击事件 */
|
|
57
|
-
public setClick(func: Function) {
|
|
58
|
-
this.$el.onclick = (e) => {
|
|
59
|
-
e.stopPropagation() // 防止穿透
|
|
60
|
-
|
|
61
|
-
// 按钮处于加载状态,禁止点击
|
|
62
|
-
if (this.isLoading) {
|
|
63
|
-
return
|
|
64
|
-
}
|
|
65
|
-
|
|
66
|
-
// 操作确认
|
|
67
|
-
if (this.opts.confirm && !this.isMessaging) {
|
|
68
|
-
const confirmRestore = () => {
|
|
69
|
-
this.isConfirming = false
|
|
70
|
-
this.$el.classList.remove('atk-btn-confirm')
|
|
71
|
-
this.$el.innerText = this.getText()
|
|
72
|
-
}
|
|
73
|
-
|
|
74
|
-
if (!this.isConfirming) {
|
|
75
|
-
this.isConfirming = true
|
|
76
|
-
this.$el.classList.add('atk-btn-confirm')
|
|
77
|
-
this.$el.innerText = this.opts.confirmText || $t('actionConfirm')
|
|
78
|
-
this.confirmRecTimer = window.setTimeout(() => confirmRestore(), 5000)
|
|
79
|
-
return
|
|
80
|
-
}
|
|
81
|
-
|
|
82
|
-
if (this.confirmRecTimer) window.clearTimeout(this.confirmRecTimer)
|
|
83
|
-
confirmRestore()
|
|
84
|
-
}
|
|
85
|
-
|
|
86
|
-
// 立刻释放掉原有的定时器(当显示消息后,用户立刻点击时)
|
|
87
|
-
if (this.msgRecTimer) {
|
|
88
|
-
this.fireMsgRecTimer()
|
|
89
|
-
this.clearMsgRecTimer()
|
|
90
|
-
return
|
|
91
|
-
}
|
|
92
|
-
|
|
93
|
-
// 触发设定的点击事件
|
|
94
|
-
func()
|
|
95
|
-
}
|
|
96
|
-
}
|
|
97
|
-
|
|
98
|
-
/** 文字刷新(动态/静态) */
|
|
99
|
-
public updateText(text?: (() => string) | string) {
|
|
100
|
-
if (text) this.opts.text = text
|
|
101
|
-
this.setLoading(false)
|
|
102
|
-
this.$el.innerText = this.getText()
|
|
103
|
-
}
|
|
104
|
-
|
|
105
|
-
/** 设置加载状态 */
|
|
106
|
-
public setLoading(value: boolean, loadingText?: string) {
|
|
107
|
-
if (this.isLoading === value) return
|
|
108
|
-
this.isLoading = value
|
|
109
|
-
if (value) {
|
|
110
|
-
this.$el.classList.add('atk-btn-loading')
|
|
111
|
-
this.$el.innerText = loadingText || `${$t('loading')}...`
|
|
112
|
-
} else {
|
|
113
|
-
this.$el.classList.remove('atk-btn-loading')
|
|
114
|
-
this.$el.innerText = this.getText()
|
|
115
|
-
}
|
|
116
|
-
}
|
|
117
|
-
|
|
118
|
-
/** 错误消息 */
|
|
119
|
-
public setError(text: string) {
|
|
120
|
-
this.setMsg(text, 'atk-btn-error')
|
|
121
|
-
}
|
|
122
|
-
|
|
123
|
-
/** 警告消息 */
|
|
124
|
-
public setWarn(text: string) {
|
|
125
|
-
this.setMsg(text, 'atk-btn-warn')
|
|
126
|
-
}
|
|
127
|
-
|
|
128
|
-
/** 成功消息 */
|
|
129
|
-
public setSuccess(text: string) {
|
|
130
|
-
this.setMsg(text, 'atk-btn-success')
|
|
131
|
-
}
|
|
132
|
-
|
|
133
|
-
/** 设置消息 */
|
|
134
|
-
public setMsg(text: string, className?: string, duringTime?: number, after?: Function) {
|
|
135
|
-
this.setLoading(false)
|
|
136
|
-
if (className) this.$el.classList.add(className)
|
|
137
|
-
this.$el.innerText = text
|
|
138
|
-
|
|
139
|
-
// 设定复原 timer
|
|
140
|
-
this.setMsgRecTimer(() => {
|
|
141
|
-
this.$el.innerText = this.getText()
|
|
142
|
-
if (className) this.$el.classList.remove(className)
|
|
143
|
-
if (after) after()
|
|
144
|
-
}, duringTime || 2500) // 消息默认显示持续 2500s
|
|
145
|
-
}
|
|
146
|
-
|
|
147
|
-
/** 设置消息复原操作定时器 */
|
|
148
|
-
private setMsgRecTimer(func: Function, duringTime: number) {
|
|
149
|
-
this.fireMsgRecTimer()
|
|
150
|
-
this.clearMsgRecTimer()
|
|
151
|
-
|
|
152
|
-
this.msgRecTimerFunc = func
|
|
153
|
-
this.msgRecTimer = window.setTimeout(() => {
|
|
154
|
-
func()
|
|
155
|
-
this.clearMsgRecTimer()
|
|
156
|
-
}, duringTime)
|
|
157
|
-
}
|
|
158
|
-
|
|
159
|
-
/** 立刻触发器复原定时器 */
|
|
160
|
-
private fireMsgRecTimer() {
|
|
161
|
-
if (this.msgRecTimerFunc) this.msgRecTimerFunc()
|
|
162
|
-
}
|
|
163
|
-
|
|
164
|
-
/** 仅清除 timer */
|
|
165
|
-
private clearMsgRecTimer() {
|
|
166
|
-
if (this.msgRecTimer) window.clearTimeout(this.msgRecTimer)
|
|
167
|
-
this.msgRecTimer = undefined
|
|
168
|
-
this.msgRecTimerFunc = undefined
|
|
169
|
-
}
|
|
170
|
-
}
|
|
@@ -1,37 +0,0 @@
|
|
|
1
|
-
import $t from '@/i18n'
|
|
2
|
-
import * as Utils from '@/lib/utils'
|
|
3
|
-
import User from '@/lib/user'
|
|
4
|
-
import type { Checker } from '.'
|
|
5
|
-
|
|
6
|
-
const AdminChecker: Checker = {
|
|
7
|
-
inputType: 'password',
|
|
8
|
-
|
|
9
|
-
request(checker, inputVal) {
|
|
10
|
-
const data = {
|
|
11
|
-
name: User.data.nick,
|
|
12
|
-
email: User.data.email,
|
|
13
|
-
password: inputVal
|
|
14
|
-
}
|
|
15
|
-
|
|
16
|
-
return (async () => {
|
|
17
|
-
const resp = await checker.getApi().user.login(data.name, data.email, data.password)
|
|
18
|
-
return resp.token
|
|
19
|
-
})()
|
|
20
|
-
},
|
|
21
|
-
|
|
22
|
-
body(checker) {
|
|
23
|
-
return Utils.createElement(`<span>${$t('adminCheck')}</span>`)
|
|
24
|
-
},
|
|
25
|
-
|
|
26
|
-
onSuccess(checker, userToken, inputVal, formEl) {
|
|
27
|
-
User.update({
|
|
28
|
-
isAdmin: true,
|
|
29
|
-
token: userToken
|
|
30
|
-
})
|
|
31
|
-
checker.getOpts().onReload()
|
|
32
|
-
},
|
|
33
|
-
|
|
34
|
-
onError(checker, err, inputVal, formEl) {}
|
|
35
|
-
}
|
|
36
|
-
|
|
37
|
-
export default AdminChecker
|
|
@@ -1,69 +0,0 @@
|
|
|
1
|
-
import $t from '@/i18n'
|
|
2
|
-
import * as Utils from '@/lib/utils'
|
|
3
|
-
import * as Ui from '@/lib/ui'
|
|
4
|
-
import type { CheckerCtx } from '.'
|
|
5
|
-
|
|
6
|
-
/** 图片验证码 */
|
|
7
|
-
export function imgBody(checker: CheckerCtx) {
|
|
8
|
-
// 图片验证方式
|
|
9
|
-
const elem = Utils.createElement(
|
|
10
|
-
`<span><img class="atk-captcha-img" src="${checker.get('img_data') || ''}">${$t('captchaCheck')}</span>`
|
|
11
|
-
);
|
|
12
|
-
|
|
13
|
-
// 刷新验证码
|
|
14
|
-
elem.querySelector<HTMLElement>('.atk-captcha-img')!.onclick = () => {
|
|
15
|
-
const imgEl = elem.querySelector('.atk-captcha-img')
|
|
16
|
-
checker.getApi().captcha.captchaGet()
|
|
17
|
-
.then((imgData) => {
|
|
18
|
-
imgEl!.setAttribute('src', imgData)
|
|
19
|
-
})
|
|
20
|
-
.catch((err) => {
|
|
21
|
-
console.error('Failed to get captcha image ', err)
|
|
22
|
-
})
|
|
23
|
-
}
|
|
24
|
-
return elem
|
|
25
|
-
}
|
|
26
|
-
|
|
27
|
-
/** iframe 形式的通用验证服务 */
|
|
28
|
-
export function iframeBody(checker: CheckerCtx) {
|
|
29
|
-
const $iframeWrap = Utils.createElement(`<div class="atk-checker-iframe-wrap"></div>`)
|
|
30
|
-
const $iframe = Utils.createElement<HTMLIFrameElement>(`<iframe class="atk-fade-in"></iframe>`)
|
|
31
|
-
$iframe.style.display = 'none'
|
|
32
|
-
Ui.showLoading($iframeWrap, { transparentBg: true })
|
|
33
|
-
$iframe.src = `${checker.getOpts().getIframeURLBase() || ''}/api/captcha/get?t=${+new Date()}`
|
|
34
|
-
$iframe.onload = () => {
|
|
35
|
-
$iframe.style.display = ''
|
|
36
|
-
Ui.hideLoading($iframeWrap)
|
|
37
|
-
}
|
|
38
|
-
$iframeWrap.append($iframe)
|
|
39
|
-
|
|
40
|
-
const $closeBtn = Utils.createElement(`<div class="atk-close-btn"><i class="atk-icon atk-icon-close"></i></div>`)
|
|
41
|
-
$iframeWrap.append($closeBtn)
|
|
42
|
-
|
|
43
|
-
checker.hideInteractInput()
|
|
44
|
-
|
|
45
|
-
// 轮询状态
|
|
46
|
-
let stop = false // 打断
|
|
47
|
-
const sleep = (ms: number) => new Promise((resolve) => { window.setTimeout(() => { resolve(null) }, ms) })
|
|
48
|
-
;(async function queryStatus() {
|
|
49
|
-
await sleep(1000)
|
|
50
|
-
if (stop) return
|
|
51
|
-
let isPass = false
|
|
52
|
-
try {
|
|
53
|
-
const resp = await checker.getApi().captcha.captchaStatus()
|
|
54
|
-
isPass = resp.is_pass
|
|
55
|
-
} catch { isPass = false }
|
|
56
|
-
if (isPass) {
|
|
57
|
-
checker.triggerSuccess()
|
|
58
|
-
} else {
|
|
59
|
-
queryStatus()
|
|
60
|
-
}
|
|
61
|
-
})()
|
|
62
|
-
|
|
63
|
-
$closeBtn.onclick = () => {
|
|
64
|
-
stop = true
|
|
65
|
-
checker.cancel()
|
|
66
|
-
}
|
|
67
|
-
|
|
68
|
-
return $iframeWrap
|
|
69
|
-
}
|
|
@@ -1,26 +0,0 @@
|
|
|
1
|
-
|
|
2
|
-
import type { Checker } from '.'
|
|
3
|
-
import * as render from './captcha-renders'
|
|
4
|
-
|
|
5
|
-
const CaptchaChecker: Checker = {
|
|
6
|
-
request(checker, inputVal) {
|
|
7
|
-
return checker.getApi().captcha.captchaCheck(inputVal)
|
|
8
|
-
},
|
|
9
|
-
|
|
10
|
-
body(checker) {
|
|
11
|
-
if (checker.get('iframe')) return render.iframeBody(checker)
|
|
12
|
-
return render.imgBody(checker)
|
|
13
|
-
},
|
|
14
|
-
|
|
15
|
-
onSuccess(checker, data, inputVal, formEl) {
|
|
16
|
-
checker.set('val', inputVal)
|
|
17
|
-
},
|
|
18
|
-
|
|
19
|
-
onError(checker, err, inputVal, formEl) {
|
|
20
|
-
formEl.querySelector<HTMLElement>('.atk-captcha-img')!.click() // 刷新验证码
|
|
21
|
-
formEl.querySelector<HTMLInputElement>('input[type="text"]')!.value = '' // 清空输入框输入
|
|
22
|
-
}
|
|
23
|
-
}
|
|
24
|
-
|
|
25
|
-
export default CaptchaChecker
|
|
26
|
-
|
|
@@ -1,192 +0,0 @@
|
|
|
1
|
-
import type Api from '@/api'
|
|
2
|
-
import Dialog from '@/components/dialog'
|
|
3
|
-
import $t from '@/i18n'
|
|
4
|
-
import type { ContextApi } from '~/types'
|
|
5
|
-
import type { Layer } from '@/layer'
|
|
6
|
-
import * as Utils from '@/lib/utils'
|
|
7
|
-
import CaptchaChecker from './captcha'
|
|
8
|
-
import AdminChecker from './admin'
|
|
9
|
-
|
|
10
|
-
export interface CheckerCaptchaPayload extends CheckerPayload {
|
|
11
|
-
imgData?: string
|
|
12
|
-
iframe?: string
|
|
13
|
-
}
|
|
14
|
-
|
|
15
|
-
export interface CheckerPayload {
|
|
16
|
-
onSuccess?: (inputVal: string, dialogEl?: HTMLElement) => void
|
|
17
|
-
onMount?: (dialogEl: HTMLElement) => void
|
|
18
|
-
onCancel?: () => void
|
|
19
|
-
}
|
|
20
|
-
|
|
21
|
-
export interface CheckerLauncherOptions {
|
|
22
|
-
getCtx: () => ContextApi
|
|
23
|
-
getApi: () => Api
|
|
24
|
-
getIframeURLBase: () => string
|
|
25
|
-
onReload: () => void
|
|
26
|
-
}
|
|
27
|
-
|
|
28
|
-
/**
|
|
29
|
-
* Checker 发射台
|
|
30
|
-
*/
|
|
31
|
-
export default class CheckerLauncher {
|
|
32
|
-
constructor(private opts: CheckerLauncherOptions) { }
|
|
33
|
-
|
|
34
|
-
public checkCaptcha(payload: CheckerCaptchaPayload) {
|
|
35
|
-
this.fire(CaptchaChecker, payload, (ctx) => {
|
|
36
|
-
ctx.set('img_data', payload.imgData)
|
|
37
|
-
ctx.set('iframe', payload.iframe)
|
|
38
|
-
})
|
|
39
|
-
}
|
|
40
|
-
|
|
41
|
-
public checkAdmin(payload: CheckerPayload) {
|
|
42
|
-
this.fire(AdminChecker, payload)
|
|
43
|
-
}
|
|
44
|
-
|
|
45
|
-
public fire(checker: Checker, payload: CheckerPayload, postFire?: (c: CheckerCtx) => void) {
|
|
46
|
-
// 显示层
|
|
47
|
-
const layer = this.opts.getCtx().get('layerManager').create(`checker-${new Date().getTime()}`)
|
|
48
|
-
layer.show()
|
|
49
|
-
|
|
50
|
-
// 构建 Checker 的上下文
|
|
51
|
-
const checkerStore: CheckerStore = {}
|
|
52
|
-
let hideInteractInput = false
|
|
53
|
-
const checkerCtx: CheckerCtx = {
|
|
54
|
-
set: (key, val) => { checkerStore[key] = val },
|
|
55
|
-
get: (key) => (checkerStore[key]),
|
|
56
|
-
getOpts: () => (this.opts),
|
|
57
|
-
getApi: () => this.opts.getApi(),
|
|
58
|
-
hideInteractInput: () => {
|
|
59
|
-
hideInteractInput = true
|
|
60
|
-
},
|
|
61
|
-
triggerSuccess: () => {
|
|
62
|
-
this.close(checker, layer)
|
|
63
|
-
if (checker.onSuccess) checker.onSuccess(checkerCtx, "", "", formEl)
|
|
64
|
-
if (payload.onSuccess) payload.onSuccess("", dialog.$el)
|
|
65
|
-
},
|
|
66
|
-
cancel: () => {
|
|
67
|
-
this.close(checker, layer)
|
|
68
|
-
if (payload.onCancel) payload.onCancel()
|
|
69
|
-
}
|
|
70
|
-
}
|
|
71
|
-
|
|
72
|
-
if (postFire) postFire(checkerCtx)
|
|
73
|
-
|
|
74
|
-
// 创建表单
|
|
75
|
-
const formEl = Utils.createElement()
|
|
76
|
-
formEl.appendChild(checker.body(checkerCtx))
|
|
77
|
-
|
|
78
|
-
// 输入框
|
|
79
|
-
const $input = Utils.createElement<HTMLInputElement>(
|
|
80
|
-
`<input id="check" type="${checker.inputType || 'text'}" autocomplete="off" required placeholder="">`
|
|
81
|
-
)
|
|
82
|
-
formEl.appendChild($input)
|
|
83
|
-
setTimeout(() => $input.focus(), 80) // 延迟 Focus
|
|
84
|
-
|
|
85
|
-
// 绑定键盘事件
|
|
86
|
-
$input.onkeyup = (evt) => {
|
|
87
|
-
if (evt.key === 'Enter' || evt.keyCode === 13) {
|
|
88
|
-
// 按下回车键
|
|
89
|
-
evt.preventDefault()
|
|
90
|
-
layer
|
|
91
|
-
.getEl()
|
|
92
|
-
.querySelector<HTMLButtonElement>('button[data-action="confirm"]')!
|
|
93
|
-
.click()
|
|
94
|
-
}
|
|
95
|
-
}
|
|
96
|
-
|
|
97
|
-
let btnTextOrg: string | undefined
|
|
98
|
-
const dialog = new Dialog(formEl)
|
|
99
|
-
|
|
100
|
-
// 确认按钮
|
|
101
|
-
dialog.setYes((btnEl) => {
|
|
102
|
-
const inputVal = $input.value.trim()
|
|
103
|
-
|
|
104
|
-
// 按钮操作
|
|
105
|
-
if (!btnTextOrg) btnTextOrg = btnEl.innerText
|
|
106
|
-
const btnTextSet = (btnText: string) => {
|
|
107
|
-
btnEl.innerText = btnText
|
|
108
|
-
btnEl.classList.add('error')
|
|
109
|
-
}
|
|
110
|
-
const btnTextRestore = () => {
|
|
111
|
-
btnEl.innerText = btnTextOrg || ''
|
|
112
|
-
btnEl.classList.remove('error')
|
|
113
|
-
}
|
|
114
|
-
|
|
115
|
-
btnEl.innerText = `${$t('loading')}...`
|
|
116
|
-
|
|
117
|
-
// 发送请求
|
|
118
|
-
checker
|
|
119
|
-
.request(checkerCtx, inputVal)
|
|
120
|
-
.then((data) => {
|
|
121
|
-
// 请求成功
|
|
122
|
-
this.close(checker, layer)
|
|
123
|
-
|
|
124
|
-
if (checker.onSuccess) checker.onSuccess(checkerCtx, data, inputVal, formEl)
|
|
125
|
-
if (payload.onSuccess) payload.onSuccess(inputVal, dialog.$el)
|
|
126
|
-
})
|
|
127
|
-
.catch((err) => {
|
|
128
|
-
// 请求失败
|
|
129
|
-
btnTextSet(String(err.msg || String(err)))
|
|
130
|
-
|
|
131
|
-
if (checker.onError) checker.onError(checkerCtx, err, inputVal, formEl)
|
|
132
|
-
|
|
133
|
-
// 错误显示 3s 后恢复按钮
|
|
134
|
-
const tf = setTimeout(() => btnTextRestore(), 3000)
|
|
135
|
-
$input.onfocus = () => {
|
|
136
|
-
btnTextRestore()
|
|
137
|
-
clearTimeout(tf)
|
|
138
|
-
}
|
|
139
|
-
})
|
|
140
|
-
|
|
141
|
-
return false
|
|
142
|
-
})
|
|
143
|
-
|
|
144
|
-
// 取消按钮
|
|
145
|
-
dialog.setNo(() => {
|
|
146
|
-
this.close(checker, layer)
|
|
147
|
-
if (payload.onCancel) payload.onCancel()
|
|
148
|
-
return false
|
|
149
|
-
})
|
|
150
|
-
|
|
151
|
-
if (hideInteractInput) {
|
|
152
|
-
$input.style.display = 'none'
|
|
153
|
-
dialog.$el.querySelector<HTMLElement>('.atk-layer-dialog-actions')!.style.display = 'none'
|
|
154
|
-
}
|
|
155
|
-
|
|
156
|
-
// 层装载 dialog 元素
|
|
157
|
-
layer.getEl().append(dialog.$el)
|
|
158
|
-
|
|
159
|
-
// onMount 回调
|
|
160
|
-
if (payload.onMount) payload.onMount(dialog.$el)
|
|
161
|
-
}
|
|
162
|
-
|
|
163
|
-
// 关闭 checker 对话框
|
|
164
|
-
private close(checker: Checker, layer: Layer) {
|
|
165
|
-
layer.destroy()
|
|
166
|
-
}
|
|
167
|
-
}
|
|
168
|
-
|
|
169
|
-
export interface Checker {
|
|
170
|
-
el?: HTMLElement
|
|
171
|
-
inputType?: 'password' | 'text'
|
|
172
|
-
body: (checker: CheckerCtx) => HTMLElement
|
|
173
|
-
request: (checker: CheckerCtx, inputVal: string) => Promise<string>
|
|
174
|
-
onSuccess?: (checker: CheckerCtx, respData: string, inputVal: string, formEl: HTMLElement) => void
|
|
175
|
-
onError?: (checker: CheckerCtx, err: any, inputVal: string, formEl: HTMLElement) => void
|
|
176
|
-
}
|
|
177
|
-
|
|
178
|
-
interface CheckerStore {
|
|
179
|
-
val?: string
|
|
180
|
-
img_data?: string
|
|
181
|
-
iframe?: string
|
|
182
|
-
}
|
|
183
|
-
|
|
184
|
-
export interface CheckerCtx {
|
|
185
|
-
get<K extends keyof CheckerStore>(key: K): CheckerStore[K]
|
|
186
|
-
set<K extends keyof CheckerStore>(key: K, val: CheckerStore[K]): void
|
|
187
|
-
getOpts(): CheckerLauncherOptions
|
|
188
|
-
getApi(): Api
|
|
189
|
-
hideInteractInput(): void
|
|
190
|
-
triggerSuccess(): void
|
|
191
|
-
cancel(): void
|
|
192
|
-
}
|
|
@@ -1,30 +0,0 @@
|
|
|
1
|
-
const darkModeMedia = window.matchMedia('(prefers-color-scheme: dark)')
|
|
2
|
-
let darkModeAutoFunc: (evt: MediaQueryListEvent) => void
|
|
3
|
-
|
|
4
|
-
export function applyDarkMode($els: HTMLElement[], darkMode: boolean|'auto') {
|
|
5
|
-
const apply = (d: boolean) => {
|
|
6
|
-
$els.forEach($el => updateClassName($el, d))
|
|
7
|
-
}
|
|
8
|
-
|
|
9
|
-
if (darkMode === 'auto') {
|
|
10
|
-
if (!darkModeAutoFunc) { // 自动切换夜间模式,事件监听
|
|
11
|
-
darkModeAutoFunc = (evt) => apply(evt.matches)
|
|
12
|
-
darkModeMedia.addEventListener('change', darkModeAutoFunc)
|
|
13
|
-
}
|
|
14
|
-
|
|
15
|
-
apply(darkModeMedia.matches)
|
|
16
|
-
} else {
|
|
17
|
-
// if the type of darkMode is boolean
|
|
18
|
-
if (darkModeAutoFunc) // 解除事件监听绑定
|
|
19
|
-
darkModeMedia.removeEventListener('change', darkModeAutoFunc)
|
|
20
|
-
|
|
21
|
-
apply(darkMode)
|
|
22
|
-
}
|
|
23
|
-
}
|
|
24
|
-
|
|
25
|
-
export const DarkModeClassName = 'atk-dark-mode'
|
|
26
|
-
|
|
27
|
-
function updateClassName($el: HTMLElement, darkMode: boolean) {
|
|
28
|
-
if (darkMode) $el.classList.add(DarkModeClassName)
|
|
29
|
-
else $el.classList.remove(DarkModeClassName)
|
|
30
|
-
}
|
package/src/components/dialog.ts
DELETED
|
@@ -1,62 +0,0 @@
|
|
|
1
|
-
import $t from '@/i18n'
|
|
2
|
-
import * as Utils from '../lib/utils'
|
|
3
|
-
|
|
4
|
-
type BtnClickHandler = (btnEl: HTMLElement, dialog: Dialog) => boolean|void
|
|
5
|
-
|
|
6
|
-
/**
|
|
7
|
-
* 对话框
|
|
8
|
-
*/
|
|
9
|
-
export default class Dialog {
|
|
10
|
-
public $el: HTMLElement
|
|
11
|
-
public $content: HTMLElement
|
|
12
|
-
public $actions: HTMLElement
|
|
13
|
-
|
|
14
|
-
constructor (contentEl: HTMLElement) {
|
|
15
|
-
this.$el = Utils.createElement(
|
|
16
|
-
`<div class="atk-layer-dialog-wrap">
|
|
17
|
-
<div class="atk-layer-dialog">
|
|
18
|
-
<div class="atk-layer-dialog-content"></div>
|
|
19
|
-
<div class="atk-layer-dialog-actions"></div>
|
|
20
|
-
</div>
|
|
21
|
-
</div>`
|
|
22
|
-
)
|
|
23
|
-
|
|
24
|
-
// 按钮
|
|
25
|
-
this.$actions = this.$el.querySelector<HTMLElement>('.atk-layer-dialog-actions')!
|
|
26
|
-
|
|
27
|
-
// 内容
|
|
28
|
-
this.$content = this.$el.querySelector('.atk-layer-dialog-content')!
|
|
29
|
-
this.$content.appendChild(contentEl)
|
|
30
|
-
}
|
|
31
|
-
|
|
32
|
-
/** 按钮 · 确定 */
|
|
33
|
-
public setYes(handler: BtnClickHandler) {
|
|
34
|
-
const btn = Utils.createElement<HTMLButtonElement>(
|
|
35
|
-
`<button data-action="confirm">${$t('confirm')}</button>`
|
|
36
|
-
)
|
|
37
|
-
btn.onclick = this.onBtnClick(handler)
|
|
38
|
-
this.$actions.appendChild(btn)
|
|
39
|
-
|
|
40
|
-
return this
|
|
41
|
-
}
|
|
42
|
-
|
|
43
|
-
/** 按钮 · 取消 */
|
|
44
|
-
public setNo(handler: BtnClickHandler) {
|
|
45
|
-
const btn = Utils.createElement<HTMLButtonElement>(
|
|
46
|
-
`<button data-action="cancel">${$t('cancel')}</button>`
|
|
47
|
-
)
|
|
48
|
-
btn.onclick = this.onBtnClick(handler)
|
|
49
|
-
this.$actions.appendChild(btn)
|
|
50
|
-
|
|
51
|
-
return this
|
|
52
|
-
}
|
|
53
|
-
|
|
54
|
-
private onBtnClick(handler: BtnClickHandler) {
|
|
55
|
-
return (evt: Event) => {
|
|
56
|
-
const re = handler(evt.currentTarget as HTMLElement, this)
|
|
57
|
-
if (re === undefined || re === true) {
|
|
58
|
-
this.$el.remove()
|
|
59
|
-
}
|
|
60
|
-
}
|
|
61
|
-
}
|
|
62
|
-
}
|