]> git.immae.eu Git - github/Chocobozzz/PeerTube.git/blame - client/src/app/shared/shared-custom-markup/custom-markup.service.ts
Add ability to set custom markdown in description
[github/Chocobozzz/PeerTube.git] / client / src / app / shared / shared-custom-markup / custom-markup.service.ts
CommitLineData
2539932e
C
1import { ComponentRef, Injectable } from '@angular/core'
2import { MarkdownService } from '@app/core'
3import {
63042139 4 ButtonMarkupData,
2539932e
C
5 ChannelMiniatureMarkupData,
6 EmbedMarkupData,
7 PlaylistMiniatureMarkupData,
8 VideoMiniatureMarkupData,
9 VideosListMarkupData
10} from '@shared/models'
2539932e 11import { DynamicElementService } from './dynamic-element.service'
8ee25e17
C
12import {
13 ButtonMarkupComponent,
14 ChannelMiniatureMarkupComponent,
15 EmbedMarkupComponent,
16 PlaylistMiniatureMarkupComponent,
17 VideoMiniatureMarkupComponent,
18 VideosListMarkupComponent
19} from './peertube-custom-tags'
2539932e
C
20
21type BuilderFunction = (el: HTMLElement) => ComponentRef<any>
22
23@Injectable()
24export class CustomMarkupService {
25 private builders: { [ selector: string ]: BuilderFunction } = {
63042139 26 'peertube-button': el => this.buttonBuilder(el),
2539932e
C
27 'peertube-video-embed': el => this.embedBuilder(el, 'video'),
28 'peertube-playlist-embed': el => this.embedBuilder(el, 'playlist'),
29 'peertube-video-miniature': el => this.videoMiniatureBuilder(el),
30 'peertube-playlist-miniature': el => this.playlistMiniatureBuilder(el),
31 'peertube-channel-miniature': el => this.channelMiniatureBuilder(el),
32 'peertube-videos-list': el => this.videosListBuilder(el)
33 }
34
8ee25e17
C
35 private customMarkdownRenderer: (text: string) => Promise<HTMLElement>
36
2539932e
C
37 constructor (
38 private dynamicElementService: DynamicElementService,
39 private markdown: MarkdownService
8ee25e17
C
40 ) {
41 this.customMarkdownRenderer = async (text: string) => this.buildElement(text)
42 }
43
44 getCustomMarkdownRenderer () {
45 return this.customMarkdownRenderer
46 }
2539932e
C
47
48 async buildElement (text: string) {
49 const html = await this.markdown.customPageMarkdownToHTML(text, this.getSupportedTags())
50
51 const rootElement = document.createElement('div')
52 rootElement.innerHTML = html
53
54 for (const selector of this.getSupportedTags()) {
55 rootElement.querySelectorAll(selector)
56 .forEach((e: HTMLElement) => {
57 try {
58 const component = this.execBuilder(selector, e)
59
60 this.dynamicElementService.injectElement(e, component)
61 } catch (err) {
62 console.error('Cannot inject component %s.', selector, err)
63 }
64 })
65 }
66
67 return rootElement
68 }
69
70 private getSupportedTags () {
71 return Object.keys(this.builders)
72 }
73
74 private execBuilder (selector: string, el: HTMLElement) {
75 return this.builders[selector](el)
76 }
77
78 private embedBuilder (el: HTMLElement, type: 'video' | 'playlist') {
79 const data = el.dataset as EmbedMarkupData
80 const component = this.dynamicElementService.createElement(EmbedMarkupComponent)
81
82 this.dynamicElementService.setModel(component, { uuid: data.uuid, type })
83
84 return component
85 }
86
87 private videoMiniatureBuilder (el: HTMLElement) {
88 const data = el.dataset as VideoMiniatureMarkupData
89 const component = this.dynamicElementService.createElement(VideoMiniatureMarkupComponent)
90
91 this.dynamicElementService.setModel(component, { uuid: data.uuid })
92
93 return component
94 }
95
96 private playlistMiniatureBuilder (el: HTMLElement) {
97 const data = el.dataset as PlaylistMiniatureMarkupData
98 const component = this.dynamicElementService.createElement(PlaylistMiniatureMarkupComponent)
99
100 this.dynamicElementService.setModel(component, { uuid: data.uuid })
101
102 return component
103 }
104
105 private channelMiniatureBuilder (el: HTMLElement) {
106 const data = el.dataset as ChannelMiniatureMarkupData
107 const component = this.dynamicElementService.createElement(ChannelMiniatureMarkupComponent)
108
109 this.dynamicElementService.setModel(component, { name: data.name })
110
111 return component
112 }
113
63042139
C
114 private buttonBuilder (el: HTMLElement) {
115 const data = el.dataset as ButtonMarkupData
116 const component = this.dynamicElementService.createElement(ButtonMarkupComponent)
117
118 const model = {
119 theme: data.theme,
120 href: data.href,
121 label: data.label,
122 blankTarget: this.buildBoolean(data.blankTarget)
123 }
124 this.dynamicElementService.setModel(component, model)
125
126 return component
127 }
128
2539932e
C
129 private videosListBuilder (el: HTMLElement) {
130 const data = el.dataset as VideosListMarkupData
131 const component = this.dynamicElementService.createElement(VideosListMarkupComponent)
132
133 const model = {
134 title: data.title,
135 description: data.description,
136 sort: data.sort,
137 categoryOneOf: this.buildArrayNumber(data.categoryOneOf),
138 languageOneOf: this.buildArrayString(data.languageOneOf),
139 count: this.buildNumber(data.count) || 10
140 }
141
142 this.dynamicElementService.setModel(component, model)
143
144 return component
145 }
146
147 private buildNumber (value: string) {
148 if (!value) return undefined
149
150 return parseInt(value, 10)
151 }
152
63042139
C
153 private buildBoolean (value: string) {
154 if (value === 'true') return true
155 if (value === 'false') return false
156
157 return undefined
158 }
159
2539932e
C
160 private buildArrayNumber (value: string) {
161 if (!value) return undefined
162
163 return value.split(',').map(v => parseInt(v, 10))
164 }
165
166 private buildArrayString (value: string) {
167 if (!value) return undefined
168
169 return value.split(',')
170 }
171}