artalk 2.5.0 → 2.5.1

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 (48) hide show
  1. package/dist/Artalk.css +1 -1
  2. package/dist/Artalk.es.js +3172 -3162
  3. package/dist/Artalk.iife.js +1 -1
  4. package/dist/Artalk.js +1 -1
  5. package/dist/ArtalkLite.css +1 -1
  6. package/dist/ArtalkLite.es.js +3175 -3165
  7. package/dist/ArtalkLite.iife.js +1 -1
  8. package/dist/ArtalkLite.js +1 -1
  9. package/dist/i18n/jp.js +1 -1
  10. package/dist/i18n/zh-TW.js +1 -1
  11. package/dist/src/context.d.ts +1 -0
  12. package/dist/src/i18n/external.d.ts +70 -0
  13. package/dist/src/i18n/index.d.ts +0 -68
  14. package/dist/src/lib/checker/index.d.ts +0 -2
  15. package/dist/src/lib/user.d.ts +6 -3
  16. package/dist/src/list/list-ui.d.ts +9 -0
  17. package/dist/src/list/list.d.ts +0 -1
  18. package/dist/src/service.d.ts +8 -2
  19. package/dist/types/context.d.ts +3 -4
  20. package/package.json +1 -1
  21. package/src/api/comment.ts +7 -7
  22. package/src/api/page.ts +0 -2
  23. package/src/api/request.ts +6 -4
  24. package/src/api/upload.ts +3 -4
  25. package/src/api/user.ts +6 -8
  26. package/src/artalk.ts +3 -1
  27. package/src/context.ts +4 -2
  28. package/src/editor/edit-mode.ts +2 -1
  29. package/src/editor/editor.ts +2 -1
  30. package/src/editor/funcs.ts +3 -2
  31. package/src/editor/plugs/header-input-plug.ts +7 -6
  32. package/src/editor/plugs/upload-plug.ts +2 -1
  33. package/src/editor/submit.ts +2 -1
  34. package/src/i18n/external.ts +10 -0
  35. package/src/i18n/index.ts +1 -9
  36. package/src/i18n/jp.ts +1 -1
  37. package/src/i18n/zh-TW.ts +1 -1
  38. package/src/layer/sidebar-layer.ts +2 -1
  39. package/src/lib/checker/admin.ts +5 -4
  40. package/src/lib/checker/index.ts +0 -2
  41. package/src/lib/user.ts +13 -7
  42. package/src/list/list-ui.ts +59 -2
  43. package/src/list/list.ts +17 -52
  44. package/src/list/paginator/holder.ts +3 -2
  45. package/src/service.ts +2 -2
  46. package/src/style/list.scss +4 -4
  47. package/types/context.d.ts +3 -4
  48. package/dist/src/editor/editor-ui.d.ts +0 -25
@@ -1,5 +1,6 @@
1
1
  import type { CommentData } from '~/types/artalk-data'
2
2
  import Editor from './editor'
3
+ import User from '../lib/user'
3
4
 
4
5
  export interface SubmitManager {
5
6
  editor: Editor
@@ -65,7 +66,7 @@ interface CustomSubmit {
65
66
 
66
67
  // ================== Submit Add =======================
67
68
  function getSubmitAddParams(m: SubmitManager) {
68
- const { nick, email, link } = m.editor.ctx.user.data
69
+ const { nick, email, link } = User.data
69
70
  const conf = m.editor.ctx.conf
70
71
  const reply = m.editor.getReplyManager()?.comment
71
72
 
@@ -0,0 +1,10 @@
1
+ import type { I18n } from '.'
2
+
3
+ export const GLOBAL_LOCALES_KEY = "ArtalkI18n"
4
+
5
+ export function defineLocaleExternal(lang: string, locale: I18n, aliases?: string[]) {
6
+ if (!window[GLOBAL_LOCALES_KEY]) window[GLOBAL_LOCALES_KEY] = {}
7
+ window[GLOBAL_LOCALES_KEY][lang] = locale
8
+ if (aliases) aliases.forEach(l => { window[GLOBAL_LOCALES_KEY][l] = locale })
9
+ return locale
10
+ }
package/src/i18n/index.ts CHANGED
@@ -1,5 +1,6 @@
1
1
  import en from './en'
2
2
  import zhCN from './zh-CN'
3
+ import { GLOBAL_LOCALES_KEY } from './external'
3
4
 
4
5
  export type I18n = typeof en
5
6
  export type I18nKeys = keyof I18n
@@ -13,15 +14,6 @@ export const internal = {
13
14
  'zh-CN': zhCN,
14
15
  }
15
16
 
16
- const GLOBAL_LOCALES_KEY = "ArtalkI18n";
17
-
18
- export function defineLocaleExternal(lang: string, locale: I18n, aliases?: string[]) {
19
- if (!window[GLOBAL_LOCALES_KEY]) window[GLOBAL_LOCALES_KEY] = {}
20
- window[GLOBAL_LOCALES_KEY][lang] = locale
21
- if (aliases) aliases.forEach(l => { window[GLOBAL_LOCALES_KEY][l] = locale })
22
- return locale
23
- }
24
-
25
17
  /**
26
18
  * find a locale object by language name
27
19
  */
package/src/i18n/jp.ts CHANGED
@@ -1,4 +1,4 @@
1
- import { defineLocaleExternal } from '.'
1
+ import { defineLocaleExternal } from './external'
2
2
 
3
3
  export default defineLocaleExternal('jp', {
4
4
  /* エディタ */
package/src/i18n/zh-TW.ts CHANGED
@@ -1,4 +1,4 @@
1
- import { defineLocaleExternal } from '.'
1
+ import { defineLocaleExternal } from './external'
2
2
 
3
3
  export default defineLocaleExternal('zh-TW', {
4
4
  /* Editor */
@@ -3,6 +3,7 @@ import Component from '@/lib/component'
3
3
  import * as Utils from '@/lib/utils'
4
4
  import * as Ui from '@/lib/ui'
5
5
  import SidebarHTML from './sidebar-layer.html?raw'
6
+ import User from '../lib/user'
6
7
  import Layer from './layer'
7
8
 
8
9
  export interface SidebarShowPayload {
@@ -83,7 +84,7 @@ export default class SidebarLayer extends Component {
83
84
  const query: any = {
84
85
  pageKey: this.conf.pageKey,
85
86
  site: this.conf.site || '',
86
- user: JSON.stringify(this.ctx.user.data),
87
+ user: JSON.stringify(User.data),
87
88
  time: +new Date()
88
89
  }
89
90
 
@@ -1,4 +1,5 @@
1
1
  import * as Utils from '../utils'
2
+ import User from '../user'
2
3
  import { Checker } from '.'
3
4
 
4
5
  const AdminChecker: Checker = {
@@ -6,8 +7,8 @@ const AdminChecker: Checker = {
6
7
 
7
8
  request(checker, inputVal) {
8
9
  const data = {
9
- name: checker.getUser().data.nick,
10
- email: checker.getUser().data.email,
10
+ name: User.data.nick,
11
+ email: User.data.email,
11
12
  password: inputVal
12
13
  }
13
14
 
@@ -22,11 +23,11 @@ const AdminChecker: Checker = {
22
23
  },
23
24
 
24
25
  onSuccess(checker, userToken, inputVal, formEl) {
25
- checker.getUser().update({
26
+ User.update({
26
27
  isAdmin: true,
27
28
  token: userToken
28
29
  })
29
- checker.getCtx().trigger('user-changed', checker.getUser().data)
30
+ checker.getCtx().trigger('user-changed', User.data)
30
31
  checker.getCtx().listReload()
31
32
  },
32
33
 
@@ -57,7 +57,6 @@ export default class CheckerLauncher {
57
57
  get: (key) => (checkerStore[key]),
58
58
  getCtx: () => (this.ctx),
59
59
  getApi: () => (this.ctx.getApi()),
60
- getUser: () => (this.ctx.user),
61
60
  getLayer: () => layer,
62
61
  hideInteractInput: () => {
63
62
  hideInteractInput = true
@@ -191,7 +190,6 @@ export interface CheckerCtx {
191
190
  set<K extends keyof CheckerStore>(key: K, val: CheckerStore[K]): void
192
191
  getCtx(): Context
193
192
  getApi(): Api
194
- getUser(): User
195
193
  getLayer(): Layer
196
194
  hideInteractInput(): void
197
195
  triggerSuccess(): void
package/src/lib/user.ts CHANGED
@@ -1,13 +1,11 @@
1
- import ArtalkConfig, { LocalUser } from "~/types/artalk-config"
1
+ import { LocalUser } from "~/types/artalk-config"
2
2
  import Context from '~/types/context'
3
3
 
4
- export default class User {
5
- public ctx: Context
4
+ class User {
5
+ public ctx?: Context
6
6
  public data: LocalUser
7
7
 
8
- public constructor(ctx: Context) {
9
- this.ctx = ctx
10
-
8
+ public constructor() {
11
9
  // 从 localStorage 导入
12
10
  const localUser = JSON.parse(window.localStorage.getItem('ArtalkUser') || '{}')
13
11
  this.data = {
@@ -19,6 +17,10 @@ export default class User {
19
17
  }
20
18
  }
21
19
 
20
+ public setContext(ctx: Context) {
21
+ this.ctx = ctx
22
+ }
23
+
22
24
  /** 保存用户到 localStorage 中 */
23
25
  public update(obj: Partial<LocalUser> = {}) {
24
26
  Object.entries(obj).forEach(([key, value]) => {
@@ -26,7 +28,7 @@ export default class User {
26
28
  })
27
29
 
28
30
  window.localStorage.setItem('ArtalkUser', JSON.stringify(this.data))
29
- this.ctx.trigger('user-changed', this.ctx.user.data)
31
+ this.ctx?.trigger('user-changed', this.data)
30
32
  }
31
33
 
32
34
  /** 注销,清除用户登录状态 */
@@ -42,3 +44,7 @@ export default class User {
42
44
  return !!this.data.nick && !!this.data.email
43
45
  }
44
46
  }
47
+
48
+ const UserInstance = new User()
49
+
50
+ export default UserInstance
@@ -1,6 +1,7 @@
1
1
  import ListLite from './list-lite'
2
2
  import * as Utils from '../lib/utils'
3
3
  import * as Ui from '../lib/ui'
4
+ import User from '../lib/user'
4
5
  import $t from '../i18n'
5
6
 
6
7
  /** 界面刷新 */
@@ -33,7 +34,7 @@ export function renderErrorDialog(list: ListLite, errMsg: string, errData?: any)
33
34
 
34
35
  const adminBtn = Utils.createElement('<span atk-only-admin-show> | <span style="cursor:pointer;">打开控制台</span></span>')
35
36
  errEl.appendChild(adminBtn)
36
- if (!list.ctx.user.data.isAdmin) adminBtn.classList.add('atk-hide')
37
+ if (!User.data.isAdmin) adminBtn.classList.add('atk-hide')
37
38
 
38
39
  let sidebarView = ''
39
40
 
@@ -43,7 +44,6 @@ export function renderErrorDialog(list: ListLite, errMsg: string, errData?: any)
43
44
  create_name: list.ctx.conf.site,
44
45
  create_urls: `${window.location.protocol}//${window.location.host}`
45
46
  }
46
- // TODO 真的是飞鸽传书啊
47
47
  sidebarView = `sites|${JSON.stringify(viewLoadParam)}`
48
48
  }
49
49
 
@@ -78,3 +78,60 @@ export function versionCheckDialog(list: ListLite, feVer: string, beVer: string)
78
78
 
79
79
  return false
80
80
  }
81
+
82
+ /** 评论排序方式选择下拉菜单 */
83
+ export function renderDropdown(conf: {
84
+ $dropdownWrap: HTMLElement,
85
+ dropdownList: [string, () => void][]
86
+ }) {
87
+ const { $dropdownWrap, dropdownList } = conf
88
+ if ($dropdownWrap.querySelector('.atk-dropdown')) return
89
+
90
+ // 修改 class
91
+ $dropdownWrap.classList.add('atk-dropdown-wrap')
92
+
93
+ // 插入图标
94
+ $dropdownWrap.append(Utils.createElement(`<span class="atk-arrow-down-icon"></span>`))
95
+
96
+ // 列表项点击事件
97
+ let curtActive = 0 // 当前选中
98
+ const onItemClick = (i: number, $item: HTMLElement, name: string, action: Function) => {
99
+ action()
100
+
101
+ // set active
102
+ curtActive = i
103
+ $dropdown.querySelectorAll('.active').forEach((e) => { e.classList.remove('active') })
104
+ $item.classList.add('active')
105
+
106
+ // 关闭层 (临时消失,取消 :hover)
107
+ $dropdown.style.display = 'none'
108
+ setTimeout(() => { $dropdown.style.display = '' }, 80)
109
+ }
110
+
111
+ // 生成列表元素
112
+ const $dropdown = Utils.createElement(`<ul class="atk-dropdown atk-fade-in"></ul>`)
113
+ dropdownList.forEach((item, i) => {
114
+ const name = item[0] as string
115
+ const action = item[1] as Function
116
+
117
+ const $item = Utils.createElement(`<li class="atk-dropdown-item"><span></span></li>`)
118
+ const $link = $item.querySelector<HTMLElement>('span')!
119
+ $link.innerText = name
120
+ $link.onclick = () => { onItemClick(i, $item, name, action) }
121
+ $dropdown.append($item)
122
+
123
+ if (i === curtActive) $item.classList.add('active') // 默认选中项
124
+ })
125
+
126
+ $dropdownWrap.append($dropdown)
127
+ }
128
+
129
+ /** 删除评论排序方式选择下拉菜单 */
130
+ export function removeDropdown(conf: {
131
+ $dropdownWrap: HTMLElement
132
+ }) {
133
+ const { $dropdownWrap } = conf
134
+ $dropdownWrap.classList.remove('atk-dropdown-wrap')
135
+ $dropdownWrap.querySelector('.atk-arrow-down-icon')?.remove()
136
+ $dropdownWrap.querySelector('.atk-dropdown')?.remove()
137
+ }
package/src/list/list.ts CHANGED
@@ -3,8 +3,10 @@ import Context from '~/types/context'
3
3
  import { version as ARTALK_VERSION } from '../../package.json'
4
4
  import * as Utils from '../lib/utils'
5
5
  import * as Ui from '../lib/ui'
6
+ import User from '../lib/user'
6
7
  import ListHTML from './list.html?raw'
7
8
  import ListLite from './list-lite'
9
+ import * as ListUi from './list-ui'
8
10
 
9
11
  export default class List extends ListLite {
10
12
  private $closeCommentBtn!: HTMLElement
@@ -77,14 +79,14 @@ export default class List extends ListLite {
77
79
  this.$commentCountNum.innerText = String(Number(this.data?.total) || 0)
78
80
 
79
81
  // 已输入个人信息
80
- if (!!this.ctx.user.data.nick && !!this.ctx.user.data.email) {
82
+ if (!!User.data.nick && !!User.data.email) {
81
83
  this.$openSidebarBtn.classList.remove('atk-hide')
82
84
  } else {
83
85
  this.$openSidebarBtn.classList.add('atk-hide')
84
86
  }
85
87
 
86
88
  this.$openSidebarBtn.querySelector<HTMLElement>('.atk-text')!
87
- .innerText = (!this.ctx.user.data.isAdmin) ? this.$t('msgCenter') : this.$t('ctrlCenter')
89
+ .innerText = (!User.data.isAdmin) ? this.$t('msgCenter') : this.$t('ctrlCenter')
88
90
 
89
91
  // 关闭评论
90
92
  if (!!this.data && !!this.data.page && this.data.page.admin_only === true) {
@@ -98,6 +100,10 @@ export default class List extends ListLite {
98
100
  // 评论列表排序 Dropdown 下拉选择层
99
101
  if (this.ctx.conf.listSort) {
100
102
  this.initDropdown()
103
+ } else {
104
+ ListUi.removeDropdown({
105
+ $dropdownWrap: this.$commentCount
106
+ })
101
107
  }
102
108
  }
103
109
 
@@ -192,63 +198,22 @@ export default class List extends ListLite {
192
198
  }
193
199
  }
194
200
 
195
- private dropdownLoaded = false
196
-
197
201
  /** 初始化选择下拉层 */
198
202
  protected initDropdown() {
199
- if (this.dropdownLoaded) return
200
- this.dropdownLoaded = true
201
-
202
- this.$dropdownWrap = this.$commentCount
203
- this.$commentCount.classList.add('atk-dropdown-wrap')
204
-
205
- // 插入图标
206
- this.$dropdownWrap.append(Utils.createElement(`<span class="atk-arrow-down-icon"></span>`))
207
-
208
203
  const reloadUseParamsEditor = (func: (p: any) => void) => {
209
- this.paramsEditor = (p) => { func(p) }
204
+ this.paramsEditor = func
210
205
  this.fetchComments(0)
211
206
  }
212
207
 
213
- // 下拉列表
214
- const dropdownList = [
215
- [this.$t('sortLatest'), () => { reloadUseParamsEditor(p => { p.sort_by = 'date_desc' }) }],
216
- [this.$t('sortBest'), () => { reloadUseParamsEditor(p => { p.sort_by = 'vote' }) }],
217
- [this.$t('sortOldest'), () => { reloadUseParamsEditor(p => { p.sort_by = 'date_asc' }) }],
218
- [this.$t('sortAuthor'), () => { reloadUseParamsEditor(p => { p.view_only_admin = true }) }],
219
- ]
220
-
221
- // 列表项点击事件
222
- let curtActive = 0 // 当前选中
223
- const onItemClick = (i: number, $item: HTMLElement, name: string, action: Function) => {
224
- action()
225
-
226
- // set active
227
- curtActive = i
228
- $dropdown.querySelectorAll('.active').forEach((e) => { e.classList.remove('active') })
229
- $item.classList.add('active')
230
-
231
- // 关闭层 (临时消失,取消 :hover)
232
- $dropdown.style.display = 'none'
233
- setTimeout(() => { $dropdown.style.display = '' }, 80)
234
- }
235
-
236
- // 生成列表元素
237
- const $dropdown = Utils.createElement(`<ul class="atk-dropdown atk-fade-in"></ul>`)
238
- dropdownList.forEach((item, i) => {
239
- const name = item[0] as string
240
- const action = item[1] as Function
241
-
242
- const $item = Utils.createElement(`<li class="atk-dropdown-item"><span></span></li>`)
243
- const $link = $item.querySelector<HTMLElement>('span')!
244
- $link.innerText = name
245
- $link.onclick = () => { onItemClick(i, $item, name, action) }
246
- $dropdown.append($item)
247
-
248
- if (i === curtActive) $item.classList.add('active') // 默认选中项
208
+ ListUi.renderDropdown({
209
+ $dropdownWrap: this.$commentCount,
210
+ dropdownList: [
211
+ [this.$t('sortLatest'), () => { reloadUseParamsEditor(p => { p.sort_by = 'date_desc' }) }],
212
+ [this.$t('sortBest'), () => { reloadUseParamsEditor(p => { p.sort_by = 'vote' }) }],
213
+ [this.$t('sortOldest'), () => { reloadUseParamsEditor(p => { p.sort_by = 'date_asc' }) }],
214
+ [this.$t('sortAuthor'), () => { reloadUseParamsEditor(p => { p.view_only_admin = true }) }],
215
+ ]
249
216
  })
250
-
251
- this.$dropdownWrap.append($dropdown)
252
217
  }
253
218
 
254
219
  public updateUnread(notifies: NotifyData[]): void {
@@ -37,8 +37,9 @@ export default class PgHolder {
37
37
  }
38
38
 
39
39
  public showErr(msg: string) {
40
- const func = this.getAdaptor().showErr
41
- if (func) func(msg)
40
+ const that = this.getAdaptor()
41
+ const func = that.showErr
42
+ if (func) func.bind(that)(msg)
42
43
  }
43
44
 
44
45
  public setMode(val: TPgMode) {
package/src/service.ts CHANGED
@@ -35,8 +35,8 @@ const services = {
35
35
 
36
36
  // User Store
37
37
  user(ctx: Context) {
38
- const user = new User(ctx)
39
- return user
38
+ User.setContext(ctx)
39
+ return User
40
40
  },
41
41
 
42
42
  // HTTP API client
@@ -177,6 +177,10 @@
177
177
  padding-bottom: 10px;
178
178
  }
179
179
 
180
+ &.atk-err .atk-text {
181
+ color: var(--at-color-red) !important;
182
+ }
183
+
180
184
  .atk-list-read-more-inner {
181
185
  cursor: pointer;
182
186
  user-select: none;
@@ -195,10 +199,6 @@
195
199
  background: var(--at-color-bg);
196
200
  border-color: var(--at-color-border);
197
201
 
198
- &.atk-err > .atk-text {
199
- color: var(--at-color-red) !important;
200
- }
201
-
202
202
  & > .atk-loading-icon {
203
203
  height: 15px;
204
204
  width: 15px;
@@ -22,14 +22,13 @@ export default interface ContextApi {
22
22
  /** 依赖注入函数 */
23
23
  inject<K extends keyof TInjectedServices>(depName: K, obj: TInjectedServices[K]): void
24
24
 
25
+ /** 获取依赖对象 */
26
+ get<K extends keyof TInjectedServices>(depName: K): TInjectedServices[K]
27
+
25
28
  /** 配置对象 */
26
29
  // TODO 修改为 getConf() 和 setConf()
27
30
  conf: ArtalkConfig
28
31
 
29
- /** 用户对象 */
30
- // TODO 修改为 getUser()
31
- user: User
32
-
33
32
  /** marked 依赖对象 */
34
33
  getMarkedInstance(): TMarked | undefined
35
34
 
@@ -1,25 +0,0 @@
1
- declare const Sel: {
2
- $header: string;
3
- $nick: string;
4
- $email: string;
5
- $link: string;
6
- $textareaWrap: string;
7
- $textarea: string;
8
- $bottom: string;
9
- $submitBtn: string;
10
- $notifyWrap: string;
11
- $plugBtnWrap: string;
12
- $plugPanelWrap: string;
13
- };
14
- export interface EditorUI extends Record<keyof typeof Sel, HTMLElement> {
15
- $el: HTMLElement;
16
- $nick: HTMLInputElement;
17
- $email: HTMLInputElement;
18
- $link: HTMLInputElement;
19
- $textarea: HTMLTextAreaElement;
20
- $submitBtn: HTMLButtonElement;
21
- $sendReply?: HTMLElement;
22
- $editCancelBtn?: HTMLElement;
23
- }
24
- export declare function render(): EditorUI;
25
- export {};