artalk 2.6.4 → 2.7.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.
- package/dist/Artalk.css +1 -1
- package/dist/Artalk.es.js +7756 -7432
- 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 +5576 -5252
- 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/{api-base.d.ts → _base.d.ts} +3 -7
- package/dist/src/api/_options.d.ts +19 -0
- package/dist/src/api/{request.d.ts → _request.d.ts} +3 -3
- package/dist/src/api/admin.d.ts +1 -1
- package/dist/src/api/captcha.d.ts +1 -1
- package/dist/src/api/comment.d.ts +2 -2
- package/dist/src/api/index.d.ts +2 -4
- package/dist/src/api/page.d.ts +3 -3
- package/dist/src/api/site.d.ts +2 -2
- package/dist/src/api/system.d.ts +13 -3
- package/dist/src/api/upload.d.ts +1 -1
- package/dist/src/api/user.d.ts +2 -2
- package/dist/src/artalk.d.ts +12 -37
- package/dist/src/comment/actions.d.ts +1 -1
- package/dist/src/comment/comment.d.ts +3 -4
- package/dist/src/comment/render.d.ts +21 -3
- package/dist/src/comment/renders/actions.d.ts +2 -2
- package/dist/src/comment/renders/avatar.d.ts +2 -2
- package/dist/src/comment/renders/content.d.ts +2 -2
- package/dist/src/comment/renders/header.d.ts +2 -2
- package/dist/src/comment/renders/index.d.ts +2 -2
- package/dist/src/comment/renders/pending.d.ts +2 -2
- package/dist/src/comment/renders/reply-at.d.ts +2 -2
- package/dist/src/comment/renders/reply-to.d.ts +2 -2
- package/dist/src/components/action-btn.d.ts +3 -5
- package/dist/src/{lib → components}/checker/admin.d.ts +1 -1
- package/dist/src/{lib → components}/checker/captcha-renders.d.ts +1 -1
- package/dist/src/{lib → components}/checker/captcha.d.ts +1 -1
- package/dist/src/{lib → components}/checker/index.d.ts +10 -7
- package/dist/src/components/dark-mode.d.ts +2 -0
- package/dist/src/components/dialog.d.ts +1 -3
- package/dist/src/components/error-dialog.d.ts +8 -0
- package/dist/src/components/pagination.d.ts +4 -3
- package/dist/src/components/read-more-btn.d.ts +3 -3
- package/dist/src/config.d.ts +24 -8
- package/dist/src/context.d.ts +16 -35
- package/dist/src/data.d.ts +27 -0
- package/dist/src/defaults.d.ts +1 -1
- package/dist/src/editor/editor.d.ts +14 -61
- package/dist/src/editor/state.d.ts +20 -0
- package/dist/src/i18n/en.d.ts +3 -0
- package/dist/src/i18n/external.d.ts +3 -0
- package/dist/src/i18n/index.d.ts +9 -0
- package/dist/src/i18n/jp.d.ts +3 -0
- package/dist/src/i18n/zh-CN.d.ts +1 -1
- package/dist/src/i18n/zh-TW.d.ts +3 -0
- package/dist/src/layer/index.d.ts +4 -3
- package/dist/src/layer/layer-manager.d.ts +9 -0
- package/dist/src/layer/layer.d.ts +8 -28
- package/dist/src/layer/scrollbar-helper.d.ts +5 -0
- package/dist/src/layer/sidebar-layer.d.ts +6 -6
- package/dist/src/layer/wrap.d.ts +13 -0
- package/dist/src/lib/component.d.ts +3 -8
- package/dist/src/lib/event-manager.d.ts +28 -0
- package/dist/src/lib/highlight.d.ts +1 -0
- package/dist/src/lib/marked-renderer.d.ts +4 -0
- package/dist/src/lib/marked.d.ts +4 -2
- package/dist/src/lib/sanitizer.d.ts +1 -0
- package/dist/src/lib/ui.d.ts +3 -2
- package/dist/src/lib/user.d.ts +8 -5
- package/dist/src/lib/utils.d.ts +11 -5
- package/dist/src/list/comment.d.ts +3 -0
- package/dist/src/list/layout.d.ts +23 -0
- package/dist/src/list/list.d.ts +13 -25
- package/dist/src/list/{list-nest.d.ts → nest.d.ts} +1 -1
- package/dist/src/list/page.d.ts +2 -0
- package/dist/src/list/paginator/index.d.ts +22 -7
- package/dist/src/list/paginator/read-more.d.ts +18 -0
- package/dist/src/list/paginator/up-down.d.ts +14 -0
- package/dist/src/main.d.ts +5 -0
- package/dist/src/plugins/admin-only-elem.d.ts +2 -0
- package/dist/src/plugins/conf-remoter.d.ts +2 -0
- package/dist/src/plugins/dark-mode.d.ts +2 -0
- package/dist/src/plugins/editor/_kit.d.ts +27 -0
- package/dist/src/plugins/editor/_plug.d.ts +29 -0
- package/dist/src/plugins/editor/_sample.d.ts +5 -0
- package/dist/src/plugins/editor/closable.d.ts +7 -0
- package/dist/src/{editor/plugs/emoticons-plug.d.ts → plugins/editor/emoticons.d.ts} +10 -16
- package/dist/src/plugins/editor/header-event.d.ts +6 -0
- package/dist/src/plugins/editor/header-link.d.ts +6 -0
- package/dist/src/plugins/editor/header-user.d.ts +16 -0
- package/dist/src/plugins/editor/index.d.ts +6 -0
- package/dist/src/plugins/editor/local-storage.d.ts +6 -0
- package/dist/src/plugins/editor/mover.d.ts +6 -0
- package/dist/src/plugins/editor/preview.d.ts +7 -0
- package/dist/src/plugins/editor/state-edit.d.ts +11 -0
- package/dist/src/plugins/editor/state-reply.d.ts +8 -0
- package/dist/src/plugins/editor/submit-add.d.ts +18 -0
- package/dist/src/plugins/editor/submit-btn.d.ts +5 -0
- package/dist/src/plugins/editor/submit.d.ts +17 -0
- package/dist/src/plugins/editor/textarea.d.ts +8 -0
- package/dist/src/plugins/editor/upload.d.ts +9 -0
- package/dist/src/plugins/editor-kit.d.ts +42 -0
- package/dist/src/plugins/index.d.ts +2 -0
- package/dist/src/plugins/list/copyright.d.ts +2 -0
- package/dist/src/plugins/list/count.d.ts +2 -0
- package/dist/src/plugins/list/dropdown.d.ts +2 -0
- package/dist/src/plugins/list/error-dialog.d.ts +2 -0
- package/dist/src/plugins/list/fetch.d.ts +2 -0
- package/dist/src/plugins/list/goto-first.d.ts +3 -0
- package/dist/src/plugins/list/goto.d.ts +2 -0
- package/dist/src/plugins/list/index.d.ts +3 -0
- package/dist/src/plugins/list/loading.d.ts +2 -0
- package/dist/src/plugins/list/no-comment.d.ts +2 -0
- package/dist/src/plugins/list/reach-bottom.d.ts +2 -0
- package/dist/src/plugins/list/sidebar-btn.d.ts +2 -0
- package/dist/src/plugins/list/time-ticking.d.ts +3 -0
- package/dist/src/plugins/list/unread-badge.d.ts +2 -0
- package/dist/src/plugins/list/unread.d.ts +2 -0
- package/dist/src/plugins/list/with-editor.d.ts +2 -0
- package/dist/src/plugins/markdown.d.ts +2 -0
- package/dist/src/plugins/stat.d.ts +13 -0
- package/dist/src/plugins/version-check.d.ts +2 -0
- package/dist/src/service.d.ts +19 -23
- package/dist/tests/e2e/comment-add.spec.d.ts +1 -0
- package/dist/types/config.d.ts +110 -0
- package/dist/types/context.d.ts +56 -136
- package/dist/types/data.d.ts +194 -0
- package/dist/types/editor.d.ts +76 -0
- package/dist/types/event.d.ts +36 -25
- package/dist/types/index.d.ts +7 -0
- package/dist/types/plugin.d.ts +2 -0
- package/dist/types/sidebar.d.ts +3 -0
- package/package.json +5 -2
- package/src/api/_base.ts +18 -0
- package/src/api/_options.ts +25 -0
- package/src/api/{request.ts → _request.ts} +19 -18
- package/src/api/admin.ts +1 -1
- package/src/api/captcha.ts +1 -1
- package/src/api/comment.ts +4 -4
- package/src/api/index.ts +3 -12
- package/src/api/page.ts +5 -5
- package/src/api/site.ts +2 -2
- package/src/api/system.ts +19 -7
- package/src/api/upload.ts +3 -3
- package/src/api/user.ts +3 -3
- package/src/artalk.ts +47 -99
- package/src/comment/actions.ts +1 -4
- package/src/comment/comment.ts +9 -6
- package/src/comment/render.ts +27 -5
- package/src/comment/renders/actions.ts +45 -45
- package/src/comment/renders/avatar.ts +7 -7
- package/src/comment/renders/content.ts +18 -18
- package/src/comment/renders/header.ts +13 -13
- package/src/comment/renders/index.ts +3 -3
- package/src/comment/renders/pending.ts +5 -5
- package/src/comment/renders/reply-at.ts +8 -8
- package/src/comment/renders/reply-to.ts +13 -13
- package/src/components/action-btn.ts +11 -13
- package/src/{lib → components}/checker/admin.ts +6 -6
- package/src/{lib → components}/checker/captcha-renders.ts +7 -6
- package/src/{lib → components}/checker/captcha.ts +1 -1
- package/src/{lib → components}/checker/index.ts +21 -26
- package/src/components/dark-mode.ts +30 -0
- package/src/components/dialog.ts +4 -9
- package/src/components/error-dialog.ts +35 -0
- package/src/components/pagination.ts +10 -6
- package/src/components/read-more-btn.ts +7 -7
- package/src/config.ts +60 -6
- package/src/context.ts +39 -144
- package/src/data.ts +110 -0
- package/src/defaults.ts +1 -1
- package/src/editor/editor.ts +39 -152
- package/src/editor/state.ts +52 -0
- package/src/i18n/en.ts +3 -0
- package/src/i18n/jp.ts +3 -0
- package/src/i18n/zh-CN.ts +4 -1
- package/src/i18n/zh-TW.ts +3 -0
- package/src/layer/index.ts +4 -4
- package/src/layer/layer-manager.ts +32 -0
- package/src/layer/layer.ts +20 -144
- package/src/layer/scrollbar-helper.ts +24 -0
- package/src/layer/sidebar-layer.ts +74 -64
- package/src/layer/wrap.ts +77 -0
- package/src/lib/component.ts +4 -11
- package/src/lib/detect.ts +1 -1
- package/src/lib/event-manager.ts +47 -0
- package/src/lib/highlight.ts +5 -0
- package/src/lib/marked-renderer.ts +32 -0
- package/src/lib/marked.ts +43 -104
- package/src/lib/sanitizer.ts +57 -0
- package/src/lib/ui.ts +22 -15
- package/src/lib/user.ts +21 -16
- package/src/lib/utils.ts +29 -18
- package/src/list/comment.ts +20 -0
- package/src/list/layout.ts +120 -0
- package/src/list/list.html +3 -1
- package/src/list/list.ts +56 -200
- package/src/list/{list-nest.ts → nest.ts} +1 -1
- package/src/list/page.ts +97 -0
- package/src/list/paginator/index.ts +20 -8
- package/src/list/paginator/read-more.ts +67 -0
- package/src/list/paginator/up-down.ts +51 -0
- package/src/main.ts +11 -0
- package/src/plugins/admin-only-elem.ts +40 -0
- package/src/plugins/conf-remoter.ts +54 -0
- package/src/plugins/dark-mode.ts +12 -0
- package/src/plugins/editor/_kit.ts +57 -0
- package/src/plugins/editor/_plug.ts +60 -0
- package/src/plugins/editor/_sample.ts +8 -0
- package/src/plugins/editor/closable.ts +44 -0
- package/src/{editor/plugs/emoticons-plug.ts → plugins/editor/emoticons.ts} +51 -52
- package/src/plugins/editor/header-event.ts +35 -0
- package/src/plugins/editor/header-link.ts +31 -0
- package/src/plugins/editor/header-user.ts +98 -0
- package/src/plugins/editor/index.ts +40 -0
- package/src/plugins/editor/local-storage.ts +36 -0
- package/src/plugins/editor/mover.ts +29 -0
- package/src/plugins/editor/preview.ts +41 -0
- package/src/plugins/editor/state-edit.ts +116 -0
- package/src/plugins/editor/state-reply.ts +91 -0
- package/src/plugins/editor/submit-add.ts +33 -0
- package/src/plugins/editor/submit-btn.ts +25 -0
- package/src/plugins/editor/submit.ts +73 -0
- package/src/plugins/editor/textarea.ts +55 -0
- package/src/plugins/editor/upload.ts +145 -0
- package/src/plugins/editor-kit.ts +161 -0
- package/src/plugins/index.ts +16 -0
- package/src/plugins/list/copyright.ts +16 -0
- package/src/plugins/list/count.ts +31 -0
- package/src/plugins/list/dropdown.ts +95 -0
- package/src/plugins/list/error-dialog.ts +22 -0
- package/src/plugins/list/fetch.ts +64 -0
- package/src/plugins/list/goto-first.ts +23 -0
- package/src/plugins/list/goto.ts +72 -0
- package/src/plugins/list/index.ts +25 -0
- package/src/plugins/list/loading.ts +17 -0
- package/src/plugins/list/no-comment.ts +25 -0
- package/src/plugins/list/reach-bottom.ts +46 -0
- package/src/plugins/list/sidebar-btn.ts +39 -0
- package/src/plugins/list/time-ticking.ts +22 -0
- package/src/plugins/list/unread-badge.ts +26 -0
- package/src/plugins/list/unread.ts +38 -0
- package/src/plugins/list/with-editor.ts +59 -0
- package/src/plugins/markdown.ts +10 -0
- package/src/plugins/stat.ts +82 -0
- package/src/plugins/version-check.ts +36 -0
- package/src/service.ts +34 -61
- package/src/style/comment.scss +5 -7
- package/src/style/editor.scss +5 -0
- package/src/style/list.scss +1 -1
- package/types/{artalk-config.d.ts → config.ts} +16 -2
- package/types/context.ts +84 -0
- package/types/{artalk-data.d.ts → data.ts} +41 -0
- package/types/editor.ts +95 -0
- package/types/event.ts +40 -0
- package/types/index.ts +7 -0
- package/types/plugin.ts +3 -0
- package/types/sidebar.ts +3 -0
- package/dist/src/comment/render-ctx.d.ts +0 -23
- package/dist/src/editor/edit-mode.d.ts +0 -9
- package/dist/src/editor/funcs.d.ts +0 -2
- package/dist/src/editor/index.d.ts +0 -2
- package/dist/src/editor/mover.d.ts +0 -8
- package/dist/src/editor/plug-manager.d.ts +0 -17
- package/dist/src/editor/plugs/editor-plug.d.ts +0 -38
- package/dist/src/editor/plugs/header-input-plug.d.ts +0 -13
- package/dist/src/editor/plugs/preview-plug.d.ts +0 -10
- package/dist/src/editor/plugs/upload-plug.d.ts +0 -10
- package/dist/src/editor/reply.d.ts +0 -9
- package/dist/src/editor/submit.d.ts +0 -16
- package/dist/src/lib/dark-mode.d.ts +0 -4
- package/dist/src/lib/stat.d.ts +0 -15
- package/dist/src/list/index.d.ts +0 -2
- package/dist/src/list/list-lite.d.ts +0 -77
- package/dist/src/list/list-ui.d.ts +0 -16
- package/dist/src/list/paginator/adaptors/index.d.ts +0 -12
- package/dist/src/list/paginator/adaptors/pagination.d.ts +0 -9
- package/dist/src/list/paginator/adaptors/read-more.d.ts +0 -10
- package/dist/src/list/paginator/holder.d.ts +0 -16
- package/dist/types/artalk-config.d.ts +0 -139
- package/dist/types/artalk-data.d.ts +0 -230
- package/dist/types/plug.d.ts +0 -4
- package/src/api/api-base.ts +0 -27
- package/src/comment/render-ctx.ts +0 -30
- package/src/editor/edit-mode.ts +0 -105
- package/src/editor/funcs.ts +0 -150
- package/src/editor/index.ts +0 -3
- package/src/editor/mover.ts +0 -43
- package/src/editor/plug-manager.ts +0 -172
- package/src/editor/plugs/editor-plug.ts +0 -69
- package/src/editor/plugs/header-input-plug.ts +0 -79
- package/src/editor/plugs/preview-plug.ts +0 -44
- package/src/editor/plugs/upload-plug.ts +0 -122
- package/src/editor/reply.ts +0 -62
- package/src/editor/submit.ts +0 -99
- package/src/lib/dark-mode.ts +0 -48
- package/src/lib/stat.ts +0 -71
- package/src/list/index.ts +0 -3
- package/src/list/list-lite.ts +0 -424
- package/src/list/list-ui.ts +0 -137
- package/src/list/paginator/adaptors/index.ts +0 -21
- package/src/list/paginator/adaptors/pagination.ts +0 -42
- package/src/list/paginator/adaptors/read-more.ts +0 -56
- package/src/list/paginator/holder.ts +0 -56
- package/types/context.d.ts +0 -142
- package/types/event.d.ts +0 -28
- package/types/plug.d.ts +0 -4
- /package/src/{editor/plugs/emoticons-plug.scss → plugins/editor/emoticons.scss} +0 -0
- /package/src/{editor/plugs/preview-plug.scss → plugins/editor/preview.scss} +0 -0
package/src/lib/marked.ts
CHANGED
|
@@ -1,133 +1,72 @@
|
|
|
1
|
-
import { marked as libMarked } from 'marked'
|
|
2
|
-
import insane from 'insane'
|
|
3
|
-
import hanabi from 'hanabi'
|
|
4
|
-
import Context from '~/types/context'
|
|
1
|
+
import { marked as libMarked, MarkedOptions } from 'marked'
|
|
5
2
|
|
|
6
|
-
|
|
3
|
+
import { sanitize } from './sanitizer'
|
|
4
|
+
import { renderCode } from './highlight'
|
|
5
|
+
import { getRenderer } from './marked-renderer'
|
|
7
6
|
|
|
7
|
+
type Replacer = (raw: string) => string
|
|
8
8
|
export type TMarked = typeof libMarked
|
|
9
9
|
|
|
10
|
+
let instance: (typeof libMarked)|undefined
|
|
11
|
+
let replacers: Replacer[] = []
|
|
12
|
+
|
|
13
|
+
const markedOptions: MarkedOptions = {
|
|
14
|
+
pedantic: false,
|
|
15
|
+
gfm: true,
|
|
16
|
+
breaks: true,
|
|
17
|
+
smartLists: true,
|
|
18
|
+
smartypants: true,
|
|
19
|
+
xhtml: false,
|
|
20
|
+
sanitize: false,
|
|
21
|
+
silent: true,
|
|
22
|
+
}
|
|
23
|
+
|
|
10
24
|
/** Get Marked instance */
|
|
11
25
|
export function getInstance() {
|
|
12
26
|
return instance
|
|
13
27
|
}
|
|
14
28
|
|
|
29
|
+
export function setReplacers(arr: Replacer[]) {
|
|
30
|
+
replacers = arr
|
|
31
|
+
}
|
|
32
|
+
|
|
15
33
|
/** 初始化 marked */
|
|
16
34
|
export function initMarked() {
|
|
17
35
|
try { if (!libMarked.name) return } catch { return }
|
|
18
36
|
|
|
19
|
-
const renderer = new libMarked.Renderer()
|
|
20
|
-
const orgLinkRenderer = renderer.link
|
|
21
|
-
renderer.link = (href, title, text) => {
|
|
22
|
-
const localLink = href?.startsWith(`${window.location.protocol}//${window.location.hostname}`);
|
|
23
|
-
const html = orgLinkRenderer.call(renderer as any, href, title, text);
|
|
24
|
-
return html.replace(/^<a /, `<a target="_blank" ${!localLink ? `rel="noreferrer noopener nofollow"` : ''} `);
|
|
25
|
-
}
|
|
26
|
-
|
|
27
|
-
renderer.code = (block, lang) => {
|
|
28
|
-
// Colorize the block only if the language is known to highlight.js
|
|
29
|
-
const realLang = (!lang ? 'plaintext' : lang)
|
|
30
|
-
let colorized = block
|
|
31
|
-
if ((window as any).hljs) {
|
|
32
|
-
if (realLang && (window as any).hljs.getLanguage(realLang)) {
|
|
33
|
-
colorized = (window as any).hljs.highlight(realLang, block).value
|
|
34
|
-
}
|
|
35
|
-
} else {
|
|
36
|
-
colorized = hanabi(block)
|
|
37
|
-
}
|
|
38
|
-
|
|
39
|
-
return `<pre rel="${realLang}">\n`
|
|
40
|
-
+ `<code class="hljs language-${realLang}">${colorized.replace(/&/g, '&')}</code>\n`
|
|
41
|
-
+ `</pre>`
|
|
42
|
-
}
|
|
43
|
-
|
|
44
37
|
// @see https://github.com/markedjs/marked/blob/4afb228d956a415624c4e5554bb8f25d047676fe/src/Tokenizer.js#L329
|
|
45
|
-
const nMarked = libMarked
|
|
46
38
|
libMarked.setOptions({
|
|
47
|
-
renderer,
|
|
48
|
-
|
|
49
|
-
gfm: true,
|
|
50
|
-
breaks: true,
|
|
51
|
-
smartLists: true,
|
|
52
|
-
smartypants: true,
|
|
53
|
-
xhtml: false,
|
|
54
|
-
sanitize: false,
|
|
55
|
-
silent: true,
|
|
39
|
+
renderer: getRenderer(),
|
|
40
|
+
...markedOptions
|
|
56
41
|
})
|
|
57
42
|
|
|
58
|
-
instance =
|
|
43
|
+
instance = libMarked
|
|
59
44
|
}
|
|
60
45
|
|
|
61
46
|
/** 解析 markdown */
|
|
62
|
-
export default function marked(
|
|
47
|
+
export default function marked(src: string): string {
|
|
63
48
|
let markedContent = getInstance()?.parse(src)
|
|
64
|
-
if (!markedContent) {
|
|
65
|
-
|
|
66
|
-
markedContent = src
|
|
67
|
-
// .replace(/\*\*(.*?)\*\*/g, '<strong>$1</strong>')
|
|
68
|
-
.replace(/```\s*([^]+?.*?[^]+?[^]+?)```/g, (_, code) => `<pre><code>${hanabi(code)}</code></pre>`)
|
|
69
|
-
// .replace(/`([^`]+?)`/g, '<code>$1</code>')
|
|
70
|
-
.replace(/!\[(.*?)\]\((.*?)\)/g, (_, alt, imgSrc) => `<img src="${imgSrc}" alt="${alt}" />`)
|
|
71
|
-
.replace(/\[(.*?)\]\((.*?)\)/g, (_, text, link) => `<a href="${link}" target="_blank">${text}</a>`)
|
|
72
|
-
.replace(/\n/g, '<br>')
|
|
49
|
+
if (!markedContent) { // 无 Markdown 模式简单处理
|
|
50
|
+
markedContent = simpleMarked(src)
|
|
73
51
|
}
|
|
74
52
|
|
|
75
|
-
|
|
76
|
-
// @link https://gist.github.com/lionel-rowe/bb384465ba4e4c81a9c8dada84167225
|
|
77
|
-
let dest = insane(markedContent, {
|
|
78
|
-
allowedClasses: {},
|
|
79
|
-
// @refer CVE-2018-8495
|
|
80
|
-
// @link https://cve.mitre.org/cgi-bin/cvename.cgi?name=CVE-2018-8495
|
|
81
|
-
// @link https://leucosite.com/Microsoft-Edge-RCE/
|
|
82
|
-
// @link https://medium.com/@knownsec404team/analysis-of-the-security-issues-of-url-scheme-in-pc-from-cve-2018-8495-934478a36756
|
|
83
|
-
allowedSchemes: [
|
|
84
|
-
'http', 'https', 'mailto',
|
|
85
|
-
'data' // for support base64 encoded image (安全性有待考虑)
|
|
86
|
-
],
|
|
87
|
-
allowedTags: [
|
|
88
|
-
'a', 'abbr', 'article', 'b', 'blockquote', 'br', 'caption', 'code', 'del', 'details', 'div', 'em',
|
|
89
|
-
'h1', 'h2', 'h3', 'h4', 'h5', 'h6', 'hr', 'i', 'img', 'ins', 'kbd', 'li', 'main', 'mark',
|
|
90
|
-
'ol', 'p', 'pre', 'section', 'span', 'strike', 'strong', 'sub', 'summary', 'sup', 'table',
|
|
91
|
-
'tbody', 'td', 'th', 'thead', 'tr', 'u', 'ul'
|
|
92
|
-
],
|
|
93
|
-
allowedAttributes: {
|
|
94
|
-
'*': ['title', 'accesskey'],
|
|
95
|
-
a: ['href', 'name', 'target', 'aria-label', 'rel'],
|
|
96
|
-
img: ['src', 'alt', 'title', 'atk-emoticon', 'aria-label'],
|
|
97
|
-
// for code highlight
|
|
98
|
-
code: ['class'],
|
|
99
|
-
span: ['class', 'style'],
|
|
100
|
-
},
|
|
101
|
-
filter: node => {
|
|
102
|
-
// allow hljs style
|
|
103
|
-
const allowed = [
|
|
104
|
-
[ 'code', /^hljs\W+language-(.*)$/ ],
|
|
105
|
-
[ 'span', /^(hljs-.*)$/ ]
|
|
106
|
-
]
|
|
107
|
-
allowed.forEach(([ tag, reg ]) => {
|
|
108
|
-
if (
|
|
109
|
-
node.tag === tag
|
|
110
|
-
&& !!node.attrs.class
|
|
111
|
-
&& !(reg as RegExp).test(node.attrs.class)
|
|
112
|
-
) {
|
|
113
|
-
delete node.attrs.class
|
|
114
|
-
}
|
|
115
|
-
})
|
|
116
|
-
|
|
117
|
-
// allow <span> set color sty
|
|
118
|
-
if (node.tag === 'span' && !!node.attrs.style
|
|
119
|
-
&& !/^color:(\W+)?#[0-9a-f]{3,6};?$/i.test(node.attrs.style)) {
|
|
120
|
-
delete node.attrs.style
|
|
121
|
-
}
|
|
122
|
-
|
|
123
|
-
return true
|
|
124
|
-
}
|
|
125
|
-
})
|
|
53
|
+
let dest = sanitize(markedContent)
|
|
126
54
|
|
|
127
55
|
// 内容替换器
|
|
128
|
-
|
|
129
|
-
if (typeof replacer === 'function')
|
|
56
|
+
replacers.forEach((replacer) => {
|
|
57
|
+
if (typeof replacer === 'function')
|
|
58
|
+
dest = replacer(dest)
|
|
130
59
|
})
|
|
131
60
|
|
|
132
61
|
return dest
|
|
133
62
|
}
|
|
63
|
+
|
|
64
|
+
function simpleMarked(src: string) {
|
|
65
|
+
return src
|
|
66
|
+
// .replace(/\*\*(.*?)\*\*/g, '<strong>$1</strong>')
|
|
67
|
+
.replace(/```\s*([^]+?.*?[^]+?[^]+?)```/g, (_, code) => `<pre><code>${renderCode(code)}</code></pre>`)
|
|
68
|
+
// .replace(/`([^`]+?)`/g, '<code>$1</code>')
|
|
69
|
+
.replace(/!\[(.*?)\]\((.*?)\)/g, (_, alt, imgSrc) => `<img src="${imgSrc}" alt="${alt}" />`)
|
|
70
|
+
.replace(/\[(.*?)\]\((.*?)\)/g, (_, text, link) => `<a href="${link}" target="_blank">${text}</a>`)
|
|
71
|
+
.replace(/\n/g, '<br>')
|
|
72
|
+
}
|
|
@@ -0,0 +1,57 @@
|
|
|
1
|
+
import insane from 'insane'
|
|
2
|
+
|
|
3
|
+
const insaneOptions = {
|
|
4
|
+
allowedClasses: {},
|
|
5
|
+
// @refer CVE-2018-8495
|
|
6
|
+
// @link https://cve.mitre.org/cgi-bin/cvename.cgi?name=CVE-2018-8495
|
|
7
|
+
// @link https://leucosite.com/Microsoft-Edge-RCE/
|
|
8
|
+
// @link https://medium.com/@knownsec404team/analysis-of-the-security-issues-of-url-scheme-in-pc-from-cve-2018-8495-934478a36756
|
|
9
|
+
allowedSchemes: [
|
|
10
|
+
'http', 'https', 'mailto',
|
|
11
|
+
'data' // for support base64 encoded image (安全性有待考虑)
|
|
12
|
+
],
|
|
13
|
+
allowedTags: [
|
|
14
|
+
'a', 'abbr', 'article', 'b', 'blockquote', 'br', 'caption', 'code', 'del', 'details', 'div', 'em',
|
|
15
|
+
'h1', 'h2', 'h3', 'h4', 'h5', 'h6', 'hr', 'i', 'img', 'ins', 'kbd', 'li', 'main', 'mark',
|
|
16
|
+
'ol', 'p', 'pre', 'section', 'span', 'strike', 'strong', 'sub', 'summary', 'sup', 'table',
|
|
17
|
+
'tbody', 'td', 'th', 'thead', 'tr', 'u', 'ul'
|
|
18
|
+
],
|
|
19
|
+
allowedAttributes: {
|
|
20
|
+
'*': ['title', 'accesskey'],
|
|
21
|
+
a: ['href', 'name', 'target', 'aria-label', 'rel'],
|
|
22
|
+
img: ['src', 'alt', 'title', 'atk-emoticon', 'aria-label'],
|
|
23
|
+
// for code highlight
|
|
24
|
+
code: ['class'],
|
|
25
|
+
span: ['class', 'style'],
|
|
26
|
+
},
|
|
27
|
+
filter: node => {
|
|
28
|
+
// allow hljs style
|
|
29
|
+
const allowed = [
|
|
30
|
+
[ 'code', /^hljs\W+language-(.*)$/ ],
|
|
31
|
+
[ 'span', /^(hljs-.*)$/ ]
|
|
32
|
+
]
|
|
33
|
+
allowed.forEach(([ tag, reg ]) => {
|
|
34
|
+
if (
|
|
35
|
+
node.tag === tag
|
|
36
|
+
&& !!node.attrs.class
|
|
37
|
+
&& !(reg as RegExp).test(node.attrs.class)
|
|
38
|
+
) {
|
|
39
|
+
delete node.attrs.class
|
|
40
|
+
}
|
|
41
|
+
})
|
|
42
|
+
|
|
43
|
+
// allow <span> set color sty
|
|
44
|
+
if (node.tag === 'span' && !!node.attrs.style
|
|
45
|
+
&& !/^color:(\W+)?#[0-9a-f]{3,6};?$/i.test(node.attrs.style)) {
|
|
46
|
+
delete node.attrs.style
|
|
47
|
+
}
|
|
48
|
+
|
|
49
|
+
return true
|
|
50
|
+
}
|
|
51
|
+
}
|
|
52
|
+
|
|
53
|
+
export function sanitize(content: string): string {
|
|
54
|
+
// @link https://github.com/markedjs/marked/discussions/1232
|
|
55
|
+
// @link https://gist.github.com/lionel-rowe/bb384465ba4e4c81a9c8dada84167225
|
|
56
|
+
return insane(content, insaneOptions)
|
|
57
|
+
}
|
package/src/lib/ui.ts
CHANGED
|
@@ -1,3 +1,4 @@
|
|
|
1
|
+
import type { NotifyLevel } from '~/types'
|
|
1
2
|
import * as Utils from './utils'
|
|
2
3
|
|
|
3
4
|
/** 显示加载 */
|
|
@@ -53,29 +54,35 @@ export function isVisible(el: HTMLElement, viewport: HTMLElement = document.docu
|
|
|
53
54
|
}
|
|
54
55
|
|
|
55
56
|
/** 滚动到元素中心 */
|
|
56
|
-
export function scrollIntoView(elem: HTMLElement, enableAnim: boolean = true) {
|
|
57
|
-
|
|
58
|
-
|
|
59
|
-
|
|
60
|
-
|
|
61
|
-
|
|
62
|
-
|
|
63
|
-
|
|
64
|
-
top: top > 0 ? top : 0,
|
|
65
|
-
left: 0,
|
|
66
|
-
// behavior: 'smooth',
|
|
67
|
-
})
|
|
57
|
+
export function scrollIntoView(elem: HTMLElement, enableAnim: boolean = true, relativeTo?: HTMLElement) {
|
|
58
|
+
let top: number
|
|
59
|
+
|
|
60
|
+
if (relativeTo) {
|
|
61
|
+
const containerRect = relativeTo.getBoundingClientRect()
|
|
62
|
+
const elementRect = elem.getBoundingClientRect()
|
|
63
|
+
top = elementRect.top - containerRect.top + relativeTo.scrollTop
|
|
64
|
+
top += Utils.getHeight(relativeTo) / 2 - Utils.getHeight(elem) / 2
|
|
68
65
|
} else {
|
|
69
|
-
|
|
70
|
-
|
|
66
|
+
const rect = elem.getBoundingClientRect()
|
|
67
|
+
const elemTop = rect.top + window.scrollY
|
|
68
|
+
top = elemTop - (window.innerHeight / 2 - rect.height / 2)
|
|
71
69
|
}
|
|
70
|
+
|
|
71
|
+
const scrollOptions: ScrollToOptions = {
|
|
72
|
+
top, left: 0,
|
|
73
|
+
// behavior: enableAnim ? 'smooth' : 'instant',
|
|
74
|
+
behavior: 'instant'
|
|
75
|
+
}
|
|
76
|
+
|
|
77
|
+
if (relativeTo) relativeTo.scroll(scrollOptions)
|
|
78
|
+
else window.scroll(scrollOptions)
|
|
72
79
|
}
|
|
73
80
|
|
|
74
81
|
/** 显示消息 */
|
|
75
82
|
export function showNotify(
|
|
76
83
|
wrapElem: HTMLElement,
|
|
77
84
|
msg: string,
|
|
78
|
-
type:
|
|
85
|
+
type: NotifyLevel,
|
|
79
86
|
) {
|
|
80
87
|
const colors = { s: '#57d59f', e: '#ff6f6c', w: '#ffc721', i: '#2ebcfc' }
|
|
81
88
|
const timeout = 3000 // 持续显示时间 ms
|
package/src/lib/user.ts
CHANGED
|
@@ -1,13 +1,14 @@
|
|
|
1
|
-
import { LocalUser } from
|
|
2
|
-
|
|
1
|
+
import type { LocalUser } from '~/types'
|
|
2
|
+
|
|
3
|
+
const LOCAL_USER_KEY = 'ArtalkUser'
|
|
3
4
|
|
|
4
5
|
class User {
|
|
5
|
-
|
|
6
|
-
|
|
6
|
+
data: LocalUser
|
|
7
|
+
onUserChanged: ((user: LocalUser) => void) | null = null
|
|
7
8
|
|
|
8
|
-
|
|
9
|
+
constructor() {
|
|
9
10
|
// 从 localStorage 导入
|
|
10
|
-
const localUser = JSON.parse(window.localStorage.getItem(
|
|
11
|
+
const localUser = JSON.parse(window.localStorage.getItem(LOCAL_USER_KEY) || '{}')
|
|
11
12
|
this.data = {
|
|
12
13
|
nick: localUser.nick || '',
|
|
13
14
|
email: localUser.email || '',
|
|
@@ -17,22 +18,26 @@ class User {
|
|
|
17
18
|
}
|
|
18
19
|
}
|
|
19
20
|
|
|
20
|
-
public setContext(ctx: Context) {
|
|
21
|
-
this.ctx = ctx
|
|
22
|
-
}
|
|
23
|
-
|
|
24
21
|
/** 保存用户到 localStorage 中 */
|
|
25
|
-
|
|
22
|
+
update(obj: Partial<LocalUser> = {}) {
|
|
26
23
|
Object.entries(obj).forEach(([key, value]) => {
|
|
27
24
|
this.data[key] = value
|
|
28
25
|
})
|
|
29
26
|
|
|
30
|
-
window.localStorage.setItem(
|
|
31
|
-
this.
|
|
27
|
+
window.localStorage.setItem(LOCAL_USER_KEY, JSON.stringify(this.data))
|
|
28
|
+
this.onUserChanged && this.onUserChanged(this.data)
|
|
29
|
+
}
|
|
30
|
+
|
|
31
|
+
public setOnUserChanged(fn: ((user: LocalUser) => void) | null) {
|
|
32
|
+
this.onUserChanged = fn
|
|
32
33
|
}
|
|
33
34
|
|
|
34
|
-
/**
|
|
35
|
-
|
|
35
|
+
/**
|
|
36
|
+
* Logout
|
|
37
|
+
*
|
|
38
|
+
* @description Logout will clear login status, but not clear user data (nick, email, link)
|
|
39
|
+
*/
|
|
40
|
+
logout() {
|
|
36
41
|
this.update({
|
|
37
42
|
token: '',
|
|
38
43
|
isAdmin: false
|
|
@@ -40,7 +45,7 @@ class User {
|
|
|
40
45
|
}
|
|
41
46
|
|
|
42
47
|
/** 是否已填写基本用户信息 */
|
|
43
|
-
|
|
48
|
+
checkHasBasicUserInfo() {
|
|
44
49
|
return !!this.data.nick && !!this.data.email
|
|
45
50
|
}
|
|
46
51
|
}
|
package/src/lib/utils.ts
CHANGED
|
@@ -1,5 +1,3 @@
|
|
|
1
|
-
import Context from '~/types/context'
|
|
2
|
-
|
|
3
1
|
export function createElement<E extends HTMLElement = HTMLElement>(htmlStr: string = ''): E {
|
|
4
2
|
const div = document.createElement('div')
|
|
5
3
|
div.innerHTML = htmlStr.trim()
|
|
@@ -29,11 +27,25 @@ export function getQueryParam(name: string) {
|
|
|
29
27
|
return match && decodeURIComponent(match[1].replace(/\+/g, ' '));
|
|
30
28
|
}
|
|
31
29
|
|
|
32
|
-
export function getOffset(el: HTMLElement) {
|
|
33
|
-
const
|
|
30
|
+
export function getOffset(el: HTMLElement, relativeTo?: HTMLElement) {
|
|
31
|
+
const getOffsetRecursive = (element: HTMLElement): { top: number, left: number } => {
|
|
32
|
+
const rect = element.getBoundingClientRect()
|
|
33
|
+
const scrollLeft = window.pageXOffset || document.documentElement.scrollLeft
|
|
34
|
+
const scrollTop = window.pageYOffset || document.documentElement.scrollTop
|
|
35
|
+
return {
|
|
36
|
+
top: rect.top + scrollTop,
|
|
37
|
+
left: rect.left + scrollLeft
|
|
38
|
+
}
|
|
39
|
+
}
|
|
40
|
+
|
|
41
|
+
const elOffset = getOffsetRecursive(el)
|
|
42
|
+
if (!relativeTo) return elOffset
|
|
43
|
+
|
|
44
|
+
const relativeToOffset = getOffsetRecursive(relativeTo)
|
|
45
|
+
|
|
34
46
|
return {
|
|
35
|
-
top:
|
|
36
|
-
left:
|
|
47
|
+
top: elOffset.top - relativeToOffset.top,
|
|
48
|
+
left: elOffset.left - relativeToOffset.left
|
|
37
49
|
}
|
|
38
50
|
}
|
|
39
51
|
|
|
@@ -55,7 +67,7 @@ export function dateFormat(date: Date) {
|
|
|
55
67
|
return `${vYear}-${vMonth}-${vDay}`
|
|
56
68
|
}
|
|
57
69
|
|
|
58
|
-
export function timeAgo(date: Date,
|
|
70
|
+
export function timeAgo(date: Date, $t: Function = (n: string) => n) {
|
|
59
71
|
try {
|
|
60
72
|
const oldTime = date.getTime()
|
|
61
73
|
const currTime = new Date().getTime()
|
|
@@ -74,17 +86,17 @@ export function timeAgo(date: Date, ctx: Context) {
|
|
|
74
86
|
// 计算相差秒数
|
|
75
87
|
const leave3 = leave2 % (60 * 1000) // 计算分钟数后剩余的毫秒数
|
|
76
88
|
const seconds = Math.round(leave3 / 1000)
|
|
77
|
-
if (seconds < 10) return
|
|
78
|
-
return `${seconds} ${
|
|
89
|
+
if (seconds < 10) return $t('now')
|
|
90
|
+
return `${seconds} ${$t('seconds')}`
|
|
79
91
|
}
|
|
80
|
-
return `${minutes} ${
|
|
92
|
+
return `${minutes} ${$t('minutes')}`
|
|
81
93
|
}
|
|
82
|
-
return `${hours} ${
|
|
94
|
+
return `${hours} ${$t('hours')}`
|
|
83
95
|
}
|
|
84
|
-
if (days < 0) return
|
|
96
|
+
if (days < 0) return $t('now')
|
|
85
97
|
|
|
86
98
|
if (days < 8) {
|
|
87
|
-
return `${days} ${
|
|
99
|
+
return `${days} ${$t('days')}`
|
|
88
100
|
}
|
|
89
101
|
|
|
90
102
|
return dateFormat(date)
|
|
@@ -115,9 +127,8 @@ export function onImagesLoaded($container: HTMLElement, event: Function) {
|
|
|
115
127
|
}
|
|
116
128
|
}
|
|
117
129
|
|
|
118
|
-
export function getGravatarURL(
|
|
119
|
-
|
|
120
|
-
return `${mirror.replace(/\/$/, '')}/${emailMD5}?${params.replace(/^\?/, '')}`
|
|
130
|
+
export function getGravatarURL(opts: { params: string, mirror: string, emailMD5: string }) {
|
|
131
|
+
return `${opts.mirror.replace(/\/$/, '')}/${opts.emailMD5}?${opts.params.replace(/^\?/, '')}`
|
|
121
132
|
}
|
|
122
133
|
|
|
123
134
|
export function sleep(ms: number) {
|
|
@@ -185,8 +196,8 @@ export function isValidURL(urlRaw: string) {
|
|
|
185
196
|
}
|
|
186
197
|
|
|
187
198
|
/** 获取基于 conf.server 的 URL */
|
|
188
|
-
export function getURLBasedOnApi(
|
|
189
|
-
return getURLBasedOn(
|
|
199
|
+
export function getURLBasedOnApi(opts: { base: string, path: string }) {
|
|
200
|
+
return getURLBasedOn(opts.base, opts.path)
|
|
190
201
|
}
|
|
191
202
|
|
|
192
203
|
/** 获取基于某个 baseURL 的 URL */
|
|
@@ -0,0 +1,20 @@
|
|
|
1
|
+
import type { ContextApi, CommentData } from '~/types'
|
|
2
|
+
import Comment from '../comment/comment'
|
|
3
|
+
|
|
4
|
+
export function createComment(ctx: ContextApi, comment: CommentData, ctxComments: CommentData[]): Comment {
|
|
5
|
+
const instance = new Comment(ctx, comment, {
|
|
6
|
+
isFlatMode: ctx.getData().getListLastFetch()?.params.flatMode!,
|
|
7
|
+
afterRender: () => {
|
|
8
|
+
ctx.trigger('comment-rendered', instance)
|
|
9
|
+
},
|
|
10
|
+
onDelete: (c: Comment) => {
|
|
11
|
+
ctx.getData().deleteComment(c.getID())
|
|
12
|
+
},
|
|
13
|
+
replyTo: (comment.rid ? ctxComments.find(c => c.id === comment.rid) : undefined)
|
|
14
|
+
})
|
|
15
|
+
|
|
16
|
+
// 渲染元素
|
|
17
|
+
instance.render()
|
|
18
|
+
|
|
19
|
+
return instance
|
|
20
|
+
}
|
|
@@ -0,0 +1,120 @@
|
|
|
1
|
+
import type { CommentData } from '~/types'
|
|
2
|
+
import * as Ui from '@/lib/ui'
|
|
3
|
+
import Comment from '../comment/comment'
|
|
4
|
+
import * as ListNest from './nest'
|
|
5
|
+
|
|
6
|
+
export interface LayoutOptions {
|
|
7
|
+
$commentsWrap: HTMLElement
|
|
8
|
+
nestSortBy: ListNest.SortByType
|
|
9
|
+
nestMax: number
|
|
10
|
+
flatMode: boolean
|
|
11
|
+
|
|
12
|
+
createCommentNode(comment: CommentData, ctxComments: CommentData[]): Comment
|
|
13
|
+
findCommentNode(id: number): Comment|undefined
|
|
14
|
+
getCommentDataList(): CommentData[]
|
|
15
|
+
}
|
|
16
|
+
|
|
17
|
+
export default class ListLayout {
|
|
18
|
+
constructor(private options: LayoutOptions) {}
|
|
19
|
+
|
|
20
|
+
// TODO refactor `if syntax` to strategy pattern
|
|
21
|
+
import(comments: CommentData[]) {
|
|
22
|
+
if (this.options.flatMode) {
|
|
23
|
+
comments.forEach((commentData: CommentData) => {
|
|
24
|
+
this.putCommentFlatMode(commentData, comments, 'append')
|
|
25
|
+
})
|
|
26
|
+
} else {
|
|
27
|
+
this.importCommentsNestMode(comments)
|
|
28
|
+
}
|
|
29
|
+
}
|
|
30
|
+
|
|
31
|
+
insert(comment: CommentData) {
|
|
32
|
+
if (!this.options.flatMode) {
|
|
33
|
+
this.insertCommentNest(comment)
|
|
34
|
+
} else {
|
|
35
|
+
this.insertCommentFlatMode(comment)
|
|
36
|
+
}
|
|
37
|
+
}
|
|
38
|
+
|
|
39
|
+
// 导入评论 · 嵌套模式
|
|
40
|
+
private importCommentsNestMode(srcData: CommentData[]) {
|
|
41
|
+
// 遍历 root 评论
|
|
42
|
+
const rootNodes = ListNest.makeNestCommentNodeList(srcData, this.options.nestSortBy, this.options.nestMax)
|
|
43
|
+
rootNodes.forEach((rootNode: ListNest.CommentNode) => {
|
|
44
|
+
const rootC = this.options.createCommentNode(rootNode.comment, srcData)
|
|
45
|
+
|
|
46
|
+
// 显示并播放渐入动画
|
|
47
|
+
this.options.$commentsWrap?.appendChild(rootC.getEl())
|
|
48
|
+
rootC.getRender().playFadeAnim()
|
|
49
|
+
|
|
50
|
+
// 加载子评论
|
|
51
|
+
const loadChildren = (parentC: Comment, parentNode: ListNest.CommentNode) => {
|
|
52
|
+
parentNode.children.forEach((node: ListNest.CommentNode) => {
|
|
53
|
+
const childD = node.comment
|
|
54
|
+
const childC = this.options.createCommentNode(childD, srcData)
|
|
55
|
+
|
|
56
|
+
// 插入到父评论中
|
|
57
|
+
parentC.putChild(childC)
|
|
58
|
+
|
|
59
|
+
// 递归加载子评论
|
|
60
|
+
loadChildren(childC, node)
|
|
61
|
+
})
|
|
62
|
+
}
|
|
63
|
+
loadChildren(rootC, rootNode)
|
|
64
|
+
|
|
65
|
+
// 限高检测
|
|
66
|
+
rootC.getRender().checkHeightLimit()
|
|
67
|
+
})
|
|
68
|
+
}
|
|
69
|
+
|
|
70
|
+
/** 导入评论 · 平铺模式 */
|
|
71
|
+
private putCommentFlatMode(cData: CommentData, ctxData: CommentData[], insertMode: 'append'|'prepend') {
|
|
72
|
+
if (cData.is_collapsed) cData.is_allow_reply = false
|
|
73
|
+
const comment = this.options.createCommentNode(cData, ctxData)
|
|
74
|
+
|
|
75
|
+
// 可见评论添加到界面
|
|
76
|
+
// 注:不可见评论用于显示 “引用内容”
|
|
77
|
+
if (cData.visible) {
|
|
78
|
+
if (insertMode === 'append') this.options.$commentsWrap?.append(comment.getEl())
|
|
79
|
+
if (insertMode === 'prepend') this.options.$commentsWrap?.prepend(comment.getEl())
|
|
80
|
+
comment.getRender().playFadeAnim()
|
|
81
|
+
}
|
|
82
|
+
|
|
83
|
+
// 平铺评论插入后 · 内容限高检测
|
|
84
|
+
comment.getRender().checkHeightLimit()
|
|
85
|
+
|
|
86
|
+
return comment
|
|
87
|
+
}
|
|
88
|
+
|
|
89
|
+
private insertCommentNest(commentData: CommentData) {
|
|
90
|
+
// 嵌套模式
|
|
91
|
+
const comment = this.options.createCommentNode(commentData, this.options.getCommentDataList())
|
|
92
|
+
|
|
93
|
+
if (commentData.rid === 0) {
|
|
94
|
+
// root评论 新增
|
|
95
|
+
this.options.$commentsWrap?.prepend(comment.getEl())
|
|
96
|
+
} else {
|
|
97
|
+
// 子评论 新增
|
|
98
|
+
const parent = this.options.findCommentNode(commentData.rid)
|
|
99
|
+
if (parent) {
|
|
100
|
+
parent.putChild(comment, (this.options.nestSortBy === 'DATE_ASC' ? 'append' : 'prepend'))
|
|
101
|
+
|
|
102
|
+
// 若父评论存在 “子评论部分” 限高,取消限高
|
|
103
|
+
comment.getParents().forEach((p) => {
|
|
104
|
+
p.getRender().heightLimitRemoveForChildren()
|
|
105
|
+
})
|
|
106
|
+
}
|
|
107
|
+
}
|
|
108
|
+
|
|
109
|
+
comment.getRender().checkHeightLimit()
|
|
110
|
+
|
|
111
|
+
Ui.scrollIntoView(comment.getEl()) // 滚动到可以见
|
|
112
|
+
comment.getRender().playFadeAnim() // 播放评论渐出动画
|
|
113
|
+
}
|
|
114
|
+
|
|
115
|
+
private insertCommentFlatMode(commentData: CommentData) {
|
|
116
|
+
// 平铺模式
|
|
117
|
+
const comment = this.putCommentFlatMode(commentData, this.options.getCommentDataList(), 'prepend')
|
|
118
|
+
Ui.scrollIntoView(comment.getEl()) // 滚动到可见
|
|
119
|
+
}
|
|
120
|
+
}
|
package/src/list/list.html
CHANGED