aboutsummaryrefslogtreecommitdiffhomepage
path: root/client/src/app/core/renderer/markdown.service.ts
diff options
context:
space:
mode:
Diffstat (limited to 'client/src/app/core/renderer/markdown.service.ts')
-rw-r--r--client/src/app/core/renderer/markdown.service.ts53
1 files changed, 36 insertions, 17 deletions
diff --git a/client/src/app/core/renderer/markdown.service.ts b/client/src/app/core/renderer/markdown.service.ts
index edddb0a66..ca1bf4eb9 100644
--- a/client/src/app/core/renderer/markdown.service.ts
+++ b/client/src/app/core/renderer/markdown.service.ts
@@ -17,12 +17,15 @@ type MarkdownParsers = {
17 enhancedMarkdownIt: MarkdownIt 17 enhancedMarkdownIt: MarkdownIt
18 enhancedWithHTMLMarkdownIt: MarkdownIt 18 enhancedWithHTMLMarkdownIt: MarkdownIt
19 19
20 completeMarkdownIt: MarkdownIt 20 unsafeMarkdownIt: MarkdownIt
21
22 customPageMarkdownIt: MarkdownIt
21} 23}
22 24
23type MarkdownConfig = { 25type MarkdownConfig = {
24 rules: string[] 26 rules: string[]
25 html: boolean 27 html: boolean
28 breaks: boolean
26 escape?: boolean 29 escape?: boolean
27} 30}
28 31
@@ -35,18 +38,24 @@ export class MarkdownService {
35 private markdownParsers: MarkdownParsers = { 38 private markdownParsers: MarkdownParsers = {
36 textMarkdownIt: null, 39 textMarkdownIt: null,
37 textWithHTMLMarkdownIt: null, 40 textWithHTMLMarkdownIt: null,
41
38 enhancedMarkdownIt: null, 42 enhancedMarkdownIt: null,
39 enhancedWithHTMLMarkdownIt: null, 43 enhancedWithHTMLMarkdownIt: null,
40 completeMarkdownIt: null 44
45 unsafeMarkdownIt: null,
46
47 customPageMarkdownIt: null
41 } 48 }
42 private parsersConfig: MarkdownParserConfigs = { 49 private parsersConfig: MarkdownParserConfigs = {
43 textMarkdownIt: { rules: TEXT_RULES, html: false }, 50 textMarkdownIt: { rules: TEXT_RULES, breaks: true, html: false },
44 textWithHTMLMarkdownIt: { rules: TEXT_WITH_HTML_RULES, html: true, escape: true }, 51 textWithHTMLMarkdownIt: { rules: TEXT_WITH_HTML_RULES, breaks: true, html: true, escape: true },
45 52
46 enhancedMarkdownIt: { rules: ENHANCED_RULES, html: false }, 53 enhancedMarkdownIt: { rules: ENHANCED_RULES, breaks: true, html: false },
47 enhancedWithHTMLMarkdownIt: { rules: ENHANCED_WITH_HTML_RULES, html: true, escape: true }, 54 enhancedWithHTMLMarkdownIt: { rules: ENHANCED_WITH_HTML_RULES, breaks: true, html: true, escape: true },
48 55
49 completeMarkdownIt: { rules: COMPLETE_RULES, html: true } 56 unsafeMarkdownIt: { rules: COMPLETE_RULES, breaks: true, html: true, escape: false },
57
58 customPageMarkdownIt: { rules: COMPLETE_RULES, breaks: false, html: true, escape: true }
50 } 59 }
51 60
52 private emojiModule: any 61 private emojiModule: any
@@ -54,22 +63,26 @@ export class MarkdownService {
54 constructor (private htmlRenderer: HtmlRendererService) {} 63 constructor (private htmlRenderer: HtmlRendererService) {}
55 64
56 textMarkdownToHTML (markdown: string, withHtml = false, withEmoji = false) { 65 textMarkdownToHTML (markdown: string, withHtml = false, withEmoji = false) {
57 if (withHtml) return this.render('textWithHTMLMarkdownIt', markdown, withEmoji) 66 if (withHtml) return this.render({ name: 'textWithHTMLMarkdownIt', markdown, withEmoji })
58 67
59 return this.render('textMarkdownIt', markdown, withEmoji) 68 return this.render({ name: 'textMarkdownIt', markdown, withEmoji })
60 } 69 }
61 70
62 enhancedMarkdownToHTML (markdown: string, withHtml = false, withEmoji = false) { 71 enhancedMarkdownToHTML (markdown: string, withHtml = false, withEmoji = false) {
63 if (withHtml) return this.render('enhancedWithHTMLMarkdownIt', markdown, withEmoji) 72 if (withHtml) return this.render({ name: 'enhancedWithHTMLMarkdownIt', markdown, withEmoji })
73
74 return this.render({ name: 'enhancedMarkdownIt', markdown, withEmoji })
75 }
64 76
65 return this.render('enhancedMarkdownIt', markdown, withEmoji) 77 unsafeMarkdownToHTML (markdown: string, _trustedInput: true) {
78 return this.render({ name: 'unsafeMarkdownIt', markdown, withEmoji: true })
66 } 79 }
67 80
68 completeMarkdownToHTML (markdown: string) { 81 customPageMarkdownToHTML (markdown: string, additionalAllowedTags: string[]) {
69 return this.render('completeMarkdownIt', markdown, true) 82 return this.render({ name: 'customPageMarkdownIt', markdown, withEmoji: true, additionalAllowedTags })
70 } 83 }
71 84
72 async processVideoTimestamps (html: string) { 85 processVideoTimestamps (html: string) {
73 return html.replace(/((\d{1,2}):)?(\d{1,2}):(\d{1,2})/g, function (str, _, h, m, s) { 86 return html.replace(/((\d{1,2}):)?(\d{1,2}):(\d{1,2})/g, function (str, _, h, m, s) {
74 const t = (3600 * +(h || 0)) + (60 * +(m || 0)) + (+(s || 0)) 87 const t = (3600 * +(h || 0)) + (60 * +(m || 0)) + (+(s || 0))
75 const url = buildVideoLink({ startTime: t }) 88 const url = buildVideoLink({ startTime: t })
@@ -77,7 +90,13 @@ export class MarkdownService {
77 }) 90 })
78 } 91 }
79 92
80 private async render (name: keyof MarkdownParsers, markdown: string, withEmoji = false) { 93 private async render (options: {
94 name: keyof MarkdownParsers
95 markdown: string
96 withEmoji: boolean
97 additionalAllowedTags?: string[]
98 }) {
99 const { name, markdown, withEmoji, additionalAllowedTags } = options
81 if (!markdown) return '' 100 if (!markdown) return ''
82 101
83 const config = this.parsersConfig[ name ] 102 const config = this.parsersConfig[ name ]
@@ -96,7 +115,7 @@ export class MarkdownService {
96 let html = this.markdownParsers[ name ].render(markdown) 115 let html = this.markdownParsers[ name ].render(markdown)
97 html = this.avoidTruncatedTags(html) 116 html = this.avoidTruncatedTags(html)
98 117
99 if (config.escape) return this.htmlRenderer.toSafeHtml(html) 118 if (config.escape) return this.htmlRenderer.toSafeHtml(html, additionalAllowedTags)
100 119
101 return html 120 return html
102 } 121 }
@@ -105,7 +124,7 @@ export class MarkdownService {
105 // FIXME: import('...') returns a struct module, containing a "default" field 124 // FIXME: import('...') returns a struct module, containing a "default" field
106 const MarkdownItClass: typeof import ('markdown-it') = (await import('markdown-it') as any).default 125 const MarkdownItClass: typeof import ('markdown-it') = (await import('markdown-it') as any).default
107 126
108 const markdownIt = new MarkdownItClass('zero', { linkify: true, breaks: true, html: config.html }) 127 const markdownIt = new MarkdownItClass('zero', { linkify: true, breaks: config.breaks, html: config.html })
109 128
110 for (const rule of config.rules) { 129 for (const rule of config.rules) {
111 markdownIt.enable(rule) 130 markdownIt.enable(rule)