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
package/src/artalk.ts CHANGED
@@ -1,29 +1,24 @@
1
- import './style/main.less'
1
+ import './style/main.scss'
2
2
 
3
- import ArtalkConfig from '~/types/artalk-config'
4
- import { EventPayloadMap, Handler } from '~/types/event'
5
- import ArtalkPlug from '~/types/plug'
6
- import Context from '~/types/context'
3
+ import type ArtalkConfig from '~/types/artalk-config'
4
+ import type { EventPayloadMap, Handler } from '~/types/event'
5
+ import type ArtalkPlug from '~/types/plug'
6
+ import type Context from '~/types/context'
7
7
  import ConcreteContext from './context'
8
8
  import defaults from './defaults'
9
-
10
- import ListLite from './list/list-lite'
11
- import CheckerLauncher from './lib/checker'
12
- import Editor from './editor'
13
- import List from './list'
14
- import SidebarLayer from './layer/sidebar-layer'
15
-
16
- import Layer from './layer'
17
- import * as Utils from './lib/utils'
18
- import * as Ui from './lib/ui'
9
+ import { handelBaseConf } from './config'
10
+ import Services from './service'
19
11
  import * as Stat from './lib/stat'
12
+ import ListLite from './list/list-lite'
20
13
 
21
14
  /**
22
15
  * Artalk
23
16
  *
24
- * @website https://artalk.js.org
17
+ * @see https://artalk.js.org
25
18
  */
26
19
  export default class Artalk {
20
+ private static instance?: Artalk
21
+
27
22
  public static ListLite = ListLite
28
23
  public static readonly defaults: ArtalkConfig = defaults
29
24
 
@@ -31,192 +26,140 @@ export default class Artalk {
31
26
  public ctx!: Context
32
27
  public $root!: HTMLElement
33
28
 
34
- /** Plugins (in global scope) */
35
- protected static Plugins: ArtalkPlug[] = [ Stat.PvCountWidget ]
36
-
37
- /** Plugins (in a instance scope) */
38
- protected instancePlugins: ArtalkPlug[] = []
39
-
40
- /** 禁用的组件 */
29
+ /** Plugins */
30
+ protected static plugins: ArtalkPlug[] = [ Stat.PvCountWidget ]
41
31
  public static DisabledComponents: string[] = []
42
32
 
43
- constructor(customConf: Partial<ArtalkConfig>) {
44
- /* 初始化基本配置 */
45
- this.conf = Artalk.HandelBaseConf(customConf)
33
+ constructor(conf: Partial<ArtalkConfig>) {
34
+ if (Artalk.instance) return Artalk.instance.update(conf)
35
+
36
+ // 初始化基本配置
37
+ this.conf = handelBaseConf(conf)
46
38
  if (this.conf.el instanceof HTMLElement) this.$root = this.conf.el
47
39
 
48
- /* 初始化 Context */
40
+ // 初始化 Context
49
41
  this.ctx = new ConcreteContext(this.conf, this.$root)
50
42
 
51
- /* 初始化组件 */
52
- this.initComponents()
53
- }
54
-
55
- /** 组件初始化 */
56
- private initComponents() {
57
- this.initLocale()
58
- this.initLayer()
59
- Utils.initMarked(this.ctx)
60
-
61
- const Components: { [name: string]: () => void } = {
62
- // CheckerLauncher
63
- checkerLauncher: () => {
64
- const checkerLauncher = new CheckerLauncher(this.ctx)
65
- this.ctx.setCheckerLauncher(checkerLauncher)
66
- },
67
-
68
- // 编辑器
69
- editor: () => {
70
- const editor = new Editor(this.ctx)
71
- this.ctx.setEditor(editor)
72
- this.$root.appendChild(editor.$el)
73
- },
74
-
75
- // 评论列表
76
- list: () => {
77
- // 评论列表
78
- const list = new List(this.ctx)
79
- this.ctx.setList(list)
80
- this.$root.appendChild(list.$el)
81
-
82
- // 评论获取
83
- list.fetchComments(0)
84
- },
85
-
86
- // 侧边栏 Layer
87
- sidebarLayer: () => {
88
- const sidebarLayer = new SidebarLayer(this.ctx)
89
- this.ctx.setSidebarLayer(sidebarLayer)
90
- },
91
-
92
- // 默认事件绑定
93
- eventsDefault: () => {
94
- this.initEventBind()
95
- }
96
- }
97
-
98
- // 组件初始化
99
- Object.entries(Components).forEach(([name, initComponent]) => {
43
+ // 内建服务初始化
44
+ Object.entries(Services).forEach(([name, initService]) => {
100
45
  if (Artalk.DisabledComponents.includes(name)) return
101
-
102
- initComponent()
46
+ const obj = initService(this.ctx)
47
+ if (obj) this.ctx.inject(name as any, obj) // auto inject deps to ctx
103
48
  })
104
49
 
105
50
  // 插件初始化 (global scope)
106
- Artalk.Plugins.forEach(plugin => {
51
+ Artalk.plugins.forEach(plugin => {
107
52
  if (typeof plugin === 'function')
108
53
  plugin(this.ctx)
109
54
  })
110
55
  }
111
56
 
112
- /** 基本配置初始化 */
113
- public static HandelBaseConf(customConf: Partial<ArtalkConfig>): ArtalkConfig {
114
- // 合并默认配置
115
- const conf: ArtalkConfig = Utils.mergeDeep(Artalk.defaults, customConf)
116
-
117
- // 绑定元素
118
- if (typeof conf.el === 'string' && !!conf.el) {
119
- try {
120
- const findEl = document.querySelector<HTMLElement>(conf.el)
121
- if (!findEl) throw Error(`Target element "${conf.el}" was not found.`)
122
- conf.el = findEl
123
- } catch (e) {
124
- console.error(e)
125
- throw new Error('Please check your Artalk `el` config.')
126
- }
127
- }
128
-
129
- // 服务器配置
130
- conf.server = conf.server.replace(/\/$/, '').replace(/\/api\/?$/, '')
131
-
132
- // 默认 pageKey
133
- if (!conf.pageKey) {
134
- // @link http://bl.ocks.org/abernier/3070589
135
- conf.pageKey = `${window.location.pathname}`
136
- }
137
-
138
- // 默认 pageTitle
139
- if (!conf.pageTitle) {
140
- conf.pageTitle = `${document.title}`
141
- }
142
-
143
- return conf
144
- }
145
-
146
- /** 事件绑定初始化 */
147
- private initEventBind() {
148
- // 锚点快速跳转评论
149
- window.addEventListener('hashchange', () => {
150
- this.ctx.listHashGotoCheck()
151
- })
57
+ /** Init Artalk */
58
+ public static init(conf: Partial<ArtalkConfig>): Artalk {
59
+ if (this.instance) return this.instance.update(conf) // 单例模式
60
+ this.instance = new Artalk(conf)
61
+ return this.instance
62
+ }
152
63
 
153
- // 本地用户数据变更
154
- this.ctx.on('user-changed', () => {
155
- this.ctx.checkAdminShowEl()
156
- this.ctx.listRefreshUI()
157
- })
64
+ /** Use Plugin (plugin will be called in instance `use` func) */
65
+ public use(plugin: ArtalkPlug) {
66
+ Artalk.plugins.push(plugin)
67
+ if (typeof plugin === 'function') plugin(this.ctx)
158
68
  }
159
69
 
160
- /** 语言初始化 */
161
- private initLocale() {
162
- if (this.conf.locale === 'auto') { // 自适应语言
163
- this.conf.locale = navigator.language
164
- }
70
+ /** Update config of Artalk */
71
+ public update(conf: Partial<ArtalkConfig>) {
72
+ if (!Artalk.instance) throw Error('cannot call `update` function before call `load`')
73
+ Artalk.instance.ctx.updateConf(conf)
74
+ return Artalk.instance
165
75
  }
166
76
 
167
- /** Layer 初始化 */
168
- private initLayer() {
169
- // 记录页面原始 Styles
170
- Layer.BodyOrgOverflow = document.body.style.overflow
171
- Layer.BodyOrgPaddingRight = document.body.style.paddingRight
77
+ /** Reload comment list of Artalk */
78
+ public reload() {
79
+ this.ctx.listReload()
172
80
  }
173
81
 
174
- /** 监听事件 */
82
+ /** Destroy instance of Artalk */
83
+ public destroy() {
84
+ if (!Artalk.instance) throw Error('cannot call `destroy` function before call `load`')
85
+ Artalk.instance.$root.remove()
86
+ delete Artalk.instance
87
+ }
88
+
89
+ /** Add an event listener */
175
90
  public on<K extends keyof EventPayloadMap>(name: K, handler: Handler<EventPayloadMap[K]>) {
176
91
  this.ctx.on(name, handler, 'external')
177
92
  }
178
93
 
179
- /** 解除监听事件 */
94
+ /** Remove an event listener */
180
95
  public off<K extends keyof EventPayloadMap>(name: K, handler: Handler<EventPayloadMap[K]>) {
181
96
  this.ctx.off(name, handler, 'external')
182
97
  }
183
98
 
184
- /** 触发事件 */
99
+ /** Trigger an event */
185
100
  public trigger<K extends keyof EventPayloadMap>(name: K, payload?: EventPayloadMap[K]) {
186
101
  this.ctx.trigger(name, payload, 'external')
187
102
  }
188
103
 
189
- /** 重新加载 */
190
- public reload() {
191
- this.ctx.listReload()
192
- }
193
-
194
- /** 设置暗黑模式 */
104
+ /** Set dark mode */
195
105
  public setDarkMode(darkMode: boolean) {
196
106
  this.ctx.setDarkMode(darkMode)
197
107
  }
198
108
 
199
- /** Use Plugin (specific instance) */
200
- public use(plugin: ArtalkPlug) {
201
- this.instancePlugins.push(plugin)
202
- if (typeof plugin === 'function') plugin(this.ctx)
203
- }
109
+ // ===========================
110
+ // Static methods
111
+ // ===========================
204
112
 
205
- /** Use Plugin (static method for global scope) */
113
+ /** Use Plugin (static method) */
206
114
  public static use(plugin: ArtalkPlug) {
207
- this.Plugins.push(plugin)
115
+ this.plugins.push(plugin)
116
+ if (this.instance && typeof plugin === 'function') plugin(this.instance.ctx)
208
117
  }
209
118
 
210
- /** @deprecated Please replace it with lowercase function name `use(...)`. */
211
- public static Use(plugin: ArtalkPlug) {
212
- this.use(plugin)
213
- console.warn('`Use(...)` is deprecated, replace it with lowercase `use(...)`.')
119
+ /** Update config of Artalk */
120
+ public static update(conf: Partial<ArtalkConfig>) {
121
+ return this.instance?.update(conf)
214
122
  }
215
123
 
216
- /** 装载数量统计元素 */
217
- public static LoadCountWidget(customConf: Partial<ArtalkConfig>) {
218
- const conf = this.HandelBaseConf(customConf)
219
- const ctx = new ConcreteContext(conf)
124
+ /** Reload comment list of Artalk */
125
+ public static reload() {
126
+ this.instance?.reload()
127
+ }
128
+
129
+ /** Destroy instance of Artalk */
130
+ public static destroy() {
131
+ this.instance?.destroy()
132
+ }
133
+
134
+ /** Add an event listener */
135
+ public static on<K extends keyof EventPayloadMap>(name: K, handler: Handler<EventPayloadMap[K]>) {
136
+ this.instance?.on(name, handler)
137
+ }
138
+
139
+ /** Remove an event listener */
140
+ public static off<K extends keyof EventPayloadMap>(name: K, handler: Handler<EventPayloadMap[K]>) {
141
+ this.instance?.off(name, handler)
142
+ }
143
+
144
+ /** Trigger an event */
145
+ public static trigger<K extends keyof EventPayloadMap>(name: K, payload?: EventPayloadMap[K]) {
146
+ this.instance?.trigger(name, payload)
147
+ }
148
+
149
+ /** Set dark mode */
150
+ public static setDarkMode(darkMode: boolean) {
151
+ this.instance?.setDarkMode(darkMode)
152
+ }
153
+
154
+ /** Load count widget */
155
+ public static loadCountWidget(conf: Partial<ArtalkConfig>) {
156
+ const ctx = new ConcreteContext(handelBaseConf(conf))
220
157
  Stat.initCountWidget({ ctx, pvAdd: false })
221
158
  }
159
+
160
+ /** @deprecated Please use `loadCountWidget` instead */
161
+ public static LoadCountWidget(conf: Partial<ArtalkConfig>) {
162
+ console.warn('The method `LoadCountWidget` is deprecated, please use `loadCountWidget` instead.')
163
+ this.loadCountWidget(conf)
164
+ }
222
165
  }
@@ -2,8 +2,9 @@ import { CommentData } from '~/types/artalk-data'
2
2
  import Context from '~/types/context'
3
3
  import Component from '../lib/component'
4
4
  import * as Utils from '../lib/utils'
5
+ import marked from '../lib/marked'
5
6
  import UADetect from '../lib/detect'
6
- import CommentRender from './render'
7
+ import CommentUI from './render'
7
8
  import CommentActions from './actions'
8
9
 
9
10
  export interface CommentConf {
@@ -18,7 +19,7 @@ export interface CommentConf {
18
19
  }
19
20
 
20
21
  export default class Comment extends Component {
21
- private renderInstance: CommentRender
22
+ private renderInstance: CommentUI
22
23
  private actionInstance: CommentActions
23
24
 
24
25
  private data: CommentData
@@ -44,7 +45,7 @@ export default class Comment extends Component {
44
45
  this.nestCurt = 1 // 现在已嵌套 n 层
45
46
 
46
47
  this.actionInstance = new CommentActions(this)
47
- this.renderInstance = new CommentRender(this)
48
+ this.renderInstance = new CommentUI(this)
48
49
  }
49
50
 
50
51
  /** 渲染 UI */
@@ -119,7 +120,7 @@ export default class Comment extends Component {
119
120
  childC.getRender().playFadeAnim()
120
121
 
121
122
  // 内容限高
122
- childC.getRender().checkHeightLimitArea('content')
123
+ childC.getRender().checkHeightLimit()
123
124
  }
124
125
 
125
126
  /** 获取存放子评论的元素对象 */
@@ -131,7 +132,7 @@ export default class Comment extends Component {
131
132
  if (this.nestCurt < this.nestMax) {
132
133
  $children = this.getRender().renderChildrenWrap()
133
134
  } else {
134
- $children = this.parent!.getChildrenEl()
135
+ $children = this.parent!.getChildrenEl()
135
136
  }
136
137
  }
137
138
 
@@ -164,7 +165,7 @@ export default class Comment extends Component {
164
165
 
165
166
  /** 获取评论 markdown 解析后的内容 */
166
167
  public getContentMarked() {
167
- return Utils.marked(this.ctx, this.data.content)
168
+ return marked(this.ctx, this.data.content)
168
169
  }
169
170
 
170
171
  /** 获取格式化后的日期 */
@@ -0,0 +1,100 @@
1
+ import * as Utils from '../lib/utils'
2
+ import $t from '../i18n'
3
+
4
+ export interface IHeightLimitConf {
5
+ /** Post expand btn click */
6
+ postExpandBtnClick?: (e: MouseEvent) => void
7
+ /** Allow Scroll */
8
+ scrollable?: boolean
9
+ }
10
+
11
+ export interface IHeightLimitRule {
12
+ /** Target element need to check */
13
+ el: HTMLElement|null|undefined
14
+
15
+ /** Max height (unit: px) */
16
+ max: number
17
+
18
+ /** Whether or not the element contains `<img />` */
19
+ imgContains?: boolean
20
+ }
21
+
22
+ export type THeightLimitRuleSet = IHeightLimitRule[]
23
+
24
+ /** Check all elements below the max height limit */
25
+ export function check(conf: IHeightLimitConf, rules: THeightLimitRuleSet) {
26
+ rules.forEach(({
27
+ el, max: maxHeight, imgContains
28
+ }) => {
29
+ const _apply = () => {
30
+ if (!el) return
31
+ if (!conf.scrollable)
32
+ applyHeightLimit({ el, maxHeight, postBtnClick: conf.postExpandBtnClick })
33
+ else
34
+ applyScrollableHeightLimit({ el, maxHeight })
35
+ }
36
+
37
+ // checking
38
+ const _check = () => {
39
+ if (el && Utils.getHeight(el) > maxHeight) _apply() // 是否超过高度
40
+ }
41
+ _check() // check now
42
+ if (imgContains && el) // check again if img contains
43
+ Utils.onImagesLoaded(el, () => _check())
44
+ })
45
+ }
46
+
47
+ /** Height limit CSS class name */
48
+ const HEIGHT_LIMIT_CSS = 'atk-height-limit'
49
+
50
+ /** Apply height limit on an element and add expand btn */
51
+ export function applyHeightLimit(obj: {
52
+ el: HTMLElement,
53
+ maxHeight: number,
54
+ postBtnClick?: (e: MouseEvent) => void
55
+ }) {
56
+ if (!obj.el) return
57
+ if (!obj.maxHeight) return
58
+ if (obj.el.classList.contains(HEIGHT_LIMIT_CSS)) return
59
+
60
+ obj.el.classList.add(HEIGHT_LIMIT_CSS)
61
+ obj.el.style.height = `${obj.maxHeight}px`
62
+ obj.el.style.overflow = 'hidden'
63
+
64
+ /* Expand button */
65
+ const $expandBtn = Utils.createElement(`<div class="atk-height-limit-btn">${$t('readMore')}</span>`)
66
+ $expandBtn.onclick = (e) => {
67
+ e.stopPropagation()
68
+ disposeHeightLimit(obj.el)
69
+
70
+ if (obj.postBtnClick) obj.postBtnClick(e)
71
+ }
72
+ obj.el.append($expandBtn)
73
+ }
74
+
75
+ /** Dispose height limit on an element and remove expand btn */
76
+ export function disposeHeightLimit($el: HTMLElement) {
77
+ if (!$el) return
78
+ if (!$el.classList.contains(HEIGHT_LIMIT_CSS)) return
79
+
80
+ $el.classList.remove(HEIGHT_LIMIT_CSS)
81
+ Array.from($el.children).forEach((e) => {
82
+ if (e.classList.contains('atk-height-limit-btn')) e.remove()
83
+ })
84
+ $el.style.height = ''
85
+ $el.style.overflow = ''
86
+ }
87
+
88
+ /** Height limit scrollable CSS class name */
89
+ const HEIGHT_LIMIT_SCROLL_CSS = 'atk-height-limit-scroll'
90
+
91
+ /** Apply scrollable height limit */
92
+ export function applyScrollableHeightLimit(obj: {
93
+ el: HTMLElement,
94
+ maxHeight: number
95
+ }) {
96
+ if (!obj.el) return
97
+ if (obj.el.classList.contains(HEIGHT_LIMIT_SCROLL_CSS)) return
98
+ obj.el.classList.add(HEIGHT_LIMIT_SCROLL_CSS)
99
+ obj.el.style.height = `${obj.maxHeight}px`
100
+ }
@@ -0,0 +1,30 @@
1
+ import Comment from './comment'
2
+ import ActionBtn from '../components/action-btn'
3
+
4
+ export default class RenderCtx {
5
+ public comment: Comment
6
+
7
+ public get ctx() { return this.comment.ctx }
8
+ public get data() { return this.comment.getData() }
9
+ public get conf() { return this.comment.conf }
10
+ public get cConf() { return this.comment.getConf() }
11
+
12
+ public $el!: HTMLElement
13
+ public $main!: HTMLElement
14
+ public $header!: HTMLElement
15
+ public $headerNick!: HTMLElement
16
+ public $headerBadgeWrap!: HTMLElement
17
+ public $body!: HTMLElement
18
+ public $content!: HTMLElement
19
+ public $childrenWrap!: HTMLElement|null
20
+ public $actions!: HTMLElement
21
+ public voteBtnUp?: ActionBtn
22
+ public voteBtnDown?: ActionBtn
23
+
24
+ public $replyTo?: HTMLElement // 回复评论内容 (平铺下显示)
25
+ public $replyAt?: HTMLElement // 回复 AT(层级嵌套下显示)
26
+
27
+ public constructor(comment: Comment) {
28
+ this.comment = comment
29
+ }
30
+ }