diff options
8 files changed, 83 insertions, 27 deletions
diff --git a/client/src/app/shared/shared-custom-markup/custom-markup-container.component.html b/client/src/app/shared/shared-custom-markup/custom-markup-container.component.html index 3ad88645d..6bf2294a3 100644 --- a/client/src/app/shared/shared-custom-markup/custom-markup-container.component.html +++ b/client/src/app/shared/shared-custom-markup/custom-markup-container.component.html | |||
@@ -1 +1 @@ | |||
<div #contentWrapper></div> | <div class="custom-markup-container" #contentWrapper></div> | ||
diff --git a/client/src/app/shared/shared-custom-markup/custom-markup-container.component.scss b/client/src/app/shared/shared-custom-markup/custom-markup-container.component.scss new file mode 100644 index 000000000..044db9536 --- /dev/null +++ b/client/src/app/shared/shared-custom-markup/custom-markup-container.component.scss | |||
@@ -0,0 +1,10 @@ | |||
1 | .custom-markup-container { | ||
2 | |||
3 | ::ng-deep .peertube-container { | ||
4 | margin: 30px 0 15px; | ||
5 | |||
6 | h4 { | ||
7 | margin-bottom: 0; | ||
8 | } | ||
9 | } | ||
10 | } | ||
diff --git a/client/src/app/shared/shared-custom-markup/custom-markup-container.component.ts b/client/src/app/shared/shared-custom-markup/custom-markup-container.component.ts index 3d49c6768..2ecdc0243 100644 --- a/client/src/app/shared/shared-custom-markup/custom-markup-container.component.ts +++ b/client/src/app/shared/shared-custom-markup/custom-markup-container.component.ts | |||
@@ -3,7 +3,8 @@ import { CustomMarkupService } from './custom-markup.service' | |||
3 | 3 | ||
4 | @Component({ | 4 | @Component({ |
5 | selector: 'my-custom-markup-container', | 5 | selector: 'my-custom-markup-container', |
6 | templateUrl: './custom-markup-container.component.html' | 6 | templateUrl: './custom-markup-container.component.html', |
7 | styleUrls: [ './custom-markup-container.component.scss' ] | ||
7 | }) | 8 | }) |
8 | export class CustomMarkupContainerComponent implements OnChanges { | 9 | export class CustomMarkupContainerComponent implements OnChanges { |
9 | @ViewChild('contentWrapper') contentWrapper: ElementRef<HTMLInputElement> | 10 | @ViewChild('contentWrapper') contentWrapper: ElementRef<HTMLInputElement> |
diff --git a/client/src/app/shared/shared-custom-markup/custom-markup.service.ts b/client/src/app/shared/shared-custom-markup/custom-markup.service.ts index dbb07914e..a3b7303d8 100644 --- a/client/src/app/shared/shared-custom-markup/custom-markup.service.ts +++ b/client/src/app/shared/shared-custom-markup/custom-markup.service.ts | |||
@@ -3,6 +3,7 @@ import { MarkdownService } from '@app/core' | |||
3 | import { | 3 | import { |
4 | ButtonMarkupData, | 4 | ButtonMarkupData, |
5 | ChannelMiniatureMarkupData, | 5 | ChannelMiniatureMarkupData, |
6 | ContainerMarkupData, | ||
6 | EmbedMarkupData, | 7 | EmbedMarkupData, |
7 | PlaylistMiniatureMarkupData, | 8 | PlaylistMiniatureMarkupData, |
8 | VideoMiniatureMarkupData, | 9 | VideoMiniatureMarkupData, |
@@ -18,11 +19,12 @@ import { | |||
18 | VideosListMarkupComponent | 19 | VideosListMarkupComponent |
19 | } from './peertube-custom-tags' | 20 | } from './peertube-custom-tags' |
20 | 21 | ||
21 | type BuilderFunction = (el: HTMLElement) => ComponentRef<any> | 22 | type AngularBuilderFunction = (el: HTMLElement) => ComponentRef<any> |
23 | type HTMLBuilderFunction = (el: HTMLElement) => HTMLElement | ||
22 | 24 | ||
23 | @Injectable() | 25 | @Injectable() |
24 | export class CustomMarkupService { | 26 | export class CustomMarkupService { |
25 | private builders: { [ selector: string ]: BuilderFunction } = { | 27 | private angularBuilders: { [ selector: string ]: AngularBuilderFunction } = { |
26 | 'peertube-button': el => this.buttonBuilder(el), | 28 | 'peertube-button': el => this.buttonBuilder(el), |
27 | 'peertube-video-embed': el => this.embedBuilder(el, 'video'), | 29 | 'peertube-video-embed': el => this.embedBuilder(el, 'video'), |
28 | 'peertube-playlist-embed': el => this.embedBuilder(el, 'playlist'), | 30 | 'peertube-playlist-embed': el => this.embedBuilder(el, 'playlist'), |
@@ -32,6 +34,10 @@ export class CustomMarkupService { | |||
32 | 'peertube-videos-list': el => this.videosListBuilder(el) | 34 | 'peertube-videos-list': el => this.videosListBuilder(el) |
33 | } | 35 | } |
34 | 36 | ||
37 | private htmlBuilders: { [ selector: string ]: HTMLBuilderFunction } = { | ||
38 | 'peertube-container': el => this.containerBuilder(el) | ||
39 | } | ||
40 | |||
35 | private customMarkdownRenderer: (text: string) => Promise<HTMLElement> | 41 | private customMarkdownRenderer: (text: string) => Promise<HTMLElement> |
36 | 42 | ||
37 | constructor ( | 43 | constructor ( |
@@ -51,11 +57,24 @@ export class CustomMarkupService { | |||
51 | const rootElement = document.createElement('div') | 57 | const rootElement = document.createElement('div') |
52 | rootElement.innerHTML = html | 58 | rootElement.innerHTML = html |
53 | 59 | ||
54 | for (const selector of this.getSupportedTags()) { | 60 | for (const selector of Object.keys(this.htmlBuilders)) { |
61 | rootElement.querySelectorAll(selector) | ||
62 | .forEach((e: HTMLElement) => { | ||
63 | try { | ||
64 | const element = this.execHTMLBuilder(selector, e) | ||
65 | // Insert as first child | ||
66 | e.insertBefore(element, e.firstChild) | ||
67 | } catch (err) { | ||
68 | console.error('Cannot inject component %s.', selector, err) | ||
69 | } | ||
70 | }) | ||
71 | } | ||
72 | |||
73 | for (const selector of Object.keys(this.angularBuilders)) { | ||
55 | rootElement.querySelectorAll(selector) | 74 | rootElement.querySelectorAll(selector) |
56 | .forEach((e: HTMLElement) => { | 75 | .forEach((e: HTMLElement) => { |
57 | try { | 76 | try { |
58 | const component = this.execBuilder(selector, e) | 77 | const component = this.execAngularBuilder(selector, e) |
59 | 78 | ||
60 | this.dynamicElementService.injectElement(e, component) | 79 | this.dynamicElementService.injectElement(e, component) |
61 | } catch (err) { | 80 | } catch (err) { |
@@ -68,11 +87,16 @@ export class CustomMarkupService { | |||
68 | } | 87 | } |
69 | 88 | ||
70 | private getSupportedTags () { | 89 | private getSupportedTags () { |
71 | return Object.keys(this.builders) | 90 | return Object.keys(this.angularBuilders) |
91 | .concat(Object.keys(this.htmlBuilders)) | ||
72 | } | 92 | } |
73 | 93 | ||
74 | private execBuilder (selector: string, el: HTMLElement) { | 94 | private execHTMLBuilder (selector: string, el: HTMLElement) { |
75 | return this.builders[selector](el) | 95 | return this.htmlBuilders[selector](el) |
96 | } | ||
97 | |||
98 | private execAngularBuilder (selector: string, el: HTMLElement) { | ||
99 | return this.angularBuilders[selector](el) | ||
76 | } | 100 | } |
77 | 101 | ||
78 | private embedBuilder (el: HTMLElement, type: 'video' | 'playlist') { | 102 | private embedBuilder (el: HTMLElement, type: 'video' | 'playlist') { |
@@ -131,8 +155,6 @@ export class CustomMarkupService { | |||
131 | const component = this.dynamicElementService.createElement(VideosListMarkupComponent) | 155 | const component = this.dynamicElementService.createElement(VideosListMarkupComponent) |
132 | 156 | ||
133 | const model = { | 157 | const model = { |
134 | title: data.title, | ||
135 | description: data.description, | ||
136 | sort: data.sort, | 158 | sort: data.sort, |
137 | categoryOneOf: this.buildArrayNumber(data.categoryOneOf), | 159 | categoryOneOf: this.buildArrayNumber(data.categoryOneOf), |
138 | languageOneOf: this.buildArrayString(data.languageOneOf), | 160 | languageOneOf: this.buildArrayString(data.languageOneOf), |
@@ -144,6 +166,31 @@ export class CustomMarkupService { | |||
144 | return component | 166 | return component |
145 | } | 167 | } |
146 | 168 | ||
169 | private containerBuilder (el: HTMLElement) { | ||
170 | const data = el.dataset as ContainerMarkupData | ||
171 | |||
172 | const root = document.createElement('div') | ||
173 | root.classList.add('peertube-container') | ||
174 | |||
175 | if (data.width) { | ||
176 | root.setAttribute('width', data.width) | ||
177 | } | ||
178 | |||
179 | if (data.title) { | ||
180 | const titleElement = document.createElement('h4') | ||
181 | titleElement.innerText = data.title | ||
182 | root.appendChild(titleElement) | ||
183 | } | ||
184 | |||
185 | if (data.description) { | ||
186 | const descriptionElement = document.createElement('div') | ||
187 | descriptionElement.innerText = data.description | ||
188 | root.appendChild(descriptionElement) | ||
189 | } | ||
190 | |||
191 | return root | ||
192 | } | ||
193 | |||
147 | private buildNumber (value: string) { | 194 | private buildNumber (value: string) { |
148 | if (!value) return undefined | 195 | if (!value) return undefined |
149 | 196 | ||
diff --git a/client/src/app/shared/shared-custom-markup/peertube-custom-tags/videos-list-markup.component.html b/client/src/app/shared/shared-custom-markup/peertube-custom-tags/videos-list-markup.component.html index 501f35e04..a2fd2fe40 100644 --- a/client/src/app/shared/shared-custom-markup/peertube-custom-tags/videos-list-markup.component.html +++ b/client/src/app/shared/shared-custom-markup/peertube-custom-tags/videos-list-markup.component.html | |||
@@ -1,13 +1,8 @@ | |||
1 | <div class="root"> | 1 | <div class="videos"> |
2 | <h4 *ngIf="title">{{ title }}</h4> | 2 | <my-video-miniature |
3 | <div *ngIf="description" class="description">{{ description }}</div> | 3 | *ngFor="let video of videos" |
4 | 4 | [video]="video" [user]="getUser()" [displayAsRow]="false" | |
5 | <div class="videos"> | 5 | [displayVideoActions]="false" [displayOptions]="displayOptions" |
6 | <my-video-miniature | 6 | > |
7 | *ngFor="let video of videos" | 7 | </my-video-miniature> |
8 | [video]="video" [user]="getUser()" [displayAsRow]="false" | ||
9 | [displayVideoActions]="false" [displayOptions]="displayOptions" | ||
10 | > | ||
11 | </my-video-miniature> | ||
12 | </div> | ||
13 | </div> | 8 | </div> |
diff --git a/client/src/app/shared/shared-custom-markup/peertube-custom-tags/videos-list-markup.component.scss b/client/src/app/shared/shared-custom-markup/peertube-custom-tags/videos-list-markup.component.scss index d8796e12e..6b7274480 100644 --- a/client/src/app/shared/shared-custom-markup/peertube-custom-tags/videos-list-markup.component.scss +++ b/client/src/app/shared/shared-custom-markup/peertube-custom-tags/videos-list-markup.component.scss | |||
@@ -3,6 +3,7 @@ | |||
3 | 3 | ||
4 | my-video-miniature { | 4 | my-video-miniature { |
5 | @include margin-right(15px); | 5 | @include margin-right(15px); |
6 | |||
6 | display: inline-block; | 7 | display: inline-block; |
7 | min-width: $video-thumbnail-width; | 8 | min-width: $video-thumbnail-width; |
8 | max-width: $video-thumbnail-width; | 9 | max-width: $video-thumbnail-width; |
diff --git a/client/src/app/shared/shared-custom-markup/peertube-custom-tags/videos-list-markup.component.ts b/client/src/app/shared/shared-custom-markup/peertube-custom-tags/videos-list-markup.component.ts index 8d9e223da..c3710484e 100644 --- a/client/src/app/shared/shared-custom-markup/peertube-custom-tags/videos-list-markup.component.ts +++ b/client/src/app/shared/shared-custom-markup/peertube-custom-tags/videos-list-markup.component.ts | |||
@@ -14,8 +14,6 @@ import { MiniatureDisplayOptions } from '../../shared-video-miniature' | |||
14 | styleUrls: [ 'videos-list-markup.component.scss' ] | 14 | styleUrls: [ 'videos-list-markup.component.scss' ] |
15 | }) | 15 | }) |
16 | export class VideosListMarkupComponent implements OnInit { | 16 | export class VideosListMarkupComponent implements OnInit { |
17 | @Input() title: string | ||
18 | @Input() description: string | ||
19 | @Input() sort = '-publishedAt' | 17 | @Input() sort = '-publishedAt' |
20 | @Input() categoryOneOf: number[] | 18 | @Input() categoryOneOf: number[] |
21 | @Input() languageOneOf: string[] | 19 | @Input() languageOneOf: string[] |
diff --git a/shared/models/custom-markup/custom-markup-data.model.ts b/shared/models/custom-markup/custom-markup-data.model.ts index 24ac3706c..d38f9412c 100644 --- a/shared/models/custom-markup/custom-markup-data.model.ts +++ b/shared/models/custom-markup/custom-markup-data.model.ts | |||
@@ -19,8 +19,6 @@ export type ChannelMiniatureMarkupData = { | |||
19 | } | 19 | } |
20 | 20 | ||
21 | export type VideosListMarkupData = { | 21 | export type VideosListMarkupData = { |
22 | title: string | ||
23 | description: string | ||
24 | sort: string | 22 | sort: string |
25 | categoryOneOf: string // coma separated values | 23 | categoryOneOf: string // coma separated values |
26 | languageOneOf: string // coma separated values | 24 | languageOneOf: string // coma separated values |
@@ -33,3 +31,9 @@ export type ButtonMarkupData = { | |||
33 | label: string | 31 | label: string |
34 | blankTarget?: string | 32 | blankTarget?: string |
35 | } | 33 | } |
34 | |||
35 | export type ContainerMarkupData = { | ||
36 | width?: string | ||
37 | title?: string | ||
38 | description?: string | ||
39 | } | ||