artalk 2.2.10 → 2.3.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 (73) hide show
  1. package/dist/Artalk.css +1 -1
  2. package/dist/Artalk.es.js +3046 -2342
  3. package/dist/Artalk.iife.js +1 -1
  4. package/dist/Artalk.js +1 -1
  5. package/dist/ArtalkLite.css +1 -0
  6. package/dist/ArtalkLite.es.js +5096 -0
  7. package/dist/ArtalkLite.iife.js +1 -0
  8. package/dist/ArtalkLite.js +1 -0
  9. package/index.html +5 -3
  10. package/package.json +7 -5
  11. package/src/api/index.ts +24 -4
  12. package/src/api/request.ts +50 -81
  13. package/src/artalk.ts +83 -57
  14. package/src/comment/actions.ts +87 -0
  15. package/src/{components/html → comment}/comment.html +1 -1
  16. package/src/comment/comment.ts +191 -0
  17. package/src/comment/index.ts +3 -0
  18. package/src/comment/render.ts +425 -0
  19. package/src/components/action-btn.ts +6 -3
  20. package/src/components/dialog.ts +7 -3
  21. package/src/components/read-more-btn.ts +6 -2
  22. package/src/context.ts +200 -13
  23. package/src/defaults.ts +19 -6
  24. package/src/editor/editor.html +18 -0
  25. package/src/editor/editor.ts +420 -0
  26. package/src/editor/index.ts +3 -0
  27. package/src/editor/plugs/editor-plug.ts +51 -0
  28. package/src/{components/editor-plugs → editor/plugs}/emoticons-plug.less +1 -0
  29. package/src/{components/editor-plugs → editor/plugs}/emoticons-plug.ts +65 -63
  30. package/src/editor/plugs/header-input-plug.ts +79 -0
  31. package/src/{components/editor-plugs → editor/plugs}/preview-plug.less +0 -0
  32. package/src/editor/plugs/preview-plug.ts +40 -0
  33. package/src/editor/plugs/upload-plug.ts +125 -0
  34. package/src/i18n/en.ts +77 -0
  35. package/src/i18n/index.ts +21 -0
  36. package/src/i18n/zh-CN.ts +81 -0
  37. package/src/layer/index.ts +4 -0
  38. package/src/{components → layer}/layer.ts +9 -9
  39. package/src/{components/html → layer}/sidebar-layer.html +0 -0
  40. package/src/{components → layer}/sidebar-layer.ts +17 -46
  41. package/src/lib/checker/admin-checker.ts +7 -6
  42. package/src/lib/checker/captcha-checker.ts +5 -5
  43. package/src/lib/checker/index.ts +22 -17
  44. package/src/lib/component.ts +7 -2
  45. package/src/lib/ui.ts +3 -10
  46. package/src/lib/user.ts +20 -3
  47. package/src/lib/utils.ts +23 -9
  48. package/src/list/index.ts +3 -0
  49. package/src/{components → list}/list-lite.ts +87 -111
  50. package/src/{components → list}/list-nest.ts +0 -0
  51. package/src/{components/html → list}/list.html +3 -6
  52. package/src/{components → list}/list.ts +37 -35
  53. package/src/style/comment.less +23 -10
  54. package/src/style/editor.less +16 -10
  55. package/src/style/list.less +4 -7
  56. package/src/style/main.less +3 -1
  57. package/src/style/pagination.less +1 -1
  58. package/test/ArtalkLite.html +15 -0
  59. package/types/artalk-config.d.ts +52 -31
  60. package/types/context.d.ts +128 -0
  61. package/types/event.d.ts +6 -66
  62. package/types/global.d.ts +1 -0
  63. package/{vite-common.config.ts → vite-base.config.ts} +6 -4
  64. package/vite-demo.config.ts +2 -4
  65. package/vite-lite.config.ts +22 -0
  66. package/vite.config.ts +9 -18
  67. package/src/components/_component.ts.txt +0 -10
  68. package/src/components/comment.ts +0 -605
  69. package/src/components/editor-plugs/_example-plug.ts.txt +0 -29
  70. package/src/components/editor-plugs/editor-plug.ts +0 -20
  71. package/src/components/editor-plugs/preview-plug.ts +0 -48
  72. package/src/components/editor.ts +0 -604
  73. package/src/components/html/editor.html +0 -18
@@ -5,6 +5,8 @@ export interface ReadMoreBtnConf {
5
5
  onClick: (offset: number) => void
6
6
 
7
7
  pageSize: number
8
+
9
+ text?: string
8
10
  }
9
11
 
10
12
  /**
@@ -17,6 +19,7 @@ export default class ReadMoreBtn {
17
19
  private $text: HTMLElement
18
20
  private offset: number = 0
19
21
  private total: number = 0
22
+ private origText: string = 'Load More'
20
23
 
21
24
  /** 是否有更多内容 */
22
25
  get hasMore() {
@@ -25,12 +28,13 @@ export default class ReadMoreBtn {
25
28
 
26
29
  public constructor(conf: ReadMoreBtnConf) {
27
30
  this.conf = conf
31
+ this.origText = this.conf.text || this.origText
28
32
 
29
33
  this.$el = Utils.createElement(
30
34
  `<div class="atk-list-read-more" style="display: none;">
31
35
  <div class="atk-list-read-more-inner">
32
36
  <div class="atk-loading-icon" style="display: none;"></div>
33
- <span class="atk-text">加载更多</span>
37
+ <span class="atk-text">${this.origText}</span>
34
38
  </div>
35
39
  </div>`)
36
40
 
@@ -68,7 +72,7 @@ export default class ReadMoreBtn {
68
72
  this.$text.innerText = errMsg
69
73
  this.$el.classList.add('atk-err')
70
74
  window.setTimeout(() => {
71
- this.$text.innerText = '查看更多'
75
+ this.$text.innerText = this.origText
72
76
  this.$el.classList.remove('atk-err')
73
77
  }, 2000) // 2s后错误提示复原
74
78
  }
package/src/context.ts CHANGED
@@ -1,46 +1,233 @@
1
1
  import { marked as libMarked } from 'marked'
2
2
  import ArtalkConfig from '~/types/artalk-config'
3
- import { EventPayloadMap, Event, EventScopeType, Handler } from '~/types/event'
3
+ import { CommentData, NotifyData } from '~/types/artalk-data'
4
+ import { Event } from '~/types/event'
5
+ import { internal as internalLocales, I18n } from './i18n'
4
6
  import User from './lib/user'
7
+ import ContextApi from '../types/context'
8
+ import Editor from './editor'
9
+ import Comment from './comment'
10
+ import ListLite from './list/list-lite'
11
+ import SidebarLayer, { SidebarShowPayload } from './layer/sidebar-layer'
12
+ import CheckerLauncher, { CheckerCaptchaPayload, CheckerPayload } from './lib/checker'
13
+ import Layer, { GetLayerWrap } from './layer'
14
+ import Api from './api'
5
15
 
6
16
  /**
7
17
  * Artalk Context
8
18
  */
9
- export default class Context {
19
+ export default class Context implements ContextApi {
20
+ /* 持有同事类 */
21
+ private api!: Api
22
+ private editor!: Editor
23
+ private list!: ListLite
24
+ private sidebarLayer!: SidebarLayer
25
+ private checkerLauncher!: CheckerLauncher
26
+
27
+ /* 运行参数 */
10
28
  public cid: number // Context 唯一标识
11
- public $root: HTMLElement
12
29
  public conf: ArtalkConfig
13
30
  public user: User
31
+ public $root: HTMLElement
32
+ public markedInstance?: typeof libMarked
33
+ public markedReplacers: ((raw: string) => string)[] = []
34
+
35
+ private commentList: Comment[] = [] // Note: 无层级结构 + 无须排列
14
36
 
37
+ /* 订阅者模式 */
15
38
  private eventList: Event[] = []
16
39
 
17
- public constructor (rootEl: HTMLElement, conf: ArtalkConfig) {
40
+ public constructor($root: HTMLElement, conf: ArtalkConfig) {
18
41
  this.cid = +new Date()
19
- this.$root = rootEl
20
42
  this.conf = conf
21
- this.user = new User(this.conf)
43
+ this.user = new User(this)
22
44
 
45
+ this.$root = $root
23
46
  this.$root.setAttribute('atk-run-id', this.cid.toString())
24
47
  }
25
48
 
26
- public on<K extends keyof EventPayloadMap>(name: K, handler: Handler<EventPayloadMap[K]>, scope: EventScopeType = 'internal') {
27
- this.eventList.push({ name, handler: handler as any, scope })
49
+ /* 设置持有的同事类 */
50
+ public setApi(api: Api): void {
51
+ this.api = api
52
+ }
53
+
54
+ public setEditor(editor: Editor): void {
55
+ this.editor = editor
56
+ }
57
+
58
+ public setList(list: ListLite): void {
59
+ this.list = list
60
+ }
61
+
62
+ public setSidebarLayer(sidebarLayer: SidebarLayer): void {
63
+ this.sidebarLayer = sidebarLayer
64
+ }
65
+
66
+ public setCheckerLauncher(checkerLauncher: CheckerLauncher): void {
67
+ this.checkerLauncher = checkerLauncher
68
+ }
69
+
70
+ public getApi() {
71
+ return this.api
72
+ }
73
+
74
+ /* 评论操作 */
75
+ public getCommentList() {
76
+ return this.commentList
77
+ }
78
+
79
+ public getCommentDataList() {
80
+ return this.commentList.map(c => c.getData())
81
+ }
82
+
83
+ public findComment(id: number): Comment|undefined {
84
+ return this.commentList.find(c => c.getData().id === id)
85
+ }
86
+
87
+ public deleteComment(_comment: number|Comment) {
88
+ let comment: Comment
89
+ if (typeof _comment === 'number') {
90
+ const findComment = this.findComment(_comment)
91
+ if (!findComment) throw Error(`Comment ${_comment} cannot be found`)
92
+ comment = findComment
93
+ } else comment = _comment
94
+
95
+ comment.getEl().remove()
96
+ this.commentList.splice(this.commentList.indexOf(comment), 1)
97
+
98
+ const listData = this.list.getData()
99
+ if (listData) listData.total -= 1 // 评论数减 1
100
+
101
+ this.list.refreshUI()
102
+ }
103
+
104
+ public clearAllComments() {
105
+ this.list.getCommentsWrapEl().innerHTML = ''
106
+ this.list.clearData()
107
+ this.commentList = []
108
+ }
109
+
110
+ public insertComment(commentData: CommentData) {
111
+ this.list.insertComment(commentData)
112
+ }
113
+
114
+ public replyComment(commentData: CommentData, $comment: HTMLElement, scroll?: boolean): void {
115
+ this.editor.setReply(commentData, $comment, scroll)
116
+ }
117
+
118
+ public cancelReplyComment(): void {
119
+ this.editor.cancelReply()
120
+ }
121
+
122
+ public updateNotifies(notifies: NotifyData[]): void {
123
+ this.list.updateUnread(notifies)
124
+ }
125
+
126
+ /* 评论列表 */
127
+ public listReload(): void {
128
+ this.list.reload()
28
129
  }
29
130
 
30
- public off<K extends keyof EventPayloadMap>(name: K, handler?: Handler<EventPayloadMap[K]>, scope: EventScopeType = 'internal') {
131
+ public listRefreshUI(): void {
132
+ this.list.refreshUI()
133
+ }
134
+
135
+ /* 编辑器 */
136
+ public editorOpen(): void {
137
+ this.editor.open()
138
+ }
139
+
140
+ public editorClose(): void {
141
+ this.editor.close()
142
+ }
143
+
144
+ public editorShowLoading(): void {
145
+ this.editor.showLoading()
146
+ }
147
+
148
+ public editorHideLoading(): void {
149
+ this.editor.hideLoading()
150
+ }
151
+
152
+ public editorShowNotify(msg, type): void {
153
+ this.editor.showNotify(msg, type)
154
+ }
155
+
156
+ public editorTravel($el: HTMLElement): void {
157
+ this.editor.travel($el)
158
+ }
159
+
160
+ public editorTravelBack(): void {
161
+ this.editor.travelBack()
162
+ }
163
+
164
+ /* 侧边栏 */
165
+ public showSidebar(payload?: SidebarShowPayload): void {
166
+ this.sidebarLayer.show(payload)
167
+ }
168
+
169
+ public hideSidebar(): void {
170
+ this.sidebarLayer.hide()
171
+ }
172
+
173
+ /* 权限检测 */
174
+ public checkAdmin(payload: CheckerPayload): void {
175
+ this.checkerLauncher.checkAdmin(payload)
176
+ }
177
+
178
+ public checkCaptcha(payload: CheckerCaptchaPayload): void {
179
+ this.checkerLauncher.checkCaptcha(payload)
180
+ }
181
+
182
+ public checkAdminShowEl() {
183
+ const items: HTMLElement[] = []
184
+
185
+ this.$root.querySelectorAll<HTMLElement>(`[atk-only-admin-show]`).forEach(item => items.push(item))
186
+
187
+ // for layer
188
+ const { $wrap: $layerWrap } = GetLayerWrap(this)
189
+ if ($layerWrap) $layerWrap.querySelectorAll<HTMLElement>(`[atk-only-admin-show]`).forEach(item => items.push(item))
190
+
191
+ // for sidebar
192
+ // TODO: 这个其实应该写在 packages/artalk-sidebar 里面的
193
+ const $sidebarEl = document.querySelector<HTMLElement>('.atk-sidebar')
194
+ if ($sidebarEl) $sidebarEl.querySelectorAll<HTMLElement>(`[atk-only-admin-show]`).forEach(item => items.push(item))
195
+
196
+ items.forEach(($item: HTMLElement) => {
197
+ if (this.user.data.isAdmin) $item.classList.remove('atk-hide')
198
+ else $item.classList.add('atk-hide')
199
+ })
200
+ }
201
+
202
+ /* 订阅模式 */
203
+ public on(name: any, handler: any, scope: any = 'internal') {
204
+ this.eventList.push({ name, handler, scope })
205
+ }
206
+
207
+ public off(name: any, handler: any, scope: any = 'internal') {
31
208
  this.eventList = this.eventList.filter((evt) => {
32
209
  if (handler) return !(evt.name === name && evt.handler === handler && evt.scope === scope)
33
210
  return !(evt.name === name && evt.scope === scope) // 删除全部相同 name event
34
211
  })
35
212
  }
36
213
 
37
- public trigger<K extends keyof EventPayloadMap>(name: K, payload?: EventPayloadMap[K], scope?: EventScopeType) {
214
+ public trigger(name: any, payload?: any, scope?: any) {
38
215
  this.eventList
39
216
  .filter((evt) => evt.name === name && (scope ? (evt.scope === scope) : true))
40
217
  .map((evt) => evt.handler)
41
- .forEach((handler) => handler(payload as any))
218
+ .forEach((handler) => handler(payload))
42
219
  }
43
220
 
44
- public markedInstance!: typeof libMarked
45
- public markedReplacers: ((raw: string) => string)[] = []
221
+ /* i18n */
222
+ public $t(key: keyof I18n, args: {[key: string]: string} = {}): string {
223
+ let locales = this.conf.locale
224
+ if (typeof locales === 'string') {
225
+ locales = internalLocales[locales]
226
+ }
227
+
228
+ let str = locales?.[key] || key
229
+ str = str.replace(/\{\s*(\w+?)\s*\}/g, (_, token) => args[token] || '')
230
+
231
+ return str
232
+ }
46
233
  }
package/src/defaults.ts CHANGED
@@ -1,26 +1,31 @@
1
- import ArtalkConfig from "~/types/artalk-config";
1
+ import ArtalkConfig from "~/types/artalk-config"
2
2
 
3
3
  const defaults: ArtalkConfig = {
4
4
  el: '',
5
5
  pageKey: '',
6
+ pageTitle: '',
6
7
  server: '',
7
8
  site: '',
8
9
 
9
- placeholder: '键入内容...',
10
- noComment: '「此时无声胜有声」',
11
- sendBtn: '发送评论',
10
+ placeholder: '',
11
+ noComment: '',
12
+ sendBtn: '',
12
13
  darkMode: false,
13
14
  editorTravel: true,
14
15
 
16
+ flatMode: 'auto',
17
+ nestMax: 2,
18
+ nestSort: 'DATE_ASC',
19
+
15
20
  emoticons: "https://cdn.jsdelivr.net/gh/ArtalkJS/Emoticons/grps/default.json",
16
21
 
17
22
  vote: true,
18
23
  voteDown: false,
19
24
  uaBadge: true,
20
25
  listSort: true,
26
+ preview: true,
27
+ countEl: '#ArtalkCount',
21
28
  pvEl: '#ArtalkPV',
22
- flatMode: 'auto',
23
- nestMax: 2,
24
29
 
25
30
  gravatar: {
26
31
  default: 'mp',
@@ -42,6 +47,14 @@ const defaults: ArtalkConfig = {
42
47
  reqTimeout: 15000,
43
48
  versionCheck: true,
44
49
  useBackendConf: false,
50
+
51
+ locale: 'zh-CN',
52
+ }
53
+
54
+ if (ARTALK_LITE) {
55
+ defaults.vote = false
56
+ defaults.uaBadge = false
57
+ defaults.emoticons = false
45
58
  }
46
59
 
47
60
  export default defaults
@@ -0,0 +1,18 @@
1
+ <div class="atk-main-editor">
2
+ <div class="atk-header">
3
+ <input name="nick" class="atk-nick" type="text" required="required">
4
+ <input name="email" class="atk-email" type="email" required="required">
5
+ <input name="link" class="atk-link" type="url">
6
+ </div>
7
+ <div class="atk-textarea-wrap">
8
+ <textarea class="atk-textarea"></textarea>
9
+ </div>
10
+ <div class="atk-plug-panel-wrap" style="display: none;"></div>
11
+ <div class="atk-bottom">
12
+ <div class="atk-item atk-plug-btn-wrap"></div>
13
+ <div class="atk-item">
14
+ <button type="button" class="atk-send-btn"></button>
15
+ </div>
16
+ </div>
17
+ <div class="atk-notify-wrap"></div>
18
+ </div>