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.
Files changed (175) hide show
  1. package/README.md +1 -1
  2. package/dist/Artalk.css +1 -1
  3. package/dist/Artalk.es.js +209 -188
  4. package/dist/Artalk.es.js.map +1 -0
  5. package/dist/Artalk.iife.js +2 -1
  6. package/dist/Artalk.iife.js.map +1 -0
  7. package/dist/Artalk.js +2 -1
  8. package/dist/Artalk.js.map +1 -0
  9. package/dist/ArtalkLite.css +1 -1
  10. package/dist/ArtalkLite.es.js +209 -188
  11. package/dist/ArtalkLite.es.js.map +1 -0
  12. package/dist/ArtalkLite.iife.js +2 -1
  13. package/dist/ArtalkLite.iife.js.map +1 -0
  14. package/dist/ArtalkLite.js +2 -1
  15. package/dist/ArtalkLite.js.map +1 -0
  16. package/dist/i18n/jp.js +1 -1
  17. package/dist/i18n/zh-TW.js +1 -1
  18. package/dist/src/api/_base.d.ts +7 -0
  19. package/dist/src/api/_options.d.ts +5 -0
  20. package/dist/src/artalk.d.ts +0 -2
  21. package/dist/src/components/checker/index.d.ts +2 -0
  22. package/dist/src/i18n/en.d.ts +4 -0
  23. package/dist/src/i18n/external.d.ts +4 -0
  24. package/dist/src/i18n/index.d.ts +12 -0
  25. package/dist/src/i18n/jp.d.ts +4 -0
  26. package/dist/src/i18n/zh-TW.d.ts +4 -0
  27. package/dist/src/lib/user.d.ts +8 -6
  28. package/dist/src/main.d.ts +3 -0
  29. package/dist/src/plugins/editor/_kit.d.ts +7 -1
  30. package/dist/src/service.d.ts +2 -8
  31. package/dist/types/event.d.ts +1 -1
  32. package/package.json +43 -17
  33. package/dist/src/components/dark-mode.d.ts +0 -2
  34. package/src/api/_base.ts +0 -18
  35. package/src/api/_options.ts +0 -25
  36. package/src/api/_request.ts +0 -104
  37. package/src/api/admin.ts +0 -18
  38. package/src/api/captcha.ts +0 -24
  39. package/src/api/comment.ts +0 -84
  40. package/src/api/index.ts +0 -29
  41. package/src/api/page.ts +0 -83
  42. package/src/api/site.ts +0 -51
  43. package/src/api/system.ts +0 -49
  44. package/src/api/upload.ts +0 -28
  45. package/src/api/user.ts +0 -132
  46. package/src/artalk.ts +0 -119
  47. package/src/comment/actions.ts +0 -83
  48. package/src/comment/comment.html +0 -18
  49. package/src/comment/comment.ts +0 -192
  50. package/src/comment/height-limit.ts +0 -100
  51. package/src/comment/index.ts +0 -3
  52. package/src/comment/render.ts +0 -150
  53. package/src/comment/renders/actions.ts +0 -114
  54. package/src/comment/renders/avatar.ts +0 -22
  55. package/src/comment/renders/content.ts +0 -39
  56. package/src/comment/renders/header.ts +0 -84
  57. package/src/comment/renders/index.ts +0 -19
  58. package/src/comment/renders/pending.ts +0 -12
  59. package/src/comment/renders/reply-at.ts +0 -16
  60. package/src/comment/renders/reply-to.ts +0 -24
  61. package/src/components/action-btn.ts +0 -170
  62. package/src/components/checker/admin.ts +0 -37
  63. package/src/components/checker/captcha-renders.ts +0 -69
  64. package/src/components/checker/captcha.ts +0 -26
  65. package/src/components/checker/index.ts +0 -192
  66. package/src/components/dark-mode.ts +0 -30
  67. package/src/components/dialog.ts +0 -62
  68. package/src/components/error-dialog.ts +0 -35
  69. package/src/components/pagination.ts +0 -153
  70. package/src/components/read-more-btn.ts +0 -92
  71. package/src/config.ts +0 -119
  72. package/src/context.ts +0 -146
  73. package/src/data.ts +0 -110
  74. package/src/defaults.ts +0 -61
  75. package/src/editor/editor.html +0 -18
  76. package/src/editor/editor.ts +0 -114
  77. package/src/editor/state.ts +0 -52
  78. package/src/editor/ui.ts +0 -36
  79. package/src/i18n/en.ts +0 -81
  80. package/src/i18n/external.ts +0 -10
  81. package/src/i18n/index.ts +0 -67
  82. package/src/i18n/jp.ts +0 -83
  83. package/src/i18n/zh-CN.ts +0 -85
  84. package/src/i18n/zh-TW.ts +0 -83
  85. package/src/layer/index.ts +0 -4
  86. package/src/layer/layer-manager.ts +0 -32
  87. package/src/layer/layer.ts +0 -39
  88. package/src/layer/scrollbar-helper.ts +0 -24
  89. package/src/layer/sidebar-layer.html +0 -8
  90. package/src/layer/sidebar-layer.ts +0 -155
  91. package/src/layer/wrap.ts +0 -77
  92. package/src/lib/component.ts +0 -12
  93. package/src/lib/detect.ts +0 -222
  94. package/src/lib/event-manager.ts +0 -47
  95. package/src/lib/highlight.ts +0 -5
  96. package/src/lib/marked-renderer.ts +0 -32
  97. package/src/lib/marked.ts +0 -72
  98. package/src/lib/sanitizer.ts +0 -57
  99. package/src/lib/ui.ts +0 -193
  100. package/src/lib/user.ts +0 -55
  101. package/src/lib/utils.ts +0 -236
  102. package/src/list/comment.ts +0 -20
  103. package/src/list/layout.ts +0 -120
  104. package/src/list/list.html +0 -20
  105. package/src/list/list.ts +0 -79
  106. package/src/list/nest.ts +0 -66
  107. package/src/list/page.ts +0 -97
  108. package/src/list/paginator/index.ts +0 -25
  109. package/src/list/paginator/read-more.ts +0 -67
  110. package/src/list/paginator/up-down.ts +0 -51
  111. package/src/main.ts +0 -5
  112. package/src/plugins/admin-only-elem.ts +0 -40
  113. package/src/plugins/conf-remoter.ts +0 -54
  114. package/src/plugins/dark-mode.ts +0 -12
  115. package/src/plugins/editor/_kit.ts +0 -57
  116. package/src/plugins/editor/_plug.ts +0 -60
  117. package/src/plugins/editor/_sample.ts +0 -8
  118. package/src/plugins/editor/closable.ts +0 -44
  119. package/src/plugins/editor/emoticons.scss +0 -72
  120. package/src/plugins/editor/emoticons.ts +0 -293
  121. package/src/plugins/editor/header-event.ts +0 -35
  122. package/src/plugins/editor/header-link.ts +0 -31
  123. package/src/plugins/editor/header-user.ts +0 -98
  124. package/src/plugins/editor/index.ts +0 -40
  125. package/src/plugins/editor/local-storage.ts +0 -36
  126. package/src/plugins/editor/mover.ts +0 -29
  127. package/src/plugins/editor/preview.scss +0 -7
  128. package/src/plugins/editor/preview.ts +0 -41
  129. package/src/plugins/editor/state-edit.ts +0 -116
  130. package/src/plugins/editor/state-reply.ts +0 -91
  131. package/src/plugins/editor/submit-add.ts +0 -33
  132. package/src/plugins/editor/submit-btn.ts +0 -25
  133. package/src/plugins/editor/submit.ts +0 -73
  134. package/src/plugins/editor/textarea.ts +0 -55
  135. package/src/plugins/editor/upload.ts +0 -145
  136. package/src/plugins/editor-kit.ts +0 -161
  137. package/src/plugins/index.ts +0 -16
  138. package/src/plugins/list/copyright.ts +0 -16
  139. package/src/plugins/list/count.ts +0 -31
  140. package/src/plugins/list/dropdown.ts +0 -95
  141. package/src/plugins/list/error-dialog.ts +0 -22
  142. package/src/plugins/list/fetch.ts +0 -64
  143. package/src/plugins/list/goto-first.ts +0 -23
  144. package/src/plugins/list/goto.ts +0 -72
  145. package/src/plugins/list/index.ts +0 -25
  146. package/src/plugins/list/loading.ts +0 -17
  147. package/src/plugins/list/no-comment.ts +0 -25
  148. package/src/plugins/list/reach-bottom.ts +0 -46
  149. package/src/plugins/list/sidebar-btn.ts +0 -39
  150. package/src/plugins/list/time-ticking.ts +0 -22
  151. package/src/plugins/list/unread-badge.ts +0 -26
  152. package/src/plugins/list/unread.ts +0 -38
  153. package/src/plugins/list/with-editor.ts +0 -59
  154. package/src/plugins/markdown.ts +0 -10
  155. package/src/plugins/stat.ts +0 -79
  156. package/src/plugins/version-check.ts +0 -37
  157. package/src/service.ts +0 -91
  158. package/src/style/_color.scss +0 -41
  159. package/src/style/_extend.scss +0 -20
  160. package/src/style/_variables.scss +0 -3
  161. package/src/style/comment.scss +0 -360
  162. package/src/style/editor.scss +0 -194
  163. package/src/style/list.scss +0 -212
  164. package/src/style/main.scss +0 -486
  165. package/src/style/pagination.scss +0 -58
  166. package/src/style/sidebar-layer.scss +0 -92
  167. package/types/config.ts +0 -153
  168. package/types/context.ts +0 -84
  169. package/types/data.ts +0 -271
  170. package/types/editor.ts +0 -95
  171. package/types/event.ts +0 -40
  172. package/types/global.d.ts +0 -1
  173. package/types/index.ts +0 -7
  174. package/types/plugin.ts +0 -3
  175. 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
- }
@@ -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
- }