Support mailto links for custom markup

pull/5548/head
Chocobozzz 2023-01-19 14:52:27 +01:00
parent a4927884b2
commit 789ba34931
No known key found for this signature in database
GPG Key ID: 583A612D890159BE
5 changed files with 74 additions and 59 deletions

View File

@ -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>

View File

@ -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
}

View File

@ -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
})
)
}

View File

@ -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
}
}

View File

@ -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: '',