]> git.immae.eu Git - github/Chocobozzz/PeerTube.git/blobdiff - client/src/app/shared/shared-custom-markup/custom-markup.service.ts
Add more filters for video miniatures
[github/Chocobozzz/PeerTube.git] / client / src / app / shared / shared-custom-markup / custom-markup.service.ts
index ffaf1571015fd997f218892cc18ecc4071ea29eb..db5f64ee80bc6b72ed2a8f4c5ee023c1b8185fa7 100644 (file)
@@ -1,24 +1,32 @@
 import { ComponentRef, Injectable } from '@angular/core'
 import { MarkdownService } from '@app/core'
 import {
+  ButtonMarkupData,
   ChannelMiniatureMarkupData,
+  ContainerMarkupData,
   EmbedMarkupData,
   PlaylistMiniatureMarkupData,
+  VideoFilter,
   VideoMiniatureMarkupData,
   VideosListMarkupData
 } from '@shared/models'
-import { ChannelMiniatureMarkupComponent } from './channel-miniature-markup.component'
 import { DynamicElementService } from './dynamic-element.service'
-import { EmbedMarkupComponent } from './embed-markup.component'
-import { PlaylistMiniatureMarkupComponent } from './playlist-miniature-markup.component'
-import { VideoMiniatureMarkupComponent } from './video-miniature-markup.component'
-import { VideosListMarkupComponent } from './videos-list-markup.component'
+import {
+  ButtonMarkupComponent,
+  ChannelMiniatureMarkupComponent,
+  EmbedMarkupComponent,
+  PlaylistMiniatureMarkupComponent,
+  VideoMiniatureMarkupComponent,
+  VideosListMarkupComponent
+} from './peertube-custom-tags'
 
-type BuilderFunction = (el: HTMLElement) => ComponentRef<any>
+type AngularBuilderFunction = (el: HTMLElement) => ComponentRef<any>
+type HTMLBuilderFunction = (el: HTMLElement) => HTMLElement
 
 @Injectable()
 export class CustomMarkupService {
-  private builders: { [ selector: string ]: BuilderFunction } = {
+  private angularBuilders: { [ selector: string ]: AngularBuilderFunction } = {
+    'peertube-button': el => this.buttonBuilder(el),
     'peertube-video-embed': el => this.embedBuilder(el, 'video'),
     'peertube-playlist-embed': el => this.embedBuilder(el, 'playlist'),
     'peertube-video-miniature': el => this.videoMiniatureBuilder(el),
@@ -27,10 +35,22 @@ export class CustomMarkupService {
     'peertube-videos-list': el => this.videosListBuilder(el)
   }
 
+  private htmlBuilders: { [ selector: string ]: HTMLBuilderFunction } = {
+    'peertube-container': el => this.containerBuilder(el)
+  }
+
+  private customMarkdownRenderer: (text: string) => Promise<HTMLElement>
+
   constructor (
     private dynamicElementService: DynamicElementService,
     private markdown: MarkdownService
-  ) { }
+  ) {
+    this.customMarkdownRenderer = async (text: string) => this.buildElement(text)
+  }
+
+  getCustomMarkdownRenderer () {
+    return this.customMarkdownRenderer
+  }
 
   async buildElement (text: string) {
     const html = await this.markdown.customPageMarkdownToHTML(text, this.getSupportedTags())
@@ -38,11 +58,24 @@ export class CustomMarkupService {
     const rootElement = document.createElement('div')
     rootElement.innerHTML = html
 
-    for (const selector of this.getSupportedTags()) {
+    for (const selector of Object.keys(this.htmlBuilders)) {
+      rootElement.querySelectorAll(selector)
+        .forEach((e: HTMLElement) => {
+          try {
+            const element = this.execHTMLBuilder(selector, e)
+            // Insert as first child
+            e.insertBefore(element, e.firstChild)
+          } catch (err) {
+            console.error('Cannot inject component %s.', selector, err)
+          }
+        })
+    }
+
+    for (const selector of Object.keys(this.angularBuilders)) {
       rootElement.querySelectorAll(selector)
         .forEach((e: HTMLElement) => {
           try {
-            const component = this.execBuilder(selector, e)
+            const component = this.execAngularBuilder(selector, e)
 
             this.dynamicElementService.injectElement(e, component)
           } catch (err) {
@@ -55,11 +88,16 @@ export class CustomMarkupService {
   }
 
   private getSupportedTags () {
-    return Object.keys(this.builders)
+    return Object.keys(this.angularBuilders)
+      .concat(Object.keys(this.htmlBuilders))
+  }
+
+  private execHTMLBuilder (selector: string, el: HTMLElement) {
+    return this.htmlBuilders[selector](el)
   }
 
-  private execBuilder (selector: string, el: HTMLElement) {
-    return this.builders[selector](el)
+  private execAngularBuilder (selector: string, el: HTMLElement) {
+    return this.angularBuilders[selector](el)
   }
 
   private embedBuilder (el: HTMLElement, type: 'video' | 'playlist') {
@@ -71,15 +109,6 @@ export class CustomMarkupService {
     return component
   }
 
-  private videoMiniatureBuilder (el: HTMLElement) {
-    const data = el.dataset as VideoMiniatureMarkupData
-    const component = this.dynamicElementService.createElement(VideoMiniatureMarkupComponent)
-
-    this.dynamicElementService.setModel(component, { uuid: data.uuid })
-
-    return component
-  }
-
   private playlistMiniatureBuilder (el: HTMLElement) {
     const data = el.dataset as PlaylistMiniatureMarkupData
     const component = this.dynamicElementService.createElement(PlaylistMiniatureMarkupComponent)
@@ -98,16 +127,45 @@ export class CustomMarkupService {
     return component
   }
 
+  private buttonBuilder (el: HTMLElement) {
+    const data = el.dataset as ButtonMarkupData
+    const component = this.dynamicElementService.createElement(ButtonMarkupComponent)
+
+    const model = {
+      theme: data.theme,
+      href: data.href,
+      label: data.label,
+      blankTarget: this.buildBoolean(data.blankTarget)
+    }
+    this.dynamicElementService.setModel(component, model)
+
+    return component
+  }
+
+  private videoMiniatureBuilder (el: HTMLElement) {
+    const data = el.dataset as VideoMiniatureMarkupData
+    const component = this.dynamicElementService.createElement(VideoMiniatureMarkupComponent)
+
+    const model = {
+      uuid: data.uuid,
+      onlyDisplayTitle: this.buildBoolean(data.onlyDisplayTitle) ?? false
+    }
+
+    this.dynamicElementService.setModel(component, model)
+
+    return component
+  }
+
   private videosListBuilder (el: HTMLElement) {
     const data = el.dataset as VideosListMarkupData
     const component = this.dynamicElementService.createElement(VideosListMarkupComponent)
 
     const model = {
-      title: data.title,
-      description: data.description,
-      sort: data.sort,
-      categoryOneOf: this.buildArrayNumber(data.categoryOneOf),
-      languageOneOf: this.buildArrayString(data.languageOneOf),
+      onlyDisplayTitle: this.buildBoolean(data.onlyDisplayTitle) ?? false,
+      sort: data.sort || '-publishedAt',
+      categoryOneOf: this.buildArrayNumber(data.categoryOneOf) ?? [],
+      languageOneOf: this.buildArrayString(data.languageOneOf) ?? [],
+      filter: this.buildBoolean(data.onlyLocal) ? 'local' as VideoFilter : undefined,
       count: this.buildNumber(data.count) || 10
     }
 
@@ -116,12 +174,44 @@ export class CustomMarkupService {
     return component
   }
 
+  private containerBuilder (el: HTMLElement) {
+    const data = el.dataset as ContainerMarkupData
+
+    const root = document.createElement('div')
+    root.classList.add('peertube-container')
+
+    if (data.width) {
+      root.setAttribute('width', data.width)
+    }
+
+    if (data.title) {
+      const titleElement = document.createElement('h4')
+      titleElement.innerText = data.title
+      root.appendChild(titleElement)
+    }
+
+    if (data.description) {
+      const descriptionElement = document.createElement('div')
+      descriptionElement.innerText = data.description
+      root.appendChild(descriptionElement)
+    }
+
+    return root
+  }
+
   private buildNumber (value: string) {
     if (!value) return undefined
 
     return parseInt(value, 10)
   }
 
+  private buildBoolean (value: string) {
+    if (value === 'true') return true
+    if (value === 'false') return false
+
+    return undefined
+  }
+
   private buildArrayNumber (value: string) {
     if (!value) return undefined