artalk 2.0.4 → 2.1.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 (91) hide show
  1. package/README.md +7 -60
  2. package/dist/Artalk.css +1 -1
  3. package/dist/Artalk.es.js +5996 -1
  4. package/dist/Artalk.iife.js +266 -1
  5. package/dist/Artalk.js +266 -1
  6. package/package.json +3 -4
  7. package/src/api/index.ts +269 -0
  8. package/src/api/request.ts +125 -0
  9. package/src/artalk.ts +153 -0
  10. package/src/components/_component.ts.txt +10 -0
  11. package/src/components/action-btn.ts +169 -0
  12. package/src/components/admin/page-list.ts +194 -0
  13. package/src/components/admin/site-list-floater.ts +98 -0
  14. package/src/components/admin/site-list.ts +289 -0
  15. package/src/components/comment.ts +478 -0
  16. package/src/components/dialog.ts +63 -0
  17. package/src/components/editor-plugs/{_ExamplePlug.ts.txt → _example-plug.ts.txt} +0 -0
  18. package/src/components/editor-plugs/{EditorPlug.ts → editor-plug.ts} +3 -3
  19. package/src/components/editor-plugs/{EmoticonsPlug.less → emoticons-plug.less} +0 -0
  20. package/src/components/editor-plugs/{EmoticonsPlug.ts → emoticons-plug.ts} +9 -9
  21. package/src/components/editor-plugs/{PreviewPlug.less → preview-plug.less} +0 -0
  22. package/src/components/editor-plugs/{PreviewPlug.ts → preview-plug.ts} +10 -10
  23. package/src/components/{Editor.ts → editor.ts} +104 -102
  24. package/src/components/html/comment.html +2 -6
  25. package/src/components/html/list.html +0 -1
  26. package/src/components/html/sidebar.html +18 -4
  27. package/src/components/item-text-editor.ts +136 -0
  28. package/src/components/layer.ts +135 -0
  29. package/src/components/list-lite.ts +507 -0
  30. package/src/components/list.ts +172 -0
  31. package/src/components/pagination.ts +150 -0
  32. package/src/components/read-more-btn.ts +71 -0
  33. package/src/components/sidebar-view.ts +26 -0
  34. package/src/components/sidebar-views/comments-view.ts +66 -0
  35. package/src/components/sidebar-views/pages-view.ts +61 -0
  36. package/src/components/sidebar-views/setting-view.ts +21 -0
  37. package/src/components/sidebar-views/sites-view.ts +42 -0
  38. package/src/components/sidebar-views/transfer-view.ts +218 -0
  39. package/src/components/sidebar.ts +288 -0
  40. package/src/context.ts +42 -0
  41. package/src/default-conf.ts +42 -0
  42. package/src/lib/checker/admin-checker.ts +33 -0
  43. package/src/lib/checker/captcha-checker.ts +38 -0
  44. package/src/lib/checker/index.ts +134 -0
  45. package/src/lib/component.ts +3 -3
  46. package/src/lib/md5.js +6 -0
  47. package/src/lib/ui.ts +64 -74
  48. package/src/lib/user.ts +2 -8
  49. package/src/lib/utils.ts +30 -11
  50. package/src/main.ts +1 -1
  51. package/src/style/_color.less +8 -2
  52. package/src/style/_extend.less +81 -0
  53. package/src/style/_variables.less +3 -0
  54. package/src/style/comment.less +60 -24
  55. package/src/style/editor.less +3 -0
  56. package/src/style/item-text-editor.less +35 -0
  57. package/src/style/list.less +51 -32
  58. package/src/style/main.less +75 -1
  59. package/src/style/page-list.less +50 -0
  60. package/src/style/pagination.less +58 -0
  61. package/src/style/sidebar.less +274 -199
  62. package/src/style/site-list.less +208 -0
  63. package/tsconfig.json +27 -0
  64. package/types/artalk-config.d.ts +68 -51
  65. package/types/artalk-data.d.ts +38 -1
  66. package/types/event.d.ts +73 -0
  67. package/types/index.d.ts +1 -6
  68. package/.github/workflows/npm.yml +0 -31
  69. package/.github/workflows/pages.yml +0 -30
  70. package/dist/src/Event.d.ts +0 -59
  71. package/dist/types/artalk-config.d.ts +0 -79
  72. package/dist/types/artalk-data.d.ts +0 -153
  73. package/dist/types/global.d.ts +0 -1
  74. package/dist/types/index.d.ts +0 -8
  75. package/dist/types/vite-env.d.ts +0 -1
  76. package/example/pjax/res1.html +0 -41
  77. package/example/pjax/res2.html +0 -41
  78. package/src/Artalk.ts +0 -160
  79. package/src/Constant.ts +0 -6
  80. package/src/Context.ts +0 -34
  81. package/src/Event.d.ts +0 -59
  82. package/src/components/Comment.ts +0 -402
  83. package/src/components/Layer.ts +0 -138
  84. package/src/components/List.ts +0 -162
  85. package/src/components/ListLite.ts +0 -407
  86. package/src/components/Sidebar.ts +0 -141
  87. package/src/components/sidebar-views/AdminView.ts +0 -523
  88. package/src/components/sidebar-views/MessageView.ts +0 -48
  89. package/src/components/sidebar-views/SidebarView.ts +0 -24
  90. package/src/lib/api.ts +0 -380
  91. package/src/lib/checker.ts +0 -164
@@ -1,36 +1,34 @@
1
1
  import '../style/editor.less'
2
2
 
3
- import Context from '../Context'
3
+ import Context from '../context'
4
4
  import Component from '../lib/component'
5
5
  import * as Utils from '../lib/utils'
6
6
  import * as Ui from '../lib/ui'
7
7
  import EditorHTML from './html/editor.html?raw'
8
8
 
9
- import EmoticonsPlug from './editor-plugs/EmoticonsPlug'
10
- import PreviewPlug from './editor-plugs/PreviewPlug'
9
+ import EmoticonsPlug from './editor-plugs/emoticons-plug'
10
+ import PreviewPlug from './editor-plugs/preview-plug'
11
11
  import { CommentData } from '~/types/artalk-data'
12
- import Api from '../lib/api'
12
+ import Api from '../api'
13
13
 
14
14
  export default class Editor extends Component {
15
15
  private readonly LOADABLE_PLUG_LIST = [EmoticonsPlug, PreviewPlug]
16
16
  public plugList: { [name: string]: any } = {}
17
17
 
18
- public el: HTMLElement
19
-
20
- public headerEl: HTMLElement
21
- public textareaWrapEl: HTMLElement
22
- public textareaEl: HTMLTextAreaElement
23
- public closeCommentEl: HTMLTextAreaElement
24
- public plugWrapEl: HTMLElement
25
- public bottomEl: HTMLElement
26
- public bottomPartLeftEl: HTMLElement
27
- public plugSwitcherWrapEl: HTMLElement
28
- public bottomPartRightEl: HTMLElement
29
- public submitBtn: HTMLButtonElement
30
- public notifyWrapEl: HTMLElement
18
+ public $header: HTMLElement
19
+ public $textareaWrap: HTMLElement
20
+ public $textarea: HTMLTextAreaElement
21
+ public $closeComment: HTMLTextAreaElement
22
+ public $plugWrap: HTMLElement
23
+ public $bottom: HTMLElement
24
+ public $bottomPartLeft: HTMLElement
25
+ public $plugSwitcherWrap: HTMLElement
26
+ public $bottomPartRight: HTMLElement
27
+ public $submitBtn: HTMLButtonElement
28
+ public $notifyWrap: HTMLElement
31
29
 
32
30
  private replyComment: CommentData|null = null
33
- private sendReplyEl: HTMLElement|null = null
31
+ private $sendReply: HTMLElement|null = null
34
32
 
35
33
  private get user () {
36
34
  return this.ctx.user
@@ -39,19 +37,19 @@ export default class Editor extends Component {
39
37
  constructor (ctx: Context) {
40
38
  super(ctx)
41
39
 
42
- this.el = Utils.createElement(EditorHTML)
40
+ this.$el = Utils.createElement(EditorHTML)
43
41
 
44
- this.headerEl = this.el.querySelector('.atk-editor-header')!
45
- this.textareaWrapEl = this.el.querySelector('.atk-editor-textarea-wrap')!
46
- this.textareaEl = this.el.querySelector('.atk-editor-textarea')!
47
- this.closeCommentEl = this.el.querySelector('.atk-close-comment')!
48
- this.plugWrapEl = this.el.querySelector('.atk-editor-plug-wrap')!
49
- this.bottomEl = this.el.querySelector('.atk-editor-bottom')!
50
- this.bottomPartLeftEl = this.el.querySelector('.atk-editor-bottom-part.atk-left')!
51
- this.plugSwitcherWrapEl = this.el.querySelector('.atk-editor-plug-switcher-wrap')!
52
- this.bottomPartRightEl = this.el.querySelector('.atk-editor-bottom-part.atk-right')!
53
- this.submitBtn = this.el.querySelector('.atk-send-btn')!
54
- this.notifyWrapEl = this.el.querySelector('.atk-editor-notify-wrap')!
42
+ this.$header = this.$el.querySelector('.atk-editor-header')!
43
+ this.$textareaWrap = this.$el.querySelector('.atk-editor-textarea-wrap')!
44
+ this.$textarea = this.$el.querySelector('.atk-editor-textarea')!
45
+ this.$closeComment = this.$el.querySelector('.atk-close-comment')!
46
+ this.$plugWrap = this.$el.querySelector('.atk-editor-plug-wrap')!
47
+ this.$bottom = this.$el.querySelector('.atk-editor-bottom')!
48
+ this.$bottomPartLeft = this.$el.querySelector('.atk-editor-bottom-part.atk-left')!
49
+ this.$plugSwitcherWrap = this.$el.querySelector('.atk-editor-plug-switcher-wrap')!
50
+ this.$bottomPartRight = this.$el.querySelector('.atk-editor-bottom-part.atk-right')!
51
+ this.$submitBtn = this.$el.querySelector('.atk-send-btn')!
52
+ this.$notifyWrap = this.$el.querySelector('.atk-editor-notify-wrap')!
55
53
 
56
54
  this.initLocalStorage()
57
55
  this.initHeader()
@@ -60,12 +58,12 @@ export default class Editor extends Component {
60
58
  this.initBottomPart()
61
59
 
62
60
  // 监听事件
63
- this.ctx.addEventListener('editor-open-comment', () => (this.openComment()))
64
- this.ctx.addEventListener('editor-close-comment', () => (this.closeComment()))
65
- this.ctx.addEventListener('editor-reply', (commentData) => (this.setReply(commentData)))
66
- this.ctx.addEventListener('editor-show-loading', () => (Ui.showLoading(this.el)))
67
- this.ctx.addEventListener('editor-hide-loading', () => (Ui.hideLoading(this.el)))
68
- this.ctx.addEventListener('editor-notify', (f) => (this.showNotify(f.msg, f.type)))
61
+ this.ctx.on('editor-open', () => (this.open()))
62
+ this.ctx.on('editor-close', () => (this.close()))
63
+ this.ctx.on('editor-reply', (commentData) => (this.setReply(commentData)))
64
+ this.ctx.on('editor-show-loading', () => (Ui.showLoading(this.$el)))
65
+ this.ctx.on('editor-hide-loading', () => (Ui.hideLoading(this.$el)))
66
+ this.ctx.on('editor-notify', (f) => (this.showNotify(f.msg, f.type)))
69
67
  }
70
68
 
71
69
  initLocalStorage () {
@@ -74,7 +72,7 @@ export default class Editor extends Component {
74
72
  this.showNotify('已自动恢复', 'i')
75
73
  this.setContent(localContent)
76
74
  }
77
- this.textareaEl.addEventListener('input', () => {
75
+ this.$textarea.addEventListener('input', () => {
78
76
  this.saveContent()
79
77
  })
80
78
  }
@@ -91,7 +89,7 @@ export default class Editor extends Component {
91
89
  }
92
90
 
93
91
  getInputEl (field: string) {
94
- const inputEl = this.headerEl.querySelector<HTMLInputElement>(`[name="${field}"]`)
92
+ const inputEl = this.$header.querySelector<HTMLInputElement>(`[name="${field}"]`)
95
93
  return inputEl
96
94
  }
97
95
 
@@ -127,7 +125,7 @@ export default class Editor extends Component {
127
125
  }
128
126
 
129
127
  // 未读消息更新
130
- this.ctx.dispatchEvent('unread-update', { notifies: data.unread, })
128
+ this.ctx.trigger('unread-update', { notifies: data.unread, })
131
129
 
132
130
  // 若用户为管理员,执行登陆操作
133
131
  if (this.user.checkHasBasicUserInfo() && !data.is_login && data.user && data.user.is_admin) {
@@ -150,7 +148,7 @@ export default class Editor extends Component {
150
148
  }
151
149
 
152
150
  showLoginDialog () {
153
- this.ctx.dispatchEvent('checker-admin', {
151
+ this.ctx.trigger('checker-admin', {
154
152
  onSuccess: () => {
155
153
  }
156
154
  })
@@ -158,7 +156,7 @@ export default class Editor extends Component {
158
156
 
159
157
  saveUser () {
160
158
  this.user.save()
161
- this.ctx.dispatchEvent('user-changed')
159
+ this.ctx.trigger('user-changed', this.ctx.user.data)
162
160
  }
163
161
 
164
162
  saveContent () {
@@ -167,10 +165,10 @@ export default class Editor extends Component {
167
165
 
168
166
  initTextarea () {
169
167
  // 占位符
170
- this.textareaEl.placeholder = this.ctx.conf.placeholder || ''
168
+ this.$textarea.placeholder = this.ctx.conf.placeholder || ''
171
169
 
172
170
  // 修复按下 Tab 输入的内容
173
- this.textareaEl.addEventListener('keydown', (e) => {
171
+ this.$textarea.addEventListener('keydown', (e) => {
174
172
  const keyCode = e.keyCode || e.which
175
173
 
176
174
  if (keyCode === 9) {
@@ -180,25 +178,25 @@ export default class Editor extends Component {
180
178
  })
181
179
 
182
180
  // 输入框高度随内容而变化
183
- this.textareaEl.addEventListener('input', (evt) => {
181
+ this.$textarea.addEventListener('input', (evt) => {
184
182
  this.adjustTextareaHeight()
185
183
  })
186
184
  }
187
185
 
188
186
  adjustTextareaHeight () {
189
- const diff = this.textareaEl.offsetHeight - this.textareaEl.clientHeight
190
- this.textareaEl.style.height = '0px' // it's a magic. 若不加此行,内容减少,高度回不去
191
- this.textareaEl.style.height = `${this.textareaEl.scrollHeight + diff}px`
187
+ const diff = this.$textarea.offsetHeight - this.$textarea.clientHeight
188
+ this.$textarea.style.height = '0px' // it's a magic. 若不加此行,内容减少,高度回不去
189
+ this.$textarea.style.height = `${this.$textarea.scrollHeight + diff}px`
192
190
  }
193
191
 
194
192
  openedPlugName: string|null = null
195
193
 
196
194
  initEditorPlug () {
197
195
  this.plugList = {}
198
- this.plugWrapEl.innerHTML = ''
199
- this.plugWrapEl.style.display = 'none'
196
+ this.$plugWrap.innerHTML = ''
197
+ this.$plugWrap.style.display = 'none'
200
198
  this.openedPlugName = null
201
- this.plugSwitcherWrapEl.innerHTML = ''
199
+ this.$plugSwitcherWrap.innerHTML = ''
202
200
 
203
201
  // 依次实例化 plug
204
202
  this.LOADABLE_PLUG_LIST.forEach((PlugObj) => {
@@ -207,27 +205,27 @@ export default class Editor extends Component {
207
205
 
208
206
  // 切换按钮
209
207
  const btnElem = Utils.createElement(`<span class="atk-editor-action atk-editor-plug-switcher">${plug.getBtnHtml()}</span>`)
210
- this.plugSwitcherWrapEl.appendChild(btnElem)
208
+ this.$plugSwitcherWrap.appendChild(btnElem)
211
209
  btnElem.addEventListener('click', () => {
212
- this.plugSwitcherWrapEl.querySelectorAll('.active').forEach(item => item.classList.remove('active'))
210
+ this.$plugSwitcherWrap.querySelectorAll('.active').forEach(item => item.classList.remove('active'))
213
211
 
214
212
  // 若点击已打开的,则收起
215
213
  if (plug.getName() === this.openedPlugName) {
216
214
  plug.onHide()
217
- this.plugWrapEl.style.display = 'none'
215
+ this.$plugWrap.style.display = 'none'
218
216
  this.openedPlugName = null
219
217
  return
220
218
  }
221
219
 
222
- if (this.plugWrapEl.querySelector(`[data-plug-name="${plug.getName()}"]`) === null) {
220
+ if (this.$plugWrap.querySelector(`[data-plug-name="${plug.getName()}"]`) === null) {
223
221
  // 需要初始化
224
222
  const plugEl = plug.getEl()
225
223
  plugEl.setAttribute('data-plug-name', plug.getName())
226
224
  plugEl.style.display = 'none'
227
- this.plugWrapEl.appendChild(plugEl)
225
+ this.$plugWrap.appendChild(plugEl)
228
226
  }
229
227
 
230
- (Array.from(this.plugWrapEl.children) as HTMLElement[]).forEach((plugItemEl: HTMLElement) => {
228
+ (Array.from(this.$plugWrap.children) as HTMLElement[]).forEach((plugItemEl: HTMLElement) => {
231
229
  const plugItemName = plugItemEl.getAttribute('data-plug-name')!
232
230
  if (plugItemName === plug.getName()) {
233
231
  plugItemEl.style.display = ''
@@ -238,7 +236,7 @@ export default class Editor extends Component {
238
236
  }
239
237
  })
240
238
 
241
- this.plugWrapEl.style.display = ''
239
+ this.$plugWrap.style.display = ''
242
240
  this.openedPlugName = plug.getName()
243
241
 
244
242
  btnElem.classList.add('active')
@@ -248,33 +246,33 @@ export default class Editor extends Component {
248
246
 
249
247
  /** 关闭编辑器插件 */
250
248
  closePlug () {
251
- this.plugWrapEl.innerHTML = ''
252
- this.plugWrapEl.style.display = 'none'
249
+ this.$plugWrap.innerHTML = ''
250
+ this.$plugWrap.style.display = 'none'
253
251
  this.openedPlugName = null
254
252
  }
255
253
 
256
254
  insertContent (val: string) {
257
255
  if ((document as any).selection) {
258
- this.textareaEl.focus();
256
+ this.$textarea.focus();
259
257
  (document as any).selection.createRange().text = val
260
- this.textareaEl.focus()
261
- } else if (this.textareaEl.selectionStart || this.textareaEl.selectionStart === 0) {
262
- const sStart = this.textareaEl.selectionStart
263
- const sEnd = this.textareaEl.selectionEnd
264
- const sT = this.textareaEl.scrollTop
265
- this.setContent(this.textareaEl.value.substring(0, sStart) + val + this.textareaEl.value.substring(sEnd, this.textareaEl.value.length))
266
- this.textareaEl.focus()
267
- this.textareaEl.selectionStart = sStart + val.length
268
- this.textareaEl.selectionEnd = sStart + val.length
269
- this.textareaEl.scrollTop = sT
258
+ this.$textarea.focus()
259
+ } else if (this.$textarea.selectionStart || this.$textarea.selectionStart === 0) {
260
+ const sStart = this.$textarea.selectionStart
261
+ const sEnd = this.$textarea.selectionEnd
262
+ const sT = this.$textarea.scrollTop
263
+ this.setContent(this.$textarea.value.substring(0, sStart) + val + this.$textarea.value.substring(sEnd, this.$textarea.value.length))
264
+ this.$textarea.focus()
265
+ this.$textarea.selectionStart = sStart + val.length
266
+ this.$textarea.selectionEnd = sStart + val.length
267
+ this.$textarea.scrollTop = sT
270
268
  } else {
271
- this.textareaEl.focus()
272
- this.textareaEl.value += val
269
+ this.$textarea.focus()
270
+ this.$textarea.value += val
273
271
  }
274
272
  }
275
273
 
276
274
  setContent (val: string) {
277
- this.textareaEl.value = val
275
+ this.$textarea.value = val
278
276
  this.saveContent()
279
277
  if (!!this.plugList && !!this.plugList.preview) {
280
278
  this.plugList.preview.updateContent()
@@ -300,7 +298,7 @@ export default class Editor extends Component {
300
298
  }
301
299
 
302
300
  getContentOriginal () {
303
- return this.textareaEl.value || '' // Tip: !!"0" === true
301
+ return this.$textarea.value || '' // Tip: !!"0" === true
304
302
  }
305
303
 
306
304
  getContentMarked () {
@@ -314,7 +312,7 @@ export default class Editor extends Component {
314
312
 
315
313
  initReply () {
316
314
  this.replyComment = null
317
- this.sendReplyEl = null
315
+ this.$sendReply = null
318
316
  }
319
317
 
320
318
  setReply (commentData: CommentData) {
@@ -322,31 +320,31 @@ export default class Editor extends Component {
322
320
  this.cancelReply()
323
321
  }
324
322
 
325
- if (this.sendReplyEl === null) {
326
- this.sendReplyEl = Utils.createElement('<div class="atk-send-reply-wrap"><div class="atk-send-reply">回复 <span class="atk-text"></span><span class="atk-cancel" title="取消 AT">×</span></div></div>');
327
- this.sendReplyEl.querySelector<HTMLElement>('.atk-text')!.innerText = `@${commentData.nick}`
328
- this.sendReplyEl.addEventListener('click', () => {
323
+ if (this.$sendReply === null) {
324
+ this.$sendReply = Utils.createElement('<div class="atk-send-reply-wrap"><div class="atk-send-reply">回复 <span class="atk-text"></span><span class="atk-cancel" title="取消 AT">×</span></div></div>');
325
+ this.$sendReply.querySelector<HTMLElement>('.atk-text')!.innerText = `@${commentData.nick}`
326
+ this.$sendReply.addEventListener('click', () => {
329
327
  this.cancelReply()
330
328
  })
331
- this.textareaWrapEl.prepend(this.sendReplyEl)
329
+ this.$textareaWrap.prepend(this.$sendReply)
332
330
  }
333
331
  this.replyComment = commentData
334
- Ui.scrollIntoView(this.el)
335
- this.textareaEl.focus()
332
+ Ui.scrollIntoView(this.$el)
333
+ this.$textarea.focus()
336
334
  }
337
335
 
338
336
  cancelReply () {
339
- if (this.sendReplyEl !== null) {
340
- this.sendReplyEl.remove()
341
- this.sendReplyEl = null
337
+ if (this.$sendReply !== null) {
338
+ this.$sendReply.remove()
339
+ this.$sendReply = null
342
340
  }
343
341
  this.replyComment = null
344
342
  }
345
343
 
346
344
  initSubmit () {
347
- this.submitBtn.innerText = this.ctx.conf.sendBtn || 'Send'
345
+ this.$submitBtn.innerText = this.ctx.conf.sendBtn || 'Send'
348
346
 
349
- this.submitBtn.addEventListener('click', (evt) => {
347
+ this.$submitBtn.addEventListener('click', (evt) => {
350
348
  const btnEl = evt.currentTarget
351
349
  this.submit()
352
350
  })
@@ -354,11 +352,13 @@ export default class Editor extends Component {
354
352
 
355
353
  async submit () {
356
354
  if (this.getContent().trim() === '') {
357
- this.textareaEl.focus()
355
+ this.$textarea.focus()
358
356
  return
359
357
  }
360
358
 
361
- Ui.showLoading(this.el)
359
+ this.ctx.trigger('editor-submit')
360
+
361
+ Ui.showLoading(this.$el)
362
362
 
363
363
  try {
364
364
  const nComment = await new Api(this.ctx).add({
@@ -369,39 +369,41 @@ export default class Editor extends Component {
369
369
  rid: this.replyComment === null ? 0 : this.replyComment.id
370
370
  })
371
371
 
372
- this.ctx.dispatchEvent('list-insert', nComment)
372
+ this.ctx.trigger('list-insert', nComment)
373
373
  this.clearEditor() // 清空编辑器
374
+ this.ctx.trigger('editor-submitted')
374
375
  } catch (err: any) {
376
+ console.error(err)
375
377
  this.showNotify(`评论失败,${err.msg || String(err)}`, 'e')
376
378
  } finally {
377
- Ui.hideLoading(this.el)
379
+ Ui.hideLoading(this.$el)
378
380
  }
379
381
  }
380
382
 
381
383
  showNotify (msg: string, type) {
382
- Ui.showNotify(this.notifyWrapEl, msg, type)
384
+ Ui.showNotify(this.$notifyWrap, msg, type)
383
385
  }
384
386
 
385
387
  /** 关闭评论 */
386
- closeComment () {
387
- this.closeCommentEl.style.display = ''
388
+ close () {
389
+ this.$closeComment.style.display = ''
388
390
 
389
391
  if (!this.user.data.isAdmin) {
390
- this.textareaEl.style.display = 'none'
392
+ this.$textarea.style.display = 'none'
391
393
  this.closePlug()
392
- this.bottomEl.style.display = 'none'
394
+ this.$bottom.style.display = 'none'
393
395
  } else {
394
396
  // 管理员一直打开评论
395
- this.textareaEl.style.display = ''
396
- this.bottomEl.style.display = ''
397
+ this.$textarea.style.display = ''
398
+ this.$bottom.style.display = ''
397
399
  }
398
400
  }
399
401
 
400
402
  /** 打开评论 */
401
- openComment () {
402
- this.closeCommentEl.style.display = 'none'
403
- this.textareaEl.style.display = ''
404
- this.bottomEl.style.display = ''
403
+ open () {
404
+ this.$closeComment.style.display = 'none'
405
+ this.$textarea.style.display = ''
406
+ this.$bottom.style.display = ''
405
407
  }
406
408
  }
407
409
 
@@ -1,18 +1,14 @@
1
1
  <div class="atk-comment-wrap" data-comment-id="">
2
2
  <div class="atk-comment">
3
3
 
4
- <div class="atk-avatar">
5
- <a target="_blank"><img src=""></a>
6
- </div>
4
+ <div class="atk-avatar"></div>
7
5
 
8
6
  <div class="atk-comment-main">
9
7
 
10
8
  <div class="atk-header">
11
- <span class="atk-nick"><a target="_blank"></a></span>
9
+ <span class="atk-nick"></span>
12
10
  <span class="atk-badge"></span>
13
11
  <span class="atk-date"></span>
14
- <span class="atk-ua ua-browser"></span>
15
- <span class="atk-ua ua-os"></span>
16
12
  </div>
17
13
 
18
14
  <div class="atk-body">
@@ -6,7 +6,6 @@
6
6
  </div>
7
7
  <div class="atk-right-action">
8
8
  <span data-action="admin-close-comment" class="atk-hide" atk-only-admin-show>关闭评论</span>
9
- <span data-action="open-admin-panel" class="atk-hide atk-on" atk-only-admin-show>控制台</span>
10
9
  <span data-action="open-sidebar" class="atk-hide atk-on">
11
10
  <span class="atk-unread-badge" style="display: none;"></span>
12
11
  通知中心
@@ -1,8 +1,22 @@
1
1
  <div class="atk-sidebar">
2
2
  <div class="atk-sidebar-inner">
3
- <div class="atk-sidebar-title-wrap"><span class="atk-title-item atk-active"></span></div>
4
- <div class="atk-sidebar-close"><svg xmlns="http://www.w3.org/2000/svg" width="24" height="24" viewBox="0 0 24 24"><path d="M19 6.41L17.59 5 12 10.59 6.41 5 5 6.41 10.59 12 5 17.59 6.41 19 12 13.41 17.59 19 19 17.59 13.41 12z"/><path d="M0 0h24v24H0z" fill="none"/></svg></div>
5
- <div class="atk-sidebar-actions"></div>
6
- <div class="atk-sidebar-content"></div>
3
+ <div class="atk-sidebar-header">
4
+ <span class="atk-avatar">
5
+ <span class="atk-site-logo"></span>
6
+ </span>
7
+ <span class="atk-menu">
8
+ <span class="atk-item atk-active atk-sidebar-title">控制中心</span>
9
+ </span>
10
+ <div class="atk-sidebar-close"><i class="atk-icon atk-icon-close"></i></div>
11
+ </div>
12
+ <div class="atk-sidebar-nav">
13
+ <div class="akt-curt-view-btn">
14
+ <div class="atk-icon"><span></span><span></span><span></span></div>
15
+ <div class="atk-text"></div>
16
+ </div>
17
+ <div class="atk-tabs"></div>
18
+ <div class="atk-tabs atk-views" style="display: none;"></div>
19
+ </div>
20
+ <div class="atk-sidebar-view-wrap"></div>
7
21
  </div>
8
22
  </div>
@@ -0,0 +1,136 @@
1
+ import '../style/item-text-editor.less'
2
+
3
+ import * as Utils from '../lib/utils'
4
+
5
+ interface ItemTextEditorConf {
6
+ initValue?: string
7
+ validator?: (value: string) => boolean
8
+ onYes?: (value: string) => boolean|void|Promise<boolean|void>
9
+ onNo?: () => boolean|void|Promise<boolean|void>
10
+ placeholder?: string
11
+ }
12
+
13
+ /**
14
+ * 通用列表项目文本编辑器
15
+ */
16
+ export default class ItemTextEditor {
17
+ private conf: ItemTextEditorConf
18
+ public $el: HTMLElement
19
+
20
+ public $input: HTMLInputElement
21
+ public $yesBtn: HTMLElement
22
+ public $noBtn: HTMLElement
23
+
24
+ public value: string = ''
25
+ public allowSubmit = true
26
+
27
+ constructor(conf: ItemTextEditorConf) {
28
+ this.conf = conf
29
+
30
+ this.$el = Utils.createElement(
31
+ `<div class="atk-item-text-editor-layer">
32
+ <div class="atk-edit-form">
33
+ <input class="atk-main-input" type="text" placeholder="输入内容..." autocomplete="off" autofocus>
34
+ </div>
35
+ <div class="atk-actions">
36
+ <div class="atk-item atk-yes-btn">
37
+ <i class="atk-icon atk-icon-yes"></i>
38
+ </div>
39
+ <div class="atk-item atk-no-btn">
40
+ <i class="atk-icon atk-icon-no"></i>
41
+ </div>
42
+ </div>
43
+ </div>`)
44
+
45
+ this.$input = this.$el.querySelector('.atk-main-input')!
46
+ this.$yesBtn = this.$el.querySelector('.atk-yes-btn')!
47
+ this.$noBtn = this.$el.querySelector('.atk-no-btn')!
48
+
49
+ this.$input.value = conf.initValue || ''
50
+ this.value = conf.initValue || ''
51
+ if (this.conf.placeholder) this.$input.placeholder = this.conf.placeholder
52
+
53
+ this.$input.oninput = () => this.onInput()
54
+ this.$input.onkeyup = (evt) => {
55
+ if (evt.key === 'Enter' || evt.keyCode === 13) { // 按下回车键
56
+ evt.preventDefault()
57
+ this.submit()
58
+ }
59
+ }
60
+
61
+ window.setTimeout(() => this.$input.focus(), 80)
62
+
63
+ this.$yesBtn.onclick = () => { this.submit() }
64
+ this.$noBtn.onclick = () => { this.cancel() }
65
+ }
66
+
67
+ public appendTo(parentDOM: HTMLElement) {
68
+ parentDOM.append(this.$el)
69
+ return this
70
+ }
71
+
72
+ private onInput() {
73
+ this.value = this.$input.value
74
+
75
+ // 验证器
76
+ if (this.conf.validator) {
77
+ const ok = this.conf.validator(this.value)
78
+ this.setAllowSubmit(ok)
79
+ if (!ok) {
80
+ this.$input.classList.add('atk-invalid')
81
+ } else {
82
+ this.$input.classList.remove('atk-invalid')
83
+ }
84
+ }
85
+ }
86
+
87
+ public setAllowSubmit(allow: boolean) {
88
+ if (this.allowSubmit === allow) return
89
+ this.allowSubmit = allow
90
+ if (!allow) {
91
+ this.$yesBtn.classList.add('.atk-disabled')
92
+ } else {
93
+ this.$yesBtn.classList.remove('.atk-disabled')
94
+ }
95
+ }
96
+
97
+ public async submit() {
98
+ if (!this.allowSubmit) return
99
+
100
+ if (this.conf.onYes) {
101
+ let isContinue: any
102
+ if (this.conf.onYes instanceof (async () => {}).constructor) {
103
+ isContinue = await this.conf.onYes(this.value)
104
+ } else {
105
+ isContinue = this.conf.onYes(this.value)
106
+ }
107
+
108
+ if (isContinue === undefined || isContinue === true) {
109
+ this.closeEditor()
110
+ }
111
+ } else {
112
+ this.closeEditor()
113
+ }
114
+ }
115
+
116
+ public async cancel() {
117
+ if (this.conf.onNo) {
118
+ let isContinue: any
119
+ if (this.conf.onNo instanceof (async () => {}).constructor) {
120
+ isContinue = await this.conf.onNo()
121
+ } else {
122
+ isContinue = this.conf.onNo()
123
+ }
124
+
125
+ if (isContinue === undefined || isContinue === true) {
126
+ this.closeEditor()
127
+ }
128
+ } else {
129
+ this.closeEditor()
130
+ }
131
+ }
132
+
133
+ public closeEditor() {
134
+ this.$el.remove()
135
+ }
136
+ }