import { MarkdownService } from '@app/shared/renderer'
import { forkJoin } from 'rxjs'
import { first } from 'rxjs/operators'
-import { peertubeTranslate } from '@shared/models'
@Component({
selector: 'my-about-instance',
this.serverService.videoLanguagesLoaded.pipe(first()),
this.serverService.videoCategoriesLoaded.pipe(first())
]).subscribe(
- async ([ res, translations ]) => {
- this.shortDescription = res.instance.shortDescription
+ async ([ about, translations ]) => {
+ this.shortDescription = about.instance.shortDescription
- this.maintenanceLifetime = res.instance.maintenanceLifetime
- this.businessModel = res.instance.businessModel
+ this.maintenanceLifetime = about.instance.maintenanceLifetime
+ this.businessModel = about.instance.businessModel
- for (const key of [ 'description', 'terms', 'codeOfConduct', 'moderationInformation', 'administrator' ]) {
- this.html[ key ] = await this.markdownService.textMarkdownToHTML(res.instance[ key ])
- }
+ this.html = await this.instanceService.buildHtml(about)
- const languagesArray = this.serverService.getVideoLanguages()
- const categoriesArray = this.serverService.getVideoCategories()
-
- this.languages = res.instance.languages
- .map(l => {
- const languageObj = languagesArray.find(la => la.id === l)
-
- return peertubeTranslate(languageObj.label, translations)
- })
-
- this.categories = res.instance.categories
- .map(c => {
- const categoryObj = categoriesArray.find(ca => ca.id === c)
-
- return peertubeTranslate(categoryObj.label, translations)
- })
+ this.languages = this.instanceService.buildTranslatedLanguages(about, translations)
+ this.categories = this.instanceService.buildTranslatedCategories(about, translations)
},
() => this.notifier.error(this.i18n('Cannot get about information from server'))
<div i18n class="inner-form-title">Moderation & NSFW</div>
<div class="form-group">
- <my-peertube-checkbox
- inputName="instanceIsNSFW" formControlName="isNSFW"
- i18n-labelText labelText="This instance is dedicated to sensitive or NSFW content"
- i18n-helpHtml helpHtml="Enabling it will allow other administrators to know that you are mainly federating sensitive content.<br /><br />
- Moreover, the NSFW checkbox on video upload will be automatically checked by default."
- ></my-peertube-checkbox>
+ <my-peertube-checkbox inputName="instanceIsNSFW" formControlName="isNSFW">
+ <ng-template ptTemplate="label">
+ <ng-container i18n>This instance is dedicated to sensitive or NSFW content</ng-container>
+ </ng-template>
+
+ <ng-template ptTemplate="help">
+ <ng-container i18n>
+ Enabling it will allow other administrators to know that you are mainly federating sensitive content.<br /><br />
+ Moreover, the NSFW checkbox on video upload will be automatically checked by default.
+ </ng-container>
+ </ng-template>
+ </my-peertube-checkbox>
</div>
<div class="form-group">
<label i18n for="instanceDefaultNSFWPolicy">Policy on videos containing sensitive content</label>
- <my-help
- helpType="custom" i18n-customHtml
- customHtml="With <strong>Do not list</strong> or <strong>Blur thumbnails</strong>, a confirmation will be requested to watch the video."
- ></my-help>
+
+ <my-help>
+ <ng-template ptTemplate="customHtml">
+ <ng-container i18n>
+ With <strong>Do not list</strong> or <strong>Blur thumbnails</strong>, a confirmation will be requested to watch the video.
+ </ng-container>
+ </ng-template>
+ </my-help>
<div class="peertube-select-container">
<select id="instanceDefaultNSFWPolicy" formControlName="defaultNSFWPolicy">
<div class="form-group">
<label i18n for="signupLimit">Your Twitter username</label>
- <my-help
- helpType="custom" i18n-customHtml
- customHtml="Indicates the Twitter account for the website or platform on which the content was published."
- ></my-help>
+
+ <my-help>
+ <ng-template ptTemplate="customHtml">
+ <ng-container i18n>Indicates the Twitter account for the website or platform on which the content was published.</ng-container>
+ </ng-template>
+ </my-help>
+
<input
type="text" id="servicesTwitterUsername"
formControlName="username" [ngClass]="{ 'input-error': formErrors['services.twitter.username'] }"
</div>
<div class="form-group">
- <my-peertube-checkbox
- inputName="servicesTwitterWhitelisted" formControlName="whitelisted"
- i18n-labelText labelText="Instance whitelisted by Twitter"
- i18n-helpHtml helpHtml="If your instance is whitelisted by Twitter, a video player will be embedded in the Twitter feed on PeerTube video share.<br />
- If the instance is not whitelisted, we use an image link card that will redirect on your PeerTube instance.<br /><br />
- Check this checkbox, save the configuration and test with a video URL of your instance (https://example.com/videos/watch/blabla) on <a target='_blank' rel='noopener noreferrer' href='https://cards-dev.twitter.com/validator'>https://cards-dev.twitter.com/validator</a> to see if you instance is whitelisted."
- ></my-peertube-checkbox>
+ <my-peertube-checkbox inputName="servicesTwitterWhitelisted" formControlName="whitelisted">
+ <ng-template ptTemplate="label">
+ <ng-container i18n>Instance whitelisted by Twitter</ng-container>
+ </ng-template>
+
+ <ng-template ptTemplate="help">
+ <ng-container i18n>
+ If your instance is whitelisted by Twitter, a video player will be embedded in the Twitter feed on PeerTube video share.<br />
+ If the instance is not whitelisted, we use an image link card that will redirect on your PeerTube instance.<br /><br />
+ Check this checkbox, save the configuration and test with a video URL of your instance (https://example.com/videos/watch/blabla) on
+ <a target='_blank' rel='noopener noreferrer' href='https://cards-dev.twitter.com/validator'>https://cards-dev.twitter.com/validator</a>
+ to see if you instance is whitelisted.
+ </ng-container>
+ </ng-template>
+ </my-peertube-checkbox>
</div>
</ng-container>
<ng-container formGroupName="transcoding">
<div class="form-group">
- <my-peertube-checkbox
- inputName="transcodingEnabled" formControlName="enabled"
- i18n-labelText labelText="Transcoding enabled"
- i18n-helpHtml helpHtml="If you disable transcoding, many videos from your users will not work!"
- ></my-peertube-checkbox>
+ <my-peertube-checkbox inputName="transcodingEnabled" formControlName="enabled">
+ <ng-template ptTemplate="label">
+ <ng-container i18n>Transcoding enabled</ng-container>
+ </ng-template>
+
+ <ng-template ptTemplate="help">
+ <ng-container i18n>If you disable transcoding, many videos from your users will not work!</ng-container>
+ </ng-template>
+ </my-peertube-checkbox>
</div>
<ng-container *ngIf="isTranscodingEnabled()">
<my-peertube-checkbox
inputName="transcodingAllowAdditionalExtensions" formControlName="allowAdditionalExtensions"
i18n-labelText labelText="Allow additional extensions"
- i18n-helpHtml helpHtml="Allow your users to upload .mkv, .mov, .avi, .flv videos"
- ></my-peertube-checkbox>
+ >
+ <ng-template ptTemplate="help">
+ <ng-container i18n>Allow your users to upload .mkv, .mov, .avi, .flv videos</ng-container>
+ </ng-template>
+ </my-peertube-checkbox>
</div>
<div class="form-group">
<my-peertube-checkbox
inputName="transcodingAllowAudioFiles" formControlName="allowAudioFiles"
i18n-labelText labelText="Allow audio files upload"
- i18n-helpHtml helpHtml="Allow your users to upload audio files that will be merged with the preview file on upload"
- ></my-peertube-checkbox>
+ >
+ <ng-template ptTemplate="help">
+ <ng-container i18n>Allow your users to upload audio files that will be merged with the preview file on upload</ng-container>
+ </ng-template>
+ </my-peertube-checkbox>
</div>
<div class="form-group">
<div i18n class="inner-form-title">
Cache
- <my-help
- helpType="custom" i18n-customHtml
- customHtml="Some files are not federated (previews, captions). We fetch them directly from the origin instance and cache them."
- ></my-help>
+ <my-help>
+ <ng-template ptTemplate="customHtml">
+ <ng-container i18n>Some files are not federated (previews, captions). We fetch them directly from the origin instance and cache them.</ng-container>
+ </ng-template>
+ </my-help>
</div>
<ng-container formGroupName="cache">
<ng-container formGroupName="customizations">
<div class="form-group">
<label i18n for="customizationJavascript">JavaScript</label>
- <my-help
- helpType="custom" i18n-customHtml
- customHtml="Write directly JavaScript code.<br />Example: <pre>console.log('my instance is amazing');</pre>"
- ></my-help>
+ <my-help>
+ <ng-template ptTemplate="customHtml">
+ <ng-container i18n>
+ Write directly JavaScript code.<br />Example: <pre>console.log('my instance is amazing');</pre>
+ </ng-container>
+ </ng-template>
+ </my-help>
+
<textarea
id="customizationJavascript" formControlName="javascript"
[ngClass]="{ 'input-error': formErrors['instance.customizations.javascript'] }"
></textarea>
+
<div *ngIf="formErrors.instance.customizations.javascript" class="form-error">{{ formErrors.instance.customizations.javascript }}</div>
</div>
<div class="form-group">
<label for="customizationCSS">CSS</label>
- <my-help
- helpType="custom"
- i18n-customHtml
- customHtml="
+
+ <my-help>
+ <ng-template ptTemplate="customHtml">
+ <ng-container i18n>
Write directly CSS code. Example:<br /><br />
- <pre>
- #custom-css {{ '{' }}
- color: red;
- {{ '}' }}
- </pre>
+<pre>
+#custom-css {{ '{' }}
+ color: red;
+{{ '}' }}
+</pre>
Prepend with <em>#custom-css</em> to override styles. Example:<br /><br />
- <pre>
- #custom-css .logged-in-email {{ '{' }}
- color: red;
- {{ '}' }}
- </pre>
- "
- ></my-help>
+<pre>
+#custom-css .logged-in-email {{ '{' }}
+ color: red;
+{{ '}' }}
+</pre>
+ </ng-container>
+ </ng-template>
+ </my-help>
+
<textarea
id="customizationCSS" formControlName="css"
[ngClass]="{ 'input-error': formErrors['instance.customizations.css'] }"
<form role="form" (ngSubmit)="updateDetails()" [formGroup]="form">
<div class="form-group">
<label i18n for="nsfwPolicy">Default policy on videos containing sensitive content</label>
- <my-help
- helpType="custom" i18n-customHtml
- customHtml="With <strong>Do not list</strong> or <strong>Blur thumbnails</strong>, a confirmation will be requested to watch the video."
- ></my-help>
+ <my-help>
+ <ng-template ptTemplate="customHtml">
+ <ng-container i18n>
+ With <strong>Do not list</strong> or <strong>Blur thumbnails</strong>, a confirmation will be requested to watch the video.
+ </ng-container>
+ </ng-template>
+ </my-help>
<div class="peertube-select-container">
<select id="nsfwPolicy" formControlName="nsfwPolicy">
<div class="form-group">
<label i18n for="videoLanguages">Only display videos in the following languages</label>
- <my-help i18n-customHtml
- customHtml="In Recently added, Trending, Local and Search pages"
- ></my-help>
+ <my-help>
+ <ng-template ptTemplate="customHtml">
+ <ng-container i18n>In Recently added, Trending, Local and Search pages</ng-container>
+ </ng-template>
+ </my-help>
<div>
<p-multiSelect
</div>
<div class="form-group form-group-terms">
- <my-peertube-checkbox
- inputName="terms" formControlName="terms"
- i18n-labelHtml
- labelHtml="I am at least 16 years old and agree to the <a href='/about/instance#terms-section' target='_blank'rel='noopener noreferrer'>Terms</a> of this instance"
- ></my-peertube-checkbox>
+ <my-peertube-checkbox inputName="terms" formControlName="terms">
+ <ng-template ptTemplate="label">
+ <ng-container i18n>
+ I am at least 16 years old and agree
+ to the <a (click)="onTermsClick($event)" href='#'>Terms</a>
+ <ng-container *ngIf="hasCodeOfConduct"> and to the <a (click)="onCodeOfConductClick($event)" href='#'>Code of Conduct</a></ng-container>
+ of this instance
+ </ng-container>
+ </ng-template>
+ </my-peertube-checkbox>
<div *ngIf="formErrors.terms" class="form-error">
{{ formErrors.terms }}
-import { Component, EventEmitter, OnInit, Output } from '@angular/core'
+import { Component, EventEmitter, Input, OnInit, Output } from '@angular/core'
import { AuthService } from '@app/core'
import { FormReactive, UserService, UserValidatorsService } from '@app/shared'
import { FormValidatorService } from '@app/shared/forms/form-validators/form-validator.service'
styleUrls: [ './register.component.scss' ]
})
export class RegisterStepUserComponent extends FormReactive implements OnInit {
+ @Input() hasCodeOfConduct = false
+
@Output() formBuilt = new EventEmitter<FormGroup>()
+ @Output() termsClick = new EventEmitter<void>()
+ @Output() codeOfConductClick = new EventEmitter<void>()
constructor (
protected formValidatorService: FormValidatorService,
.subscribe(([ oldValue, newValue ]) => this.onDisplayNameChange(oldValue, newValue))
}
+ onTermsClick (event: Event) {
+ event.preventDefault()
+ this.termsClick.emit()
+ }
+
+ onCodeOfConductClick (event: Event) {
+ event.preventDefault()
+ this.codeOfConductClick.emit()
+ }
+
private onDisplayNameChange (oldDisplayName: string, newDisplayName: string) {
const username = this.form.value['username'] || ''
<my-signup-success *ngIf="signupDone" [message]="success"></my-signup-success>
<div *ngIf="info" class="alert alert-info">{{ info }}</div>
- <div class="wrapper" *ngIf="!signupDone">
- <div>
+ <div class="wrapper" [hidden]="signupDone">
+ <div class="register-form">
<my-custom-stepper linear *ngIf="!signupDone">
<cdk-step [stepControl]="formStepUser" i18n-label label="User information">
- <my-register-step-user (formBuilt)="onUserFormBuilt($event)"></my-register-step-user>
+ <my-register-step-user
+ [hasCodeOfConduct]="!!aboutHtml.codeOfConduct"
+ (formBuilt)="onUserFormBuilt($event)" (termsClick)="onTermsClick()" (codeOfConductClick)="onCodeOfConductClick()"
+ >
+ </my-register-step-user>
<button i18n cdkStepperNext [disabled]="!formStepUser || !formStepUser.valid">Next</button>
</cdk-step>
</my-custom-stepper>
</div>
- <div>
- <label i18n>Features found on this instance</label>
- <my-instance-features-table></my-instance-features-table>
+ <div class="instance-information">
+ <ngb-accordion [closeOthers]="true" #accordion="ngbAccordion">
+ <ngb-panel id="instance-features" i18n-title title="Features found on this instance">
+ <ng-template ngbPanelContent>
+ <my-instance-features-table></my-instance-features-table>
+ </ng-template>
+ </ngb-panel>
+
+ <ng-container *ngIf="about">
+ <ngb-panel
+ *ngIf="aboutHtml.administrator || about.instance.maintenanceLifetime || about.instance.businessModel"
+ id="admin-sustainability" i18n-title title="Administrators & Sustainability"
+ >
+ <ng-template ngbPanelContent>
+ <div class="block">
+ <strong i18n>Who are we?</strong>
+ <div [innerHTML]="aboutHtml.administrator"></div>
+ </div>
+
+ <div class="block">
+ <strong i18n>How long do we plan to maintain this instance?</strong>
+ <div [innerHTML]="about.instance.maintenanceLifetime"></div>
+ </div>
+
+ <div class="block">
+ <strong i18n>How will we pay this instance?</strong>
+ <div [innerHTML]="about.instance.businessModel"></div>
+ </div>
+ </ng-template>
+ </ngb-panel>
+
+ <ngb-panel *ngIf="aboutHtml.moderationInformation" id="moderation-information" i18n-title title="Moderation information">
+ <ng-template ngbPanelContent>
+ <div class="block" [innerHTML]="aboutHtml.moderationInformation"></div>
+ </ng-template>
+ </ngb-panel>
+
+ <ngb-panel *ngIf="aboutHtml.codeOfConduct" id="code-of-conduct" i18n-title title="Code of conduct">
+ <ng-template ngbPanelContent>
+ <div class="block" [innerHTML]="aboutHtml.codeOfConduct"></div>
+ </ng-template>
+ </ngb-panel>
+
+ <ngb-panel *ngIf="aboutHtml.terms" id="terms" i18n-title title="Terms">
+ <ng-template ngbPanelContent>
+ <div class="block" [innerHTML]="aboutHtml.terms"></div>
+ </ng-template>
+ </ngb-panel>
+ </ng-container>
+ </ngb-accordion>
</div>
</div>
@import '_variables';
@import '_mixins';
+@import "./_bootstrap-variables";
+
+@import '~bootstrap/scss/functions';
+@import '~bootstrap/scss/variables';
.alert {
font-size: 15px;
& > div {
margin-bottom: 40px;
- width: 450px;
+
+ &.register-form {
+ width: 450px;
+ }
+
+ &.instance-information {
+ width: 600px;
+ margin-bottom: 40px;
+
+ .block {
+ font-size: 15px;
+ margin-bottom: 15px;
+ padding: 0 $btn-padding-x;
+ }
+
+ @media screen and (max-width: 1500px) {
+ width: 450px;
+ }
+
+ ngb-accordion ::ng-deep {
+ .btn {
+ font-weight: $font-semibold !important;
+ color: var(--mainForegroundColor) !important;
+ }
+ }
+ }
@media screen and (max-width: 500px) {
width: auto;
}
}
-my-instance-features-table {
- display: block;
-
- margin-bottom: 40px;
-}
-
.form-group-terms {
margin: 30px 0;
}
-import { Component } from '@angular/core'
+import { Component, OnInit, ViewChild } from '@angular/core'
import { AuthService, Notifier, RedirectService, ServerService } from '@app/core'
import { UserService, UserValidatorsService } from '@app/shared'
import { I18n } from '@ngx-translate/i18n-polyfill'
import { UserRegister } from '@shared/models/users/user-register.model'
import { FormGroup } from '@angular/forms'
+import { About } from '@shared/models/server'
+import { InstanceService } from '@app/shared/instance/instance.service'
+import { NgbAccordion } from '@ng-bootstrap/ng-bootstrap'
@Component({
selector: 'my-register',
templateUrl: './register.component.html',
styleUrls: [ './register.component.scss' ]
})
-export class RegisterComponent {
+export class RegisterComponent implements OnInit {
+ @ViewChild('accordion', { static: true }) accordion: NgbAccordion
+
info: string = null
error: string = null
success: string = null
signupDone = false
+ about: About
+ aboutHtml = {
+ description: '',
+ terms: '',
+ codeOfConduct: '',
+ moderationInformation: '',
+ administrator: ''
+ }
+
formStepUser: FormGroup
formStepChannel: FormGroup
private userService: UserService,
private serverService: ServerService,
private redirectService: RedirectService,
+ private instanceService: InstanceService,
private i18n: I18n
) {
}
return this.serverService.getConfig().signup.requiresEmailVerification
}
+ ngOnInit (): void {
+ this.instanceService.getAbout()
+ .subscribe(
+ async about => {
+ this.about = about
+
+ this.aboutHtml = await this.instanceService.buildHtml(about)
+ },
+
+ err => this.notifier.error(err.message)
+ )
+ }
+
hasSameChannelAndAccountNames () {
return this.getUsername() === this.getChannelName()
}
this.formStepChannel = form
}
+ onTermsClick () {
+ if (this.accordion) this.accordion.toggle('terms')
+ }
+
+ onCodeOfConductClick () {
+ if (this.accordion) this.accordion.toggle('code-of-conduct')
+ }
+
signup () {
this.error = null
import { RegisterStepUserComponent } from './register-step-user.component'
import { CustomStepperComponent } from './custom-stepper.component'
import { SignupSharedModule } from '@app/+signup/shared/signup-shared.module'
+import { NgbAccordionModule } from '@ng-bootstrap/ng-bootstrap'
@NgModule({
imports: [
RegisterRoutingModule,
SharedModule,
CdkStepperModule,
- SignupSharedModule
+ SignupSharedModule,
+ NgbAccordionModule
],
declarations: [
or create an account on another instance
</a>
- <my-help
- *ngIf="signupAllowed === false" helpType="custom" i18n-customHtml
- customHtml="User registration is not allowed on this instance, but you can register on many others!"
- ></my-help>
+ <my-help *ngIf="signupAllowed === false">
+ <ng-template ptTemplate="customHtml">
+ <ng-container i18n>User registration is not allowed on this instance, but you can register on many others!</ng-container>
+ </ng-template>
+ </my-help>
</div>
<div *ngIf="formErrors.username" class="form-error">
@Directive({
selector: '[ptTemplate]'
})
-export class PeerTubeTemplateDirective {
- @Input('ptTemplate') name: string
+export class PeerTubeTemplateDirective <T extends string> {
+ @Input('ptTemplate') name: T
constructor (public template: TemplateRef<any>) {
// empty
<input type="checkbox" [(ngModel)]="checked" (ngModelChange)="onModelChange()" [id]="inputName" [disabled]="disabled" />
<span role="checkbox" [attr.aria-checked]="checked"></span>
<span *ngIf="labelText">{{ labelText }}</span>
- <span *ngIf="labelHtml" [innerHTML]="labelHtml"></span>
+
+ <span *ngIf="labelTemplate">
+ <ng-container *ngTemplateOutlet="labelTemplate"></ng-container>
+ </span>
</label>
- <my-help *ngIf="helpHtml" [tooltipPlacement]="helpPlacement" helpType="custom" i18n-customHtml [customHtml]="helpHtml"></my-help>
+ <my-help *ngIf="helpTemplate" [tooltipPlacement]="helpPlacement" helpType="custom">
+ <ng-template ptTemplate="customHtml">
+ <ng-template *ngTemplateOutlet="helpTemplate"></ng-template>
+ </ng-template>
+ </my-help>
</div>
-import { ChangeDetectorRef, Component, forwardRef, Input, OnChanges, SimpleChanges } from '@angular/core'
+import { AfterContentInit, ChangeDetectorRef, Component, ContentChildren, forwardRef, Input, QueryList, TemplateRef } from '@angular/core'
import { ControlValueAccessor, NG_VALUE_ACCESSOR } from '@angular/forms'
+import { PeerTubeTemplateDirective } from '@app/shared/angular/peertube-template.directive'
@Component({
selector: 'my-peertube-checkbox',
}
]
})
-export class PeertubeCheckboxComponent implements ControlValueAccessor {
+export class PeertubeCheckboxComponent implements ControlValueAccessor, AfterContentInit {
@Input() checked = false
@Input() inputName: string
@Input() labelText: string
- @Input() labelHtml: string
- @Input() helpHtml: string
@Input() helpPlacement = 'top'
@Input() disabled = false
+ @ContentChildren(PeerTubeTemplateDirective) templates: QueryList<PeerTubeTemplateDirective<'label' | 'help'>>
+
// FIXME: https://github.com/angular/angular/issues/10816#issuecomment-307567836
@Input() onPushWorkaround = false
+ labelTemplate: TemplateRef<any>
+ helpTemplate: TemplateRef<any>
+
constructor (private cdr: ChangeDetectorRef) { }
+ ngAfterContentInit () {
+ {
+ const t = this.templates.find(t => t.name === 'label')
+ if (t) this.labelTemplate = t.template
+ }
+
+ {
+ const t = this.templates.find(t => t.name === 'help')
+ if (t) this.helpTemplate = t.template
+ }
+ }
+
propagateChange = (_: any) => { /* empty */ }
writeValue (checked: boolean) {
<ng-container *ngIf="initialUserVideoQuota !== -1">
{{ initialUserVideoQuota | bytes: 0 }} <ng-container *ngIf="dailyUserVideoQuota !== -1">({{ dailyUserVideoQuota | bytes: 0 }} per day)</ng-container>
- <my-help tooltipPlacement="auto" helpType="custom" [customHtml]="quotaHelpIndication"></my-help>
+ <my-help tooltipPlacement="auto" helpType="custom">
+ <ng-template ptTemplate="customHtml">
+ <div [innerHTML]="quotaHelpIndication"></div>
+ </ng-template>
+ </my-help>
</ng-container>
<ng-container i18n *ngIf="initialUserVideoQuota === -1">
import { environment } from '../../../environments/environment'
import { RestExtractor, RestService } from '../rest'
import { About } from '../../../../../shared/models/server'
+import { MarkdownService } from '@app/shared/renderer'
+import { peertubeTranslate } from '@shared/models'
+import { ServerService } from '@app/core'
@Injectable()
export class InstanceService {
constructor (
private authHttp: HttpClient,
private restService: RestService,
- private restExtractor: RestExtractor
+ private restExtractor: RestExtractor,
+ private markdownService: MarkdownService,
+ private serverService: ServerService
) {
}
.pipe(catchError(res => this.restExtractor.handleError(res)))
}
+
+ async buildHtml (about: About) {
+ const html = {
+ description: '',
+ terms: '',
+ codeOfConduct: '',
+ moderationInformation: '',
+ administrator: ''
+ }
+
+ for (const key of [ 'description', 'terms', 'codeOfConduct', 'moderationInformation', 'administrator' ]) {
+ html[ key ] = await this.markdownService.textMarkdownToHTML(about.instance[ key ])
+ }
+
+ return html
+ }
+
+ buildTranslatedLanguages (about: About, translations: any) {
+ const languagesArray = this.serverService.getVideoLanguages()
+
+ return about.instance.languages
+ .map(l => {
+ const languageObj = languagesArray.find(la => la.id === l)
+
+ return peertubeTranslate(languageObj.label, translations)
+ })
+ }
+
+ buildTranslatedCategories (about: About, translations: any) {
+ const categoriesArray = this.serverService.getVideoCategories()
+
+ return about.instance.categories
+ .map(c => {
+ const categoryObj = categoriesArray.find(ca => ca.id === c)
+
+ return peertubeTranslate(categoryObj.label, translations)
+ })
+ }
}
<ng-template #tooltipTemplate>
- <ng-template [ngIf]="preHtml">
- <p [innerHTML]="preHtml"></p>
- <br />
- </ng-template>
+ <p *ngIf="preHtmlTemplate">
+ <ng-template *ngTemplateOutlet="preHtmlTemplate"></ng-template>
+ </p>
- <p [innerHTML]="mainHtml"></p>
+ <ng-container *ngIf="preHtmlTemplate && (customHtmlTemplate || mainHtml || postHtmlTemplate)">
+ <br /><br />
+ </ng-container>
- <ng-template [ngIf]="postHtml">
- <br />
- <p [innerHTML]="postHtml"></p>
- </ng-template>
+ <p *ngIf="customHtmlTemplate">
+ <ng-template *ngTemplateOutlet="customHtmlTemplate"></ng-template>
+ </p>
+
+ <p *ngIf="mainHtml" [innerHTML]="mainHtml"></p>
+
+ <ng-container *ngIf="(customHtmlTemplate || mainHtml) && postHtmlTemplate">
+ <br /><br />
+ </ng-container>
+
+ <p *ngIf="postHtmlTemplate">
+ <ng-template *ngTemplateOutlet="postHtmlTemplate"></ng-template>
+ </p>
</ng-template>
<span
-import { Component, Input, OnChanges, OnInit } from '@angular/core'
+import { AfterContentInit, Component, ContentChildren, Input, OnChanges, OnInit, QueryList, TemplateRef } from '@angular/core'
import { I18n } from '@ngx-translate/i18n-polyfill'
import { MarkdownService } from '@app/shared/renderer'
+import { PeerTubeTemplateDirective } from '@app/shared/angular/peertube-template.directive'
@Component({
selector: 'my-help',
templateUrl: './help.component.html'
})
-export class HelpComponent implements OnInit, OnChanges {
- @Input() preHtml = ''
- @Input() postHtml = ''
- @Input() customHtml = ''
+export class HelpComponent implements OnInit, OnChanges, AfterContentInit {
@Input() helpType: 'custom' | 'markdownText' | 'markdownEnhanced' = 'custom'
@Input() tooltipPlacement = 'right'
+ @ContentChildren(PeerTubeTemplateDirective) templates: QueryList<PeerTubeTemplateDirective<'preHtml' | 'customHtml' | 'postHtml'>>
+
isPopoverOpened = false
mainHtml = ''
+ preHtmlTemplate: TemplateRef<any>
+ customHtmlTemplate: TemplateRef<any>
+ postHtmlTemplate: TemplateRef<any>
+
constructor (private i18n: I18n) { }
ngOnInit () {
this.init()
}
+ ngAfterContentInit () {
+ {
+ const t = this.templates.find(t => t.name === 'preHtml')
+ if (t) this.preHtmlTemplate = t.template
+ }
+
+ {
+ const t = this.templates.find(t => t.name === 'customHtml')
+ if (t) this.customHtmlTemplate = t.template
+ }
+
+ {
+ const t = this.templates.find(t => t.name === 'postHtml')
+ if (t) this.postHtmlTemplate = t.template
+ }
+ }
+
ngOnChanges () {
this.init()
}
}
private init () {
- if (this.helpType === 'custom') {
- this.mainHtml = this.customHtml
- return
- }
-
if (this.helpType === 'markdownText') {
this.mainHtml = this.formatMarkdownSupport(MarkdownService.TEXT_RULES)
return
<span *ngIf="interact">Remote interact</span>
</button>
- <my-help *ngIf="!interact && showHelp"
- helpType="custom"
- i18n-customHtml customHtml="You can subscribe to the channel via any ActivityPub-capable fediverse instance. For instance with Mastodon or Pleroma you can type the channel URL in the search box and subscribe there.">
+ <my-help *ngIf="!interact && showHelp">
+ <ng-template ptTemplate="customHtml">
+ <ng-container i18n>
+ You can subscribe to the channel via any ActivityPub-capable fediverse instance.<br /><br />
+ For instance with Mastodon or Pleroma you can type the channel URL in the search box and subscribe there.
+ </ng-container>
+ </ng-template>
</my-help>
- <my-help *ngIf="showHelp && interact"
- helpType="custom"
- i18n-customHtml customHtml="You can interact with this via any ActivityPub-capable fediverse instance. For instance with Mastodon or Pleroma you can type the current URL in the search box and interact with it there.">
+ <my-help *ngIf="showHelp && interact">
+ <ng-template ptTemplate="customHtml">
+ <ng-container i18n>
+ You can interact with this via any ActivityPub-capable fediverse instance.<br /><br />
+ For instance with Mastodon or Pleroma you can type the current URL in the search box and interact with it there.
+ </ng-container>
+ </ng-template>
</my-help>
-</form>
\ No newline at end of file
+</form>
@Input() titlePage: string
@Input() miniatureDisplayOptions: MiniatureDisplayOptions
@Input() getVideosObservableFunction: (page: number, sort?: VideoSortField) => Observable<ResultList<Video>>
- @ContentChildren(PeerTubeTemplateDirective) templates: QueryList<PeerTubeTemplateDirective>
+ @ContentChildren(PeerTubeTemplateDirective) templates: QueryList<PeerTubeTemplateDirective<'rowButtons' | 'globalButtons'>>
@Output() selectionChange = new EventEmitter<SelectionType>()
@Output() videosModelChange = new EventEmitter<Video[]>()
<div class="form-group">
<label i18n class="label-tags">Tags</label>
- <my-help i18n-preHtml preHtml="Tags could be used to suggest relevant recommendations.</br>Press Enter to add a new tag."></my-help>
+
+ <my-help>
+ <ng-template ptTemplate="customHtml">
+ <ng-container i18n>
+ Tags could be used to suggest relevant recommendations. <br />
+ Press Enter to add a new tag.
+ </ng-container>
+ </ng-template>
+ </my-help>
+
<tag-input
[validators]="tagValidators" [errorMessages]="tagValidatorsMessages"
i18n-placeholder placeholder="+ Tag" i18n-secondaryPlaceholder secondaryPlaceholder="Enter a new tag"
<div class="form-group">
<label i18n for="description">Description</label>
- <my-help helpType="markdownText" i18n-preHtml preHtml="Video descriptions are truncated by default and require manual action to expand them."></my-help>
+
+ <my-help helpType="markdownText">
+ <ng-template ptTemplate="preHtml">
+ <ng-container i18n>
+ Video descriptions are truncated by default and require manual action to expand them.
+ </ng-container>
+ </ng-template>
+ </my-help>
+
<my-markdown-textarea truncate="250" formControlName="description"></my-markdown-textarea>
<div *ngIf="formErrors.description" class="form-error">
</div>
</div>
- <my-peertube-checkbox
- inputName="nsfw" formControlName="nsfw"
- i18n-labelText labelText="This video contains mature or explicit content"
- i18n-helpHtml helpHtml="Some instances do not list videos containing mature or explicit content by default."
- helpPlacement="bottom-right"
- ></my-peertube-checkbox>
-
- <my-peertube-checkbox
- *ngIf="waitTranscodingEnabled"
- inputName="waitTranscoding" formControlName="waitTranscoding"
- i18n-labelText labelText="Wait transcoding before publishing the video"
- i18n-helpHtml helpHtml="If you decide not to wait for transcoding before publishing the video, it could be unplayable until transcoding ends."
- helpPlacement="bottom-right"
- ></my-peertube-checkbox>
+ <my-peertube-checkbox inputName="nsfw" formControlName="nsfw" helpPlacement="bottom-right">
+ <ng-template ptTemplate="label">
+ <ng-container i18n>This video contains mature or explicit content</ng-container>
+ </ng-template>
+
+ <ng-template ptTemplate="help">
+ <ng-container i18n>Some instances do not list videos containing mature or explicit content by default.</ng-container>
+ </ng-template>
+ </my-peertube-checkbox>
+
+ <my-peertube-checkbox *ngIf="waitTranscodingEnabled" inputName="waitTranscoding" formControlName="waitTranscoding" helpPlacement="bottom-right">
+ <ng-template ptTemplate="label">
+ <ng-container i18n>Wait transcoding before publishing the video</ng-container>
+ </ng-template>
+
+ <ng-template ptTemplate="help">
+ <ng-container i18n>If you decide not to wait for transcoding before publishing the video, it could be unplayable until transcoding ends.</ng-container>
+ </ng-template>
+ </my-peertube-checkbox>
</div>
</div>
<div class="form-group form-group-magnet-uri">
<label i18n for="magnetUri">Paste magnet URI</label>
- <my-help
- helpType="custom" i18n-customHtml
- customHtml="You can import any torrent file that points to a mp4 file. You should make sure you have diffusion rights over the content it points to, otherwise it could cause legal trouble to yourself and your instance."
- ></my-help>
+ <my-help>
+ <ng-template ptTemplate="customHtml">
+ <ng-container i18n>
+ You can import any torrent file that points to a mp4 file.
+ You should make sure you have diffusion rights over the content it points to, otherwise it could cause legal trouble to yourself and your instance.
+ </ng-container>
+ </ng-template>
+ </my-help>
<input type="text" id="magnetUri" [(ngModel)]="magnetUri" />
</div>
<div class="form-group">
<label i18n for="targetUrl">URL</label>
- <my-help
- helpType="custom" i18n-customHtml
- customHtml="You can import any URL <a href='https://rg3.github.io/youtube-dl/supportedsites.html' target='_blank' rel='noopener noreferrer'>supported by youtube-dl</a> or URL that points to a raw MP4 file. You should make sure you have diffusion rights over the content it points to, otherwise it could cause legal trouble to yourself and your instance."
- ></my-help>
+
+ <my-help>
+ <ng-template ptTemplate="customHtml">
+ <ng-container i18n>
+ You can import any URL <a href='https://rg3.github.io/youtube-dl/supportedsites.html' target='_blank' rel='noopener noreferrer'>supported by youtube-dl</a>
+ or URL that points to a raw MP4 file.
+ You should make sure you have diffusion rights over the content it points to, otherwise it could cause legal trouble to yourself and your instance.
+ </ng-container>
+ </ng-template>
+ </my-help>
<input type="text" id="targetUrl" [(ngModel)]="targetUrl" />
</div>