Browse Source

Support mailto links for custom markup

Chocobozzz 1 year ago
parent
commit
789ba34931

+ 20 - 20
client/src/app/+about/about-instance/about-instance.component.html

@@ -21,7 +21,7 @@
 
     <div class="anchor" id="administrators-and-sustainability"></div>
     <a
-      *ngIf="html.administrator || html.maintenanceLifetime || html.businessModel"
+      *ngIf="aboutHTML.administrator || aboutHTML.maintenanceLifetime || aboutHTML.businessModel"
       class="anchor-link"
       routerLink="/about/instance"
       fragment="administrators-and-sustainability"
@@ -33,7 +33,7 @@
       </h2>
     </a>
 
-    <div class="block administrator" *ngIf="html.administrator">
+    <div class="block administrator" *ngIf="aboutHTML.administrator">
       <div class="anchor" id="administrators"></div>
       <a
         class="anchor-link"
@@ -44,10 +44,10 @@
         <h3 i18n class="section-title">Who we are</h3>
       </a>
 
-      <div [innerHTML]="html.administrator"></div>
+      <div [innerHTML]="aboutHTML.administrator"></div>
     </div>
 
-    <div class="block creation-reason" *ngIf="html.creationReason">
+    <div class="block creation-reason" *ngIf="aboutHTML.creationReason">
       <div class="anchor" id="creation-reason"></div>
       <a
         class="anchor-link"
@@ -58,10 +58,10 @@
         <h3 i18n class="section-title">Why we created this instance</h3>
       </a>
 
-      <div [innerHTML]="html.creationReason"></div>
+      <div [innerHTML]="aboutHTML.creationReason"></div>
     </div>
 
-    <div class="block maintenance-lifetime" *ngIf="html.maintenanceLifetime">
+    <div class="block maintenance-lifetime" *ngIf="aboutHTML.maintenanceLifetime">
       <div class="anchor" id="maintenance-lifetime"></div>
       <a
         class="anchor-link"
@@ -72,10 +72,10 @@
         <h3 i18n class="section-title">How long we plan to maintain this instance</h3>
       </a>
 
-      <div [innerHTML]="html.maintenanceLifetime"></div>
+      <div [innerHTML]="aboutHTML.maintenanceLifetime"></div>
     </div>
 
-    <div class="block business-model" *ngIf="html.businessModel">
+    <div class="block business-model" *ngIf="aboutHTML.businessModel">
         <div class="anchor" id="business-model"></div>
         <a
           class="anchor-link"
@@ -86,12 +86,12 @@
           <h3 i18n class="section-title">How we will pay for keeping our instance running</h3>
         </a>
 
-      <div [innerHTML]="html.businessModel"></div>
+      <div [innerHTML]="aboutHTML.businessModel"></div>
     </div>
 
     <div class="anchor" id="information"></div>
     <a
-      *ngIf="descriptionContent"
+      *ngIf="descriptionElement"
       class="anchor-link"
       routerLink="/about/instance"
       fragment="information"
@@ -113,13 +113,13 @@
         <h3 i18n class="section-title">Description</h3>
       </a>
 
-      <my-custom-markup-container [content]="descriptionContent"></my-custom-markup-container>
+      <my-custom-markup-container [content]="descriptionElement"></my-custom-markup-container>
     </div>
 
     <div myPluginSelector pluginSelectorId="about-instance-moderation">
       <div class="anchor" id="moderation"></div>
       <a
-        *ngIf="html.moderationInformation || html.codeOfConduct || html.terms"
+        *ngIf="aboutHTML.moderationInformation || aboutHTML.codeOfConduct || aboutHTML.terms"
         class="anchor-link"
         routerLink="/about/instance"
         fragment="moderation"
@@ -130,7 +130,7 @@
         </h2>
       </a>
 
-      <div class="block moderation-information" *ngIf="html.moderationInformation">
+      <div class="block moderation-information" *ngIf="aboutHTML.moderationInformation">
         <div class="anchor" id="moderation-information"></div>
         <a
           class="anchor-link"
@@ -141,10 +141,10 @@
           <h3 i18n class="section-title">Moderation information</h3>
         </a>
 
-        <div [innerHTML]="html.moderationInformation"></div>
+        <div [innerHTML]="aboutHTML.moderationInformation"></div>
       </div>
 
-      <div class="block code-of-conduct" *ngIf="html.codeOfConduct">
+      <div class="block code-of-conduct" *ngIf="aboutHTML.codeOfConduct">
         <div class="anchor" id="code-of-conduct"></div>
         <a
           class="anchor-link"
@@ -155,7 +155,7 @@
           <h3 i18n class="section-title">Code of conduct</h3>
         </a>
 
-        <div [innerHTML]="html.codeOfConduct"></div>
+        <div [innerHTML]="aboutHTML.codeOfConduct"></div>
       </div>
 
       <div class="block terms">
@@ -169,14 +169,14 @@
           <h3 i18n class="section-title">Terms</h3>
         </a>
 
-        <div [innerHTML]="html.terms"></div>
+        <div [innerHTML]="aboutHTML.terms"></div>
       </div>
     </div>
 
     <div myPluginSelector pluginSelectorId="about-instance-other-information">
       <div class="anchor" id="other-information"></div>
       <a
-        *ngIf="html.hardwareInformation"
+        *ngIf="aboutHTML.hardwareInformation"
         class="anchor-link"
         routerLink="/about/instance"
         fragment="other-information"
@@ -187,7 +187,7 @@
         </h2>
       </a>
 
-      <div class="block hardware-information" *ngIf="html.hardwareInformation">
+      <div class="block hardware-information" *ngIf="aboutHTML.hardwareInformation">
         <div class="anchor" id="hardware-information"></div>
         <a
           class="anchor-link"
@@ -198,7 +198,7 @@
           <h3 i18n class="section-title">Hardware information</h3>
         </a>
 
-        <div [innerHTML]="html.hardwareInformation"></div>
+        <div [innerHTML]="aboutHTML.hardwareInformation"></div>
       </div>
     </div>
   </div>

+ 15 - 26
client/src/app/+about/about-instance/about-instance.component.ts

@@ -2,7 +2,7 @@ import { ViewportScroller } from '@angular/common'
 import { AfterViewChecked, Component, ElementRef, OnInit, ViewChild } from '@angular/core'
 import { ActivatedRoute } from '@angular/router'
 import { Notifier, ServerService } from '@app/core'
-import { InstanceService } from '@app/shared/shared-instance'
+import { AboutHTML } from '@app/shared/shared-instance'
 import { copyToClipboard } from '@root-helpers/utils'
 import { HTMLServerConfig } from '@shared/models/server'
 import { ResolverData } from './about-instance.resolver'
@@ -17,22 +17,12 @@ export class AboutInstanceComponent implements OnInit, AfterViewChecked {
   @ViewChild('descriptionWrapper') descriptionWrapper: ElementRef<HTMLInputElement>
   @ViewChild('contactAdminModal', { static: true }) contactAdminModal: ContactAdminModalComponent
 
-  shortDescription = ''
-  descriptionContent: string
-
-  html = {
-    terms: '',
-    codeOfConduct: '',
-    moderationInformation: '',
-    administrator: '',
-    creationReason: '',
-    maintenanceLifetime: '',
-    businessModel: '',
-    hardwareInformation: ''
-  }
+  aboutHTML: AboutHTML
+  descriptionElement: HTMLDivElement
 
   languages: string[] = []
   categories: string[] = []
+  shortDescription = ''
 
   initialized = false
 
@@ -44,8 +34,7 @@ export class AboutInstanceComponent implements OnInit, AfterViewChecked {
     private viewportScroller: ViewportScroller,
     private route: ActivatedRoute,
     private notifier: Notifier,
-    private serverService: ServerService,
-    private instanceService: InstanceService
+    private serverService: ServerService
   ) {}
 
   get instanceName () {
@@ -60,8 +49,16 @@ export class AboutInstanceComponent implements OnInit, AfterViewChecked {
     return this.serverConfig.instance.isNSFW
   }
 
-  async ngOnInit () {
-    const { about, languages, categories }: ResolverData = this.route.snapshot.data.instanceData
+  ngOnInit () {
+    const { about, languages, categories, aboutHTML, descriptionElement }: ResolverData = this.route.snapshot.data.instanceData
+
+    this.aboutHTML = aboutHTML
+    this.descriptionElement = descriptionElement
+
+    this.languages = languages
+    this.categories = categories
+
+    this.shortDescription = about.instance.shortDescription
 
     this.serverConfig = this.serverService.getHTMLConfig()
 
@@ -73,14 +70,6 @@ export class AboutInstanceComponent implements OnInit, AfterViewChecked {
       this.contactAdminModal.show(prefill)
     })
 
-    this.languages = languages
-    this.categories = categories
-
-    this.shortDescription = about.instance.shortDescription
-    this.descriptionContent = about.instance.description
-
-    this.html = await this.instanceService.buildHtml(about)
-
     this.initialized = true
   }
 

+ 20 - 5
client/src/app/+about/about-instance/about-instance.resolver.ts

@@ -2,16 +2,25 @@ import { forkJoin } from 'rxjs'
 import { map, switchMap } from 'rxjs/operators'
 import { Injectable } from '@angular/core'
 import { Resolve } from '@angular/router'
-import { InstanceService } from '@app/shared/shared-instance'
+import { CustomMarkupService } from '@app/shared/shared-custom-markup'
+import { AboutHTML, InstanceService } from '@app/shared/shared-instance'
 import { About } from '@shared/models/server'
 
-export type ResolverData = { about: About, languages: string[], categories: string[] }
+export type ResolverData = {
+  about: About
+  languages: string[]
+  categories: string[]
+  aboutHTML: AboutHTML
+  descriptionElement: HTMLDivElement
+}
 
 @Injectable()
 export class AboutInstanceResolver implements Resolve<any> {
 
   constructor (
-    private instanceService: InstanceService
+    private instanceService: InstanceService,
+    private customMarkupService: CustomMarkupService
+
   ) {}
 
   resolve () {
@@ -19,9 +28,15 @@ export class AboutInstanceResolver implements Resolve<any> {
                .pipe(
                  switchMap(about => {
                    return forkJoin([
+                     Promise.resolve(about),
                      this.instanceService.buildTranslatedLanguages(about),
-                     this.instanceService.buildTranslatedCategories(about)
-                   ]).pipe(map(([ languages, categories ]) => ({ about, languages, categories }) as ResolverData))
+                     this.instanceService.buildTranslatedCategories(about),
+                     this.instanceService.buildHtml(about),
+                     this.customMarkupService.buildElement(about.instance.description)
+                   ])
+                 }),
+                 map(([ about, languages, categories, aboutHTML, { rootElement } ]) => {
+                   return { about, languages, categories, aboutHTML, descriptionElement: rootElement } as ResolverData
                  })
                )
   }

+ 13 - 7
client/src/app/shared/shared-custom-markup/custom-markup-container.component.ts

@@ -6,9 +6,9 @@ import { CustomMarkupService } from './custom-markup.service'
   templateUrl: './custom-markup-container.component.html'
 })
 export class CustomMarkupContainerComponent implements OnChanges {
-  @ViewChild('contentWrapper') contentWrapper: ElementRef<HTMLInputElement>
+  @ViewChild('contentWrapper', { static: true }) contentWrapper: ElementRef<HTMLInputElement>
 
-  @Input() content: string
+  @Input() content: string | HTMLDivElement
 
   displayed = false
 
@@ -17,17 +17,23 @@ export class CustomMarkupContainerComponent implements OnChanges {
   ) { }
 
   async ngOnChanges () {
-    await this.buildElement()
+    await this.rebuild()
   }
 
-  private async buildElement () {
-    if (!this.content) return
+  private async rebuild () {
+    if (this.content instanceof HTMLDivElement) {
+      return this.loadElement(this.content)
+    }
 
     const { rootElement, componentsLoaded } = await this.customMarkupService.buildElement(this.content)
-    this.contentWrapper.nativeElement.appendChild(rootElement)
-
     await componentsLoaded
 
+    return this.loadElement(rootElement)
+  }
+
+  private loadElement (el: HTMLDivElement) {
+    this.contentWrapper.nativeElement.appendChild(el)
+
     this.displayed = true
   }
 }

+ 6 - 1
client/src/app/shared/shared-instance/instance.service.ts

@@ -7,6 +7,11 @@ import { peertubeTranslate } from '@shared/core-utils/i18n'
 import { About } from '@shared/models'
 import { environment } from '../../../environments/environment'
 
+export type AboutHTML = Pick<About['instance'],
+'terms' | 'codeOfConduct' | 'moderationInformation' | 'administrator' | 'creationReason' |
+'maintenanceLifetime' | 'businessModel' | 'hardwareInformation'
+>
+
 @Injectable()
 export class InstanceService {
   private static BASE_CONFIG_URL = environment.apiUrl + '/api/v1/config'
@@ -39,7 +44,7 @@ export class InstanceService {
   }
 
   async buildHtml (about: About) {
-    const html = {
+    const html: AboutHTML = {
       terms: '',
       codeOfConduct: '',
       moderationInformation: '',