aboutsummaryrefslogtreecommitdiffhomepage
path: root/client/src/app
diff options
context:
space:
mode:
Diffstat (limited to 'client/src/app')
-rw-r--r--client/src/app/+about/about-instance/about-instance.component.ts31
-rw-r--r--client/src/app/+admin/config/edit-custom-config/edit-custom-config.component.html147
-rw-r--r--client/src/app/+my-account/my-account-settings/my-account-video-settings/my-account-video-settings.component.html19
-rw-r--r--client/src/app/+signup/+register/register-step-user.component.html15
-rw-r--r--client/src/app/+signup/+register/register-step-user.component.ts16
-rw-r--r--client/src/app/+signup/+register/register.component.html63
-rw-r--r--client/src/app/+signup/+register/register.component.scss37
-rw-r--r--client/src/app/+signup/+register/register.component.ts40
-rw-r--r--client/src/app/+signup/+register/register.module.ts4
-rw-r--r--client/src/app/login/login.component.html9
-rw-r--r--client/src/app/shared/angular/peertube-template.directive.ts4
-rw-r--r--client/src/app/shared/forms/peertube-checkbox.component.html11
-rw-r--r--client/src/app/shared/forms/peertube-checkbox.component.ts24
-rw-r--r--client/src/app/shared/instance/instance-features-table.component.html6
-rw-r--r--client/src/app/shared/instance/instance.service.ts45
-rw-r--r--client/src/app/shared/misc/help.component.html28
-rw-r--r--client/src/app/shared/misc/help.component.ts36
-rw-r--r--client/src/app/shared/user-subscription/remote-subscribe.component.html22
-rw-r--r--client/src/app/shared/video/videos-selection.component.ts2
-rw-r--r--client/src/app/videos/+video-edit/shared/video-edit.component.html54
-rw-r--r--client/src/app/videos/+video-edit/video-add-components/video-import-torrent.component.html12
-rw-r--r--client/src/app/videos/+video-edit/video-add-components/video-import-url.component.html14
22 files changed, 467 insertions, 172 deletions
diff --git a/client/src/app/+about/about-instance/about-instance.component.ts b/client/src/app/+about/about-instance/about-instance.component.ts
index 0af1dca9c..e2c448501 100644
--- a/client/src/app/+about/about-instance/about-instance.component.ts
+++ b/client/src/app/+about/about-instance/about-instance.component.ts
@@ -6,7 +6,6 @@ import { InstanceService } from '@app/shared/instance/instance.service'
6import { MarkdownService } from '@app/shared/renderer' 6import { MarkdownService } from '@app/shared/renderer'
7import { forkJoin } from 'rxjs' 7import { forkJoin } from 'rxjs'
8import { first } from 'rxjs/operators' 8import { first } from 'rxjs/operators'
9import { peertubeTranslate } from '@shared/models'
10 9
11@Component({ 10@Component({
12 selector: 'my-about-instance', 11 selector: 'my-about-instance',
@@ -59,32 +58,16 @@ export class AboutInstanceComponent implements OnInit {
59 this.serverService.videoLanguagesLoaded.pipe(first()), 58 this.serverService.videoLanguagesLoaded.pipe(first()),
60 this.serverService.videoCategoriesLoaded.pipe(first()) 59 this.serverService.videoCategoriesLoaded.pipe(first())
61 ]).subscribe( 60 ]).subscribe(
62 async ([ res, translations ]) => { 61 async ([ about, translations ]) => {
63 this.shortDescription = res.instance.shortDescription 62 this.shortDescription = about.instance.shortDescription
64 63
65 this.maintenanceLifetime = res.instance.maintenanceLifetime 64 this.maintenanceLifetime = about.instance.maintenanceLifetime
66 this.businessModel = res.instance.businessModel 65 this.businessModel = about.instance.businessModel
67 66
68 for (const key of [ 'description', 'terms', 'codeOfConduct', 'moderationInformation', 'administrator' ]) { 67 this.html = await this.instanceService.buildHtml(about)
69 this.html[ key ] = await this.markdownService.textMarkdownToHTML(res.instance[ key ])
70 }
71 68
72 const languagesArray = this.serverService.getVideoLanguages() 69 this.languages = this.instanceService.buildTranslatedLanguages(about, translations)
73 const categoriesArray = this.serverService.getVideoCategories() 70 this.categories = this.instanceService.buildTranslatedCategories(about, translations)
74
75 this.languages = res.instance.languages
76 .map(l => {
77 const languageObj = languagesArray.find(la => la.id === l)
78
79 return peertubeTranslate(languageObj.label, translations)
80 })
81
82 this.categories = res.instance.categories
83 .map(c => {
84 const categoryObj = categoriesArray.find(ca => ca.id === c)
85
86 return peertubeTranslate(categoryObj.label, translations)
87 })
88 }, 71 },
89 72
90 () => this.notifier.error(this.i18n('Cannot get about information from server')) 73 () => this.notifier.error(this.i18n('Cannot get about information from server'))
diff --git a/client/src/app/+admin/config/edit-custom-config/edit-custom-config.component.html b/client/src/app/+admin/config/edit-custom-config/edit-custom-config.component.html
index 50df8a8ac..5aa6fda3c 100644
--- a/client/src/app/+admin/config/edit-custom-config/edit-custom-config.component.html
+++ b/client/src/app/+admin/config/edit-custom-config/edit-custom-config.component.html
@@ -63,20 +63,30 @@
63 <div i18n class="inner-form-title">Moderation & NSFW</div> 63 <div i18n class="inner-form-title">Moderation & NSFW</div>
64 64
65 <div class="form-group"> 65 <div class="form-group">
66 <my-peertube-checkbox 66 <my-peertube-checkbox inputName="instanceIsNSFW" formControlName="isNSFW">
67 inputName="instanceIsNSFW" formControlName="isNSFW" 67 <ng-template ptTemplate="label">
68 i18n-labelText labelText="This instance is dedicated to sensitive or NSFW content" 68 <ng-container i18n>This instance is dedicated to sensitive or NSFW content</ng-container>
69 i18n-helpHtml helpHtml="Enabling it will allow other administrators to know that you are mainly federating sensitive content.<br /><br /> 69 </ng-template>
70 Moreover, the NSFW checkbox on video upload will be automatically checked by default." 70
71 ></my-peertube-checkbox> 71 <ng-template ptTemplate="help">
72 <ng-container i18n>
73 Enabling it will allow other administrators to know that you are mainly federating sensitive content.<br /><br />
74 Moreover, the NSFW checkbox on video upload will be automatically checked by default.
75 </ng-container>
76 </ng-template>
77 </my-peertube-checkbox>
72 </div> 78 </div>
73 79
74 <div class="form-group"> 80 <div class="form-group">
75 <label i18n for="instanceDefaultNSFWPolicy">Policy on videos containing sensitive content</label> 81 <label i18n for="instanceDefaultNSFWPolicy">Policy on videos containing sensitive content</label>
76 <my-help 82
77 helpType="custom" i18n-customHtml 83 <my-help>
78 customHtml="With <strong>Do not list</strong> or <strong>Blur thumbnails</strong>, a confirmation will be requested to watch the video." 84 <ng-template ptTemplate="customHtml">
79 ></my-help> 85 <ng-container i18n>
86 With <strong>Do not list</strong> or <strong>Blur thumbnails</strong>, a confirmation will be requested to watch the video.
87 </ng-container>
88 </ng-template>
89 </my-help>
80 90
81 <div class="peertube-select-container"> 91 <div class="peertube-select-container">
82 <select id="instanceDefaultNSFWPolicy" formControlName="defaultNSFWPolicy"> 92 <select id="instanceDefaultNSFWPolicy" formControlName="defaultNSFWPolicy">
@@ -374,10 +384,13 @@
374 384
375 <div class="form-group"> 385 <div class="form-group">
376 <label i18n for="signupLimit">Your Twitter username</label> 386 <label i18n for="signupLimit">Your Twitter username</label>
377 <my-help 387
378 helpType="custom" i18n-customHtml 388 <my-help>
379 customHtml="Indicates the Twitter account for the website or platform on which the content was published." 389 <ng-template ptTemplate="customHtml">
380 ></my-help> 390 <ng-container i18n>Indicates the Twitter account for the website or platform on which the content was published.</ng-container>
391 </ng-template>
392 </my-help>
393
381 <input 394 <input
382 type="text" id="servicesTwitterUsername" 395 type="text" id="servicesTwitterUsername"
383 formControlName="username" [ngClass]="{ 'input-error': formErrors['services.twitter.username'] }" 396 formControlName="username" [ngClass]="{ 'input-error': formErrors['services.twitter.username'] }"
@@ -386,13 +399,21 @@
386 </div> 399 </div>
387 400
388 <div class="form-group"> 401 <div class="form-group">
389 <my-peertube-checkbox 402 <my-peertube-checkbox inputName="servicesTwitterWhitelisted" formControlName="whitelisted">
390 inputName="servicesTwitterWhitelisted" formControlName="whitelisted" 403 <ng-template ptTemplate="label">
391 i18n-labelText labelText="Instance whitelisted by Twitter" 404 <ng-container i18n>Instance whitelisted by Twitter</ng-container>
392 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 /> 405 </ng-template>
393 If the instance is not whitelisted, we use an image link card that will redirect on your PeerTube instance.<br /><br /> 406
394 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." 407 <ng-template ptTemplate="help">
395 ></my-peertube-checkbox> 408 <ng-container i18n>
409 If your instance is whitelisted by Twitter, a video player will be embedded in the Twitter feed on PeerTube video share.<br />
410 If the instance is not whitelisted, we use an image link card that will redirect on your PeerTube instance.<br /><br />
411 Check this checkbox, save the configuration and test with a video URL of your instance (https://example.com/videos/watch/blabla) on
412 <a target='_blank' rel='noopener noreferrer' href='https://cards-dev.twitter.com/validator'>https://cards-dev.twitter.com/validator</a>
413 to see if you instance is whitelisted.
414 </ng-container>
415 </ng-template>
416 </my-peertube-checkbox>
396 </div> 417 </div>
397 418
398 </ng-container> 419 </ng-container>
@@ -408,11 +429,15 @@
408 429
409 <ng-container formGroupName="transcoding"> 430 <ng-container formGroupName="transcoding">
410 <div class="form-group"> 431 <div class="form-group">
411 <my-peertube-checkbox 432 <my-peertube-checkbox inputName="transcodingEnabled" formControlName="enabled">
412 inputName="transcodingEnabled" formControlName="enabled" 433 <ng-template ptTemplate="label">
413 i18n-labelText labelText="Transcoding enabled" 434 <ng-container i18n>Transcoding enabled</ng-container>
414 i18n-helpHtml helpHtml="If you disable transcoding, many videos from your users will not work!" 435 </ng-template>
415 ></my-peertube-checkbox> 436
437 <ng-template ptTemplate="help">
438 <ng-container i18n>If you disable transcoding, many videos from your users will not work!</ng-container>
439 </ng-template>
440 </my-peertube-checkbox>
416 </div> 441 </div>
417 442
418 <ng-container *ngIf="isTranscodingEnabled()"> 443 <ng-container *ngIf="isTranscodingEnabled()">
@@ -421,16 +446,22 @@
421 <my-peertube-checkbox 446 <my-peertube-checkbox
422 inputName="transcodingAllowAdditionalExtensions" formControlName="allowAdditionalExtensions" 447 inputName="transcodingAllowAdditionalExtensions" formControlName="allowAdditionalExtensions"
423 i18n-labelText labelText="Allow additional extensions" 448 i18n-labelText labelText="Allow additional extensions"
424 i18n-helpHtml helpHtml="Allow your users to upload .mkv, .mov, .avi, .flv videos" 449 >
425 ></my-peertube-checkbox> 450 <ng-template ptTemplate="help">
451 <ng-container i18n>Allow your users to upload .mkv, .mov, .avi, .flv videos</ng-container>
452 </ng-template>
453 </my-peertube-checkbox>
426 </div> 454 </div>
427 455
428 <div class="form-group"> 456 <div class="form-group">
429 <my-peertube-checkbox 457 <my-peertube-checkbox
430 inputName="transcodingAllowAudioFiles" formControlName="allowAudioFiles" 458 inputName="transcodingAllowAudioFiles" formControlName="allowAudioFiles"
431 i18n-labelText labelText="Allow audio files upload" 459 i18n-labelText labelText="Allow audio files upload"
432 i18n-helpHtml helpHtml="Allow your users to upload audio files that will be merged with the preview file on upload" 460 >
433 ></my-peertube-checkbox> 461 <ng-template ptTemplate="help">
462 <ng-container i18n>Allow your users to upload audio files that will be merged with the preview file on upload</ng-container>
463 </ng-template>
464 </my-peertube-checkbox>
434 </div> 465 </div>
435 466
436 <div class="form-group"> 467 <div class="form-group">
@@ -460,10 +491,11 @@
460 <div i18n class="inner-form-title"> 491 <div i18n class="inner-form-title">
461 Cache 492 Cache
462 493
463 <my-help 494 <my-help>
464 helpType="custom" i18n-customHtml 495 <ng-template ptTemplate="customHtml">
465 customHtml="Some files are not federated (previews, captions). We fetch them directly from the origin instance and cache them." 496 <ng-container i18n>Some files are not federated (previews, captions). We fetch them directly from the origin instance and cache them.</ng-container>
466 ></my-help> 497 </ng-template>
498 </my-help>
467 </div> 499 </div>
468 500
469 <ng-container formGroupName="cache"> 501 <ng-container formGroupName="cache">
@@ -492,38 +524,45 @@
492 <ng-container formGroupName="customizations"> 524 <ng-container formGroupName="customizations">
493 <div class="form-group"> 525 <div class="form-group">
494 <label i18n for="customizationJavascript">JavaScript</label> 526 <label i18n for="customizationJavascript">JavaScript</label>
495 <my-help 527 <my-help>
496 helpType="custom" i18n-customHtml 528 <ng-template ptTemplate="customHtml">
497 customHtml="Write directly JavaScript code.<br />Example: <pre>console.log('my instance is amazing');</pre>" 529 <ng-container i18n>
498 ></my-help> 530 Write directly JavaScript code.<br />Example: <pre>console.log('my instance is amazing');</pre>
531 </ng-container>
532 </ng-template>
533 </my-help>
534
499 <textarea 535 <textarea
500 id="customizationJavascript" formControlName="javascript" 536 id="customizationJavascript" formControlName="javascript"
501 [ngClass]="{ 'input-error': formErrors['instance.customizations.javascript'] }" 537 [ngClass]="{ 'input-error': formErrors['instance.customizations.javascript'] }"
502 ></textarea> 538 ></textarea>
539
503 <div *ngIf="formErrors.instance.customizations.javascript" class="form-error">{{ formErrors.instance.customizations.javascript }}</div> 540 <div *ngIf="formErrors.instance.customizations.javascript" class="form-error">{{ formErrors.instance.customizations.javascript }}</div>
504 </div> 541 </div>
505 542
506 <div class="form-group"> 543 <div class="form-group">
507 <label for="customizationCSS">CSS</label> 544 <label for="customizationCSS">CSS</label>
508 <my-help 545
509 helpType="custom" 546 <my-help>
510 i18n-customHtml 547 <ng-template ptTemplate="customHtml">
511 customHtml=" 548 <ng-container i18n>
512 Write directly CSS code. Example:<br /><br /> 549 Write directly CSS code. Example:<br /><br />
513 <pre> 550<pre>
514 #custom-css {{ '{' }} 551#custom-css {{ '{' }}
515 color: red; 552 color: red;
516 {{ '}' }} 553{{ '}' }}
517 </pre> 554</pre>
518 555
519 Prepend with <em>#custom-css</em> to override styles. Example:<br /><br /> 556 Prepend with <em>#custom-css</em> to override styles. Example:<br /><br />
520 <pre> 557<pre>
521 #custom-css .logged-in-email {{ '{' }} 558#custom-css .logged-in-email {{ '{' }}
522 color: red; 559 color: red;
523 {{ '}' }} 560{{ '}' }}
524 </pre> 561</pre>
525 " 562 </ng-container>
526 ></my-help> 563 </ng-template>
564 </my-help>
565
527 <textarea 566 <textarea
528 id="customizationCSS" formControlName="css" 567 id="customizationCSS" formControlName="css"
529 [ngClass]="{ 'input-error': formErrors['instance.customizations.css'] }" 568 [ngClass]="{ 'input-error': formErrors['instance.customizations.css'] }"
diff --git a/client/src/app/+my-account/my-account-settings/my-account-video-settings/my-account-video-settings.component.html b/client/src/app/+my-account/my-account-settings/my-account-video-settings/my-account-video-settings.component.html
index caa032149..a11238925 100644
--- a/client/src/app/+my-account/my-account-settings/my-account-video-settings/my-account-video-settings.component.html
+++ b/client/src/app/+my-account/my-account-settings/my-account-video-settings/my-account-video-settings.component.html
@@ -1,10 +1,13 @@
1<form role="form" (ngSubmit)="updateDetails()" [formGroup]="form"> 1<form role="form" (ngSubmit)="updateDetails()" [formGroup]="form">
2 <div class="form-group"> 2 <div class="form-group">
3 <label i18n for="nsfwPolicy">Default policy on videos containing sensitive content</label> 3 <label i18n for="nsfwPolicy">Default policy on videos containing sensitive content</label>
4 <my-help 4 <my-help>
5 helpType="custom" i18n-customHtml 5 <ng-template ptTemplate="customHtml">
6 customHtml="With <strong>Do not list</strong> or <strong>Blur thumbnails</strong>, a confirmation will be requested to watch the video." 6 <ng-container i18n>
7 ></my-help> 7 With <strong>Do not list</strong> or <strong>Blur thumbnails</strong>, a confirmation will be requested to watch the video.
8 </ng-container>
9 </ng-template>
10 </my-help>
8 11
9 <div class="peertube-select-container"> 12 <div class="peertube-select-container">
10 <select id="nsfwPolicy" formControlName="nsfwPolicy"> 13 <select id="nsfwPolicy" formControlName="nsfwPolicy">
@@ -17,9 +20,11 @@
17 20
18 <div class="form-group"> 21 <div class="form-group">
19 <label i18n for="videoLanguages">Only display videos in the following languages</label> 22 <label i18n for="videoLanguages">Only display videos in the following languages</label>
20 <my-help i18n-customHtml 23 <my-help>
21 customHtml="In Recently added, Trending, Local and Search pages" 24 <ng-template ptTemplate="customHtml">
22 ></my-help> 25 <ng-container i18n>In Recently added, Trending, Local and Search pages</ng-container>
26 </ng-template>
27 </my-help>
23 28
24 <div> 29 <div>
25 <p-multiSelect 30 <p-multiSelect
diff --git a/client/src/app/+signup/+register/register-step-user.component.html b/client/src/app/+signup/+register/register-step-user.component.html
index 47b3be8cc..4381702ae 100644
--- a/client/src/app/+signup/+register/register-step-user.component.html
+++ b/client/src/app/+signup/+register/register-step-user.component.html
@@ -60,11 +60,16 @@
60 </div> 60 </div>
61 61
62 <div class="form-group form-group-terms"> 62 <div class="form-group form-group-terms">
63 <my-peertube-checkbox 63 <my-peertube-checkbox inputName="terms" formControlName="terms">
64 inputName="terms" formControlName="terms" 64 <ng-template ptTemplate="label">
65 i18n-labelHtml 65 <ng-container i18n>
66 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" 66 I am at least 16 years old and agree
67 ></my-peertube-checkbox> 67 to the <a (click)="onTermsClick($event)" href='#'>Terms</a>
68 <ng-container *ngIf="hasCodeOfConduct"> and to the <a (click)="onCodeOfConductClick($event)" href='#'>Code of Conduct</a></ng-container>
69 of this instance
70 </ng-container>
71 </ng-template>
72 </my-peertube-checkbox>
68 73
69 <div *ngIf="formErrors.terms" class="form-error"> 74 <div *ngIf="formErrors.terms" class="form-error">
70 {{ formErrors.terms }} 75 {{ formErrors.terms }}
diff --git a/client/src/app/+signup/+register/register-step-user.component.ts b/client/src/app/+signup/+register/register-step-user.component.ts
index 3b71fd3c4..6c96f20b4 100644
--- a/client/src/app/+signup/+register/register-step-user.component.ts
+++ b/client/src/app/+signup/+register/register-step-user.component.ts
@@ -1,4 +1,4 @@
1import { Component, EventEmitter, OnInit, Output } from '@angular/core' 1import { Component, EventEmitter, Input, OnInit, Output } from '@angular/core'
2import { AuthService } from '@app/core' 2import { AuthService } from '@app/core'
3import { FormReactive, UserService, UserValidatorsService } from '@app/shared' 3import { FormReactive, UserService, UserValidatorsService } from '@app/shared'
4import { FormValidatorService } from '@app/shared/forms/form-validators/form-validator.service' 4import { FormValidatorService } from '@app/shared/forms/form-validators/form-validator.service'
@@ -12,7 +12,11 @@ import { concat, of } from 'rxjs'
12 styleUrls: [ './register.component.scss' ] 12 styleUrls: [ './register.component.scss' ]
13}) 13})
14export class RegisterStepUserComponent extends FormReactive implements OnInit { 14export class RegisterStepUserComponent extends FormReactive implements OnInit {
15 @Input() hasCodeOfConduct = false
16
15 @Output() formBuilt = new EventEmitter<FormGroup>() 17 @Output() formBuilt = new EventEmitter<FormGroup>()
18 @Output() termsClick = new EventEmitter<void>()
19 @Output() codeOfConductClick = new EventEmitter<void>()
16 20
17 constructor ( 21 constructor (
18 protected formValidatorService: FormValidatorService, 22 protected formValidatorService: FormValidatorService,
@@ -45,6 +49,16 @@ export class RegisterStepUserComponent extends FormReactive implements OnInit {
45 .subscribe(([ oldValue, newValue ]) => this.onDisplayNameChange(oldValue, newValue)) 49 .subscribe(([ oldValue, newValue ]) => this.onDisplayNameChange(oldValue, newValue))
46 } 50 }
47 51
52 onTermsClick (event: Event) {
53 event.preventDefault()
54 this.termsClick.emit()
55 }
56
57 onCodeOfConductClick (event: Event) {
58 event.preventDefault()
59 this.codeOfConductClick.emit()
60 }
61
48 private onDisplayNameChange (oldDisplayName: string, newDisplayName: string) { 62 private onDisplayNameChange (oldDisplayName: string, newDisplayName: string) {
49 const username = this.form.value['username'] || '' 63 const username = this.form.value['username'] || ''
50 64
diff --git a/client/src/app/+signup/+register/register.component.html b/client/src/app/+signup/+register/register.component.html
index d7e47c1a8..e7440fe1e 100644
--- a/client/src/app/+signup/+register/register.component.html
+++ b/client/src/app/+signup/+register/register.component.html
@@ -7,11 +7,15 @@
7 <my-signup-success *ngIf="signupDone" [message]="success"></my-signup-success> 7 <my-signup-success *ngIf="signupDone" [message]="success"></my-signup-success>
8 <div *ngIf="info" class="alert alert-info">{{ info }}</div> 8 <div *ngIf="info" class="alert alert-info">{{ info }}</div>
9 9
10 <div class="wrapper" *ngIf="!signupDone"> 10 <div class="wrapper" [hidden]="signupDone">
11 <div> 11 <div class="register-form">
12 <my-custom-stepper linear *ngIf="!signupDone"> 12 <my-custom-stepper linear *ngIf="!signupDone">
13 <cdk-step [stepControl]="formStepUser" i18n-label label="User information"> 13 <cdk-step [stepControl]="formStepUser" i18n-label label="User information">
14 <my-register-step-user (formBuilt)="onUserFormBuilt($event)"></my-register-step-user> 14 <my-register-step-user
15 [hasCodeOfConduct]="!!aboutHtml.codeOfConduct"
16 (formBuilt)="onUserFormBuilt($event)" (termsClick)="onTermsClick()" (codeOfConductClick)="onCodeOfConductClick()"
17 >
18 </my-register-step-user>
15 19
16 <button i18n cdkStepperNext [disabled]="!formStepUser || !formStepUser.valid">Next</button> 20 <button i18n cdkStepperNext [disabled]="!formStepUser || !formStepUser.valid">Next</button>
17 </cdk-step> 21 </cdk-step>
@@ -38,9 +42,56 @@
38 </my-custom-stepper> 42 </my-custom-stepper>
39 </div> 43 </div>
40 44
41 <div> 45 <div class="instance-information">
42 <label i18n>Features found on this instance</label> 46 <ngb-accordion [closeOthers]="true" #accordion="ngbAccordion">
43 <my-instance-features-table></my-instance-features-table> 47 <ngb-panel id="instance-features" i18n-title title="Features found on this instance">
48 <ng-template ngbPanelContent>
49 <my-instance-features-table></my-instance-features-table>
50 </ng-template>
51 </ngb-panel>
52
53 <ng-container *ngIf="about">
54 <ngb-panel
55 *ngIf="aboutHtml.administrator || about.instance.maintenanceLifetime || about.instance.businessModel"
56 id="admin-sustainability" i18n-title title="Administrators & Sustainability"
57 >
58 <ng-template ngbPanelContent>
59 <div class="block">
60 <strong i18n>Who are we?</strong>
61 <div [innerHTML]="aboutHtml.administrator"></div>
62 </div>
63
64 <div class="block">
65 <strong i18n>How long do we plan to maintain this instance?</strong>
66 <div [innerHTML]="about.instance.maintenanceLifetime"></div>
67 </div>
68
69 <div class="block">
70 <strong i18n>How will we pay this instance?</strong>
71 <div [innerHTML]="about.instance.businessModel"></div>
72 </div>
73 </ng-template>
74 </ngb-panel>
75
76 <ngb-panel *ngIf="aboutHtml.moderationInformation" id="moderation-information" i18n-title title="Moderation information">
77 <ng-template ngbPanelContent>
78 <div class="block" [innerHTML]="aboutHtml.moderationInformation"></div>
79 </ng-template>
80 </ngb-panel>
81
82 <ngb-panel *ngIf="aboutHtml.codeOfConduct" id="code-of-conduct" i18n-title title="Code of conduct">
83 <ng-template ngbPanelContent>
84 <div class="block" [innerHTML]="aboutHtml.codeOfConduct"></div>
85 </ng-template>
86 </ngb-panel>
87
88 <ngb-panel *ngIf="aboutHtml.terms" id="terms" i18n-title title="Terms">
89 <ng-template ngbPanelContent>
90 <div class="block" [innerHTML]="aboutHtml.terms"></div>
91 </ng-template>
92 </ngb-panel>
93 </ng-container>
94 </ngb-accordion>
44 </div> 95 </div>
45 </div> 96 </div>
46 97
diff --git a/client/src/app/+signup/+register/register.component.scss b/client/src/app/+signup/+register/register.component.scss
index 9405b5293..2f62dd59d 100644
--- a/client/src/app/+signup/+register/register.component.scss
+++ b/client/src/app/+signup/+register/register.component.scss
@@ -1,5 +1,9 @@
1@import '_variables'; 1@import '_variables';
2@import '_mixins'; 2@import '_mixins';
3@import "./_bootstrap-variables";
4
5@import '~bootstrap/scss/functions';
6@import '~bootstrap/scss/variables';
3 7
4.alert { 8.alert {
5 font-size: 15px; 9 font-size: 15px;
@@ -13,7 +17,32 @@
13 17
14 & > div { 18 & > div {
15 margin-bottom: 40px; 19 margin-bottom: 40px;
16 width: 450px; 20
21 &.register-form {
22 width: 450px;
23 }
24
25 &.instance-information {
26 width: 600px;
27 margin-bottom: 40px;
28
29 .block {
30 font-size: 15px;
31 margin-bottom: 15px;
32 padding: 0 $btn-padding-x;
33 }
34
35 @media screen and (max-width: 1500px) {
36 width: 450px;
37 }
38
39 ngb-accordion ::ng-deep {
40 .btn {
41 font-weight: $font-semibold !important;
42 color: var(--mainForegroundColor) !important;
43 }
44 }
45 }
17 46
18 @media screen and (max-width: 500px) { 47 @media screen and (max-width: 500px) {
19 width: auto; 48 width: auto;
@@ -21,12 +50,6 @@
21 } 50 }
22} 51}
23 52
24my-instance-features-table {
25 display: block;
26
27 margin-bottom: 40px;
28}
29
30.form-group-terms { 53.form-group-terms {
31 margin: 30px 0; 54 margin: 30px 0;
32} 55}
diff --git a/client/src/app/+signup/+register/register.component.ts b/client/src/app/+signup/+register/register.component.ts
index cd6059728..d470ef4dc 100644
--- a/client/src/app/+signup/+register/register.component.ts
+++ b/client/src/app/+signup/+register/register.component.ts
@@ -1,21 +1,35 @@
1import { Component } from '@angular/core' 1import { Component, OnInit, ViewChild } from '@angular/core'
2import { AuthService, Notifier, RedirectService, ServerService } from '@app/core' 2import { AuthService, Notifier, RedirectService, ServerService } from '@app/core'
3import { UserService, UserValidatorsService } from '@app/shared' 3import { UserService, UserValidatorsService } from '@app/shared'
4import { I18n } from '@ngx-translate/i18n-polyfill' 4import { I18n } from '@ngx-translate/i18n-polyfill'
5import { UserRegister } from '@shared/models/users/user-register.model' 5import { UserRegister } from '@shared/models/users/user-register.model'
6import { FormGroup } from '@angular/forms' 6import { FormGroup } from '@angular/forms'
7import { About } from '@shared/models/server'
8import { InstanceService } from '@app/shared/instance/instance.service'
9import { NgbAccordion } from '@ng-bootstrap/ng-bootstrap'
7 10
8@Component({ 11@Component({
9 selector: 'my-register', 12 selector: 'my-register',
10 templateUrl: './register.component.html', 13 templateUrl: './register.component.html',
11 styleUrls: [ './register.component.scss' ] 14 styleUrls: [ './register.component.scss' ]
12}) 15})
13export class RegisterComponent { 16export class RegisterComponent implements OnInit {
17 @ViewChild('accordion', { static: true }) accordion: NgbAccordion
18
14 info: string = null 19 info: string = null
15 error: string = null 20 error: string = null
16 success: string = null 21 success: string = null
17 signupDone = false 22 signupDone = false
18 23
24 about: About
25 aboutHtml = {
26 description: '',
27 terms: '',
28 codeOfConduct: '',
29 moderationInformation: '',
30 administrator: ''
31 }
32
19 formStepUser: FormGroup 33 formStepUser: FormGroup
20 formStepChannel: FormGroup 34 formStepChannel: FormGroup
21 35
@@ -26,6 +40,7 @@ export class RegisterComponent {
26 private userService: UserService, 40 private userService: UserService,
27 private serverService: ServerService, 41 private serverService: ServerService,
28 private redirectService: RedirectService, 42 private redirectService: RedirectService,
43 private instanceService: InstanceService,
29 private i18n: I18n 44 private i18n: I18n
30 ) { 45 ) {
31 } 46 }
@@ -34,6 +49,19 @@ export class RegisterComponent {
34 return this.serverService.getConfig().signup.requiresEmailVerification 49 return this.serverService.getConfig().signup.requiresEmailVerification
35 } 50 }
36 51
52 ngOnInit (): void {
53 this.instanceService.getAbout()
54 .subscribe(
55 async about => {
56 this.about = about
57
58 this.aboutHtml = await this.instanceService.buildHtml(about)
59 },
60
61 err => this.notifier.error(err.message)
62 )
63 }
64
37 hasSameChannelAndAccountNames () { 65 hasSameChannelAndAccountNames () {
38 return this.getUsername() === this.getChannelName() 66 return this.getUsername() === this.getChannelName()
39 } 67 }
@@ -58,6 +86,14 @@ export class RegisterComponent {
58 this.formStepChannel = form 86 this.formStepChannel = form
59 } 87 }
60 88
89 onTermsClick () {
90 if (this.accordion) this.accordion.toggle('terms')
91 }
92
93 onCodeOfConductClick () {
94 if (this.accordion) this.accordion.toggle('code-of-conduct')
95 }
96
61 signup () { 97 signup () {
62 this.error = null 98 this.error = null
63 99
diff --git a/client/src/app/+signup/+register/register.module.ts b/client/src/app/+signup/+register/register.module.ts
index 46336cbd0..e55f83990 100644
--- a/client/src/app/+signup/+register/register.module.ts
+++ b/client/src/app/+signup/+register/register.module.ts
@@ -7,13 +7,15 @@ import { RegisterStepChannelComponent } from './register-step-channel.component'
7import { RegisterStepUserComponent } from './register-step-user.component' 7import { RegisterStepUserComponent } from './register-step-user.component'
8import { CustomStepperComponent } from './custom-stepper.component' 8import { CustomStepperComponent } from './custom-stepper.component'
9import { SignupSharedModule } from '@app/+signup/shared/signup-shared.module' 9import { SignupSharedModule } from '@app/+signup/shared/signup-shared.module'
10import { NgbAccordionModule } from '@ng-bootstrap/ng-bootstrap'
10 11
11@NgModule({ 12@NgModule({
12 imports: [ 13 imports: [
13 RegisterRoutingModule, 14 RegisterRoutingModule,
14 SharedModule, 15 SharedModule,
15 CdkStepperModule, 16 CdkStepperModule,
16 SignupSharedModule 17 SignupSharedModule,
18 NgbAccordionModule
17 ], 19 ],
18 20
19 declarations: [ 21 declarations: [
diff --git a/client/src/app/login/login.component.html b/client/src/app/login/login.component.html
index 4efe3fb22..683355960 100644
--- a/client/src/app/login/login.component.html
+++ b/client/src/app/login/login.component.html
@@ -23,10 +23,11 @@
23 or create an account on another instance 23 or create an account on another instance
24 </a> 24 </a>
25 25
26 <my-help 26 <my-help *ngIf="signupAllowed === false">
27 *ngIf="signupAllowed === false" helpType="custom" i18n-customHtml 27 <ng-template ptTemplate="customHtml">
28 customHtml="User registration is not allowed on this instance, but you can register on many others!" 28 <ng-container i18n>User registration is not allowed on this instance, but you can register on many others!</ng-container>
29 ></my-help> 29 </ng-template>
30 </my-help>
30 </div> 31 </div>
31 32
32 <div *ngIf="formErrors.username" class="form-error"> 33 <div *ngIf="formErrors.username" class="form-error">
diff --git a/client/src/app/shared/angular/peertube-template.directive.ts b/client/src/app/shared/angular/peertube-template.directive.ts
index a514b6057..e04c25d9a 100644
--- a/client/src/app/shared/angular/peertube-template.directive.ts
+++ b/client/src/app/shared/angular/peertube-template.directive.ts
@@ -3,8 +3,8 @@ import { Directive, Input, TemplateRef } from '@angular/core'
3@Directive({ 3@Directive({
4 selector: '[ptTemplate]' 4 selector: '[ptTemplate]'
5}) 5})
6export class PeerTubeTemplateDirective { 6export class PeerTubeTemplateDirective <T extends string> {
7 @Input('ptTemplate') name: string 7 @Input('ptTemplate') name: T
8 8
9 constructor (public template: TemplateRef<any>) { 9 constructor (public template: TemplateRef<any>) {
10 // empty 10 // empty
diff --git a/client/src/app/shared/forms/peertube-checkbox.component.html b/client/src/app/shared/forms/peertube-checkbox.component.html
index 571a1a673..f1e3bf0bf 100644
--- a/client/src/app/shared/forms/peertube-checkbox.component.html
+++ b/client/src/app/shared/forms/peertube-checkbox.component.html
@@ -3,8 +3,15 @@
3 <input type="checkbox" [(ngModel)]="checked" (ngModelChange)="onModelChange()" [id]="inputName" [disabled]="disabled" /> 3 <input type="checkbox" [(ngModel)]="checked" (ngModelChange)="onModelChange()" [id]="inputName" [disabled]="disabled" />
4 <span role="checkbox" [attr.aria-checked]="checked"></span> 4 <span role="checkbox" [attr.aria-checked]="checked"></span>
5 <span *ngIf="labelText">{{ labelText }}</span> 5 <span *ngIf="labelText">{{ labelText }}</span>
6 <span *ngIf="labelHtml" [innerHTML]="labelHtml"></span> 6
7 <span *ngIf="labelTemplate">
8 <ng-container *ngTemplateOutlet="labelTemplate"></ng-container>
9 </span>
7 </label> 10 </label>
8 11
9 <my-help *ngIf="helpHtml" [tooltipPlacement]="helpPlacement" helpType="custom" i18n-customHtml [customHtml]="helpHtml"></my-help> 12 <my-help *ngIf="helpTemplate" [tooltipPlacement]="helpPlacement" helpType="custom">
13 <ng-template ptTemplate="customHtml">
14 <ng-template *ngTemplateOutlet="helpTemplate"></ng-template>
15 </ng-template>
16 </my-help>
10</div> 17</div>
diff --git a/client/src/app/shared/forms/peertube-checkbox.component.ts b/client/src/app/shared/forms/peertube-checkbox.component.ts
index a4b72aa37..3b8f39ed0 100644
--- a/client/src/app/shared/forms/peertube-checkbox.component.ts
+++ b/client/src/app/shared/forms/peertube-checkbox.component.ts
@@ -1,5 +1,6 @@
1import { ChangeDetectorRef, Component, forwardRef, Input, OnChanges, SimpleChanges } from '@angular/core' 1import { AfterContentInit, ChangeDetectorRef, Component, ContentChildren, forwardRef, Input, QueryList, TemplateRef } from '@angular/core'
2import { ControlValueAccessor, NG_VALUE_ACCESSOR } from '@angular/forms' 2import { ControlValueAccessor, NG_VALUE_ACCESSOR } from '@angular/forms'
3import { PeerTubeTemplateDirective } from '@app/shared/angular/peertube-template.directive'
3 4
4@Component({ 5@Component({
5 selector: 'my-peertube-checkbox', 6 selector: 'my-peertube-checkbox',
@@ -13,20 +14,35 @@ import { ControlValueAccessor, NG_VALUE_ACCESSOR } from '@angular/forms'
13 } 14 }
14 ] 15 ]
15}) 16})
16export class PeertubeCheckboxComponent implements ControlValueAccessor { 17export class PeertubeCheckboxComponent implements ControlValueAccessor, AfterContentInit {
17 @Input() checked = false 18 @Input() checked = false
18 @Input() inputName: string 19 @Input() inputName: string
19 @Input() labelText: string 20 @Input() labelText: string
20 @Input() labelHtml: string
21 @Input() helpHtml: string
22 @Input() helpPlacement = 'top' 21 @Input() helpPlacement = 'top'
23 @Input() disabled = false 22 @Input() disabled = false
24 23
24 @ContentChildren(PeerTubeTemplateDirective) templates: QueryList<PeerTubeTemplateDirective<'label' | 'help'>>
25
25 // FIXME: https://github.com/angular/angular/issues/10816#issuecomment-307567836 26 // FIXME: https://github.com/angular/angular/issues/10816#issuecomment-307567836
26 @Input() onPushWorkaround = false 27 @Input() onPushWorkaround = false
27 28
29 labelTemplate: TemplateRef<any>
30 helpTemplate: TemplateRef<any>
31
28 constructor (private cdr: ChangeDetectorRef) { } 32 constructor (private cdr: ChangeDetectorRef) { }
29 33
34 ngAfterContentInit () {
35 {
36 const t = this.templates.find(t => t.name === 'label')
37 if (t) this.labelTemplate = t.template
38 }
39
40 {
41 const t = this.templates.find(t => t.name === 'help')
42 if (t) this.helpTemplate = t.template
43 }
44 }
45
30 propagateChange = (_: any) => { /* empty */ } 46 propagateChange = (_: any) => { /* empty */ }
31 47
32 writeValue (checked: boolean) { 48 writeValue (checked: boolean) {
diff --git a/client/src/app/shared/instance/instance-features-table.component.html b/client/src/app/shared/instance/instance-features-table.component.html
index 845876f55..d1cb8fcbe 100644
--- a/client/src/app/shared/instance/instance-features-table.component.html
+++ b/client/src/app/shared/instance/instance-features-table.component.html
@@ -43,7 +43,11 @@
43 <ng-container *ngIf="initialUserVideoQuota !== -1"> 43 <ng-container *ngIf="initialUserVideoQuota !== -1">
44 {{ initialUserVideoQuota | bytes: 0 }} <ng-container *ngIf="dailyUserVideoQuota !== -1">({{ dailyUserVideoQuota | bytes: 0 }} per day)</ng-container> 44 {{ initialUserVideoQuota | bytes: 0 }} <ng-container *ngIf="dailyUserVideoQuota !== -1">({{ dailyUserVideoQuota | bytes: 0 }} per day)</ng-container>
45 45
46 <my-help tooltipPlacement="auto" helpType="custom" [customHtml]="quotaHelpIndication"></my-help> 46 <my-help tooltipPlacement="auto" helpType="custom">
47 <ng-template ptTemplate="customHtml">
48 <div [innerHTML]="quotaHelpIndication"></div>
49 </ng-template>
50 </my-help>
47 </ng-container> 51 </ng-container>
48 52
49 <ng-container i18n *ngIf="initialUserVideoQuota === -1"> 53 <ng-container i18n *ngIf="initialUserVideoQuota === -1">
diff --git a/client/src/app/shared/instance/instance.service.ts b/client/src/app/shared/instance/instance.service.ts
index d0c96941d..7c76bc98b 100644
--- a/client/src/app/shared/instance/instance.service.ts
+++ b/client/src/app/shared/instance/instance.service.ts
@@ -4,6 +4,9 @@ import { Injectable } from '@angular/core'
4import { environment } from '../../../environments/environment' 4import { environment } from '../../../environments/environment'
5import { RestExtractor, RestService } from '../rest' 5import { RestExtractor, RestService } from '../rest'
6import { About } from '../../../../../shared/models/server' 6import { About } from '../../../../../shared/models/server'
7import { MarkdownService } from '@app/shared/renderer'
8import { peertubeTranslate } from '@shared/models'
9import { ServerService } from '@app/core'
7 10
8@Injectable() 11@Injectable()
9export class InstanceService { 12export class InstanceService {
@@ -13,7 +16,9 @@ export class InstanceService {
13 constructor ( 16 constructor (
14 private authHttp: HttpClient, 17 private authHttp: HttpClient,
15 private restService: RestService, 18 private restService: RestService,
16 private restExtractor: RestExtractor 19 private restExtractor: RestExtractor,
20 private markdownService: MarkdownService,
21 private serverService: ServerService
17 ) { 22 ) {
18 } 23 }
19 24
@@ -34,4 +39,42 @@ export class InstanceService {
34 .pipe(catchError(res => this.restExtractor.handleError(res))) 39 .pipe(catchError(res => this.restExtractor.handleError(res)))
35 40
36 } 41 }
42
43 async buildHtml (about: About) {
44 const html = {
45 description: '',
46 terms: '',
47 codeOfConduct: '',
48 moderationInformation: '',
49 administrator: ''
50 }
51
52 for (const key of [ 'description', 'terms', 'codeOfConduct', 'moderationInformation', 'administrator' ]) {
53 html[ key ] = await this.markdownService.textMarkdownToHTML(about.instance[ key ])
54 }
55
56 return html
57 }
58
59 buildTranslatedLanguages (about: About, translations: any) {
60 const languagesArray = this.serverService.getVideoLanguages()
61
62 return about.instance.languages
63 .map(l => {
64 const languageObj = languagesArray.find(la => la.id === l)
65
66 return peertubeTranslate(languageObj.label, translations)
67 })
68 }
69
70 buildTranslatedCategories (about: About, translations: any) {
71 const categoriesArray = this.serverService.getVideoCategories()
72
73 return about.instance.categories
74 .map(c => {
75 const categoryObj = categoriesArray.find(ca => ca.id === c)
76
77 return peertubeTranslate(categoryObj.label, translations)
78 })
79 }
37} 80}
diff --git a/client/src/app/shared/misc/help.component.html b/client/src/app/shared/misc/help.component.html
index e31eef06a..9a6d3e48e 100644
--- a/client/src/app/shared/misc/help.component.html
+++ b/client/src/app/shared/misc/help.component.html
@@ -1,15 +1,25 @@
1<ng-template #tooltipTemplate> 1<ng-template #tooltipTemplate>
2 <ng-template [ngIf]="preHtml"> 2 <p *ngIf="preHtmlTemplate">
3 <p [innerHTML]="preHtml"></p> 3 <ng-template *ngTemplateOutlet="preHtmlTemplate"></ng-template>
4 <br /> 4 </p>
5 </ng-template>
6 5
7 <p [innerHTML]="mainHtml"></p> 6 <ng-container *ngIf="preHtmlTemplate && (customHtmlTemplate || mainHtml || postHtmlTemplate)">
7 <br /><br />
8 </ng-container>
8 9
9 <ng-template [ngIf]="postHtml"> 10 <p *ngIf="customHtmlTemplate">
10 <br /> 11 <ng-template *ngTemplateOutlet="customHtmlTemplate"></ng-template>
11 <p [innerHTML]="postHtml"></p> 12 </p>
12 </ng-template> 13
14 <p *ngIf="mainHtml" [innerHTML]="mainHtml"></p>
15
16 <ng-container *ngIf="(customHtmlTemplate || mainHtml) && postHtmlTemplate">
17 <br /><br />
18 </ng-container>
19
20 <p *ngIf="postHtmlTemplate">
21 <ng-template *ngTemplateOutlet="postHtmlTemplate"></ng-template>
22 </p>
13</ng-template> 23</ng-template>
14 24
15<span 25<span
diff --git a/client/src/app/shared/misc/help.component.ts b/client/src/app/shared/misc/help.component.ts
index f3426f70f..18ba8ad5e 100644
--- a/client/src/app/shared/misc/help.component.ts
+++ b/client/src/app/shared/misc/help.component.ts
@@ -1,6 +1,7 @@
1import { Component, Input, OnChanges, OnInit } from '@angular/core' 1import { AfterContentInit, Component, ContentChildren, Input, OnChanges, OnInit, QueryList, TemplateRef } from '@angular/core'
2import { I18n } from '@ngx-translate/i18n-polyfill' 2import { I18n } from '@ngx-translate/i18n-polyfill'
3import { MarkdownService } from '@app/shared/renderer' 3import { MarkdownService } from '@app/shared/renderer'
4import { PeerTubeTemplateDirective } from '@app/shared/angular/peertube-template.directive'
4 5
5@Component({ 6@Component({
6 selector: 'my-help', 7 selector: 'my-help',
@@ -8,22 +9,42 @@ import { MarkdownService } from '@app/shared/renderer'
8 templateUrl: './help.component.html' 9 templateUrl: './help.component.html'
9}) 10})
10 11
11export class HelpComponent implements OnInit, OnChanges { 12export class HelpComponent implements OnInit, OnChanges, AfterContentInit {
12 @Input() preHtml = ''
13 @Input() postHtml = ''
14 @Input() customHtml = ''
15 @Input() helpType: 'custom' | 'markdownText' | 'markdownEnhanced' = 'custom' 13 @Input() helpType: 'custom' | 'markdownText' | 'markdownEnhanced' = 'custom'
16 @Input() tooltipPlacement = 'right' 14 @Input() tooltipPlacement = 'right'
17 15
16 @ContentChildren(PeerTubeTemplateDirective) templates: QueryList<PeerTubeTemplateDirective<'preHtml' | 'customHtml' | 'postHtml'>>
17
18 isPopoverOpened = false 18 isPopoverOpened = false
19 mainHtml = '' 19 mainHtml = ''
20 20
21 preHtmlTemplate: TemplateRef<any>
22 customHtmlTemplate: TemplateRef<any>
23 postHtmlTemplate: TemplateRef<any>
24
21 constructor (private i18n: I18n) { } 25 constructor (private i18n: I18n) { }
22 26
23 ngOnInit () { 27 ngOnInit () {
24 this.init() 28 this.init()
25 } 29 }
26 30
31 ngAfterContentInit () {
32 {
33 const t = this.templates.find(t => t.name === 'preHtml')
34 if (t) this.preHtmlTemplate = t.template
35 }
36
37 {
38 const t = this.templates.find(t => t.name === 'customHtml')
39 if (t) this.customHtmlTemplate = t.template
40 }
41
42 {
43 const t = this.templates.find(t => t.name === 'postHtml')
44 if (t) this.postHtmlTemplate = t.template
45 }
46 }
47
27 ngOnChanges () { 48 ngOnChanges () {
28 this.init() 49 this.init()
29 } 50 }
@@ -37,11 +58,6 @@ export class HelpComponent implements OnInit, OnChanges {
37 } 58 }
38 59
39 private init () { 60 private init () {
40 if (this.helpType === 'custom') {
41 this.mainHtml = this.customHtml
42 return
43 }
44
45 if (this.helpType === 'markdownText') { 61 if (this.helpType === 'markdownText') {
46 this.mainHtml = this.formatMarkdownSupport(MarkdownService.TEXT_RULES) 62 this.mainHtml = this.formatMarkdownSupport(MarkdownService.TEXT_RULES)
47 return 63 return
diff --git a/client/src/app/shared/user-subscription/remote-subscribe.component.html b/client/src/app/shared/user-subscription/remote-subscribe.component.html
index ec3636b3e..59ee1cb04 100644
--- a/client/src/app/shared/user-subscription/remote-subscribe.component.html
+++ b/client/src/app/shared/user-subscription/remote-subscribe.component.html
@@ -12,13 +12,21 @@
12 <span *ngIf="interact">Remote interact</span> 12 <span *ngIf="interact">Remote interact</span>
13 </button> 13 </button>
14 14
15 <my-help *ngIf="!interact && showHelp" 15 <my-help *ngIf="!interact && showHelp">
16 helpType="custom" 16 <ng-template ptTemplate="customHtml">
17 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."> 17 <ng-container i18n>
18 You can subscribe to the channel via any ActivityPub-capable fediverse instance.<br /><br />
19 For instance with Mastodon or Pleroma you can type the channel URL in the search box and subscribe there.
20 </ng-container>
21 </ng-template>
18 </my-help> 22 </my-help>
19 23
20 <my-help *ngIf="showHelp && interact" 24 <my-help *ngIf="showHelp && interact">
21 helpType="custom" 25 <ng-template ptTemplate="customHtml">
22 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."> 26 <ng-container i18n>
27 You can interact with this via any ActivityPub-capable fediverse instance.<br /><br />
28 For instance with Mastodon or Pleroma you can type the current URL in the search box and interact with it there.
29 </ng-container>
30 </ng-template>
23 </my-help> 31 </my-help>
24</form> \ No newline at end of file 32</form>
diff --git a/client/src/app/shared/video/videos-selection.component.ts b/client/src/app/shared/video/videos-selection.component.ts
index 994e0fa1e..064420056 100644
--- a/client/src/app/shared/video/videos-selection.component.ts
+++ b/client/src/app/shared/video/videos-selection.component.ts
@@ -35,7 +35,7 @@ export class VideosSelectionComponent extends AbstractVideoList implements OnIni
35 @Input() titlePage: string 35 @Input() titlePage: string
36 @Input() miniatureDisplayOptions: MiniatureDisplayOptions 36 @Input() miniatureDisplayOptions: MiniatureDisplayOptions
37 @Input() getVideosObservableFunction: (page: number, sort?: VideoSortField) => Observable<ResultList<Video>> 37 @Input() getVideosObservableFunction: (page: number, sort?: VideoSortField) => Observable<ResultList<Video>>
38 @ContentChildren(PeerTubeTemplateDirective) templates: QueryList<PeerTubeTemplateDirective> 38 @ContentChildren(PeerTubeTemplateDirective) templates: QueryList<PeerTubeTemplateDirective<'rowButtons' | 'globalButtons'>>
39 39
40 @Output() selectionChange = new EventEmitter<SelectionType>() 40 @Output() selectionChange = new EventEmitter<SelectionType>()
41 @Output() videosModelChange = new EventEmitter<Video[]>() 41 @Output() videosModelChange = new EventEmitter<Video[]>()
diff --git a/client/src/app/videos/+video-edit/shared/video-edit.component.html b/client/src/app/videos/+video-edit/shared/video-edit.component.html
index 217cadc66..245ae42b6 100644
--- a/client/src/app/videos/+video-edit/shared/video-edit.component.html
+++ b/client/src/app/videos/+video-edit/shared/video-edit.component.html
@@ -15,7 +15,16 @@
15 15
16 <div class="form-group"> 16 <div class="form-group">
17 <label i18n class="label-tags">Tags</label> 17 <label i18n class="label-tags">Tags</label>
18 <my-help i18n-preHtml preHtml="Tags could be used to suggest relevant recommendations.</br>Press Enter to add a new tag."></my-help> 18
19 <my-help>
20 <ng-template ptTemplate="customHtml">
21 <ng-container i18n>
22 Tags could be used to suggest relevant recommendations. <br />
23 Press Enter to add a new tag.
24 </ng-container>
25 </ng-template>
26 </my-help>
27
19 <tag-input 28 <tag-input
20 [validators]="tagValidators" [errorMessages]="tagValidatorsMessages" 29 [validators]="tagValidators" [errorMessages]="tagValidatorsMessages"
21 i18n-placeholder placeholder="+ Tag" i18n-secondaryPlaceholder secondaryPlaceholder="Enter a new tag" 30 i18n-placeholder placeholder="+ Tag" i18n-secondaryPlaceholder secondaryPlaceholder="Enter a new tag"
@@ -25,7 +34,15 @@
25 34
26 <div class="form-group"> 35 <div class="form-group">
27 <label i18n for="description">Description</label> 36 <label i18n for="description">Description</label>
28 <my-help helpType="markdownText" i18n-preHtml preHtml="Video descriptions are truncated by default and require manual action to expand them."></my-help> 37
38 <my-help helpType="markdownText">
39 <ng-template ptTemplate="preHtml">
40 <ng-container i18n>
41 Video descriptions are truncated by default and require manual action to expand them.
42 </ng-container>
43 </ng-template>
44 </my-help>
45
29 <my-markdown-textarea truncate="250" formControlName="description"></my-markdown-textarea> 46 <my-markdown-textarea truncate="250" formControlName="description"></my-markdown-textarea>
30 47
31 <div *ngIf="formErrors.description" class="form-error"> 48 <div *ngIf="formErrors.description" class="form-error">
@@ -114,20 +131,25 @@
114 </div> 131 </div>
115 </div> 132 </div>
116 133
117 <my-peertube-checkbox 134 <my-peertube-checkbox inputName="nsfw" formControlName="nsfw" helpPlacement="bottom-right">
118 inputName="nsfw" formControlName="nsfw" 135 <ng-template ptTemplate="label">
119 i18n-labelText labelText="This video contains mature or explicit content" 136 <ng-container i18n>This video contains mature or explicit content</ng-container>
120 i18n-helpHtml helpHtml="Some instances do not list videos containing mature or explicit content by default." 137 </ng-template>
121 helpPlacement="bottom-right" 138
122 ></my-peertube-checkbox> 139 <ng-template ptTemplate="help">
123 140 <ng-container i18n>Some instances do not list videos containing mature or explicit content by default.</ng-container>
124 <my-peertube-checkbox 141 </ng-template>
125 *ngIf="waitTranscodingEnabled" 142 </my-peertube-checkbox>
126 inputName="waitTranscoding" formControlName="waitTranscoding" 143
127 i18n-labelText labelText="Wait transcoding before publishing the video" 144 <my-peertube-checkbox *ngIf="waitTranscodingEnabled" inputName="waitTranscoding" formControlName="waitTranscoding" helpPlacement="bottom-right">
128 i18n-helpHtml helpHtml="If you decide not to wait for transcoding before publishing the video, it could be unplayable until transcoding ends." 145 <ng-template ptTemplate="label">
129 helpPlacement="bottom-right" 146 <ng-container i18n>Wait transcoding before publishing the video</ng-container>
130 ></my-peertube-checkbox> 147 </ng-template>
148
149 <ng-template ptTemplate="help">
150 <ng-container i18n>If you decide not to wait for transcoding before publishing the video, it could be unplayable until transcoding ends.</ng-container>
151 </ng-template>
152 </my-peertube-checkbox>
131 153
132 </div> 154 </div>
133 </div> 155 </div>
diff --git a/client/src/app/videos/+video-edit/video-add-components/video-import-torrent.component.html b/client/src/app/videos/+video-edit/video-add-components/video-import-torrent.component.html
index 7a495fea5..c290fd4b1 100644
--- a/client/src/app/videos/+video-edit/video-add-components/video-import-torrent.component.html
+++ b/client/src/app/videos/+video-edit/video-add-components/video-import-torrent.component.html
@@ -12,10 +12,14 @@
12 12
13 <div class="form-group form-group-magnet-uri"> 13 <div class="form-group form-group-magnet-uri">
14 <label i18n for="magnetUri">Paste magnet URI</label> 14 <label i18n for="magnetUri">Paste magnet URI</label>
15 <my-help 15 <my-help>
16 helpType="custom" i18n-customHtml 16 <ng-template ptTemplate="customHtml">
17 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." 17 <ng-container i18n>
18 ></my-help> 18 You can import any torrent file that points to a mp4 file.
19 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.
20 </ng-container>
21 </ng-template>
22 </my-help>
19 23
20 <input type="text" id="magnetUri" [(ngModel)]="magnetUri" /> 24 <input type="text" id="magnetUri" [(ngModel)]="magnetUri" />
21 </div> 25 </div>
diff --git a/client/src/app/videos/+video-edit/video-add-components/video-import-url.component.html b/client/src/app/videos/+video-edit/video-add-components/video-import-url.component.html
index e4f19faa8..09d0b8272 100644
--- a/client/src/app/videos/+video-edit/video-add-components/video-import-url.component.html
+++ b/client/src/app/videos/+video-edit/video-add-components/video-import-url.component.html
@@ -4,10 +4,16 @@
4 4
5 <div class="form-group"> 5 <div class="form-group">
6 <label i18n for="targetUrl">URL</label> 6 <label i18n for="targetUrl">URL</label>
7 <my-help 7
8 helpType="custom" i18n-customHtml 8 <my-help>
9 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." 9 <ng-template ptTemplate="customHtml">
10 ></my-help> 10 <ng-container i18n>
11 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>
12 or URL that points to a raw MP4 file.
13 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.
14 </ng-container>
15 </ng-template>
16 </my-help>
11 17
12 <input type="text" id="targetUrl" [(ngModel)]="targetUrl" /> 18 <input type="text" id="targetUrl" [(ngModel)]="targetUrl" />
13 </div> 19 </div>