artalk 2.7.0 → 2.7.2
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.
- package/README.md +1 -1
- package/dist/Artalk.css +1 -1
- package/dist/Artalk.es.js +209 -188
- package/dist/Artalk.es.js.map +1 -0
- package/dist/Artalk.iife.js +2 -1
- package/dist/Artalk.iife.js.map +1 -0
- package/dist/Artalk.js +2 -1
- package/dist/Artalk.js.map +1 -0
- package/dist/ArtalkLite.css +1 -1
- package/dist/ArtalkLite.es.js +209 -188
- package/dist/ArtalkLite.es.js.map +1 -0
- package/dist/ArtalkLite.iife.js +2 -1
- package/dist/ArtalkLite.iife.js.map +1 -0
- package/dist/ArtalkLite.js +2 -1
- package/dist/ArtalkLite.js.map +1 -0
- package/dist/i18n/jp.js +1 -1
- package/dist/i18n/zh-TW.js +1 -1
- package/dist/src/api/_base.d.ts +7 -0
- package/dist/src/api/_options.d.ts +5 -0
- package/dist/src/artalk.d.ts +0 -2
- package/dist/src/components/checker/index.d.ts +2 -0
- package/dist/src/i18n/en.d.ts +4 -0
- package/dist/src/i18n/external.d.ts +4 -0
- package/dist/src/i18n/index.d.ts +12 -0
- package/dist/src/i18n/jp.d.ts +4 -0
- package/dist/src/i18n/zh-TW.d.ts +4 -0
- package/dist/src/lib/user.d.ts +8 -6
- package/dist/src/main.d.ts +3 -0
- package/dist/src/plugins/editor/_kit.d.ts +7 -1
- package/dist/src/service.d.ts +2 -8
- package/dist/types/event.d.ts +1 -1
- package/package.json +43 -17
- package/dist/src/components/dark-mode.d.ts +0 -2
- package/src/api/_base.ts +0 -18
- package/src/api/_options.ts +0 -25
- package/src/api/_request.ts +0 -104
- package/src/api/admin.ts +0 -18
- package/src/api/captcha.ts +0 -24
- package/src/api/comment.ts +0 -84
- package/src/api/index.ts +0 -29
- package/src/api/page.ts +0 -83
- package/src/api/site.ts +0 -51
- package/src/api/system.ts +0 -49
- package/src/api/upload.ts +0 -28
- package/src/api/user.ts +0 -132
- package/src/artalk.ts +0 -119
- package/src/comment/actions.ts +0 -83
- package/src/comment/comment.html +0 -18
- package/src/comment/comment.ts +0 -192
- package/src/comment/height-limit.ts +0 -100
- package/src/comment/index.ts +0 -3
- package/src/comment/render.ts +0 -150
- package/src/comment/renders/actions.ts +0 -114
- package/src/comment/renders/avatar.ts +0 -22
- package/src/comment/renders/content.ts +0 -39
- package/src/comment/renders/header.ts +0 -84
- package/src/comment/renders/index.ts +0 -19
- package/src/comment/renders/pending.ts +0 -12
- package/src/comment/renders/reply-at.ts +0 -16
- package/src/comment/renders/reply-to.ts +0 -24
- package/src/components/action-btn.ts +0 -170
- package/src/components/checker/admin.ts +0 -37
- package/src/components/checker/captcha-renders.ts +0 -69
- package/src/components/checker/captcha.ts +0 -26
- package/src/components/checker/index.ts +0 -192
- package/src/components/dark-mode.ts +0 -30
- package/src/components/dialog.ts +0 -62
- package/src/components/error-dialog.ts +0 -35
- package/src/components/pagination.ts +0 -153
- package/src/components/read-more-btn.ts +0 -92
- package/src/config.ts +0 -119
- package/src/context.ts +0 -146
- package/src/data.ts +0 -110
- package/src/defaults.ts +0 -61
- package/src/editor/editor.html +0 -18
- package/src/editor/editor.ts +0 -114
- package/src/editor/state.ts +0 -52
- package/src/editor/ui.ts +0 -36
- package/src/i18n/en.ts +0 -81
- package/src/i18n/external.ts +0 -10
- package/src/i18n/index.ts +0 -67
- package/src/i18n/jp.ts +0 -83
- package/src/i18n/zh-CN.ts +0 -85
- package/src/i18n/zh-TW.ts +0 -83
- package/src/layer/index.ts +0 -4
- package/src/layer/layer-manager.ts +0 -32
- package/src/layer/layer.ts +0 -39
- package/src/layer/scrollbar-helper.ts +0 -24
- package/src/layer/sidebar-layer.html +0 -8
- package/src/layer/sidebar-layer.ts +0 -155
- package/src/layer/wrap.ts +0 -77
- package/src/lib/component.ts +0 -12
- package/src/lib/detect.ts +0 -222
- package/src/lib/event-manager.ts +0 -47
- package/src/lib/highlight.ts +0 -5
- package/src/lib/marked-renderer.ts +0 -32
- package/src/lib/marked.ts +0 -72
- package/src/lib/sanitizer.ts +0 -57
- package/src/lib/ui.ts +0 -193
- package/src/lib/user.ts +0 -55
- package/src/lib/utils.ts +0 -236
- package/src/list/comment.ts +0 -20
- package/src/list/layout.ts +0 -120
- package/src/list/list.html +0 -20
- package/src/list/list.ts +0 -79
- package/src/list/nest.ts +0 -66
- package/src/list/page.ts +0 -97
- package/src/list/paginator/index.ts +0 -25
- package/src/list/paginator/read-more.ts +0 -67
- package/src/list/paginator/up-down.ts +0 -51
- package/src/main.ts +0 -5
- package/src/plugins/admin-only-elem.ts +0 -40
- package/src/plugins/conf-remoter.ts +0 -54
- package/src/plugins/dark-mode.ts +0 -12
- package/src/plugins/editor/_kit.ts +0 -57
- package/src/plugins/editor/_plug.ts +0 -60
- package/src/plugins/editor/_sample.ts +0 -8
- package/src/plugins/editor/closable.ts +0 -44
- package/src/plugins/editor/emoticons.scss +0 -72
- package/src/plugins/editor/emoticons.ts +0 -293
- package/src/plugins/editor/header-event.ts +0 -35
- package/src/plugins/editor/header-link.ts +0 -31
- package/src/plugins/editor/header-user.ts +0 -98
- package/src/plugins/editor/index.ts +0 -40
- package/src/plugins/editor/local-storage.ts +0 -36
- package/src/plugins/editor/mover.ts +0 -29
- package/src/plugins/editor/preview.scss +0 -7
- package/src/plugins/editor/preview.ts +0 -41
- package/src/plugins/editor/state-edit.ts +0 -116
- package/src/plugins/editor/state-reply.ts +0 -91
- package/src/plugins/editor/submit-add.ts +0 -33
- package/src/plugins/editor/submit-btn.ts +0 -25
- package/src/plugins/editor/submit.ts +0 -73
- package/src/plugins/editor/textarea.ts +0 -55
- package/src/plugins/editor/upload.ts +0 -145
- package/src/plugins/editor-kit.ts +0 -161
- package/src/plugins/index.ts +0 -16
- package/src/plugins/list/copyright.ts +0 -16
- package/src/plugins/list/count.ts +0 -31
- package/src/plugins/list/dropdown.ts +0 -95
- package/src/plugins/list/error-dialog.ts +0 -22
- package/src/plugins/list/fetch.ts +0 -64
- package/src/plugins/list/goto-first.ts +0 -23
- package/src/plugins/list/goto.ts +0 -72
- package/src/plugins/list/index.ts +0 -25
- package/src/plugins/list/loading.ts +0 -17
- package/src/plugins/list/no-comment.ts +0 -25
- package/src/plugins/list/reach-bottom.ts +0 -46
- package/src/plugins/list/sidebar-btn.ts +0 -39
- package/src/plugins/list/time-ticking.ts +0 -22
- package/src/plugins/list/unread-badge.ts +0 -26
- package/src/plugins/list/unread.ts +0 -38
- package/src/plugins/list/with-editor.ts +0 -59
- package/src/plugins/markdown.ts +0 -10
- package/src/plugins/stat.ts +0 -79
- package/src/plugins/version-check.ts +0 -37
- package/src/service.ts +0 -91
- package/src/style/_color.scss +0 -41
- package/src/style/_extend.scss +0 -20
- package/src/style/_variables.scss +0 -3
- package/src/style/comment.scss +0 -360
- package/src/style/editor.scss +0 -194
- package/src/style/list.scss +0 -212
- package/src/style/main.scss +0 -486
- package/src/style/pagination.scss +0 -58
- package/src/style/sidebar-layer.scss +0 -92
- package/types/config.ts +0 -153
- package/types/context.ts +0 -84
- package/types/data.ts +0 -271
- package/types/editor.ts +0 -95
- package/types/event.ts +0 -40
- package/types/global.d.ts +0 -1
- package/types/index.ts +0 -7
- package/types/plugin.ts +0 -3
- package/types/sidebar.ts +0 -3
package/src/comment/comment.ts
DELETED
|
@@ -1,192 +0,0 @@
|
|
|
1
|
-
import type { CommentData, ContextApi } from '~/types'
|
|
2
|
-
import Component from '../lib/component'
|
|
3
|
-
import * as Utils from '../lib/utils'
|
|
4
|
-
import marked from '../lib/marked'
|
|
5
|
-
import UADetect from '../lib/detect'
|
|
6
|
-
import CommentUI from './render'
|
|
7
|
-
import CommentActions from './actions'
|
|
8
|
-
|
|
9
|
-
export interface CommentConf {
|
|
10
|
-
isUnread?: boolean
|
|
11
|
-
openURL?: string
|
|
12
|
-
isFlatMode: boolean
|
|
13
|
-
replyTo?: CommentData
|
|
14
|
-
afterRender?: () => void
|
|
15
|
-
openEvt?: () => void
|
|
16
|
-
onReplyBtnClick?: Function
|
|
17
|
-
onDelete?: Function
|
|
18
|
-
}
|
|
19
|
-
|
|
20
|
-
export default class Comment extends Component {
|
|
21
|
-
private renderInstance: CommentUI
|
|
22
|
-
private actionInstance: CommentActions
|
|
23
|
-
|
|
24
|
-
private data: CommentData
|
|
25
|
-
private cConf: CommentConf
|
|
26
|
-
|
|
27
|
-
private parent: Comment|null
|
|
28
|
-
private children: Comment[] = []
|
|
29
|
-
|
|
30
|
-
private nestCurt: number // 当前嵌套层数
|
|
31
|
-
private nestMax: number // 最大嵌套层数
|
|
32
|
-
|
|
33
|
-
constructor(ctx: ContextApi, data: CommentData, conf: CommentConf) {
|
|
34
|
-
super(ctx)
|
|
35
|
-
|
|
36
|
-
// 最大嵌套数
|
|
37
|
-
this.nestMax = ctx.conf.nestMax || 3
|
|
38
|
-
|
|
39
|
-
this.cConf = conf
|
|
40
|
-
this.data = { ...data }
|
|
41
|
-
this.data.date = this.data.date.replace(/-/g, '/') // 解决 Safari 日期解析 NaN 问题
|
|
42
|
-
|
|
43
|
-
this.parent = null
|
|
44
|
-
this.nestCurt = 1 // 现在已嵌套 n 层
|
|
45
|
-
|
|
46
|
-
this.actionInstance = new CommentActions(this)
|
|
47
|
-
this.renderInstance = new CommentUI(this)
|
|
48
|
-
}
|
|
49
|
-
|
|
50
|
-
/** 渲染 UI */
|
|
51
|
-
public render() {
|
|
52
|
-
const newEl = this.renderInstance.render()
|
|
53
|
-
|
|
54
|
-
if (this.$el) this.$el.replaceWith(newEl)
|
|
55
|
-
this.$el = newEl
|
|
56
|
-
|
|
57
|
-
if (this.cConf.afterRender) this.cConf.afterRender()
|
|
58
|
-
}
|
|
59
|
-
|
|
60
|
-
/** 获取评论操作实例对象 */
|
|
61
|
-
public getActions() {
|
|
62
|
-
return this.actionInstance
|
|
63
|
-
}
|
|
64
|
-
|
|
65
|
-
/** 获取评论渲染器实例对象 */
|
|
66
|
-
public getRender() {
|
|
67
|
-
return this.renderInstance
|
|
68
|
-
}
|
|
69
|
-
|
|
70
|
-
/** 获取评论数据 */
|
|
71
|
-
public getData() {
|
|
72
|
-
return this.data
|
|
73
|
-
}
|
|
74
|
-
|
|
75
|
-
/** 设置数据 */
|
|
76
|
-
public setData(data: CommentData) {
|
|
77
|
-
this.data = data
|
|
78
|
-
|
|
79
|
-
this.render()
|
|
80
|
-
this.getRender().playFadeAnimForBody()
|
|
81
|
-
}
|
|
82
|
-
|
|
83
|
-
/** 获取父评论 */
|
|
84
|
-
public getParent() {
|
|
85
|
-
return this.parent
|
|
86
|
-
}
|
|
87
|
-
|
|
88
|
-
/** 获取所有子评论 */
|
|
89
|
-
public getChildren() {
|
|
90
|
-
return this.children
|
|
91
|
-
}
|
|
92
|
-
|
|
93
|
-
/** 获取当前嵌套层数 */
|
|
94
|
-
public getNestCurt() {
|
|
95
|
-
return this.nestCurt
|
|
96
|
-
}
|
|
97
|
-
|
|
98
|
-
/** 判断是否为根评论 */
|
|
99
|
-
public getIsRoot() {
|
|
100
|
-
return this.data.rid === 0
|
|
101
|
-
}
|
|
102
|
-
|
|
103
|
-
/** 获取评论 ID */
|
|
104
|
-
public getID() {
|
|
105
|
-
return this.data.id
|
|
106
|
-
}
|
|
107
|
-
|
|
108
|
-
/** 置入子评论 */
|
|
109
|
-
public putChild(childC: Comment, insertMode: 'append'|'prepend' = 'append') {
|
|
110
|
-
childC.parent = this
|
|
111
|
-
childC.nestCurt = this.nestCurt + 1 // 嵌套层数 +1
|
|
112
|
-
|
|
113
|
-
this.children.push(childC)
|
|
114
|
-
|
|
115
|
-
const $children = this.getChildrenEl()
|
|
116
|
-
if (insertMode === 'append') $children.append(childC.getEl())
|
|
117
|
-
else if (insertMode === 'prepend') $children.prepend(childC.getEl())
|
|
118
|
-
|
|
119
|
-
childC.getRender().playFadeAnim()
|
|
120
|
-
|
|
121
|
-
// 内容限高
|
|
122
|
-
childC.getRender().checkHeightLimit()
|
|
123
|
-
}
|
|
124
|
-
|
|
125
|
-
/** 获取存放子评论的元素对象 */
|
|
126
|
-
public getChildrenEl(): HTMLElement {
|
|
127
|
-
let $children = this.getRender().getChildrenWrap()
|
|
128
|
-
|
|
129
|
-
if (!$children) {
|
|
130
|
-
// console.log(this.nestCurt)
|
|
131
|
-
if (this.nestCurt < this.nestMax) {
|
|
132
|
-
$children = this.getRender().renderChildrenWrap()
|
|
133
|
-
} else {
|
|
134
|
-
$children = this.parent!.getChildrenEl()
|
|
135
|
-
}
|
|
136
|
-
}
|
|
137
|
-
|
|
138
|
-
return $children
|
|
139
|
-
}
|
|
140
|
-
|
|
141
|
-
/** 获取所有父评论 */
|
|
142
|
-
public getParents() {
|
|
143
|
-
const parents: Comment[] = []
|
|
144
|
-
const once = (c: Comment) => {
|
|
145
|
-
if (c.parent) {
|
|
146
|
-
parents.push(c.parent)
|
|
147
|
-
once(c.parent)
|
|
148
|
-
}
|
|
149
|
-
}
|
|
150
|
-
|
|
151
|
-
once(this)
|
|
152
|
-
return parents
|
|
153
|
-
}
|
|
154
|
-
|
|
155
|
-
/** 获取评论元素对象 */
|
|
156
|
-
public getEl() {
|
|
157
|
-
return this.$el
|
|
158
|
-
}
|
|
159
|
-
|
|
160
|
-
/** 获取 Gravatar 头像 URL */
|
|
161
|
-
public getGravatarURL() {
|
|
162
|
-
return Utils.getGravatarURL({
|
|
163
|
-
mirror: this.ctx.conf.gravatar.mirror,
|
|
164
|
-
params: this.ctx.conf.gravatar.params,
|
|
165
|
-
emailMD5: this.data.email_encrypted,
|
|
166
|
-
})
|
|
167
|
-
}
|
|
168
|
-
|
|
169
|
-
/** 获取评论 markdown 解析后的内容 */
|
|
170
|
-
public getContentMarked() {
|
|
171
|
-
return marked(this.data.content)
|
|
172
|
-
}
|
|
173
|
-
|
|
174
|
-
/** 获取格式化后的日期 */
|
|
175
|
-
public getDateFormatted() {
|
|
176
|
-
return Utils.timeAgo(new Date(this.data.date), this.ctx.$t)
|
|
177
|
-
}
|
|
178
|
-
|
|
179
|
-
/** 获取用户 UserAgent 信息 */
|
|
180
|
-
public getUserUA() {
|
|
181
|
-
const info = UADetect(this.data.ua)
|
|
182
|
-
return {
|
|
183
|
-
browser: `${info.browser} ${info.version}`,
|
|
184
|
-
os: `${info.os} ${info.osVersion}`
|
|
185
|
-
}
|
|
186
|
-
}
|
|
187
|
-
|
|
188
|
-
/** 获取配置 */
|
|
189
|
-
public getConf() {
|
|
190
|
-
return this.cConf
|
|
191
|
-
}
|
|
192
|
-
}
|
|
@@ -1,100 +0,0 @@
|
|
|
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
|
-
}
|
package/src/comment/index.ts
DELETED
package/src/comment/render.ts
DELETED
|
@@ -1,150 +0,0 @@
|
|
|
1
|
-
import type Comment from './comment'
|
|
2
|
-
import ActionBtn from '../components/action-btn'
|
|
3
|
-
import * as Utils from '../lib/utils'
|
|
4
|
-
import * as Ui from '../lib/ui'
|
|
5
|
-
|
|
6
|
-
import * as HeightLimit from './height-limit'
|
|
7
|
-
import CommentHTML from './comment.html?raw'
|
|
8
|
-
import loadRenders from './renders'
|
|
9
|
-
|
|
10
|
-
export default class Render {
|
|
11
|
-
public comment: Comment
|
|
12
|
-
|
|
13
|
-
public get ctx() { return this.comment.ctx }
|
|
14
|
-
public get data() { return this.comment.getData() }
|
|
15
|
-
public get conf() { return this.comment.conf }
|
|
16
|
-
public get cConf() { return this.comment.getConf() }
|
|
17
|
-
|
|
18
|
-
public $el!: HTMLElement
|
|
19
|
-
public $main!: HTMLElement
|
|
20
|
-
public $header!: HTMLElement
|
|
21
|
-
public $headerNick!: HTMLElement
|
|
22
|
-
public $headerBadgeWrap!: HTMLElement
|
|
23
|
-
public $body!: HTMLElement
|
|
24
|
-
public $content!: HTMLElement
|
|
25
|
-
public $childrenWrap!: HTMLElement|null
|
|
26
|
-
public $actions!: HTMLElement
|
|
27
|
-
public voteBtnUp?: ActionBtn
|
|
28
|
-
public voteBtnDown?: ActionBtn
|
|
29
|
-
|
|
30
|
-
public $replyTo?: HTMLElement // 回复评论内容 (平铺下显示)
|
|
31
|
-
public $replyAt?: HTMLElement // 回复 AT(层级嵌套下显示)
|
|
32
|
-
|
|
33
|
-
public constructor(comment: Comment) {
|
|
34
|
-
this.comment = comment
|
|
35
|
-
}
|
|
36
|
-
|
|
37
|
-
public render() {
|
|
38
|
-
// init ui elements
|
|
39
|
-
this.$el = Utils.createElement(CommentHTML)
|
|
40
|
-
|
|
41
|
-
this.$main = this.$el.querySelector('.atk-main')!
|
|
42
|
-
this.$header = this.$el.querySelector('.atk-header')!
|
|
43
|
-
this.$body = this.$el.querySelector('.atk-body')!
|
|
44
|
-
this.$content = this.$body.querySelector('.atk-content')!
|
|
45
|
-
this.$actions = this.$el.querySelector('.atk-actions')!
|
|
46
|
-
|
|
47
|
-
this.$el.setAttribute('id', `atk-comment-${this.data.id}`)
|
|
48
|
-
|
|
49
|
-
// call all renders
|
|
50
|
-
loadRenders(this)
|
|
51
|
-
|
|
52
|
-
this.recoveryChildrenWrap()
|
|
53
|
-
|
|
54
|
-
return this.$el
|
|
55
|
-
}
|
|
56
|
-
|
|
57
|
-
/** 内容限高检测 */
|
|
58
|
-
public checkHeightLimit() {
|
|
59
|
-
const conf = this.ctx.conf.heightLimit
|
|
60
|
-
if (!conf || !conf.content || !conf.children) return // 关闭限高
|
|
61
|
-
|
|
62
|
-
const contentMaxH = conf.content
|
|
63
|
-
const childrenMaxH = conf.children
|
|
64
|
-
|
|
65
|
-
HeightLimit.check({
|
|
66
|
-
postExpandBtnClick: () => {
|
|
67
|
-
// 子评论数仅有 1,直接取消限高
|
|
68
|
-
const children = this.comment.getChildren()
|
|
69
|
-
if (children.length === 1) HeightLimit.disposeHeightLimit(children[0].getRender().$content)
|
|
70
|
-
},
|
|
71
|
-
scrollable: conf.scrollable
|
|
72
|
-
}, [
|
|
73
|
-
// 评论内容限高
|
|
74
|
-
{ el: this.$content, max: contentMaxH, imgContains: true },
|
|
75
|
-
{ el: this.$replyTo, max: contentMaxH, imgContains: true },
|
|
76
|
-
// 子评论区域限高(仅嵌套模式)
|
|
77
|
-
{ el: this.$childrenWrap, max: childrenMaxH, imgContains: false }
|
|
78
|
-
])
|
|
79
|
-
}
|
|
80
|
-
|
|
81
|
-
/** 子评论区域移除限高 */
|
|
82
|
-
public heightLimitRemoveForChildren() {
|
|
83
|
-
if (!this.$childrenWrap) return
|
|
84
|
-
HeightLimit.disposeHeightLimit(this.$childrenWrap)
|
|
85
|
-
}
|
|
86
|
-
|
|
87
|
-
/** 渐出动画 */
|
|
88
|
-
playFadeAnim() {
|
|
89
|
-
Ui.playFadeInAnim(this.comment.getRender().$el)
|
|
90
|
-
}
|
|
91
|
-
|
|
92
|
-
/** 渐出动画 · 评论内容区域 */
|
|
93
|
-
playFadeAnimForBody() {
|
|
94
|
-
Ui.playFadeInAnim(this.comment.getRender().$body)
|
|
95
|
-
}
|
|
96
|
-
|
|
97
|
-
/** 获取子评论 Wrap */
|
|
98
|
-
public getChildrenWrap() {
|
|
99
|
-
return this.$childrenWrap
|
|
100
|
-
}
|
|
101
|
-
|
|
102
|
-
/** 初始化子评论区域 Wrap */
|
|
103
|
-
public renderChildrenWrap() {
|
|
104
|
-
if (!this.$childrenWrap) {
|
|
105
|
-
this.$childrenWrap = Utils.createElement('<div class="atk-comment-children"></div>')
|
|
106
|
-
this.$main.append(this.$childrenWrap)
|
|
107
|
-
}
|
|
108
|
-
|
|
109
|
-
return this.$childrenWrap
|
|
110
|
-
}
|
|
111
|
-
|
|
112
|
-
/** 恢复原有的子评论区域 Wrap */
|
|
113
|
-
public recoveryChildrenWrap() {
|
|
114
|
-
if (this.$childrenWrap) {
|
|
115
|
-
this.$main.append(this.$childrenWrap)
|
|
116
|
-
}
|
|
117
|
-
}
|
|
118
|
-
|
|
119
|
-
/** 设置已读 */
|
|
120
|
-
public setUnread(val: boolean) {
|
|
121
|
-
if (val) this.$el.classList.add('atk-unread')
|
|
122
|
-
else this.$el.classList.remove('atk-unread')
|
|
123
|
-
}
|
|
124
|
-
|
|
125
|
-
/** 设置为可点击的评论 */
|
|
126
|
-
public setOpenable(val: boolean) {
|
|
127
|
-
if (val) this.$el.classList.add('atk-openable')
|
|
128
|
-
else this.$el.classList.remove('atk-openable')
|
|
129
|
-
}
|
|
130
|
-
|
|
131
|
-
/** 设置点击评论打开置顶 URL */
|
|
132
|
-
public setOpenURL(url: string) {
|
|
133
|
-
this.setOpenable(true)
|
|
134
|
-
this.$el.onclick = (evt) => {
|
|
135
|
-
evt.preventDefault()
|
|
136
|
-
window.open(url)
|
|
137
|
-
|
|
138
|
-
if (this.cConf.openEvt) this.cConf.openEvt()
|
|
139
|
-
}
|
|
140
|
-
}
|
|
141
|
-
|
|
142
|
-
/** 设置点击评论时的操作 */
|
|
143
|
-
public setOpenAction(action: () => void) {
|
|
144
|
-
this.setOpenable(true)
|
|
145
|
-
this.$el.onclick = (evt) => {
|
|
146
|
-
evt.preventDefault()
|
|
147
|
-
action()
|
|
148
|
-
}
|
|
149
|
-
}
|
|
150
|
-
}
|
|
@@ -1,114 +0,0 @@
|
|
|
1
|
-
import * as Utils from '../../lib/utils'
|
|
2
|
-
import ActionBtn from '../../components/action-btn'
|
|
3
|
-
import type Render from '../render'
|
|
4
|
-
|
|
5
|
-
/**
|
|
6
|
-
* 评论操作按钮界面
|
|
7
|
-
*/
|
|
8
|
-
export default function renderActions(r: Render) {
|
|
9
|
-
Object.entries({
|
|
10
|
-
renderVote, renderReply,
|
|
11
|
-
// 管理员操作
|
|
12
|
-
renderCollapse, renderModerator, renderPin, renderEdit, renderDel
|
|
13
|
-
}).forEach(([name, render]) => {
|
|
14
|
-
render(r)
|
|
15
|
-
})
|
|
16
|
-
}
|
|
17
|
-
|
|
18
|
-
|
|
19
|
-
// 操作按钮 - 投票
|
|
20
|
-
function renderVote(r: Render) {
|
|
21
|
-
if (!r.ctx.conf.vote) return // 关闭投票功能
|
|
22
|
-
|
|
23
|
-
// 赞同按钮
|
|
24
|
-
r.voteBtnUp = new ActionBtn(() => `${r.ctx.$t('voteUp')} (${r.data.vote_up || 0})`).appendTo(r.$actions)
|
|
25
|
-
r.voteBtnUp.setClick(() => {
|
|
26
|
-
r.comment.getActions().vote('up')
|
|
27
|
-
})
|
|
28
|
-
|
|
29
|
-
// 反对按钮
|
|
30
|
-
if (r.ctx.conf.voteDown) {
|
|
31
|
-
r.voteBtnDown = new ActionBtn(() => `${r.ctx.$t('voteDown')} (${r.data.vote_down || 0})`).appendTo(r.$actions)
|
|
32
|
-
r.voteBtnDown.setClick(() => {
|
|
33
|
-
r.comment.getActions().vote('down')
|
|
34
|
-
})
|
|
35
|
-
}
|
|
36
|
-
}
|
|
37
|
-
|
|
38
|
-
// 操作按钮 - 回复
|
|
39
|
-
function renderReply(r: Render) {
|
|
40
|
-
if (!r.data.is_allow_reply) return // 不允许回复
|
|
41
|
-
|
|
42
|
-
const replyBtn = Utils.createElement(`<span>${r.ctx.$t('reply')}</span>`)
|
|
43
|
-
r.$actions.append(replyBtn)
|
|
44
|
-
replyBtn.addEventListener('click', (e) => {
|
|
45
|
-
e.stopPropagation() // 防止穿透
|
|
46
|
-
if (!r.cConf.onReplyBtnClick) {
|
|
47
|
-
r.ctx.replyComment(r.data, r.$el)
|
|
48
|
-
} else {
|
|
49
|
-
r.cConf.onReplyBtnClick()
|
|
50
|
-
}
|
|
51
|
-
})
|
|
52
|
-
}
|
|
53
|
-
|
|
54
|
-
// 操作按钮 - 折叠
|
|
55
|
-
function renderCollapse(r: Render) {
|
|
56
|
-
const collapseBtn = new ActionBtn({
|
|
57
|
-
text: () => (r.data.is_collapsed ? r.ctx.$t('expand') : r.ctx.$t('collapse')),
|
|
58
|
-
adminOnly: true
|
|
59
|
-
})
|
|
60
|
-
collapseBtn.appendTo(r.$actions)
|
|
61
|
-
collapseBtn.setClick(() => {
|
|
62
|
-
r.comment.getActions().adminEdit('collapsed', collapseBtn)
|
|
63
|
-
})
|
|
64
|
-
}
|
|
65
|
-
|
|
66
|
-
// 操作按钮 - 审核
|
|
67
|
-
function renderModerator(r: Render) {
|
|
68
|
-
const pendingBtn = new ActionBtn({
|
|
69
|
-
text: () => (r.data.is_pending ? r.ctx.$t('pending') : r.ctx.$t('approved')),
|
|
70
|
-
adminOnly: true
|
|
71
|
-
})
|
|
72
|
-
pendingBtn.appendTo(r.$actions)
|
|
73
|
-
pendingBtn.setClick(() => {
|
|
74
|
-
r.comment.getActions().adminEdit('pending', pendingBtn)
|
|
75
|
-
})
|
|
76
|
-
}
|
|
77
|
-
|
|
78
|
-
// 操作按钮 - 置顶
|
|
79
|
-
function renderPin(r: Render) {
|
|
80
|
-
const pinnedBtn = new ActionBtn({
|
|
81
|
-
text: () => (r.data.is_pinned ? r.ctx.$t('unpin') : r.ctx.$t('pin')),
|
|
82
|
-
adminOnly: true
|
|
83
|
-
})
|
|
84
|
-
pinnedBtn.appendTo(r.$actions)
|
|
85
|
-
pinnedBtn.setClick(() => {
|
|
86
|
-
r.comment.getActions().adminEdit('pinned', pinnedBtn)
|
|
87
|
-
})
|
|
88
|
-
}
|
|
89
|
-
|
|
90
|
-
// 操作按钮 - 编辑
|
|
91
|
-
function renderEdit(r: Render) {
|
|
92
|
-
const editBtn = new ActionBtn({
|
|
93
|
-
text: r.ctx.$t('edit'),
|
|
94
|
-
adminOnly: true
|
|
95
|
-
})
|
|
96
|
-
editBtn.appendTo(r.$actions)
|
|
97
|
-
editBtn.setClick(() => {
|
|
98
|
-
r.ctx.editComment(r.data, r.$el)
|
|
99
|
-
})
|
|
100
|
-
}
|
|
101
|
-
|
|
102
|
-
// 操作按钮 - 删除
|
|
103
|
-
function renderDel(r: Render) {
|
|
104
|
-
const delBtn = new ActionBtn({
|
|
105
|
-
text: r.ctx.$t('delete'),
|
|
106
|
-
confirm: true,
|
|
107
|
-
confirmText: r.ctx.$t('deleteConfirm'),
|
|
108
|
-
adminOnly: true,
|
|
109
|
-
})
|
|
110
|
-
delBtn.appendTo(r.$actions)
|
|
111
|
-
delBtn.setClick(() => {
|
|
112
|
-
r.comment.getActions().adminDelete(delBtn)
|
|
113
|
-
})
|
|
114
|
-
}
|
|
@@ -1,22 +0,0 @@
|
|
|
1
|
-
import * as Utils from '../../lib/utils'
|
|
2
|
-
import type Render from '../render'
|
|
3
|
-
|
|
4
|
-
/**
|
|
5
|
-
* 评论头像界面
|
|
6
|
-
*/
|
|
7
|
-
export default function renderAvatar(r: Render) {
|
|
8
|
-
const $avatar = r.$el.querySelector<HTMLElement>('.atk-avatar')!
|
|
9
|
-
const $avatarImg = Utils.createElement<HTMLImageElement>('<img />')
|
|
10
|
-
|
|
11
|
-
const avatarURLBuilder = r.conf.avatarURLBuilder
|
|
12
|
-
$avatarImg.src = avatarURLBuilder ? avatarURLBuilder(r.data) : r.comment.getGravatarURL()
|
|
13
|
-
|
|
14
|
-
if (r.data.link) {
|
|
15
|
-
const $avatarA = Utils.createElement<HTMLLinkElement>('<a target="_blank" rel="noreferrer noopener nofollow"></a>')
|
|
16
|
-
$avatarA.href = Utils.isValidURL(r.data.link) ? r.data.link : `https://${r.data.link}`
|
|
17
|
-
$avatarA.append($avatarImg)
|
|
18
|
-
$avatar.append($avatarA)
|
|
19
|
-
} else {
|
|
20
|
-
$avatar.append($avatarImg)
|
|
21
|
-
}
|
|
22
|
-
}
|
|
@@ -1,39 +0,0 @@
|
|
|
1
|
-
import * as Utils from '../../lib/utils'
|
|
2
|
-
import * as Ui from '../../lib/ui'
|
|
3
|
-
import type Render from '../render'
|
|
4
|
-
|
|
5
|
-
/**
|
|
6
|
-
* 评论内容界面
|
|
7
|
-
*/
|
|
8
|
-
export default function renderContent(r: Render) {
|
|
9
|
-
if (!r.data.is_collapsed) {
|
|
10
|
-
r.$content.innerHTML = r.comment.getContentMarked()
|
|
11
|
-
r.$content.classList.remove('atk-hide', 'atk-collapsed')
|
|
12
|
-
return
|
|
13
|
-
}
|
|
14
|
-
|
|
15
|
-
// 内容 & 折叠
|
|
16
|
-
r.$content.classList.add('atk-hide', 'atk-type-collapsed')
|
|
17
|
-
const collapsedInfoEl = Utils.createElement(`
|
|
18
|
-
<div class="atk-collapsed">
|
|
19
|
-
<span class="atk-text">${r.ctx.$t('collapsedMsg')}</span>
|
|
20
|
-
<span class="atk-show-btn">${r.ctx.$t('expand')}</span>
|
|
21
|
-
</div>`)
|
|
22
|
-
r.$body.insertAdjacentElement('beforeend', collapsedInfoEl)
|
|
23
|
-
|
|
24
|
-
const contentShowBtn = collapsedInfoEl.querySelector<HTMLElement>('.atk-show-btn')!
|
|
25
|
-
contentShowBtn.addEventListener('click', (e) => {
|
|
26
|
-
e.stopPropagation() // 防止穿透
|
|
27
|
-
|
|
28
|
-
if (r.$content.classList.contains('atk-hide')) {
|
|
29
|
-
r.$content.innerHTML = r.comment.getContentMarked()
|
|
30
|
-
r.$content.classList.remove('atk-hide')
|
|
31
|
-
Ui.playFadeInAnim(r.$content)
|
|
32
|
-
contentShowBtn.innerText = r.ctx.$t('collapse')
|
|
33
|
-
} else {
|
|
34
|
-
r.$content.innerHTML = ''
|
|
35
|
-
r.$content.classList.add('atk-hide')
|
|
36
|
-
contentShowBtn.innerText = r.ctx.$t('expand')
|
|
37
|
-
}
|
|
38
|
-
})
|
|
39
|
-
}
|
|
@@ -1,84 +0,0 @@
|
|
|
1
|
-
import * as Utils from '../../lib/utils'
|
|
2
|
-
import type Render from '../render'
|
|
3
|
-
|
|
4
|
-
/**
|
|
5
|
-
* 评论头部界面
|
|
6
|
-
*/
|
|
7
|
-
export default function renderHeader(r: Render) {
|
|
8
|
-
Object.entries({
|
|
9
|
-
renderNick, renderVerifyBadge, renderDate, renderUABadge
|
|
10
|
-
}).forEach(([name, render]) => {
|
|
11
|
-
render(r)
|
|
12
|
-
})
|
|
13
|
-
}
|
|
14
|
-
|
|
15
|
-
function renderNick(r: Render) {
|
|
16
|
-
r.$headerNick = r.$el.querySelector<HTMLElement>('.atk-nick')!
|
|
17
|
-
|
|
18
|
-
if (r.data.link) {
|
|
19
|
-
const $nickA = Utils.createElement<HTMLLinkElement>('<a target="_blank" rel="noreferrer noopener nofollow"></a>')
|
|
20
|
-
$nickA.innerText = r.data.nick
|
|
21
|
-
$nickA.href = Utils.isValidURL(r.data.link) ? r.data.link : `https://${r.data.link}`
|
|
22
|
-
r.$headerNick.append($nickA)
|
|
23
|
-
} else {
|
|
24
|
-
r.$headerNick.innerText = r.data.nick
|
|
25
|
-
}
|
|
26
|
-
}
|
|
27
|
-
|
|
28
|
-
function renderVerifyBadge(ctx: Render) {
|
|
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: Render) {
|
|
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: Render) {
|
|
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
|
-
}
|