artalk 2.4.3 → 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.
Files changed (145) hide show
  1. package/README.md +27 -0
  2. package/dist/Artalk.css +1 -1
  3. package/dist/Artalk.es.js +4895 -4067
  4. package/dist/Artalk.iife.js +1 -1
  5. package/dist/Artalk.js +1 -1
  6. package/dist/ArtalkLite.css +1 -1
  7. package/dist/ArtalkLite.es.js +2496 -1779
  8. package/dist/ArtalkLite.iife.js +1 -1
  9. package/dist/ArtalkLite.js +1 -1
  10. package/dist/i18n/jp.js +1 -1
  11. package/dist/i18n/zh-TW.js +1 -1
  12. package/dist/src/api/index.d.ts +2 -2
  13. package/dist/src/api/system.d.ts +5 -2
  14. package/dist/src/artalk.d.ts +42 -34
  15. package/dist/src/comment/comment.d.ts +2 -2
  16. package/dist/src/comment/height-limit.d.ts +30 -0
  17. package/dist/src/comment/render-ctx.d.ts +23 -0
  18. package/dist/src/comment/render.d.ts +2 -50
  19. package/dist/src/comment/renders/actions.d.ts +5 -0
  20. package/dist/src/comment/renders/avatar.d.ts +5 -0
  21. package/dist/src/comment/renders/content.d.ts +5 -0
  22. package/dist/src/comment/renders/header.d.ts +5 -0
  23. package/dist/src/comment/renders/index.d.ts +2 -0
  24. package/dist/src/comment/renders/pending.d.ts +5 -0
  25. package/dist/src/comment/renders/reply-at.d.ts +5 -0
  26. package/dist/src/comment/renders/reply-to.d.ts +5 -0
  27. package/dist/src/components/dialog.d.ts +1 -1
  28. package/dist/src/config.d.ts +8 -0
  29. package/dist/src/context.d.ts +15 -29
  30. package/dist/src/editor/edit-mode.d.ts +9 -0
  31. package/dist/src/editor/editor-ui.d.ts +25 -0
  32. package/dist/src/editor/editor.d.ts +37 -45
  33. package/dist/src/editor/funcs.d.ts +2 -0
  34. package/dist/src/editor/mover.d.ts +8 -0
  35. package/dist/src/editor/plug-manager.d.ts +17 -0
  36. package/dist/src/editor/plugs/editor-plug.d.ts +13 -1
  37. package/dist/src/editor/reply.d.ts +9 -0
  38. package/dist/src/editor/submit.d.ts +16 -0
  39. package/dist/src/editor/ui.d.ts +25 -0
  40. package/dist/src/i18n/index.d.ts +11 -7
  41. package/dist/src/layer/index.d.ts +2 -2
  42. package/dist/src/layer/layer.d.ts +1 -1
  43. package/dist/src/lib/checker/captcha-renders.d.ts +5 -0
  44. package/dist/src/lib/checker/index.d.ts +18 -10
  45. package/dist/src/lib/dark-mode.d.ts +4 -0
  46. package/dist/src/lib/marked.d.ts +9 -0
  47. package/dist/src/lib/utils.d.ts +1 -5
  48. package/dist/src/list/list-lite.d.ts +15 -11
  49. package/dist/src/list/list-nest.d.ts +2 -2
  50. package/dist/src/list/list-ui.d.ts +7 -0
  51. package/dist/src/list/paginator/adaptors/index.d.ts +12 -0
  52. package/dist/src/list/paginator/adaptors/pagination.d.ts +9 -0
  53. package/dist/src/list/paginator/adaptors/read-more.d.ts +10 -0
  54. package/dist/src/list/paginator/holder.d.ts +16 -0
  55. package/dist/src/list/paginator/index.d.ts +10 -0
  56. package/dist/src/service.d.ts +40 -0
  57. package/dist/types/artalk-config.d.ts +5 -2
  58. package/dist/types/artalk-data.d.ts +3 -3
  59. package/dist/types/context.d.ts +11 -17
  60. package/dist/types/global.d.ts +1 -0
  61. package/package.json +6 -7
  62. package/src/api/system.ts +3 -12
  63. package/src/artalk.ts +101 -158
  64. package/src/comment/comment.ts +7 -6
  65. package/src/comment/height-limit.ts +100 -0
  66. package/src/comment/render-ctx.ts +30 -0
  67. package/src/comment/render.ts +31 -375
  68. package/src/comment/renders/actions.ts +114 -0
  69. package/src/comment/renders/avatar.ts +22 -0
  70. package/src/comment/renders/content.ts +39 -0
  71. package/src/comment/renders/header.ts +84 -0
  72. package/src/comment/renders/index.ts +19 -0
  73. package/src/comment/renders/pending.ts +12 -0
  74. package/src/comment/renders/reply-at.ts +16 -0
  75. package/src/comment/renders/reply-to.ts +24 -0
  76. package/src/config.ts +65 -0
  77. package/src/context.ts +31 -88
  78. package/src/defaults.ts +1 -0
  79. package/src/editor/edit-mode.ts +102 -0
  80. package/src/editor/editor.ts +100 -394
  81. package/src/editor/funcs.ts +96 -0
  82. package/src/editor/mover.ts +43 -0
  83. package/src/editor/plug-manager.ts +172 -0
  84. package/src/editor/plugs/editor-plug.ts +20 -2
  85. package/src/editor/plugs/{emoticons-plug.less → emoticons-plug.scss} +5 -4
  86. package/src/editor/plugs/emoticons-plug.ts +2 -1
  87. package/src/editor/plugs/header-input-plug.ts +5 -5
  88. package/src/editor/plugs/{preview-plug.less → preview-plug.scss} +1 -1
  89. package/src/editor/plugs/preview-plug.ts +8 -4
  90. package/src/editor/plugs/upload-plug.ts +10 -13
  91. package/src/editor/reply.ts +62 -0
  92. package/src/editor/submit.ts +98 -0
  93. package/src/editor/ui.ts +36 -0
  94. package/src/i18n/index.ts +21 -10
  95. package/src/layer/index.ts +2 -2
  96. package/src/layer/layer.ts +4 -4
  97. package/src/layer/sidebar-layer.ts +2 -1
  98. package/src/lib/checker/admin.ts +36 -0
  99. package/src/lib/checker/captcha-renders.ts +68 -0
  100. package/src/lib/checker/captcha.ts +26 -0
  101. package/src/lib/checker/index.ts +38 -20
  102. package/src/lib/dark-mode.ts +48 -0
  103. package/src/lib/marked.ts +133 -0
  104. package/src/lib/utils.ts +1 -123
  105. package/src/list/list-lite.ts +59 -162
  106. package/src/list/list-ui.ts +80 -0
  107. package/src/list/list.ts +16 -8
  108. package/src/list/paginator/adaptors/index.ts +21 -0
  109. package/src/list/paginator/adaptors/pagination.ts +42 -0
  110. package/src/list/paginator/adaptors/read-more.ts +56 -0
  111. package/src/list/paginator/holder.ts +55 -0
  112. package/src/list/paginator/index.ts +13 -0
  113. package/src/service.ts +118 -0
  114. package/src/style/{_color.less → _color.scss} +3 -3
  115. package/src/style/{_extend.less → _extend.scss} +1 -1
  116. package/src/style/_variables.scss +3 -0
  117. package/src/style/{comment.less → comment.scss} +36 -12
  118. package/src/style/{editor.less → editor.scss} +11 -11
  119. package/src/style/{list.less → list.scss} +8 -6
  120. package/src/style/{main.less → main.scss} +24 -23
  121. package/src/style/{sidebar-layer.less → sidebar-layer.scss} +8 -8
  122. package/types/artalk-config.d.ts +5 -2
  123. package/types/artalk-data.d.ts +3 -3
  124. package/types/context.d.ts +11 -17
  125. package/types/global.d.ts +1 -0
  126. package/CNAME +0 -1
  127. package/LICENSE +0 -165
  128. package/index.html +0 -157
  129. package/postcss.config.js +0 -5
  130. package/scripts/build-i18n.mjs +0 -46
  131. package/src/lib/checker/admin-checker.ts +0 -36
  132. package/src/lib/checker/captcha-checker.ts +0 -84
  133. package/src/style/_variables.less +0 -3
  134. package/test/ArtalkCount.html +0 -16
  135. package/test/ArtalkI18n.html +0 -16
  136. package/test/ArtalkLite.html +0 -15
  137. package/test/CSRF.html +0 -26
  138. package/tsconfig.json +0 -12
  139. package/vite-base.config.ts +0 -21
  140. package/vite-demo.config.ts +0 -12
  141. package/vite-lite.config.ts +0 -22
  142. package/vite.config.ts +0 -27
  143. /package/dist/src/lib/checker/{admin-checker.d.ts → admin.d.ts} +0 -0
  144. /package/dist/src/lib/checker/{captcha-checker.d.ts → captcha.d.ts} +0 -0
  145. /package/src/style/{pagination.less → pagination.scss} +0 -0
@@ -0,0 +1,84 @@
1
+ import * as Utils from '../../lib/utils'
2
+ import RenderCtx from '../render-ctx'
3
+
4
+ /**
5
+ * 评论头部界面
6
+ */
7
+ export default function renderHeader(ctx: RenderCtx) {
8
+ Object.entries({
9
+ renderNick, renderVerifyBadge, renderDate, renderUABadge
10
+ }).forEach(([name, render]) => {
11
+ render(ctx)
12
+ })
13
+ }
14
+
15
+ function renderNick(ctx: RenderCtx) {
16
+ ctx.$headerNick = ctx.$el.querySelector<HTMLElement>('.atk-nick')!
17
+
18
+ if (ctx.data.link) {
19
+ const $nickA = Utils.createElement<HTMLLinkElement>('<a target="_blank" rel="noreferrer noopener nofollow"></a>')
20
+ $nickA.innerText = ctx.data.nick
21
+ $nickA.href = Utils.isValidURL(ctx.data.link) ? ctx.data.link : `https://${ctx.data.link}`
22
+ ctx.$headerNick.append($nickA)
23
+ } else {
24
+ ctx.$headerNick.innerText = ctx.data.nick
25
+ }
26
+ }
27
+
28
+ function renderVerifyBadge(ctx: RenderCtx) {
29
+ ctx.$headerBadgeWrap = ctx.$el.querySelector<HTMLElement>('.atk-badge-wrap')!
30
+ ctx.$headerBadgeWrap.innerHTML = ''
31
+
32
+ const badgeText = ctx.data.badge_name
33
+ const badgeColor = ctx.data.badge_color
34
+ if (badgeText) {
35
+ const $badge = Utils.createElement(`<span class="atk-badge"></span>`)
36
+ $badge.innerText = badgeText.replace('管理员', ctx.ctx.$t('admin')) // i18n patch
37
+ $badge.style.backgroundColor = badgeColor || ''
38
+ ctx.$headerBadgeWrap.append($badge)
39
+ }
40
+
41
+ if (ctx.data.is_pinned) {
42
+ const $pinnedBadge = Utils.createElement(`<span class="atk-pinned-badge">${ctx.ctx.$t('pin')}</span>`) // 置顶徽章
43
+ ctx.$headerBadgeWrap.append($pinnedBadge)
44
+ }
45
+ }
46
+
47
+ function renderDate(ctx: RenderCtx) {
48
+ const $date = ctx.$el.querySelector<HTMLElement>('.atk-date')!
49
+ $date.innerText = ctx.comment.getDateFormatted()
50
+ $date.setAttribute('data-atk-comment-date', String(+new Date(ctx.data.date)))
51
+ }
52
+
53
+ function renderUABadge(ctx: RenderCtx) {
54
+ if (!ctx.ctx.conf.uaBadge && !ctx.data.ip_region) return
55
+
56
+ let $uaWrap = ctx.$header.querySelector('atk-ua-wrap')
57
+ if (!$uaWrap) {
58
+ $uaWrap = Utils.createElement(`<span class="atk-ua-wrap"></span>`)
59
+ ctx.$header.append($uaWrap)
60
+ }
61
+
62
+ $uaWrap.innerHTML = ''
63
+
64
+ if (ctx.data.ip_region) {
65
+ const $regionBadge = Utils.createElement(`<span class="atk-region-badge"></span>`)
66
+ $regionBadge.innerText = ctx.data.ip_region
67
+ $uaWrap.append($regionBadge)
68
+ }
69
+
70
+ if (ctx.ctx.conf.uaBadge) {
71
+ const { browser, os } = ctx.comment.getUserUA()
72
+ if (String(browser).trim()) {
73
+ const $uaBrowser = Utils.createElement(`<span class="atk-ua ua-browser"></span>`)
74
+ $uaBrowser.innerText = browser
75
+ $uaWrap.append($uaBrowser)
76
+ }
77
+
78
+ if (String(os).trim()) {
79
+ const $usOS = Utils.createElement(`<span class="atk-ua ua-os"></span>`)
80
+ $usOS.innerText = os
81
+ $uaWrap.append($usOS)
82
+ }
83
+ }
84
+ }
@@ -0,0 +1,19 @@
1
+ import RenderCtx from '../render-ctx'
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(ctx: RenderCtx) {
16
+ Object.entries(Renders).forEach(([ name, render ]) => {
17
+ render(ctx)
18
+ })
19
+ }
@@ -0,0 +1,12 @@
1
+ import * as Utils from '../../lib/utils'
2
+ import RenderCtx from '../render-ctx'
3
+
4
+ /**
5
+ * 待审核状态界面
6
+ */
7
+ export default function renderPending(ctx: RenderCtx) {
8
+ if (!ctx.data.is_pending) return
9
+
10
+ const pendingEl = Utils.createElement(`<div class="atk-pending">${ctx.ctx.$t('pendingMsg')}</div>`)
11
+ ctx.$body.prepend(pendingEl)
12
+ }
@@ -0,0 +1,16 @@
1
+ import * as Utils from '../../lib/utils'
2
+ import RenderCtx from '../render-ctx'
3
+
4
+ /**
5
+ * 层级嵌套模式显示 AT 界面
6
+ */
7
+ export default function renderReplyAt(ctx: RenderCtx) {
8
+ if (ctx.cConf.isFlatMode || ctx.data.rid === 0) return // not 平铺模式 或 根评论
9
+ if (!ctx.cConf.replyTo) return
10
+
11
+ ctx.$replyAt = Utils.createElement(`<span class="atk-item atk-reply-at"><span class="atk-arrow"></span><span class="atk-nick"></span></span>`)
12
+ ctx.$replyAt.querySelector<HTMLElement>('.atk-nick')!.innerText = `${ctx.cConf.replyTo.nick}`
13
+ ctx.$replyAt.onclick = () => { ctx.comment.getActions().goToReplyComment() }
14
+
15
+ ctx.$headerBadgeWrap.insertAdjacentElement('afterend', ctx.$replyAt)
16
+ }
@@ -0,0 +1,24 @@
1
+ import * as Utils from '../../lib/utils'
2
+ import marked from '../../lib/marked'
3
+ import RenderCtx from '../render-ctx'
4
+
5
+ /**
6
+ * 回复的对象界面
7
+ */
8
+ export default function renderReplyTo(ctx: RenderCtx) {
9
+ if (!ctx.cConf.isFlatMode) return // 仅平铺模式显示
10
+ if (!ctx.cConf.replyTo) return
11
+
12
+ ctx.$replyTo = Utils.createElement(`
13
+ <div class="atk-reply-to">
14
+ <div class="atk-meta">${ctx.ctx.$t('reply')} <span class="atk-nick"></span>:</div>
15
+ <div class="atk-content"></div>
16
+ </div>`)
17
+ const $nick = ctx.$replyTo.querySelector<HTMLElement>('.atk-nick')!
18
+ $nick.innerText = `@${ctx.cConf.replyTo.nick}`
19
+ $nick.onclick = () => { ctx.comment.getActions().goToReplyComment() }
20
+ let replyContent = marked(ctx.ctx, ctx.cConf.replyTo.content)
21
+ if (ctx.cConf.replyTo.is_collapsed) replyContent = `[${ctx.ctx.$t('collapsed')}]`
22
+ ctx.$replyTo.querySelector<HTMLElement>('.atk-content')!.innerHTML = replyContent
23
+ ctx.$body.prepend(ctx.$replyTo)
24
+ }
package/src/config.ts ADDED
@@ -0,0 +1,65 @@
1
+ import type ArtalkConfig from '~/types/artalk-config'
2
+ import * as Utils from './lib/utils'
3
+ import Defaults from './defaults'
4
+
5
+ export default { handelBaseConf }
6
+
7
+ /** 基本配置初始化 */
8
+ export function handelBaseConf(customConf: Partial<ArtalkConfig>): ArtalkConfig {
9
+ // 合并默认配置
10
+ const conf: ArtalkConfig = Utils.mergeDeep(Defaults, customConf)
11
+
12
+ // 绑定元素
13
+ if (typeof conf.el === 'string' && !!conf.el) {
14
+ try {
15
+ const findEl = document.querySelector<HTMLElement>(conf.el)
16
+ if (!findEl) throw Error(`Target element "${conf.el}" was not found.`)
17
+ conf.el = findEl
18
+ } catch (e) {
19
+ console.error(e)
20
+ throw new Error('Please check your Artalk `el` config.')
21
+ }
22
+ }
23
+
24
+ // 服务器配置
25
+ conf.server = conf.server.replace(/\/$/, '').replace(/\/api\/?$/, '')
26
+
27
+ // 默认 pageKey
28
+ if (!conf.pageKey) {
29
+ // @link http://bl.ocks.org/abernier/3070589
30
+ conf.pageKey = `${window.location.pathname}`
31
+ }
32
+
33
+ // 默认 pageTitle
34
+ if (!conf.pageTitle) {
35
+ conf.pageTitle = `${document.title}`
36
+ }
37
+
38
+ // 自适应语言
39
+ if (conf.locale === 'auto') {
40
+ conf.locale = navigator.language
41
+ }
42
+
43
+ return conf
44
+ }
45
+
46
+ export function handleBackendRefConf(conf: Partial<ArtalkConfig>) {
47
+ const DisabledKeys: (keyof ArtalkConfig)[] = [
48
+ 'el', 'pageKey', 'pageTitle', 'server', 'site', 'darkMode'
49
+ ]
50
+ Object.keys(conf).forEach(k => {
51
+ if (DisabledKeys.includes(k as any)) delete conf[k]
52
+ })
53
+
54
+ // Patch: `emoticons` config string to json
55
+ if (conf.emoticons && typeof conf.emoticons === "string") {
56
+ conf.emoticons = conf.emoticons.trim()
57
+ if (conf.emoticons.startsWith("[") || conf.emoticons.startsWith("{")) {
58
+ conf.emoticons = JSON.parse(conf.emoticons) // pase json
59
+ } else if (conf.emoticons === "false") {
60
+ conf.emoticons = false
61
+ }
62
+ }
63
+
64
+ return conf
65
+ }
package/src/context.ts CHANGED
@@ -1,37 +1,31 @@
1
- import { marked as libMarked } from 'marked'
2
- import ArtalkConfig from '~/types/artalk-config'
3
- import { CommentData, NotifyData } from '~/types/artalk-data'
4
- import { Event } from '~/types/event'
5
- import getI18n, { I18n } from './i18n'
6
- import User from './lib/user'
1
+ import type ArtalkConfig from '~/types/artalk-config'
2
+ import type { CommentData, NotifyData } from '~/types/artalk-data'
3
+ import type { Event } from '~/types/event'
4
+ import type ContextApi from '~/types/context'
5
+ import type { TInjectedServices } from './service'
6
+
7
7
  import * as Utils from './lib/utils'
8
- import ContextApi from '../types/context'
9
- import Editor from './editor'
8
+ import * as DarkMode from './lib/dark-mode'
9
+ import * as marked from './lib/marked'
10
+ import { CheckerCaptchaPayload, CheckerPayload } from './lib/checker'
11
+
12
+ import * as I18n from './i18n'
13
+ import { getLayerWrap } from './layer'
14
+ import { SidebarShowPayload } from './layer/sidebar-layer'
10
15
  import Comment from './comment'
11
- import ListLite from './list/list-lite'
12
- import SidebarLayer, { SidebarShowPayload } from './layer/sidebar-layer'
13
- import CheckerLauncher, { CheckerCaptchaPayload, CheckerPayload } from './lib/checker'
14
- import Layer, { GetLayerWrap } from './layer'
15
16
  import Api from './api'
16
17
  import List from './list'
17
18
 
19
+ // Auto dependency injection
20
+ interface Context extends TInjectedServices { }
21
+
18
22
  /**
19
23
  * Artalk Context
20
24
  */
21
- export default class Context implements ContextApi {
22
- /* 持有同事类 */
23
- private api!: Api
24
- private editor!: Editor
25
- private list?: ListLite
26
- private sidebarLayer!: SidebarLayer
27
- private checkerLauncher!: CheckerLauncher
28
-
25
+ class Context implements ContextApi {
29
26
  /* 运行参数 */
30
- public cid: number // Context 唯一标识
31
27
  public conf: ArtalkConfig
32
- public user: User
33
28
  public $root: HTMLElement
34
- public markedInstance?: typeof libMarked
35
29
  public markedReplacers: ((raw: string) => string)[] = []
36
30
 
37
31
  private commentList: Comment[] = [] // Note: 无层级结构 + 无须排列
@@ -40,41 +34,17 @@ export default class Context implements ContextApi {
40
34
  private eventList: Event[] = []
41
35
 
42
36
  public constructor(conf: ArtalkConfig, $root?: HTMLElement) {
43
- this.cid = +new Date()
44
37
  this.conf = conf
45
- this.user = new User(this)
46
38
 
47
39
  this.$root = $root || document.createElement('div')
48
- this.$root.setAttribute('atk-run-id', this.cid.toString())
49
40
  this.$root.classList.add('artalk')
50
41
  this.$root.innerHTML = ''
51
42
 
52
43
  this.api = new Api(this)
53
-
54
- this.on('conf-loaded', () => {
55
- this.refreshDarkModeConf()
56
- })
57
- }
58
-
59
- /* 设置持有的同事类 */
60
- public setApi(api: Api): void {
61
- this.api = api
62
- }
63
-
64
- public setEditor(editor: Editor): void {
65
- this.editor = editor
66
- }
67
-
68
- public setList(list: ListLite): void {
69
- this.list = list
70
44
  }
71
45
 
72
- public setSidebarLayer(sidebarLayer: SidebarLayer): void {
73
- this.sidebarLayer = sidebarLayer
74
- }
75
-
76
- public setCheckerLauncher(checkerLauncher: CheckerLauncher): void {
77
- this.checkerLauncher = checkerLauncher
46
+ public inject(depName: string, obj: any) {
47
+ this[depName] = obj
78
48
  }
79
49
 
80
50
  public getApi() {
@@ -164,7 +134,7 @@ export default class Context implements ContextApi {
164
134
  }
165
135
 
166
136
  public listHashGotoCheck(): void {
167
- if (!this.list || this.list !instanceof List) return
137
+ if (!this.list || !(this.list instanceof List)) return
168
138
  const list = this.list as List
169
139
 
170
140
  list.goToCommentDelay = false
@@ -224,7 +194,7 @@ export default class Context implements ContextApi {
224
194
  this.$root.querySelectorAll<HTMLElement>(`[atk-only-admin-show]`).forEach(item => items.push(item))
225
195
 
226
196
  // for layer
227
- const { $wrap: $layerWrap } = GetLayerWrap(this)
197
+ const { $wrap: $layerWrap } = getLayerWrap()
228
198
  if ($layerWrap) $layerWrap.querySelectorAll<HTMLElement>(`[atk-only-admin-show]`).forEach(item => items.push(item))
229
199
 
230
200
  // for sidebar
@@ -258,49 +228,22 @@ export default class Context implements ContextApi {
258
228
  }
259
229
 
260
230
  /* i18n */
261
- public $t(key: keyof I18n, args: {[key: string]: string} = {}): string {
262
- return getI18n(this.conf.locale, key, args)
231
+ public $t(key: I18n.I18nKeys, args: {[key: string]: string} = {}): string {
232
+ return I18n.t(key, args)
263
233
  }
264
234
 
265
235
  public setDarkMode(darkMode: boolean): void {
266
- if (this.conf.darkMode === darkMode) return
267
-
268
- const darkModeClassName = 'atk-dark-mode'
269
-
270
- this.conf.darkMode = darkMode
271
-
272
- if (darkMode) this.$root.classList.add(darkModeClassName)
273
- else this.$root.classList.remove(darkModeClassName)
274
-
275
- // for Layer
276
- const { $wrap: $layerWrap } = GetLayerWrap(this)
277
- if ($layerWrap) {
278
- if (darkMode) $layerWrap.classList.add(darkModeClassName)
279
- else $layerWrap.classList.remove(darkModeClassName)
280
- }
236
+ DarkMode.setDarkMode(this, darkMode)
281
237
  }
282
238
 
283
- private darkModeMedia = window.matchMedia('(prefers-color-scheme: dark)')
284
- private darkModeAutoFunc?: (evt: MediaQueryListEvent) => void
285
- private refreshDarkModeConf(): void {
286
- if (this.conf.darkMode === 'auto') {
287
- // 自动切换暗黑模式,事件监听
288
- this.setDarkMode(this.darkModeMedia.matches)
289
- if (!this.darkModeAutoFunc) {
290
- this.darkModeAutoFunc = (evt) => { this.setDarkMode(evt.matches) }
291
- this.darkModeMedia.addEventListener('change', this.darkModeAutoFunc)
292
- }
293
- } else {
294
- if (this.darkModeAutoFunc) {
295
- // 解除事件监听绑定
296
- this.darkModeMedia.removeEventListener('change', this.darkModeAutoFunc)
297
- }
298
- this.setDarkMode(this.conf.darkMode || false)
299
- }
239
+ public updateConf(nConf: Partial<ArtalkConfig>): void {
240
+ this.conf = Utils.mergeDeep(this.conf, nConf)
241
+ this.trigger('conf-loaded')
300
242
  }
301
243
 
302
- public updateConf(conf: Partial<ArtalkConfig>): void {
303
- this.conf = Utils.mergeDeep(this.conf, conf)
304
- this.trigger('conf-loaded')
244
+ public getMarkedInstance() {
245
+ return marked.getInstance()
305
246
  }
306
247
  }
248
+
249
+ export default Context
package/src/defaults.ts CHANGED
@@ -41,6 +41,7 @@ const defaults: ArtalkConfig = {
41
41
  heightLimit: {
42
42
  content: 300,
43
43
  children: 400,
44
+ scrollable: false,
44
45
  },
45
46
 
46
47
  imgUpload: true,
@@ -0,0 +1,102 @@
1
+ import type { CommentData } from '~/types/artalk-data'
2
+ import * as Utils from '../lib/utils'
3
+ import Editor from './editor'
4
+
5
+ export interface EditModeManager {
6
+ editor: Editor
7
+ comment?: CommentData
8
+ setEdit: (comment: CommentData, $comment: HTMLElement) => void
9
+ cancelEdit: () => void
10
+ }
11
+
12
+ export function createEditModeManager(editor: Editor) {
13
+ const m: EditModeManager = {
14
+ editor,
15
+ comment: undefined,
16
+ setEdit: (c, e) => edit(m, c, e),
17
+ cancelEdit: () => cancelEdit(m)
18
+ }
19
+
20
+ initEditModeSubmit(m)
21
+
22
+ return m
23
+ }
24
+
25
+ function edit(m: EditModeManager, comment: CommentData, $comment: HTMLElement) {
26
+ cancelEdit(m)
27
+ m.editor.cancelReply()
28
+
29
+ const ui = m.editor.getUI()
30
+ if (!ui.$editCancelBtn) {
31
+ const $btn = Utils.createElement(
32
+ `<div class="atk-send-reply">` +
33
+ `${m.editor.$t('editCancel')} ` +
34
+ `<span class="atk-cancel">×</span>` +
35
+ `</div>`
36
+ )
37
+ $btn.onclick = () => {
38
+ cancelEdit(m)
39
+ }
40
+ ui.$textareaWrap.append($btn)
41
+ ui.$editCancelBtn = $btn
42
+ }
43
+ m.comment = comment
44
+
45
+ ui.$header.style.display = 'none' // TODO support modify header information
46
+
47
+ m.editor.travel($comment)
48
+
49
+ ui.$nick.value = comment.nick || ''
50
+ ui.$email.value = comment.email || ''
51
+ ui.$link.value = comment.link || ''
52
+
53
+ m.editor.setContent(comment.content)
54
+ ui.$textarea.focus()
55
+
56
+ m.editor.refreshSendBtnText()
57
+ }
58
+
59
+ function cancelEdit(m: EditModeManager) {
60
+ if (!m.comment) return
61
+
62
+ const ui = m.editor.getUI()
63
+
64
+ if (ui.$editCancelBtn) {
65
+ ui.$editCancelBtn.remove()
66
+ ui.$editCancelBtn = undefined
67
+ }
68
+
69
+ m.comment = undefined
70
+ m.editor.travelBack()
71
+
72
+ const { nick, email, link } = m.editor.ctx.user.data
73
+ ui.$nick.value = nick
74
+ ui.$email.value = email
75
+ ui.$link.value = link
76
+
77
+ m.editor.setContent('')
78
+ m.editor.refreshSendBtnText()
79
+
80
+ ui.$header.style.display = '' // TODO support modify header information
81
+ }
82
+
83
+ function initEditModeSubmit(m: EditModeManager) {
84
+ m.editor.getSubmitManager()!.registerCustom({
85
+ activeCond: () => !!m.comment, // active this custom submit when edit mode
86
+ req: async () => {
87
+ const saveData = {
88
+ content: m.editor.getFinalContent(),
89
+ nick: m.editor.getUI().$nick.value,
90
+ email: m.editor.getUI().$email.value,
91
+ link: m.editor.getUI().$link.value,
92
+ }
93
+ const nComment = await m.editor.ctx.getApi().comment.commentEdit({
94
+ ...m.comment, ...saveData
95
+ })
96
+ return nComment
97
+ },
98
+ post: (nComment: CommentData) => {
99
+ m.editor.ctx.updateComment(nComment)
100
+ }
101
+ })
102
+ }