Migrate to bootstrap 4 and ng-bootstrap
This commit is contained in:
parent
b34a444e29
commit
63347a0ff9
|
@ -46,6 +46,7 @@
|
||||||
"@angular/service-worker": "~6.1.0",
|
"@angular/service-worker": "~6.1.0",
|
||||||
"@angularclass/hmr": "^2.1.3",
|
"@angularclass/hmr": "^2.1.3",
|
||||||
"@neos21/bootstrap3-glyphicons": "^1.0.1",
|
"@neos21/bootstrap3-glyphicons": "^1.0.1",
|
||||||
|
"@ng-bootstrap/ng-bootstrap": "^2.2.2",
|
||||||
"@ngx-loading-bar/core": "^2.0.0",
|
"@ngx-loading-bar/core": "^2.0.0",
|
||||||
"@ngx-loading-bar/http-client": "^2.0.0",
|
"@ngx-loading-bar/http-client": "^2.0.0",
|
||||||
"@ngx-loading-bar/router": "^2.0.0",
|
"@ngx-loading-bar/router": "^2.0.0",
|
||||||
|
@ -86,7 +87,6 @@
|
||||||
"linkifyjs": "^2.1.5",
|
"linkifyjs": "^2.1.5",
|
||||||
"lodash-es": "^4.17.4",
|
"lodash-es": "^4.17.4",
|
||||||
"markdown-it": "^8.4.0",
|
"markdown-it": "^8.4.0",
|
||||||
"ngx-bootstrap": "3.0.1",
|
|
||||||
"ngx-chips": "1.9.3",
|
"ngx-chips": "1.9.3",
|
||||||
"ngx-clipboard": "11.1.1",
|
"ngx-clipboard": "11.1.1",
|
||||||
"ngx-pipes": "^2.1.7",
|
"ngx-pipes": "^2.1.7",
|
||||||
|
|
|
@ -1,7 +1,6 @@
|
||||||
import { NgModule } from '@angular/core'
|
import { NgModule } from '@angular/core'
|
||||||
import { ConfigComponent, EditCustomConfigComponent } from '@app/+admin/config'
|
import { ConfigComponent, EditCustomConfigComponent } from '@app/+admin/config'
|
||||||
import { ConfigService } from '@app/+admin/config/shared/config.service'
|
import { ConfigService } from '@app/+admin/config/shared/config.service'
|
||||||
import { TabsModule } from 'ngx-bootstrap/tabs'
|
|
||||||
import { TableModule } from 'primeng/table'
|
import { TableModule } from 'primeng/table'
|
||||||
import { SharedModule } from '../shared'
|
import { SharedModule } from '../shared'
|
||||||
import { AdminRoutingModule } from './admin-routing.module'
|
import { AdminRoutingModule } from './admin-routing.module'
|
||||||
|
@ -18,7 +17,6 @@ import { VideoBlacklistComponent, VideoBlacklistListComponent } from './video-bl
|
||||||
@NgModule({
|
@NgModule({
|
||||||
imports: [
|
imports: [
|
||||||
AdminRoutingModule,
|
AdminRoutingModule,
|
||||||
TabsModule.forRoot(),
|
|
||||||
TableModule,
|
TableModule,
|
||||||
SharedModule
|
SharedModule
|
||||||
],
|
],
|
||||||
|
|
|
@ -1,290 +1,295 @@
|
||||||
<form role="form" [formGroup]="form">
|
<form role="form" [formGroup]="form">
|
||||||
|
|
||||||
<tabset class="root-tabset bootstrap">
|
<ngb-tabset class="root-tabset bootstrap">
|
||||||
|
|
||||||
<tab i18n-heading heading="Basic configuration">
|
<ngb-tab i18n-title title="Basic configuration">
|
||||||
|
<ng-template ngbTabContent>
|
||||||
|
|
||||||
<div i18n class="inner-form-title">Instance</div>
|
<div i18n class="inner-form-title">Instance</div>
|
||||||
|
|
||||||
<div class="form-group">
|
|
||||||
<label i18n for="instanceName">Name</label>
|
|
||||||
<input
|
|
||||||
type="text" id="instanceName"
|
|
||||||
formControlName="instanceName" [ngClass]="{ 'input-error': formErrors['instanceName'] }"
|
|
||||||
>
|
|
||||||
<div *ngIf="formErrors.instanceName" class="form-error">
|
|
||||||
{{ formErrors.instanceName }}
|
|
||||||
</div>
|
|
||||||
</div>
|
|
||||||
|
|
||||||
<div class="form-group">
|
|
||||||
<label i18n for="instanceShortDescription">Short description</label>
|
|
||||||
<textarea
|
|
||||||
id="instanceShortDescription" formControlName="instanceShortDescription"
|
|
||||||
[ngClass]="{ 'input-error': formErrors['instanceShortDescription'] }"
|
|
||||||
></textarea>
|
|
||||||
<div *ngIf="formErrors.instanceShortDescription" class="form-error">
|
|
||||||
{{ formErrors.instanceShortDescription }}
|
|
||||||
</div>
|
|
||||||
</div>
|
|
||||||
|
|
||||||
<div class="form-group">
|
|
||||||
<label i18n for="instanceDescription">Description</label><my-help helpType="markdownText"></my-help>
|
|
||||||
<my-markdown-textarea
|
|
||||||
id="instanceDescription" formControlName="instanceDescription" textareaWidth="500px" [previewColumn]="true"
|
|
||||||
[classes]="{ 'input-error': formErrors['instanceDescription'] }"
|
|
||||||
></my-markdown-textarea>
|
|
||||||
<div *ngIf="formErrors.instanceDescription" class="form-error">
|
|
||||||
{{ formErrors.instanceDescription }}
|
|
||||||
</div>
|
|
||||||
</div>
|
|
||||||
|
|
||||||
<div class="form-group">
|
|
||||||
<label i18n for="instanceTerms">Terms</label><my-help helpType="markdownText"></my-help>
|
|
||||||
<my-markdown-textarea
|
|
||||||
id="instanceTerms" formControlName="instanceTerms" textareaWidth="500px" [previewColumn]="true"
|
|
||||||
[ngClass]="{ 'input-error': formErrors['instanceTerms'] }"
|
|
||||||
></my-markdown-textarea>
|
|
||||||
<div *ngIf="formErrors.instanceTerms" class="form-error">
|
|
||||||
{{ formErrors.instanceTerms }}
|
|
||||||
</div>
|
|
||||||
</div>
|
|
||||||
|
|
||||||
<div class="form-group">
|
|
||||||
<label i18n for="instanceDefaultClientRoute">Default client route</label>
|
|
||||||
<div class="peertube-select-container">
|
|
||||||
<select id="instanceDefaultClientRoute" formControlName="instanceDefaultClientRoute">
|
|
||||||
<option i18n value="/videos/trending">Videos Trending</option>
|
|
||||||
<option i18n value="/videos/recently-added">Videos Recently Added</option>
|
|
||||||
<option i18n value="/videos/local">Local videos</option>
|
|
||||||
</select>
|
|
||||||
</div>
|
|
||||||
<div *ngIf="formErrors.instanceDefaultClientRoute" class="form-error">
|
|
||||||
{{ formErrors.instanceDefaultClientRoute }}
|
|
||||||
</div>
|
|
||||||
</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>
|
|
||||||
|
|
||||||
<div class="peertube-select-container">
|
|
||||||
<select id="instanceDefaultNSFWPolicy" formControlName="instanceDefaultNSFWPolicy">
|
|
||||||
<option i18n value="do_not_list">Do not list</option>
|
|
||||||
<option i18n value="blur">Blur thumbnails</option>
|
|
||||||
<option i18n value="display">Display</option>
|
|
||||||
</select>
|
|
||||||
</div>
|
|
||||||
<div *ngIf="formErrors.instanceDefaultNSFWPolicy" class="form-error">
|
|
||||||
{{ formErrors.instanceDefaultNSFWPolicy }}
|
|
||||||
</div>
|
|
||||||
</div>
|
|
||||||
|
|
||||||
<div i18n class="inner-form-title">Signup</div>
|
|
||||||
|
|
||||||
<my-peertube-checkbox
|
|
||||||
inputName="signupEnabled" formControlName="signupEnabled"
|
|
||||||
i18n-labelText labelText="Signup enabled"
|
|
||||||
></my-peertube-checkbox>
|
|
||||||
|
|
||||||
<div *ngIf="isSignupEnabled()" class="form-group">
|
|
||||||
<label i18n for="signupLimit">Signup limit</label>
|
|
||||||
<input
|
|
||||||
type="text" id="signupLimit"
|
|
||||||
formControlName="signupLimit" [ngClass]="{ 'input-error': formErrors['signupLimit'] }"
|
|
||||||
>
|
|
||||||
<div *ngIf="formErrors.signupLimit" class="form-error">
|
|
||||||
{{ formErrors.signupLimit }}
|
|
||||||
</div>
|
|
||||||
</div>
|
|
||||||
|
|
||||||
<div i18n class="inner-form-title">Import</div>
|
|
||||||
|
|
||||||
<my-peertube-checkbox
|
|
||||||
inputName="importVideosHttpEnabled" formControlName="importVideosHttpEnabled"
|
|
||||||
i18n-labelText labelText="Video import with HTTP enabled"
|
|
||||||
></my-peertube-checkbox>
|
|
||||||
|
|
||||||
<my-peertube-checkbox
|
|
||||||
inputName="importVideosTorrentEnabled" formControlName="importVideosTorrentEnabled"
|
|
||||||
i18n-labelText labelText="Video import with a torrent file or a magnet URI enabled"
|
|
||||||
></my-peertube-checkbox>
|
|
||||||
|
|
||||||
<div i18n class="inner-form-title">Administrator</div>
|
|
||||||
|
|
||||||
<div class="form-group">
|
|
||||||
<label i18n for="adminEmail">Admin email</label>
|
|
||||||
<input
|
|
||||||
type="text" id="adminEmail"
|
|
||||||
formControlName="adminEmail" [ngClass]="{ 'input-error': formErrors['adminEmail'] }"
|
|
||||||
>
|
|
||||||
<div *ngIf="formErrors.adminEmail" class="form-error">
|
|
||||||
{{ formErrors.adminEmail }}
|
|
||||||
</div>
|
|
||||||
</div>
|
|
||||||
|
|
||||||
<div i18n class="inner-form-title">Users</div>
|
|
||||||
|
|
||||||
<div class="form-group">
|
|
||||||
<label i18n for="userVideoQuota">User default video quota</label>
|
|
||||||
<div class="peertube-select-container">
|
|
||||||
<select id="userVideoQuota" formControlName="userVideoQuota">
|
|
||||||
<option *ngFor="let videoQuotaOption of videoQuotaOptions" [value]="videoQuotaOption.value">
|
|
||||||
{{ videoQuotaOption.label }}
|
|
||||||
</option>
|
|
||||||
</select>
|
|
||||||
</div>
|
|
||||||
<div *ngIf="formErrors.userVideoQuota" class="form-error">
|
|
||||||
{{ formErrors.userVideoQuota }}
|
|
||||||
</div>
|
|
||||||
</div>
|
|
||||||
</tab>
|
|
||||||
|
|
||||||
<tab i18n-heading heading="Services">
|
|
||||||
|
|
||||||
<div i18n class="inner-form-title">Twitter</div>
|
|
||||||
|
|
||||||
<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>
|
|
||||||
<input
|
|
||||||
type="text" id="servicesTwitterUsername"
|
|
||||||
formControlName="servicesTwitterUsername" [ngClass]="{ 'input-error': formErrors['servicesTwitterUsername'] }"
|
|
||||||
>
|
|
||||||
<div *ngIf="formErrors.servicesTwitterUsername" class="form-error">
|
|
||||||
{{ formErrors.servicesTwitterUsername }}
|
|
||||||
</div>
|
|
||||||
</div>
|
|
||||||
|
|
||||||
<my-peertube-checkbox
|
|
||||||
inputName="servicesTwitterWhitelisted" formControlName="servicesTwitterWhitelisted"
|
|
||||||
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>
|
|
||||||
</tab>
|
|
||||||
|
|
||||||
<tab i18n-heading heading="Advanced configuration">
|
|
||||||
|
|
||||||
<div i18n class="inner-form-title">Transcoding</div>
|
|
||||||
|
|
||||||
<my-peertube-checkbox
|
|
||||||
inputName="transcodingEnabled" formControlName="transcodingEnabled"
|
|
||||||
i18n-labelText labelText="Transcoding enabled"
|
|
||||||
i18n-helpHtml helpHtml="If you disable transcoding, many videos from your users will not work!"
|
|
||||||
></my-peertube-checkbox>
|
|
||||||
|
|
||||||
<ng-template [ngIf]="isTranscodingEnabled()">
|
|
||||||
|
|
||||||
<div class="form-group">
|
<div class="form-group">
|
||||||
<label i18n for="transcodingThreads">Transcoding threads</label>
|
<label i18n for="instanceName">Name</label>
|
||||||
|
<input
|
||||||
|
type="text" id="instanceName"
|
||||||
|
formControlName="instanceName" [ngClass]="{ 'input-error': formErrors['instanceName'] }"
|
||||||
|
>
|
||||||
|
<div *ngIf="formErrors.instanceName" class="form-error">
|
||||||
|
{{ formErrors.instanceName }}
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
|
||||||
|
<div class="form-group">
|
||||||
|
<label i18n for="instanceShortDescription">Short description</label>
|
||||||
|
<textarea
|
||||||
|
id="instanceShortDescription" formControlName="instanceShortDescription"
|
||||||
|
[ngClass]="{ 'input-error': formErrors['instanceShortDescription'] }"
|
||||||
|
></textarea>
|
||||||
|
<div *ngIf="formErrors.instanceShortDescription" class="form-error">
|
||||||
|
{{ formErrors.instanceShortDescription }}
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
|
||||||
|
<div class="form-group">
|
||||||
|
<label i18n for="instanceDescription">Description</label><my-help helpType="markdownText"></my-help>
|
||||||
|
<my-markdown-textarea
|
||||||
|
id="instanceDescription" formControlName="instanceDescription" textareaWidth="500px" [previewColumn]="true"
|
||||||
|
[classes]="{ 'input-error': formErrors['instanceDescription'] }"
|
||||||
|
></my-markdown-textarea>
|
||||||
|
<div *ngIf="formErrors.instanceDescription" class="form-error">
|
||||||
|
{{ formErrors.instanceDescription }}
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
|
||||||
|
<div class="form-group">
|
||||||
|
<label i18n for="instanceTerms">Terms</label><my-help helpType="markdownText"></my-help>
|
||||||
|
<my-markdown-textarea
|
||||||
|
id="instanceTerms" formControlName="instanceTerms" textareaWidth="500px" [previewColumn]="true"
|
||||||
|
[ngClass]="{ 'input-error': formErrors['instanceTerms'] }"
|
||||||
|
></my-markdown-textarea>
|
||||||
|
<div *ngIf="formErrors.instanceTerms" class="form-error">
|
||||||
|
{{ formErrors.instanceTerms }}
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
|
||||||
|
<div class="form-group">
|
||||||
|
<label i18n for="instanceDefaultClientRoute">Default client route</label>
|
||||||
<div class="peertube-select-container">
|
<div class="peertube-select-container">
|
||||||
<select id="transcodingThreads" formControlName="transcodingThreads">
|
<select id="instanceDefaultClientRoute" formControlName="instanceDefaultClientRoute">
|
||||||
<option *ngFor="let transcodingThreadOption of transcodingThreadOptions" [value]="transcodingThreadOption.value">
|
<option i18n value="/videos/trending">Videos Trending</option>
|
||||||
{{ transcodingThreadOption.label }}
|
<option i18n value="/videos/recently-added">Videos Recently Added</option>
|
||||||
|
<option i18n value="/videos/local">Local videos</option>
|
||||||
|
</select>
|
||||||
|
</div>
|
||||||
|
<div *ngIf="formErrors.instanceDefaultClientRoute" class="form-error">
|
||||||
|
{{ formErrors.instanceDefaultClientRoute }}
|
||||||
|
</div>
|
||||||
|
</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>
|
||||||
|
|
||||||
|
<div class="peertube-select-container">
|
||||||
|
<select id="instanceDefaultNSFWPolicy" formControlName="instanceDefaultNSFWPolicy">
|
||||||
|
<option i18n value="do_not_list">Do not list</option>
|
||||||
|
<option i18n value="blur">Blur thumbnails</option>
|
||||||
|
<option i18n value="display">Display</option>
|
||||||
|
</select>
|
||||||
|
</div>
|
||||||
|
<div *ngIf="formErrors.instanceDefaultNSFWPolicy" class="form-error">
|
||||||
|
{{ formErrors.instanceDefaultNSFWPolicy }}
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
|
||||||
|
<div i18n class="inner-form-title">Signup</div>
|
||||||
|
|
||||||
|
<my-peertube-checkbox
|
||||||
|
inputName="signupEnabled" formControlName="signupEnabled"
|
||||||
|
i18n-labelText labelText="Signup enabled"
|
||||||
|
></my-peertube-checkbox>
|
||||||
|
|
||||||
|
<div *ngIf="isSignupEnabled()" class="form-group">
|
||||||
|
<label i18n for="signupLimit">Signup limit</label>
|
||||||
|
<input
|
||||||
|
type="text" id="signupLimit"
|
||||||
|
formControlName="signupLimit" [ngClass]="{ 'input-error': formErrors['signupLimit'] }"
|
||||||
|
>
|
||||||
|
<div *ngIf="formErrors.signupLimit" class="form-error">
|
||||||
|
{{ formErrors.signupLimit }}
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
|
||||||
|
<div i18n class="inner-form-title">Import</div>
|
||||||
|
|
||||||
|
<my-peertube-checkbox
|
||||||
|
inputName="importVideosHttpEnabled" formControlName="importVideosHttpEnabled"
|
||||||
|
i18n-labelText labelText="Video import with HTTP enabled"
|
||||||
|
></my-peertube-checkbox>
|
||||||
|
|
||||||
|
<my-peertube-checkbox
|
||||||
|
inputName="importVideosTorrentEnabled" formControlName="importVideosTorrentEnabled"
|
||||||
|
i18n-labelText labelText="Video import with a torrent file or a magnet URI enabled"
|
||||||
|
></my-peertube-checkbox>
|
||||||
|
|
||||||
|
<div i18n class="inner-form-title">Administrator</div>
|
||||||
|
|
||||||
|
<div class="form-group">
|
||||||
|
<label i18n for="adminEmail">Admin email</label>
|
||||||
|
<input
|
||||||
|
type="text" id="adminEmail"
|
||||||
|
formControlName="adminEmail" [ngClass]="{ 'input-error': formErrors['adminEmail'] }"
|
||||||
|
>
|
||||||
|
<div *ngIf="formErrors.adminEmail" class="form-error">
|
||||||
|
{{ formErrors.adminEmail }}
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
|
||||||
|
<div i18n class="inner-form-title">Users</div>
|
||||||
|
|
||||||
|
<div class="form-group">
|
||||||
|
<label i18n for="userVideoQuota">User default video quota</label>
|
||||||
|
<div class="peertube-select-container">
|
||||||
|
<select id="userVideoQuota" formControlName="userVideoQuota">
|
||||||
|
<option *ngFor="let videoQuotaOption of videoQuotaOptions" [value]="videoQuotaOption.value">
|
||||||
|
{{ videoQuotaOption.label }}
|
||||||
</option>
|
</option>
|
||||||
</select>
|
</select>
|
||||||
</div>
|
</div>
|
||||||
<div *ngIf="formErrors.transcodingThreads" class="form-error">
|
<div *ngIf="formErrors.userVideoQuota" class="form-error">
|
||||||
{{ formErrors.transcodingThreads }}
|
{{ formErrors.userVideoQuota }}
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
</ng-template>
|
||||||
|
</ngb-tab>
|
||||||
|
|
||||||
|
<ngb-tab i18n-title title="Services">
|
||||||
|
<ng-template ngbTabContent>
|
||||||
|
<div i18n class="inner-form-title">Twitter</div>
|
||||||
|
|
||||||
|
<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>
|
||||||
|
<input
|
||||||
|
type="text" id="servicesTwitterUsername"
|
||||||
|
formControlName="servicesTwitterUsername" [ngClass]="{ 'input-error': formErrors['servicesTwitterUsername'] }"
|
||||||
|
>
|
||||||
|
<div *ngIf="formErrors.servicesTwitterUsername" class="form-error">
|
||||||
|
{{ formErrors.servicesTwitterUsername }}
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
|
|
||||||
<div class="form-group" *ngFor="let resolution of resolutions">
|
<my-peertube-checkbox
|
||||||
<my-peertube-checkbox
|
inputName="servicesTwitterWhitelisted" formControlName="servicesTwitterWhitelisted"
|
||||||
[inputName]="getResolutionKey(resolution)" [formControlName]="getResolutionKey(resolution)"
|
i18n-labelText labelText="Instance whitelisted by Twitter"
|
||||||
i18n-labelText labelText="Resolution {{resolution}} enabled"
|
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 />
|
||||||
></my-peertube-checkbox>
|
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>
|
||||||
|
</ng-template>
|
||||||
|
</ngb-tab>
|
||||||
|
|
||||||
|
<ngb-tab i18n-title title="Advanced configuration">
|
||||||
|
<ng-template ngbTabContent>
|
||||||
|
|
||||||
|
<div i18n class="inner-form-title">Transcoding</div>
|
||||||
|
|
||||||
|
<my-peertube-checkbox
|
||||||
|
inputName="transcodingEnabled" formControlName="transcodingEnabled"
|
||||||
|
i18n-labelText labelText="Transcoding enabled"
|
||||||
|
i18n-helpHtml helpHtml="If you disable transcoding, many videos from your users will not work!"
|
||||||
|
></my-peertube-checkbox>
|
||||||
|
|
||||||
|
<ng-template [ngIf]="isTranscodingEnabled()">
|
||||||
|
|
||||||
|
<div class="form-group">
|
||||||
|
<label i18n for="transcodingThreads">Transcoding threads</label>
|
||||||
|
<div class="peertube-select-container">
|
||||||
|
<select id="transcodingThreads" formControlName="transcodingThreads">
|
||||||
|
<option *ngFor="let transcodingThreadOption of transcodingThreadOptions" [value]="transcodingThreadOption.value">
|
||||||
|
{{ transcodingThreadOption.label }}
|
||||||
|
</option>
|
||||||
|
</select>
|
||||||
|
</div>
|
||||||
|
<div *ngIf="formErrors.transcodingThreads" class="form-error">
|
||||||
|
{{ formErrors.transcodingThreads }}
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
|
||||||
|
<div class="form-group" *ngFor="let resolution of resolutions">
|
||||||
|
<my-peertube-checkbox
|
||||||
|
[inputName]="getResolutionKey(resolution)" [formControlName]="getResolutionKey(resolution)"
|
||||||
|
i18n-labelText labelText="Resolution {{resolution}} enabled"
|
||||||
|
></my-peertube-checkbox>
|
||||||
|
|
||||||
|
</div>
|
||||||
|
</ng-template>
|
||||||
|
|
||||||
|
<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>
|
||||||
|
</div>
|
||||||
|
|
||||||
|
<div class="form-group">
|
||||||
|
<label i18n for="cachePreviewsSize">Previews cache size</label>
|
||||||
|
<input
|
||||||
|
type="text" id="cachePreviewsSize"
|
||||||
|
formControlName="cachePreviewsSize" [ngClass]="{ 'input-error': formErrors['cachePreviewsSize'] }"
|
||||||
|
>
|
||||||
|
<div *ngIf="formErrors.cachePreviewsSize" class="form-error">
|
||||||
|
{{ formErrors.cachePreviewsSize }}
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
|
||||||
|
<div class="form-group">
|
||||||
|
<label i18n for="cachePreviewsSize">Video captions cache size</label>
|
||||||
|
<input
|
||||||
|
type="text" id="cacheCaptionsSize"
|
||||||
|
formControlName="cacheCaptionsSize" [ngClass]="{ 'input-error': formErrors['cacheCaptionsSize'] }"
|
||||||
|
>
|
||||||
|
<div *ngIf="formErrors.cacheCaptionsSize" class="form-error">
|
||||||
|
{{ formErrors.cacheCaptionsSize }}
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
|
||||||
|
<div i18n class="inner-form-title">Customizations</div>
|
||||||
|
|
||||||
|
<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>
|
||||||
|
<textarea
|
||||||
|
id="customizationJavascript" formControlName="customizationJavascript"
|
||||||
|
[ngClass]="{ 'input-error': formErrors['customizationJavascript'] }"
|
||||||
|
></textarea>
|
||||||
|
<div *ngIf="formErrors.customizationJavascript" class="form-error">
|
||||||
|
{{ formErrors.customizationJavascript }}
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
|
||||||
|
<div class="form-group">
|
||||||
|
<label for="customizationCSS">CSS</label>
|
||||||
|
<my-help
|
||||||
|
helpType="custom"
|
||||||
|
i18n-customHtml
|
||||||
|
customHtml="
|
||||||
|
Write directly CSS code. Example:<br />
|
||||||
|
<pre>
|
||||||
|
body {{ '{' }}
|
||||||
|
background-color: red;
|
||||||
|
{{ '}' }}
|
||||||
|
</pre>
|
||||||
|
|
||||||
|
Prepend with <em>#custom-css</em> to override styles. Example:
|
||||||
|
<pre>
|
||||||
|
#custom-css .logged-in-email {{ '{' }}
|
||||||
|
color: red;
|
||||||
|
{{ '}' }}
|
||||||
|
</pre>
|
||||||
|
"
|
||||||
|
></my-help>
|
||||||
|
<textarea
|
||||||
|
id="customizationCSS" formControlName="customizationCSS"
|
||||||
|
[ngClass]="{ 'input-error': formErrors['customizationCSS'] }"
|
||||||
|
></textarea>
|
||||||
|
<div *ngIf="formErrors.customizationCSS" class="form-error">
|
||||||
|
{{ formErrors.customizationCSS }}
|
||||||
|
</div>
|
||||||
</div>
|
</div>
|
||||||
</ng-template>
|
</ng-template>
|
||||||
|
</ngb-tab>
|
||||||
<div i18n class="inner-form-title">
|
</ngb-tabset>
|
||||||
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>
|
|
||||||
</div>
|
|
||||||
|
|
||||||
<div class="form-group">
|
|
||||||
<label i18n for="cachePreviewsSize">Previews cache size</label>
|
|
||||||
<input
|
|
||||||
type="text" id="cachePreviewsSize"
|
|
||||||
formControlName="cachePreviewsSize" [ngClass]="{ 'input-error': formErrors['cachePreviewsSize'] }"
|
|
||||||
>
|
|
||||||
<div *ngIf="formErrors.cachePreviewsSize" class="form-error">
|
|
||||||
{{ formErrors.cachePreviewsSize }}
|
|
||||||
</div>
|
|
||||||
</div>
|
|
||||||
|
|
||||||
<div class="form-group">
|
|
||||||
<label i18n for="cachePreviewsSize">Video captions cache size</label>
|
|
||||||
<input
|
|
||||||
type="text" id="cacheCaptionsSize"
|
|
||||||
formControlName="cacheCaptionsSize" [ngClass]="{ 'input-error': formErrors['cacheCaptionsSize'] }"
|
|
||||||
>
|
|
||||||
<div *ngIf="formErrors.cacheCaptionsSize" class="form-error">
|
|
||||||
{{ formErrors.cacheCaptionsSize }}
|
|
||||||
</div>
|
|
||||||
</div>
|
|
||||||
|
|
||||||
<div i18n class="inner-form-title">Customizations</div>
|
|
||||||
|
|
||||||
<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>
|
|
||||||
<textarea
|
|
||||||
id="customizationJavascript" formControlName="customizationJavascript"
|
|
||||||
[ngClass]="{ 'input-error': formErrors['customizationJavascript'] }"
|
|
||||||
></textarea>
|
|
||||||
<div *ngIf="formErrors.customizationJavascript" class="form-error">
|
|
||||||
{{ formErrors.customizationJavascript }}
|
|
||||||
</div>
|
|
||||||
</div>
|
|
||||||
|
|
||||||
<div class="form-group">
|
|
||||||
<label for="customizationCSS">CSS</label>
|
|
||||||
<my-help
|
|
||||||
helpType="custom"
|
|
||||||
i18n-customHtml
|
|
||||||
customHtml="
|
|
||||||
Write directly CSS code. Example:<br />
|
|
||||||
<pre>
|
|
||||||
body {{ '{' }}
|
|
||||||
background-color: red;
|
|
||||||
{{ '}' }}
|
|
||||||
</pre>
|
|
||||||
|
|
||||||
Prepend with <em>#custom-css</em> to override styles. Example:
|
|
||||||
<pre>
|
|
||||||
#custom-css .logged-in-email {{ '{' }}
|
|
||||||
color: red;
|
|
||||||
{{ '}' }}
|
|
||||||
</pre>
|
|
||||||
"
|
|
||||||
></my-help>
|
|
||||||
<textarea
|
|
||||||
id="customizationCSS" formControlName="customizationCSS"
|
|
||||||
[ngClass]="{ 'input-error': formErrors['customizationCSS'] }"
|
|
||||||
></textarea>
|
|
||||||
<div *ngIf="formErrors.customizationCSS" class="form-error">
|
|
||||||
{{ formErrors.customizationCSS }}
|
|
||||||
</div>
|
|
||||||
</div>
|
|
||||||
</tab>
|
|
||||||
</tabset>
|
|
||||||
|
|
||||||
<input (click)="formValidated()" type="submit" i18n-value value="Update configuration" [disabled]="!form.valid">
|
<input (click)="formValidated()" type="submit" i18n-value value="Update configuration" [disabled]="!form.valid">
|
||||||
<span class="form-error" i18n *ngIf="!form.valid">It seems the configuration is invalid. Please search potential errors in the different tabs.</span>
|
<span class="form-error" i18n *ngIf="!form.valid">It seems the configuration is invalid. Please search potential errors in the different tabs.</span>
|
||||||
|
|
|
@ -18,5 +18,5 @@
|
||||||
It seems that you are not on a HTTPS server. Your webserver needs to have TLS activated in order to follow servers.
|
It seems that you are not on a HTTPS server. Your webserver needs to have TLS activated in order to follow servers.
|
||||||
</div>
|
</div>
|
||||||
|
|
||||||
<input type="submit" i18n-value value="Add following" [disabled]="hostsError || !hostsString" class="btn btn-default">
|
<input type="submit" i18n-value value="Add following" [disabled]="hostsError || !hostsString" class="btn btn-secondary">
|
||||||
</form>
|
</form>
|
||||||
|
|
|
@ -1,13 +1,15 @@
|
||||||
<div class="admin-sub-header">
|
<div class="admin-sub-header">
|
||||||
<div i18n class="form-sub-title">Manage follows</div>
|
<div i18n class="form-sub-title">Manage follows</div>
|
||||||
|
|
||||||
<tabset #followsMenuTabs>
|
<ngb-tabset #followsMenuTabs type="pills">
|
||||||
<tab *ngFor="let link of links">
|
|
||||||
<ng-template tabHeading>
|
<ngb-tab *ngFor="let link of links">
|
||||||
|
<ng-template ngbTabTitle>
|
||||||
<a class="tab-link" [routerLink]="link.path">{{ link.title }}</a>
|
<a class="tab-link" [routerLink]="link.path">{{ link.title }}</a>
|
||||||
</ng-template>
|
</ng-template>
|
||||||
</tab>
|
</ngb-tab>
|
||||||
</tabset>
|
|
||||||
|
</ngb-tabset>
|
||||||
</div>
|
</div>
|
||||||
|
|
||||||
<router-outlet></router-outlet>
|
<router-outlet></router-outlet>
|
||||||
|
|
|
@ -2,9 +2,3 @@
|
||||||
flex-grow: 0;
|
flex-grow: 0;
|
||||||
margin-right: 30px;
|
margin-right: 30px;
|
||||||
}
|
}
|
||||||
|
|
||||||
/deep/ .tab-content {
|
|
||||||
height: 0;
|
|
||||||
min-height: 0;
|
|
||||||
padding: 0;
|
|
||||||
}
|
|
||||||
|
|
|
@ -1,14 +1,14 @@
|
||||||
import { AfterViewInit, Component, OnInit, ViewChild } from '@angular/core'
|
import { AfterViewInit, Component, OnInit, ViewChild } from '@angular/core'
|
||||||
import { NavigationEnd, Router } from '@angular/router'
|
import { NavigationEnd, Router } from '@angular/router'
|
||||||
import { TabsetComponent } from 'ngx-bootstrap/tabs'
|
|
||||||
import { I18n } from '@ngx-translate/i18n-polyfill'
|
import { I18n } from '@ngx-translate/i18n-polyfill'
|
||||||
|
import { NgbTabset } from '@ng-bootstrap/ng-bootstrap'
|
||||||
|
|
||||||
@Component({
|
@Component({
|
||||||
templateUrl: './follows.component.html',
|
templateUrl: './follows.component.html',
|
||||||
styleUrls: [ './follows.component.scss' ]
|
styleUrls: [ './follows.component.scss' ]
|
||||||
})
|
})
|
||||||
export class FollowsComponent implements OnInit, AfterViewInit {
|
export class FollowsComponent implements OnInit, AfterViewInit {
|
||||||
@ViewChild('followsMenuTabs') followsMenuTabs: TabsetComponent
|
@ViewChild('followsMenuTabs') followsMenuTabs: NgbTabset
|
||||||
|
|
||||||
links: { path: string, title: string }[] = []
|
links: { path: string, title: string }[] = []
|
||||||
|
|
||||||
|
@ -53,8 +53,8 @@ export class FollowsComponent implements OnInit, AfterViewInit {
|
||||||
for (let i = 0; i < this.links.length; i++) {
|
for (let i = 0; i < this.links.length; i++) {
|
||||||
const path = this.links[i].path
|
const path = this.links[i].path
|
||||||
|
|
||||||
if (url.endsWith(path) === true && this.followsMenuTabs.tabs[i]) {
|
if (url.endsWith(path) === true) {
|
||||||
this.followsMenuTabs.tabs[i].active = true
|
this.followsMenuTabs.select(path)
|
||||||
return
|
return
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
@ -1,31 +1,25 @@
|
||||||
<div bsModal #confirmModal="bs-modal" [config]="{ animated: false }" class="modal" tabindex="-1" role="dialog">
|
<ng-template #confirmModal let-close="close" let-dismiss="dismiss">
|
||||||
<div class="modal-dialog">
|
|
||||||
<div class="modal-content">
|
|
||||||
|
|
||||||
<div class="modal-header">
|
<div class="modal-header">
|
||||||
<span class="close" aria-hidden="true" (click)="cancel()"></span>
|
<h4 class="modal-title">{{ title }}</h4>
|
||||||
<h4 class="modal-title">{{ title }}</h4>
|
<span class="close" aria-label="Close" role="button" (click)="dismiss()"></span>
|
||||||
</div>
|
</div>
|
||||||
|
|
||||||
<div class="modal-body" >
|
<div class="modal-body" >
|
||||||
<div [innerHtml]="message"></div>
|
<div [innerHtml]="message"></div>
|
||||||
|
|
||||||
<div *ngIf="inputLabel && expectedInputValue" class="form-group">
|
<div *ngIf="inputLabel && expectedInputValue" class="form-group">
|
||||||
<label for="confirmInput">{{ inputLabel }}</label>
|
<label for="confirmInput">{{ inputLabel }}</label>
|
||||||
<input type="text" id="confirmInput" name="confirmInput" [(ngModel)]="inputValue" />
|
<input type="text" id="confirmInput" name="confirmInput" [(ngModel)]="inputValue" />
|
||||||
</div>
|
|
||||||
|
|
||||||
<div class="form-group inputs">
|
|
||||||
<span i18n class="action-button action-button-cancel" (click)="cancel()">
|
|
||||||
Cancel
|
|
||||||
</span>
|
|
||||||
|
|
||||||
<input
|
|
||||||
type="submit" [value]="confirmButtonText" class="action-button-submit" [disabled]="isConfirmationDisabled()"
|
|
||||||
(click)="confirm()"
|
|
||||||
>
|
|
||||||
</div>
|
|
||||||
</div>
|
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
</div>
|
|
||||||
|
<div class="modal-footer inputs">
|
||||||
|
<span i18n class="action-button action-button-cancel" (click)="dismiss()" role="button">Cancel</span>
|
||||||
|
|
||||||
|
<input
|
||||||
|
type="submit" [value]="confirmButtonText" class="action-button-submit" [disabled]="isConfirmationDisabled()"
|
||||||
|
(click)="close()"
|
||||||
|
>
|
||||||
|
</div>
|
||||||
|
</ng-template>
|
||||||
|
|
|
@ -1,9 +1,8 @@
|
||||||
import { Component, HostListener, OnInit, ViewChild } from '@angular/core'
|
import { Component, ElementRef, HostListener, OnInit, ViewChild } from '@angular/core'
|
||||||
|
|
||||||
import { ModalDirective } from 'ngx-bootstrap/modal'
|
|
||||||
|
|
||||||
import { ConfirmService } from './confirm.service'
|
import { ConfirmService } from './confirm.service'
|
||||||
import { I18n } from '@ngx-translate/i18n-polyfill'
|
import { I18n } from '@ngx-translate/i18n-polyfill'
|
||||||
|
import { NgbModal } from '@ng-bootstrap/ng-bootstrap'
|
||||||
|
import { NgbModalRef } from '@ng-bootstrap/ng-bootstrap/modal/modal-ref'
|
||||||
|
|
||||||
@Component({
|
@Component({
|
||||||
selector: 'my-confirm',
|
selector: 'my-confirm',
|
||||||
|
@ -11,7 +10,7 @@ import { I18n } from '@ngx-translate/i18n-polyfill'
|
||||||
styleUrls: [ './confirm.component.scss' ]
|
styleUrls: [ './confirm.component.scss' ]
|
||||||
})
|
})
|
||||||
export class ConfirmComponent implements OnInit {
|
export class ConfirmComponent implements OnInit {
|
||||||
@ViewChild('confirmModal') confirmModal: ModalDirective
|
@ViewChild('confirmModal') confirmModal: ElementRef
|
||||||
|
|
||||||
title = ''
|
title = ''
|
||||||
message = ''
|
message = ''
|
||||||
|
@ -21,7 +20,10 @@ export class ConfirmComponent implements OnInit {
|
||||||
inputValue = ''
|
inputValue = ''
|
||||||
confirmButtonText = ''
|
confirmButtonText = ''
|
||||||
|
|
||||||
|
private openedModal: NgbModalRef
|
||||||
|
|
||||||
constructor (
|
constructor (
|
||||||
|
private modalService: NgbModal,
|
||||||
private confirmService: ConfirmService,
|
private confirmService: ConfirmService,
|
||||||
private i18n: I18n
|
private i18n: I18n
|
||||||
) {
|
) {
|
||||||
|
@ -29,11 +31,6 @@ export class ConfirmComponent implements OnInit {
|
||||||
}
|
}
|
||||||
|
|
||||||
ngOnInit () {
|
ngOnInit () {
|
||||||
this.confirmModal.config = {
|
|
||||||
backdrop: 'static',
|
|
||||||
keyboard: false
|
|
||||||
}
|
|
||||||
|
|
||||||
this.confirmService.showConfirm.subscribe(
|
this.confirmService.showConfirm.subscribe(
|
||||||
({ title, message, expectedInputValue, inputLabel, confirmButtonText }) => {
|
({ title, message, expectedInputValue, inputLabel, confirmButtonText }) => {
|
||||||
this.title = title
|
this.title = title
|
||||||
|
@ -49,16 +46,9 @@ export class ConfirmComponent implements OnInit {
|
||||||
)
|
)
|
||||||
}
|
}
|
||||||
|
|
||||||
@HostListener('keydown.enter')
|
@HostListener('document:keydown.enter')
|
||||||
confirm () {
|
confirm () {
|
||||||
this.confirmService.confirmResponse.next(true)
|
if (this.openedModal) this.openedModal.close()
|
||||||
this.hideModal()
|
|
||||||
}
|
|
||||||
|
|
||||||
@HostListener('keydown.esc')
|
|
||||||
cancel () {
|
|
||||||
this.confirmService.confirmResponse.next(false)
|
|
||||||
this.hideModal()
|
|
||||||
}
|
}
|
||||||
|
|
||||||
isConfirmationDisabled () {
|
isConfirmationDisabled () {
|
||||||
|
@ -70,10 +60,11 @@ export class ConfirmComponent implements OnInit {
|
||||||
|
|
||||||
showModal () {
|
showModal () {
|
||||||
this.inputValue = ''
|
this.inputValue = ''
|
||||||
this.confirmModal.show()
|
|
||||||
}
|
|
||||||
|
|
||||||
hideModal () {
|
this.openedModal = this.modalService.open(this.confirmModal)
|
||||||
this.confirmModal.hide()
|
|
||||||
|
this.openedModal.result
|
||||||
|
.then(() => this.confirmService.confirmResponse.next(true))
|
||||||
|
.catch(() => this.confirmService.confirmResponse.next(false))
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
@ -8,7 +8,6 @@ import { LoadingBarHttpClientModule } from '@ngx-loading-bar/http-client'
|
||||||
import { LoadingBarRouterModule } from '@ngx-loading-bar/router'
|
import { LoadingBarRouterModule } from '@ngx-loading-bar/router'
|
||||||
|
|
||||||
import { SimpleNotificationsModule } from 'angular2-notifications'
|
import { SimpleNotificationsModule } from 'angular2-notifications'
|
||||||
import { ModalModule } from 'ngx-bootstrap/modal'
|
|
||||||
|
|
||||||
import { AuthService } from './auth'
|
import { AuthService } from './auth'
|
||||||
import { ConfirmComponent, ConfirmService } from './confirm'
|
import { ConfirmComponent, ConfirmService } from './confirm'
|
||||||
|
@ -23,7 +22,6 @@ import { ServerService } from './server'
|
||||||
FormsModule,
|
FormsModule,
|
||||||
BrowserAnimationsModule,
|
BrowserAnimationsModule,
|
||||||
|
|
||||||
ModalModule,
|
|
||||||
SimpleNotificationsModule.forRoot(),
|
SimpleNotificationsModule.forRoot(),
|
||||||
|
|
||||||
LoadingBarHttpClientModule,
|
LoadingBarHttpClientModule,
|
||||||
|
|
|
@ -50,35 +50,29 @@
|
||||||
</form>
|
</form>
|
||||||
</div>
|
</div>
|
||||||
|
|
||||||
<div bsModal #forgotPasswordModal="bs-modal" (onShown)="onForgotPasswordModalShown()" class="modal" tabindex="-1">
|
<!--<ng-template #forgotPasswordModal (onShown)="onForgotPasswordModalShown()">-->
|
||||||
<div class="modal-dialog">
|
<ng-template #forgotPasswordModal>
|
||||||
<div class="modal-content">
|
<div class="modal-header">
|
||||||
|
<h4 i18n class="modal-title">Forgot your password</h4>
|
||||||
|
<span class="close" aria-hidden="true" (click)="hideForgotPasswordModal()"></span>
|
||||||
|
</div>
|
||||||
|
|
||||||
<div class="modal-header">
|
<div class="modal-body">
|
||||||
<span class="close" aria-hidden="true" (click)="hideForgotPasswordModal()"></span>
|
<div class="form-group">
|
||||||
<h4 i18n class="modal-title">Forgot your password</h4>
|
<label i18n for="forgot-password-email">Email</label>
|
||||||
</div>
|
<input
|
||||||
|
type="email" id="forgot-password-email" i18n-placeholder placeholder="Email address" required
|
||||||
<div class="modal-body">
|
[(ngModel)]="forgotPasswordEmail" #forgotPasswordEmailInput
|
||||||
<div class="form-group">
|
>
|
||||||
<label i18n for="forgot-password-email">Email</label>
|
|
||||||
<input
|
|
||||||
type="email" id="forgot-password-email" i18n-placeholder placeholder="Email address" required
|
|
||||||
[(ngModel)]="forgotPasswordEmail" #forgotPasswordEmailInput
|
|
||||||
>
|
|
||||||
</div>
|
|
||||||
|
|
||||||
<div class="form-group inputs">
|
|
||||||
<span i18n class="action-button action-button-cancel" (click)="hideForgotPasswordModal()">
|
|
||||||
Cancel
|
|
||||||
</span>
|
|
||||||
|
|
||||||
<input
|
|
||||||
type="submit" i18n-value value="Send me an email to reset my password" class="action-button-submit"
|
|
||||||
(click)="askResetPassword()" [disabled]="!forgotPasswordEmailInput.validity.valid"
|
|
||||||
>
|
|
||||||
</div>
|
|
||||||
</div>
|
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
</div>
|
|
||||||
|
<div class="modal-footer inputs">
|
||||||
|
<span i18n class="action-button action-button-cancel" (click)="hideForgotPasswordModal()">Cancel</span>
|
||||||
|
|
||||||
|
<input
|
||||||
|
type="submit" i18n-value value="Send me an email to reset my password" class="action-button-submit"
|
||||||
|
(click)="askResetPassword()" [disabled]="!forgotPasswordEmailInput.validity.valid"
|
||||||
|
>
|
||||||
|
</div>
|
||||||
|
</ng-template>
|
||||||
|
|
|
@ -2,12 +2,12 @@ import { Component, ElementRef, OnInit, ViewChild } from '@angular/core'
|
||||||
import { RedirectService, ServerService } from '@app/core'
|
import { RedirectService, ServerService } from '@app/core'
|
||||||
import { UserService } from '@app/shared'
|
import { UserService } from '@app/shared'
|
||||||
import { NotificationsService } from 'angular2-notifications'
|
import { NotificationsService } from 'angular2-notifications'
|
||||||
import { ModalDirective } from 'ngx-bootstrap/modal'
|
|
||||||
import { AuthService } from '../core'
|
import { AuthService } from '../core'
|
||||||
import { FormReactive } from '../shared'
|
import { FormReactive } from '../shared'
|
||||||
import { I18n } from '@ngx-translate/i18n-polyfill'
|
import { I18n } from '@ngx-translate/i18n-polyfill'
|
||||||
import { FormValidatorService } from '@app/shared/forms/form-validators/form-validator.service'
|
import { FormValidatorService } from '@app/shared/forms/form-validators/form-validator.service'
|
||||||
import { LoginValidatorsService } from '@app/shared/forms/form-validators/login-validators.service'
|
import { LoginValidatorsService } from '@app/shared/forms/form-validators/login-validators.service'
|
||||||
|
import { NgbModal, NgbModalRef } from '@ng-bootstrap/ng-bootstrap'
|
||||||
|
|
||||||
@Component({
|
@Component({
|
||||||
selector: 'my-login',
|
selector: 'my-login',
|
||||||
|
@ -16,14 +16,17 @@ import { LoginValidatorsService } from '@app/shared/forms/form-validators/login-
|
||||||
})
|
})
|
||||||
|
|
||||||
export class LoginComponent extends FormReactive implements OnInit {
|
export class LoginComponent extends FormReactive implements OnInit {
|
||||||
@ViewChild('forgotPasswordModal') forgotPasswordModal: ModalDirective
|
@ViewChild('forgotPasswordModal') forgotPasswordModal: ElementRef
|
||||||
@ViewChild('forgotPasswordEmailInput') forgotPasswordEmailInput: ElementRef
|
@ViewChild('forgotPasswordEmailInput') forgotPasswordEmailInput: ElementRef
|
||||||
|
|
||||||
error: string = null
|
error: string = null
|
||||||
forgotPasswordEmail = ''
|
forgotPasswordEmail = ''
|
||||||
|
|
||||||
|
private openedForgotPasswordModal: NgbModalRef
|
||||||
|
|
||||||
constructor (
|
constructor (
|
||||||
protected formValidatorService: FormValidatorService,
|
protected formValidatorService: FormValidatorService,
|
||||||
|
private modalService: NgbModal,
|
||||||
private loginValidatorsService: LoginValidatorsService,
|
private loginValidatorsService: LoginValidatorsService,
|
||||||
private authService: AuthService,
|
private authService: AuthService,
|
||||||
private userService: UserService,
|
private userService: UserService,
|
||||||
|
@ -84,10 +87,10 @@ export class LoginComponent extends FormReactive implements OnInit {
|
||||||
}
|
}
|
||||||
|
|
||||||
openForgotPasswordModal () {
|
openForgotPasswordModal () {
|
||||||
this.forgotPasswordModal.show()
|
this.openedForgotPasswordModal = this.modalService.open(this.forgotPasswordModal)
|
||||||
}
|
}
|
||||||
|
|
||||||
hideForgotPasswordModal () {
|
hideForgotPasswordModal () {
|
||||||
this.forgotPasswordModal.hide()
|
this.openedForgotPasswordModal.close()
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
@ -1,15 +1,10 @@
|
||||||
<div bsModal #modal="bs-modal" class="modal" tabindex="-1">
|
<ng-template #modal let-hide="close">
|
||||||
<div class="modal-dialog">
|
<div class="modal-header">
|
||||||
<div class="modal-content">
|
<h4 i18n class="modal-title">Change the language</h4>
|
||||||
|
<span class="close" aria-label="Close" role="button" (click)="hide()"></span>
|
||||||
<div class="modal-header">
|
|
||||||
<span class="close" aria-hidden="true" (click)="hide()"></span>
|
|
||||||
<h4 i18n class="modal-title">Change the language</h4>
|
|
||||||
</div>
|
|
||||||
|
|
||||||
<div class="modal-body" *ngFor="let lang of languages">
|
|
||||||
<a [href]="buildLanguageLink(lang)">{{ lang.label }}</a>
|
|
||||||
</div>
|
|
||||||
</div>
|
|
||||||
</div>
|
</div>
|
||||||
</div>
|
|
||||||
|
<div class="modal-body">
|
||||||
|
<a *ngFor="let lang of languages" [href]="buildLanguageLink(lang)">{{ lang.label }}</a>
|
||||||
|
</div>
|
||||||
|
</ng-template>
|
||||||
|
|
|
@ -1,19 +1,12 @@
|
||||||
@import '_variables';
|
@import '_variables';
|
||||||
@import '_mixins';
|
@import '_mixins';
|
||||||
|
|
||||||
.modal {
|
|
||||||
z-index: 10005;
|
|
||||||
}
|
|
||||||
|
|
||||||
.modal-title {
|
|
||||||
text-align: center;
|
|
||||||
}
|
|
||||||
|
|
||||||
.modal-body {
|
.modal-body {
|
||||||
text-align: center;
|
text-align: center;
|
||||||
|
|
||||||
a {
|
a {
|
||||||
|
display: block;
|
||||||
font-size: 16px;
|
font-size: 16px;
|
||||||
margin-top: 10px;
|
margin: 15px;
|
||||||
}
|
}
|
||||||
}
|
}
|
|
@ -1,6 +1,6 @@
|
||||||
import { Component, ViewChild } from '@angular/core'
|
import { Component, ElementRef, ViewChild } from '@angular/core'
|
||||||
import { ModalDirective } from 'ngx-bootstrap/modal'
|
|
||||||
import { I18N_LOCALES } from '../../../../shared'
|
import { I18N_LOCALES } from '../../../../shared'
|
||||||
|
import { NgbModal } from '@ng-bootstrap/ng-bootstrap'
|
||||||
|
|
||||||
@Component({
|
@Component({
|
||||||
selector: 'my-language-chooser',
|
selector: 'my-language-chooser',
|
||||||
|
@ -8,21 +8,17 @@ import { I18N_LOCALES } from '../../../../shared'
|
||||||
styleUrls: [ './language-chooser.component.scss' ]
|
styleUrls: [ './language-chooser.component.scss' ]
|
||||||
})
|
})
|
||||||
export class LanguageChooserComponent {
|
export class LanguageChooserComponent {
|
||||||
@ViewChild('modal') modal: ModalDirective
|
@ViewChild('modal') modal: ElementRef
|
||||||
|
|
||||||
languages: { [ id: string ]: string }[] = []
|
languages: { id: string, label: string }[] = []
|
||||||
|
|
||||||
constructor () {
|
constructor (private modalService: NgbModal) {
|
||||||
this.languages = Object.keys(I18N_LOCALES)
|
this.languages = Object.keys(I18N_LOCALES)
|
||||||
.map(k => ({ id: k, label: I18N_LOCALES[k] }))
|
.map(k => ({ id: k, label: I18N_LOCALES[k] }))
|
||||||
}
|
}
|
||||||
|
|
||||||
show () {
|
show () {
|
||||||
this.modal.show()
|
this.modalService.open(this.modal)
|
||||||
}
|
|
||||||
|
|
||||||
hide () {
|
|
||||||
this.modal.hide()
|
|
||||||
}
|
}
|
||||||
|
|
||||||
buildLanguageLink (lang: { id: string }) {
|
buildLanguageLink (lang: { id: string }) {
|
||||||
|
|
|
@ -11,24 +11,22 @@
|
||||||
<div class="logged-in-email">{{ user.username }}</div>
|
<div class="logged-in-email">{{ user.username }}</div>
|
||||||
</div>
|
</div>
|
||||||
|
|
||||||
<div class="logged-in-more" dropdown placement="right" container="body">
|
<div class="logged-in-more" ngbDropdown placement="bottom-right">
|
||||||
<span class="glyphicon glyphicon-option-vertical" dropdownToggle></span>
|
<span class="glyphicon glyphicon-option-vertical" ngbDropdownToggle role="button"></span>
|
||||||
|
|
||||||
<ul *dropdownMenu class="dropdown-menu">
|
<div ngbDropdownMenu>
|
||||||
<li>
|
<a *ngIf="user.account" i18n [routerLink]="[ '/accounts', user.account.nameWithHost ]" class="dropdown-item">
|
||||||
<a i18n [routerLink]="[ '/accounts', user.account?.nameWithHost ]" class="dropdown-item" title="My public profile">
|
My public profile
|
||||||
My public profile
|
</a>
|
||||||
</a>
|
|
||||||
|
|
||||||
<a i18n routerLink="/my-account" class="dropdown-item" title="My account">
|
<a i18n routerLink="/my-account" class="dropdown-item">
|
||||||
My account
|
My account
|
||||||
</a>
|
</a>
|
||||||
|
|
||||||
<a i18n (click)="logout($event)" class="dropdown-item" title="Log out" href="#">
|
<a i18n (click)="logout($event)" class="dropdown-item" href="#">
|
||||||
Log out
|
Log out
|
||||||
</a>
|
</a>
|
||||||
</li>
|
</div>
|
||||||
</ul>
|
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
|
|
||||||
|
|
|
@ -69,6 +69,10 @@ menu {
|
||||||
.glyphicon {
|
.glyphicon {
|
||||||
cursor: pointer;
|
cursor: pointer;
|
||||||
font-size: 18px;
|
font-size: 18px;
|
||||||
|
|
||||||
|
&::after {
|
||||||
|
border: none;
|
||||||
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
@ -17,7 +17,7 @@
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
|
|
||||||
<div class="results-filter" [collapse]="isSearchFilterCollapsed">
|
<div class="results-filter" [ngbCollapse]="isSearchFilterCollapsed">
|
||||||
<my-search-filters [advancedSearch]="advancedSearch" (filtered)="onFiltered()"></my-search-filters>
|
<my-search-filters [advancedSearch]="advancedSearch" (filtered)="onFiltered()"></my-search-filters>
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
|
|
|
@ -4,14 +4,14 @@ import { SearchComponent } from '@app/search/search.component'
|
||||||
import { SearchService } from '@app/search/search.service'
|
import { SearchService } from '@app/search/search.service'
|
||||||
import { SearchRoutingModule } from '@app/search/search-routing.module'
|
import { SearchRoutingModule } from '@app/search/search-routing.module'
|
||||||
import { SearchFiltersComponent } from '@app/search/search-filters.component'
|
import { SearchFiltersComponent } from '@app/search/search-filters.component'
|
||||||
import { CollapseModule } from 'ngx-bootstrap/collapse'
|
import { NgbCollapseModule } from '@ng-bootstrap/ng-bootstrap'
|
||||||
|
|
||||||
@NgModule({
|
@NgModule({
|
||||||
imports: [
|
imports: [
|
||||||
SearchRoutingModule,
|
SearchRoutingModule,
|
||||||
SharedModule,
|
SharedModule,
|
||||||
|
|
||||||
CollapseModule.forRoot()
|
NgbCollapseModule.forRoot()
|
||||||
],
|
],
|
||||||
|
|
||||||
declarations: [
|
declarations: [
|
||||||
|
|
|
@ -5,8 +5,13 @@
|
||||||
id="description" name="description">
|
id="description" name="description">
|
||||||
</textarea>
|
</textarea>
|
||||||
|
|
||||||
<tabset *ngIf="arePreviewsDisplayed()" class="previews">
|
<ngb-tabset *ngIf="arePreviewsDisplayed()" class="previews" type="pills">
|
||||||
<tab *ngIf="truncate !== undefined" i18n-heading heading="Truncated preview" [innerHTML]="truncatedPreviewHTML"></tab>
|
<ngb-tab *ngIf="truncate !== undefined" i18n-title title="Truncated preview">
|
||||||
<tab i18n-heading heading="Complete preview" [innerHTML]="previewHTML"></tab>
|
<ng-template ngbTabContent><div [innerHTML]="truncatedPreviewHTML"></div></ng-template>
|
||||||
</tabset>
|
</ngb-tab>
|
||||||
|
|
||||||
|
<ngb-tab i18n-title title="Complete preview">
|
||||||
|
<ng-template ngbTabContent><div [innerHTML]="previewHTML"></div></ng-template>
|
||||||
|
</ngb-tab>
|
||||||
|
</ngb-tabset>
|
||||||
</div>
|
</div>
|
||||||
|
|
|
@ -18,9 +18,8 @@
|
||||||
title="Get help"
|
title="Get help"
|
||||||
i18n-title
|
i18n-title
|
||||||
[attr.aria-pressed]="isPopoverOpened"
|
[attr.aria-pressed]="isPopoverOpened"
|
||||||
[popover]="tooltipTemplate"
|
[ngbPopover]="tooltipTemplate"
|
||||||
[placement]="tooltipPlacement"
|
[placement]="tooltipPlacement"
|
||||||
[outsideClick]="true"
|
|
||||||
(onHidden)="onPopoverHidden()"
|
(onHidden)="onPopoverHidden()"
|
||||||
(onShown)="onPopoverShown()"
|
(onShown)="onPopoverShown()"
|
||||||
></span>
|
></span>
|
||||||
|
|
|
@ -8,11 +8,6 @@ import { HelpComponent } from '@app/shared/misc/help.component'
|
||||||
import { InfiniteScrollerDirective } from '@app/shared/video/infinite-scroller.directive'
|
import { InfiniteScrollerDirective } from '@app/shared/video/infinite-scroller.directive'
|
||||||
import { MarkdownService } from '@app/videos/shared'
|
import { MarkdownService } from '@app/videos/shared'
|
||||||
|
|
||||||
import { BsDropdownModule } from 'ngx-bootstrap/dropdown'
|
|
||||||
import { ModalModule } from 'ngx-bootstrap/modal'
|
|
||||||
import { PopoverModule } from 'ngx-bootstrap/popover'
|
|
||||||
import { TabsModule } from 'ngx-bootstrap/tabs'
|
|
||||||
import { TooltipModule } from 'ngx-bootstrap/tooltip'
|
|
||||||
import { BytesPipe, KeysPipe, NgPipesModule } from 'ngx-pipes'
|
import { BytesPipe, KeysPipe, NgPipesModule } from 'ngx-pipes'
|
||||||
import { SharedModule as PrimeSharedModule } from 'primeng/components/common/shared'
|
import { SharedModule as PrimeSharedModule } from 'primeng/components/common/shared'
|
||||||
|
|
||||||
|
@ -53,6 +48,7 @@ import { VideoCaptionService } from '@app/shared/video-caption'
|
||||||
import { PeertubeCheckboxComponent } from '@app/shared/forms/peertube-checkbox.component'
|
import { PeertubeCheckboxComponent } from '@app/shared/forms/peertube-checkbox.component'
|
||||||
import { VideoImportService } from '@app/shared/video-import/video-import.service'
|
import { VideoImportService } from '@app/shared/video-import/video-import.service'
|
||||||
import { ActionDropdownComponent } from '@app/shared/buttons/action-dropdown.component'
|
import { ActionDropdownComponent } from '@app/shared/buttons/action-dropdown.component'
|
||||||
|
import { NgbDropdownModule, NgbModalModule, NgbPopoverModule, NgbTabsetModule, NgbTooltipModule } from '@ng-bootstrap/ng-bootstrap'
|
||||||
|
|
||||||
@NgModule({
|
@NgModule({
|
||||||
imports: [
|
imports: [
|
||||||
|
@ -62,11 +58,11 @@ import { ActionDropdownComponent } from '@app/shared/buttons/action-dropdown.com
|
||||||
RouterModule,
|
RouterModule,
|
||||||
HttpClientModule,
|
HttpClientModule,
|
||||||
|
|
||||||
BsDropdownModule.forRoot(),
|
NgbDropdownModule.forRoot(),
|
||||||
ModalModule.forRoot(),
|
NgbModalModule.forRoot(),
|
||||||
PopoverModule.forRoot(),
|
NgbPopoverModule.forRoot(),
|
||||||
TabsModule.forRoot(),
|
NgbTabsetModule.forRoot(),
|
||||||
TooltipModule.forRoot(),
|
NgbTooltipModule.forRoot(),
|
||||||
|
|
||||||
PrimeSharedModule,
|
PrimeSharedModule,
|
||||||
NgPipesModule
|
NgPipesModule
|
||||||
|
@ -97,11 +93,12 @@ import { ActionDropdownComponent } from '@app/shared/buttons/action-dropdown.com
|
||||||
RouterModule,
|
RouterModule,
|
||||||
HttpClientModule,
|
HttpClientModule,
|
||||||
|
|
||||||
BsDropdownModule,
|
NgbDropdownModule,
|
||||||
ModalModule,
|
NgbModalModule,
|
||||||
PopoverModule,
|
NgbPopoverModule,
|
||||||
TabsModule,
|
NgbTabsetModule,
|
||||||
TooltipModule,
|
NgbTooltipModule,
|
||||||
|
|
||||||
PrimeSharedModule,
|
PrimeSharedModule,
|
||||||
BytesPipe,
|
BytesPipe,
|
||||||
KeysPipe,
|
KeysPipe,
|
||||||
|
|
|
@ -1,13 +1,10 @@
|
||||||
<div class="video-feed">
|
<div class="video-feed">
|
||||||
<span *ngIf="syndicationItems.length !== 0" class="icon icon-syndication"
|
<span
|
||||||
[popover]="feedsList"
|
*ngIf="syndicationItems.length !== 0" [ngbPopover]="feedsList" placement="bottom"
|
||||||
placement="bottom"
|
class="icon icon-syndication" role="button"
|
||||||
[outsideClick]="true">
|
></span>
|
||||||
</span>
|
|
||||||
|
|
||||||
<ng-template #feedsList>
|
<ng-template #feedsList>
|
||||||
<div *ngFor="let item of syndicationItems">
|
<a *ngFor="let item of syndicationItems" [href]="item.url" target="_blank" rel="noopener noreferrer">{{ item.label }}</a>
|
||||||
<a [href]="item.url" target="_blank" rel="noopener noreferrer">{{ item.label }}</a>
|
|
||||||
</div>
|
|
||||||
</ng-template>
|
</ng-template>
|
||||||
</div>
|
</div>
|
|
@ -5,6 +5,7 @@
|
||||||
@include disable-default-a-behaviour;
|
@include disable-default-a-behaviour;
|
||||||
|
|
||||||
color: black;
|
color: black;
|
||||||
|
display: block;
|
||||||
}
|
}
|
||||||
|
|
||||||
.icon {
|
.icon {
|
||||||
|
|
|
@ -1,47 +1,45 @@
|
||||||
<div bsModal #modal="bs-modal" class="modal" tabindex="-1">
|
<ng-template #modal>
|
||||||
<div class="modal-dialog">
|
<ng-container [formGroup]="form">
|
||||||
<div class="modal-content" [formGroup]="form">
|
|
||||||
|
|
||||||
<div class="modal-header">
|
<div class="modal-header">
|
||||||
<span class="close" aria-hidden="true" (click)="hide()"></span>
|
<h4 i18n class="modal-title">Add caption</h4>
|
||||||
<h4 i18n class="modal-title">Add caption</h4>
|
<span class="close" aria-label="Close" role="button" (click)="hide()"></span>
|
||||||
|
</div>
|
||||||
|
|
||||||
|
<div class="modal-body">
|
||||||
|
<label i18n for="language">Language</label>
|
||||||
|
<div class="peertube-select-container">
|
||||||
|
<select id="language" formControlName="language">
|
||||||
|
<option></option>
|
||||||
|
<option *ngFor="let language of videoCaptionLanguages" [value]="language.id">{{ language.label }}</option>
|
||||||
|
</select>
|
||||||
</div>
|
</div>
|
||||||
|
|
||||||
<div class="modal-body">
|
<div *ngIf="formErrors.language" class="form-error">
|
||||||
<label i18n for="language">Language</label>
|
{{ formErrors.language }}
|
||||||
<div class="peertube-select-container">
|
</div>
|
||||||
<select id="language" formControlName="language">
|
|
||||||
<option></option>
|
|
||||||
<option *ngFor="let language of videoCaptionLanguages" [value]="language.id">{{ language.label }}</option>
|
|
||||||
</select>
|
|
||||||
</div>
|
|
||||||
|
|
||||||
<div *ngIf="formErrors.language" class="form-error">
|
<div class="caption-file">
|
||||||
{{ formErrors.language }}
|
<my-reactive-file
|
||||||
</div>
|
formControlName="captionfile" inputName="captionfile" i18n-inputLabel inputLabel="Select the caption file"
|
||||||
|
[extensions]="videoCaptionExtensions" [maxFileSize]="videoCaptionMaxSize" [displayFilename]="true"
|
||||||
|
></my-reactive-file>
|
||||||
|
</div>
|
||||||
|
|
||||||
<div class="caption-file">
|
<div *ngIf="isReplacingExistingCaption()" class="warning-replace-caption" i18n>
|
||||||
<my-reactive-file
|
This will replace an existing caption!
|
||||||
formControlName="captionfile" inputName="captionfile" i18n-inputLabel inputLabel="Select the caption file"
|
|
||||||
[extensions]="videoCaptionExtensions" [maxFileSize]="videoCaptionMaxSize" [displayFilename]="true"
|
|
||||||
></my-reactive-file>
|
|
||||||
</div>
|
|
||||||
|
|
||||||
<div *ngIf="isReplacingExistingCaption()" class="warning-replace-caption" i18n>
|
|
||||||
This will replace an existing caption!
|
|
||||||
</div>
|
|
||||||
|
|
||||||
<div class="form-group inputs">
|
|
||||||
<span i18n class="action-button action-button-cancel" (click)="hide()">
|
|
||||||
Cancel
|
|
||||||
</span>
|
|
||||||
|
|
||||||
<input
|
|
||||||
type="submit" i18n-value value="Add this caption" class="action-button-submit"
|
|
||||||
[disabled]="!form.valid" (click)="addCaption()"
|
|
||||||
>
|
|
||||||
</div>
|
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
</div>
|
|
||||||
</div>
|
<div class="modal-footer inputs">
|
||||||
|
<span i18n class="action-button action-button-cancel" (click)="hide()">
|
||||||
|
Cancel
|
||||||
|
</span>
|
||||||
|
|
||||||
|
<input
|
||||||
|
type="submit" i18n-value value="Add this caption" class="action-button-submit"
|
||||||
|
[disabled]="!form.valid" (click)="addCaption()"
|
||||||
|
>
|
||||||
|
</div>
|
||||||
|
</ng-container>
|
||||||
|
</ng-template>
|
||||||
|
|
|
@ -1,10 +1,10 @@
|
||||||
import { Component, EventEmitter, Input, OnInit, Output, ViewChild } from '@angular/core'
|
import { Component, ElementRef, EventEmitter, Input, OnInit, Output, ViewChild } from '@angular/core'
|
||||||
import { ModalDirective } from 'ngx-bootstrap/modal'
|
|
||||||
import { FormReactive } from '@app/shared'
|
import { FormReactive } from '@app/shared'
|
||||||
import { FormValidatorService } from '@app/shared/forms/form-validators/form-validator.service'
|
import { FormValidatorService } from '@app/shared/forms/form-validators/form-validator.service'
|
||||||
import { VideoCaptionsValidatorsService } from '@app/shared/forms/form-validators/video-captions-validators.service'
|
import { VideoCaptionsValidatorsService } from '@app/shared/forms/form-validators/video-captions-validators.service'
|
||||||
import { ServerService } from '@app/core'
|
import { ServerService } from '@app/core'
|
||||||
import { VideoCaptionEdit } from '@app/shared/video-caption/video-caption-edit.model'
|
import { VideoCaptionEdit } from '@app/shared/video-caption/video-caption-edit.model'
|
||||||
|
import { NgbModal, NgbModalRef } from '@ng-bootstrap/ng-bootstrap'
|
||||||
|
|
||||||
@Component({
|
@Component({
|
||||||
selector: 'my-video-caption-add-modal',
|
selector: 'my-video-caption-add-modal',
|
||||||
|
@ -17,14 +17,16 @@ export class VideoCaptionAddModalComponent extends FormReactive implements OnIni
|
||||||
|
|
||||||
@Output() captionAdded = new EventEmitter<VideoCaptionEdit>()
|
@Output() captionAdded = new EventEmitter<VideoCaptionEdit>()
|
||||||
|
|
||||||
@ViewChild('modal') modal: ModalDirective
|
@ViewChild('modal') modal: ElementRef
|
||||||
|
|
||||||
videoCaptionLanguages = []
|
videoCaptionLanguages = []
|
||||||
|
|
||||||
|
private openedModal: NgbModalRef
|
||||||
private closingModal = false
|
private closingModal = false
|
||||||
|
|
||||||
constructor (
|
constructor (
|
||||||
protected formValidatorService: FormValidatorService,
|
protected formValidatorService: FormValidatorService,
|
||||||
|
private modalService: NgbModal,
|
||||||
private serverService: ServerService,
|
private serverService: ServerService,
|
||||||
private videoCaptionsValidatorsService: VideoCaptionsValidatorsService
|
private videoCaptionsValidatorsService: VideoCaptionsValidatorsService
|
||||||
) {
|
) {
|
||||||
|
@ -51,13 +53,12 @@ export class VideoCaptionAddModalComponent extends FormReactive implements OnIni
|
||||||
show () {
|
show () {
|
||||||
this.closingModal = false
|
this.closingModal = false
|
||||||
|
|
||||||
this.modal.show()
|
this.openedModal = this.modalService.open(this.modal, { keyboard: false })
|
||||||
}
|
}
|
||||||
|
|
||||||
hide () {
|
hide () {
|
||||||
this.closingModal = true
|
this.closingModal = true
|
||||||
|
this.openedModal.close()
|
||||||
this.modal.hide()
|
|
||||||
}
|
}
|
||||||
|
|
||||||
isReplacingExistingCaption () {
|
isReplacingExistingCaption () {
|
||||||
|
|
|
@ -1,215 +1,223 @@
|
||||||
<div class="video-edit row" [formGroup]="form">
|
<div class="video-edit" [formGroup]="form">
|
||||||
<tabset class="root-tabset bootstrap">
|
<ngb-tabset class="root-tabset bootstrap">
|
||||||
|
|
||||||
<tab i18n-heading heading="Basic info">
|
<ngb-tab i18n-title title="Basic info">
|
||||||
<div class="col-md-8">
|
<ng-template ngbTabContent>
|
||||||
<div class="form-group">
|
<div class="row">
|
||||||
<label i18n for="name">Title</label>
|
<div class="col-md-8">
|
||||||
<input type="text" id="name" formControlName="name" />
|
<div class="form-group">
|
||||||
<div *ngIf="formErrors.name" class="form-error">
|
<label i18n for="name">Title</label>
|
||||||
{{ formErrors.name }}
|
<input type="text" id="name" formControlName="name" />
|
||||||
</div>
|
<div *ngIf="formErrors.name" class="form-error">
|
||||||
</div>
|
{{ formErrors.name }}
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
|
||||||
<div class="form-group">
|
<div class="form-group">
|
||||||
<label i18n class="label-tags">Tags</label> <span i18n>(press Enter to add)</span>
|
<label i18n class="label-tags">Tags</label> <span i18n>(press Enter to add)</span>
|
||||||
<tag-input
|
<tag-input
|
||||||
[validators]="tagValidators" [errorMessages]="tagValidatorsMessages"
|
[validators]="tagValidators" [errorMessages]="tagValidatorsMessages"
|
||||||
formControlName="tags" maxItems="5" modelAsStrings="true"
|
formControlName="tags" maxItems="5" modelAsStrings="true"
|
||||||
></tag-input>
|
></tag-input>
|
||||||
</div>
|
</div>
|
||||||
|
|
||||||
<div class="form-group">
|
<div class="form-group">
|
||||||
<label i18n for="description">Description</label>
|
<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" i18n-preHtml preHtml="Video descriptions are truncated by default and require manual action to expand them."></my-help>
|
||||||
<my-markdown-textarea truncate="250" formControlName="description"></my-markdown-textarea>
|
<my-markdown-textarea truncate="250" formControlName="description"></my-markdown-textarea>
|
||||||
|
|
||||||
<div *ngIf="formErrors.description" class="form-error">
|
<div *ngIf="formErrors.description" class="form-error">
|
||||||
{{ formErrors.description }}
|
{{ formErrors.description }}
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
</div>
|
|
||||||
|
|
||||||
<div class="col-md-4">
|
|
||||||
<div class="form-group">
|
|
||||||
<label i18n>Channel</label>
|
|
||||||
<div class="peertube-select-container">
|
|
||||||
<select formControlName="channelId">
|
|
||||||
<option *ngFor="let channel of userVideoChannels" [value]="channel.id">{{ channel.label }}</option>
|
|
||||||
</select>
|
|
||||||
</div>
|
|
||||||
</div>
|
|
||||||
|
|
||||||
<div class="form-group">
|
|
||||||
<label i18n for="category">Category</label>
|
|
||||||
<div class="peertube-select-container">
|
|
||||||
<select id="category" formControlName="category">
|
|
||||||
<option></option>
|
|
||||||
<option *ngFor="let category of videoCategories" [value]="category.id">{{ category.label }}</option>
|
|
||||||
</select>
|
|
||||||
</div>
|
</div>
|
||||||
|
|
||||||
<div *ngIf="formErrors.category" class="form-error">
|
<div class="col-md-4">
|
||||||
{{ formErrors.category }}
|
<div class="form-group">
|
||||||
|
<label i18n>Channel</label>
|
||||||
|
<div class="peertube-select-container">
|
||||||
|
<select formControlName="channelId">
|
||||||
|
<option *ngFor="let channel of userVideoChannels" [value]="channel.id">{{ channel.label }}</option>
|
||||||
|
</select>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
|
||||||
|
<div class="form-group">
|
||||||
|
<label i18n for="category">Category</label>
|
||||||
|
<div class="peertube-select-container">
|
||||||
|
<select id="category" formControlName="category">
|
||||||
|
<option></option>
|
||||||
|
<option *ngFor="let category of videoCategories" [value]="category.id">{{ category.label }}</option>
|
||||||
|
</select>
|
||||||
|
</div>
|
||||||
|
|
||||||
|
<div *ngIf="formErrors.category" class="form-error">
|
||||||
|
{{ formErrors.category }}
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
|
||||||
|
<div class="form-group">
|
||||||
|
<label i18n for="licence">Licence</label>
|
||||||
|
<div class="peertube-select-container">
|
||||||
|
<select id="licence" formControlName="licence">
|
||||||
|
<option></option>
|
||||||
|
<option *ngFor="let licence of videoLicences" [value]="licence.id">{{ licence.label }}</option>
|
||||||
|
</select>
|
||||||
|
</div>
|
||||||
|
|
||||||
|
<div *ngIf="formErrors.licence" class="form-error">
|
||||||
|
{{ formErrors.licence }}
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
|
||||||
|
<div class="form-group">
|
||||||
|
<label i18n for="language">Language</label>
|
||||||
|
<div class="peertube-select-container">
|
||||||
|
<select id="language" formControlName="language">
|
||||||
|
<option></option>
|
||||||
|
<option *ngFor="let language of videoLanguages" [value]="language.id">{{ language.label }}</option>
|
||||||
|
</select>
|
||||||
|
</div>
|
||||||
|
|
||||||
|
<div *ngIf="formErrors.language" class="form-error">
|
||||||
|
{{ formErrors.language }}
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
|
||||||
|
<div class="form-group">
|
||||||
|
<label i18n for="privacy">Privacy</label>
|
||||||
|
<div class="peertube-select-container">
|
||||||
|
<select id="privacy" formControlName="privacy">
|
||||||
|
<option></option>
|
||||||
|
<option *ngFor="let privacy of videoPrivacies" [value]="privacy.id">{{ privacy.label }}</option>
|
||||||
|
<option *ngIf="schedulePublicationPossible" [value]="SPECIAL_SCHEDULED_PRIVACY">Scheduled</option>
|
||||||
|
</select>
|
||||||
|
</div>
|
||||||
|
|
||||||
|
<div *ngIf="formErrors.privacy" class="form-error">
|
||||||
|
{{ formErrors.privacy }}
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
|
||||||
|
<div *ngIf="schedulePublicationEnabled" class="form-group">
|
||||||
|
<label i18n for="schedulePublicationAt">Schedule publication ({{ calendarTimezone }})</label>
|
||||||
|
<p-calendar
|
||||||
|
id="schedulePublicationAt" formControlName="schedulePublicationAt" [dateFormat]="calendarDateFormat"
|
||||||
|
[locale]="calendarLocale" [minDate]="minScheduledDate" [showTime]="true" [hideOnDateTimeSelect]="true"
|
||||||
|
>
|
||||||
|
</p-calendar>
|
||||||
|
|
||||||
|
<div *ngIf="formErrors.schedulePublicationAt" class="form-error">
|
||||||
|
{{ formErrors.schedulePublicationAt }}
|
||||||
|
</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."
|
||||||
|
></my-peertube-checkbox>
|
||||||
|
|
||||||
|
<my-peertube-checkbox
|
||||||
|
inputName="commentsEnabled" formControlName="commentsEnabled"
|
||||||
|
i18n-labelText labelText="Enable video comments"
|
||||||
|
></my-peertube-checkbox>
|
||||||
|
|
||||||
|
<my-peertube-checkbox
|
||||||
|
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."
|
||||||
|
></my-peertube-checkbox>
|
||||||
|
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
|
</ng-template>
|
||||||
|
</ngb-tab>
|
||||||
|
|
||||||
<div class="form-group">
|
<ngb-tab i18n-title title="Captions">
|
||||||
<label i18n for="licence">Licence</label>
|
<ng-template ngbTabContent>
|
||||||
<div class="peertube-select-container">
|
<div class="captions">
|
||||||
<select id="licence" formControlName="licence">
|
|
||||||
<option></option>
|
<div class="captions-header">
|
||||||
<option *ngFor="let licence of videoLicences" [value]="licence.id">{{ licence.label }}</option>
|
<a (click)="openAddCaptionModal()" class="create-caption">
|
||||||
</select>
|
<span class="icon icon-add"></span>
|
||||||
|
<ng-container i18n>Add another caption</ng-container>
|
||||||
|
</a>
|
||||||
</div>
|
</div>
|
||||||
|
|
||||||
<div *ngIf="formErrors.licence" class="form-error">
|
<div class="form-group" *ngFor="let videoCaption of videoCaptions">
|
||||||
{{ formErrors.licence }}
|
|
||||||
</div>
|
|
||||||
</div>
|
|
||||||
|
|
||||||
<div class="form-group">
|
<div class="caption-entry">
|
||||||
<label i18n for="language">Language</label>
|
<ng-container *ngIf="!videoCaption.action">
|
||||||
<div class="peertube-select-container">
|
<a
|
||||||
<select id="language" formControlName="language">
|
i18n-title title="See the subtitle file" class="caption-entry-label" target="_blank" rel="noopener noreferrer"
|
||||||
<option></option>
|
[href]="videoCaption.captionPath"
|
||||||
<option *ngFor="let language of videoLanguages" [value]="language.id">{{ language.label }}</option>
|
>{{ videoCaption.language.label }}</a>
|
||||||
</select>
|
|
||||||
|
<div class="caption-entry-state">Already uploaded ✔</div>
|
||||||
|
|
||||||
|
<span i18n class="caption-entry-delete" (click)="deleteCaption(videoCaption)">Delete</span>
|
||||||
|
</ng-container>
|
||||||
|
|
||||||
|
<ng-container *ngIf="videoCaption.action === 'CREATE'">
|
||||||
|
<span class="caption-entry-label">{{ videoCaption.language.label }}</span>
|
||||||
|
|
||||||
|
<div class="caption-entry-state caption-entry-state-create">Will be created on update</div>
|
||||||
|
|
||||||
|
<span i18n class="caption-entry-delete" (click)="deleteCaption(videoCaption)">Cancel create</span>
|
||||||
|
</ng-container>
|
||||||
|
|
||||||
|
<ng-container *ngIf="videoCaption.action === 'REMOVE'">
|
||||||
|
<span class="caption-entry-label">{{ videoCaption.language.label }}</span>
|
||||||
|
|
||||||
|
<div class="caption-entry-state caption-entry-state-delete">Will be deleted on update</div>
|
||||||
|
|
||||||
|
<span i18n class="caption-entry-delete" (click)="deleteCaption(videoCaption)">Cancel deletion</span>
|
||||||
|
</ng-container>
|
||||||
|
</div>
|
||||||
</div>
|
</div>
|
||||||
|
|
||||||
<div *ngIf="formErrors.language" class="form-error">
|
<div class="no-caption" *ngIf="videoCaptions?.length === 0">
|
||||||
{{ formErrors.language }}
|
No captions for now.
|
||||||
</div>
|
|
||||||
</div>
|
|
||||||
|
|
||||||
<div class="form-group">
|
|
||||||
<label i18n for="privacy">Privacy</label>
|
|
||||||
<div class="peertube-select-container">
|
|
||||||
<select id="privacy" formControlName="privacy">
|
|
||||||
<option></option>
|
|
||||||
<option *ngFor="let privacy of videoPrivacies" [value]="privacy.id">{{ privacy.label }}</option>
|
|
||||||
<option *ngIf="schedulePublicationPossible" [value]="SPECIAL_SCHEDULED_PRIVACY">Scheduled</option>
|
|
||||||
</select>
|
|
||||||
</div>
|
</div>
|
||||||
|
|
||||||
<div *ngIf="formErrors.privacy" class="form-error">
|
</div>
|
||||||
{{ formErrors.privacy }}
|
</ng-template>
|
||||||
|
</ngb-tab>
|
||||||
|
|
||||||
|
<ngb-tab i18n-title title="Advanced settings">
|
||||||
|
<ng-template ngbTabContent>
|
||||||
|
<div class="advanced-settings">
|
||||||
|
<div class="form-group">
|
||||||
|
<my-video-image
|
||||||
|
i18n-inputLabel inputLabel="Upload thumbnail" inputName="thumbnailfile" formControlName="thumbnailfile"
|
||||||
|
previewWidth="200px" previewHeight="110px"
|
||||||
|
></my-video-image>
|
||||||
|
</div>
|
||||||
|
|
||||||
|
<div class="form-group">
|
||||||
|
<my-video-image
|
||||||
|
i18n-inputLabel inputLabel="Upload preview" inputName="previewfile" formControlName="previewfile"
|
||||||
|
previewWidth="360px" previewHeight="200px"
|
||||||
|
></my-video-image>
|
||||||
|
</div>
|
||||||
|
|
||||||
|
<div class="form-group">
|
||||||
|
<label i18n for="support">Support</label>
|
||||||
|
<my-help helpType="markdownEnhanced" i18n-preHtml preHtml="Short text to tell people how they can support you (membership platform...)."></my-help>
|
||||||
|
<my-markdown-textarea
|
||||||
|
id="support" formControlName="support" textareaWidth="500px" [previewColumn]="true" markdownType="enhanced"
|
||||||
|
[classes]="{ 'input-error': formErrors['support'] }"
|
||||||
|
></my-markdown-textarea>
|
||||||
|
<div *ngIf="formErrors.support" class="form-error">
|
||||||
|
{{ formErrors.support }}
|
||||||
|
</div>
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
|
</ng-template>
|
||||||
|
</ngb-tab>
|
||||||
|
|
||||||
<div *ngIf="schedulePublicationEnabled" class="form-group">
|
</ngb-tabset>
|
||||||
<label i18n for="schedulePublicationAt">Schedule publication ({{ calendarTimezone }})</label>
|
|
||||||
<p-calendar
|
|
||||||
id="schedulePublicationAt" formControlName="schedulePublicationAt" [dateFormat]="calendarDateFormat"
|
|
||||||
[locale]="calendarLocale" [minDate]="minScheduledDate" [showTime]="true" [hideOnDateTimeSelect]="true"
|
|
||||||
>
|
|
||||||
</p-calendar>
|
|
||||||
|
|
||||||
<div *ngIf="formErrors.schedulePublicationAt" class="form-error">
|
|
||||||
{{ formErrors.schedulePublicationAt }}
|
|
||||||
</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."
|
|
||||||
></my-peertube-checkbox>
|
|
||||||
|
|
||||||
<my-peertube-checkbox
|
|
||||||
inputName="commentsEnabled" formControlName="commentsEnabled"
|
|
||||||
i18n-labelText labelText="Enable video comments"
|
|
||||||
></my-peertube-checkbox>
|
|
||||||
|
|
||||||
<my-peertube-checkbox
|
|
||||||
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."
|
|
||||||
></my-peertube-checkbox>
|
|
||||||
|
|
||||||
</div>
|
|
||||||
</tab>
|
|
||||||
|
|
||||||
<tab i18n-heading heading="Captions">
|
|
||||||
<div class="col-md-12 captions">
|
|
||||||
|
|
||||||
<div class="captions-header">
|
|
||||||
<a (click)="openAddCaptionModal()" class="create-caption">
|
|
||||||
<span class="icon icon-add"></span>
|
|
||||||
<ng-container i18n>Add another caption</ng-container>
|
|
||||||
</a>
|
|
||||||
</div>
|
|
||||||
|
|
||||||
<div class="form-group" *ngFor="let videoCaption of videoCaptions">
|
|
||||||
|
|
||||||
<div class="caption-entry">
|
|
||||||
<ng-container *ngIf="!videoCaption.action">
|
|
||||||
<a
|
|
||||||
i18n-title title="See the subtitle file" class="caption-entry-label" target="_blank" rel="noopener noreferrer"
|
|
||||||
[href]="videoCaption.captionPath"
|
|
||||||
>{{ videoCaption.language.label }}</a>
|
|
||||||
|
|
||||||
<div class="caption-entry-state">Already uploaded ✔</div>
|
|
||||||
|
|
||||||
<span i18n class="caption-entry-delete" (click)="deleteCaption(videoCaption)">Delete</span>
|
|
||||||
</ng-container>
|
|
||||||
|
|
||||||
<ng-container *ngIf="videoCaption.action === 'CREATE'">
|
|
||||||
<span class="caption-entry-label">{{ videoCaption.language.label }}</span>
|
|
||||||
|
|
||||||
<div class="caption-entry-state caption-entry-state-create">Will be created on update</div>
|
|
||||||
|
|
||||||
<span i18n class="caption-entry-delete" (click)="deleteCaption(videoCaption)">Cancel create</span>
|
|
||||||
</ng-container>
|
|
||||||
|
|
||||||
<ng-container *ngIf="videoCaption.action === 'REMOVE'">
|
|
||||||
<span class="caption-entry-label">{{ videoCaption.language.label }}</span>
|
|
||||||
|
|
||||||
<div class="caption-entry-state caption-entry-state-delete">Will be deleted on update</div>
|
|
||||||
|
|
||||||
<span i18n class="caption-entry-delete" (click)="deleteCaption(videoCaption)">Cancel deletion</span>
|
|
||||||
</ng-container>
|
|
||||||
</div>
|
|
||||||
</div>
|
|
||||||
|
|
||||||
<div class="no-caption" *ngIf="videoCaptions?.length === 0">
|
|
||||||
No captions for now.
|
|
||||||
</div>
|
|
||||||
|
|
||||||
</div>
|
|
||||||
</tab>
|
|
||||||
|
|
||||||
<tab i18n-heading heading="Advanced settings">
|
|
||||||
<div class="col-md-12 advanced-settings">
|
|
||||||
<div class="form-group">
|
|
||||||
<my-video-image
|
|
||||||
i18n-inputLabel inputLabel="Upload thumbnail" inputName="thumbnailfile" formControlName="thumbnailfile"
|
|
||||||
previewWidth="200px" previewHeight="110px"
|
|
||||||
></my-video-image>
|
|
||||||
</div>
|
|
||||||
|
|
||||||
<div class="form-group">
|
|
||||||
<my-video-image
|
|
||||||
i18n-inputLabel inputLabel="Upload preview" inputName="previewfile" formControlName="previewfile"
|
|
||||||
previewWidth="360px" previewHeight="200px"
|
|
||||||
></my-video-image>
|
|
||||||
</div>
|
|
||||||
|
|
||||||
<div class="form-group">
|
|
||||||
<label i18n for="support">Support</label>
|
|
||||||
<my-help helpType="markdownEnhanced" i18n-preHtml preHtml="Short text to tell people how they can support you (membership platform...)."></my-help>
|
|
||||||
<my-markdown-textarea
|
|
||||||
id="support" formControlName="support" textareaWidth="500px" [previewColumn]="true" markdownType="enhanced"
|
|
||||||
[classes]="{ 'input-error': formErrors['support'] }"
|
|
||||||
></my-markdown-textarea>
|
|
||||||
<div *ngIf="formErrors.support" class="form-error">
|
|
||||||
{{ formErrors.support }}
|
|
||||||
</div>
|
|
||||||
</div>
|
|
||||||
</div>
|
|
||||||
</tab>
|
|
||||||
|
|
||||||
</tabset>
|
|
||||||
|
|
||||||
</div>
|
</div>
|
||||||
|
|
||||||
|
|
|
@ -111,6 +111,8 @@
|
||||||
border: none;
|
border: none;
|
||||||
padding: 0;
|
padding: 0;
|
||||||
outline: 0;
|
outline: 0;
|
||||||
|
color: inherit;
|
||||||
|
font-weight: $font-semibold;
|
||||||
}
|
}
|
||||||
|
|
||||||
.icon.icon-validate {
|
.icon.icon-validate {
|
||||||
|
@ -143,15 +145,7 @@ p-calendar {
|
||||||
|
|
||||||
/deep/ {
|
/deep/ {
|
||||||
.root-tabset > .nav {
|
.root-tabset > .nav {
|
||||||
margin-left: 15px;
|
|
||||||
margin-bottom: 15px;
|
margin-bottom: 15px;
|
||||||
|
|
||||||
.nav-link {
|
|
||||||
display: flex !important;
|
|
||||||
align-items: center;
|
|
||||||
height: 30px !important;
|
|
||||||
padding: 0 15px !important;
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
.ng2-tag-input {
|
.ng2-tag-input {
|
||||||
|
|
|
@ -1,5 +1,4 @@
|
||||||
import { NgModule } from '@angular/core'
|
import { NgModule } from '@angular/core'
|
||||||
import { TabsModule } from 'ngx-bootstrap/tabs'
|
|
||||||
import { TagInputModule } from 'ngx-chips'
|
import { TagInputModule } from 'ngx-chips'
|
||||||
import { SharedModule } from '../../../shared/'
|
import { SharedModule } from '../../../shared/'
|
||||||
import { VideoEditComponent } from './video-edit.component'
|
import { VideoEditComponent } from './video-edit.component'
|
||||||
|
@ -23,7 +22,6 @@ import { VideoCaptionAddModalComponent } from './video-caption-add-modal.compone
|
||||||
|
|
||||||
exports: [
|
exports: [
|
||||||
TagInputModule,
|
TagInputModule,
|
||||||
TabsModule,
|
|
||||||
CalendarModule,
|
CalendarModule,
|
||||||
|
|
||||||
VideoEditComponent
|
VideoEditComponent
|
||||||
|
|
|
@ -1,47 +1,42 @@
|
||||||
<div bsModal #modal="bs-modal" class="modal" tabindex="-1">
|
<ng-template #modal let-hide="close">
|
||||||
<div class="modal-dialog">
|
<div class="modal-header">
|
||||||
<div class="modal-content">
|
<h4 i18n class="modal-title">Download video</h4>
|
||||||
|
<span class="close" aria-hidden="true" (click)="hide()"></span>
|
||||||
|
</div>
|
||||||
|
|
||||||
<div class="modal-header">
|
<div class="modal-body">
|
||||||
<span class="close" aria-hidden="true" (click)="hide()"></span>
|
<div class="peertube-select-container">
|
||||||
<h4 i18n class="modal-title">Download video</h4>
|
<select [(ngModel)]="resolutionId">
|
||||||
|
<option *ngFor="let file of video.files" [value]="file.resolution.id">{{ file.resolution.label }}</option>
|
||||||
|
</select>
|
||||||
|
</div>
|
||||||
|
|
||||||
|
<div class="download-type">
|
||||||
|
<div class="peertube-radio-container">
|
||||||
|
<input type="radio" name="download" id="download-direct" [(ngModel)]="downloadType" value="direct">
|
||||||
|
<label i18n for="download-direct">Direct download</label>
|
||||||
</div>
|
</div>
|
||||||
|
|
||||||
<div class="modal-body">
|
<div class="peertube-radio-container">
|
||||||
<div class="peertube-select-container">
|
<input type="radio" name="download" id="download-torrent" [(ngModel)]="downloadType" value="torrent">
|
||||||
<select [(ngModel)]="resolutionId">
|
<label i18n for="download-torrent">Torrent (.torrent file)</label>
|
||||||
<option *ngFor="let file of video.files" [value]="file.resolution.id">{{ file.resolution.label }}</option>
|
</div>
|
||||||
</select>
|
|
||||||
</div>
|
|
||||||
|
|
||||||
<div class="download-type">
|
<div class="peertube-radio-container">
|
||||||
<div class="peertube-radio-container">
|
<input type="radio" name="download" id="download-magnet" [(ngModel)]="downloadType" value="magnet">
|
||||||
<input type="radio" name="download" id="download-direct" [(ngModel)]="downloadType" value="direct">
|
<label i18n for="download-magnet">Torrent (magnet link)</label>
|
||||||
<label i18n for="download-direct">Direct download</label>
|
|
||||||
</div>
|
|
||||||
|
|
||||||
<div class="peertube-radio-container">
|
|
||||||
<input type="radio" name="download" id="download-torrent" [(ngModel)]="downloadType" value="torrent">
|
|
||||||
<label i18n for="download-torrent">Torrent (.torrent file)</label>
|
|
||||||
</div>
|
|
||||||
|
|
||||||
<div class="peertube-radio-container">
|
|
||||||
<input type="radio" name="download" id="download-magnet" [(ngModel)]="downloadType" value="magnet">
|
|
||||||
<label i18n for="download-magnet">Torrent (magnet link)</label>
|
|
||||||
</div>
|
|
||||||
</div>
|
|
||||||
|
|
||||||
<div class="form-group inputs">
|
|
||||||
<span i18n class="action-button action-button-cancel" (click)="hide()">
|
|
||||||
Cancel
|
|
||||||
</span>
|
|
||||||
|
|
||||||
<input
|
|
||||||
type="submit" i18n-value value="Download" class="action-button-submit"
|
|
||||||
(click)="download()"
|
|
||||||
>
|
|
||||||
</div>
|
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
</div>
|
|
||||||
|
<div class="modal-footer inputs">
|
||||||
|
<span i18n class="action-button action-button-cancel" (click)="hide()">
|
||||||
|
Cancel
|
||||||
|
</span>
|
||||||
|
|
||||||
|
<input
|
||||||
|
type="submit" i18n-value value="Download" class="action-button-submit"
|
||||||
|
(click)="download()"
|
||||||
|
>
|
||||||
|
</div>
|
||||||
|
</ng-template>
|
||||||
|
|
|
@ -1,6 +1,6 @@
|
||||||
import { Component, Input, OnInit, ViewChild } from '@angular/core'
|
import { Component, ElementRef, Input, OnInit, ViewChild } from '@angular/core'
|
||||||
import { ModalDirective } from 'ngx-bootstrap/modal'
|
|
||||||
import { VideoDetails } from '../../../shared/video/video-details.model'
|
import { VideoDetails } from '../../../shared/video/video-details.model'
|
||||||
|
import { NgbModal } from '@ng-bootstrap/ng-bootstrap'
|
||||||
|
|
||||||
@Component({
|
@Component({
|
||||||
selector: 'my-video-download',
|
selector: 'my-video-download',
|
||||||
|
@ -10,12 +10,12 @@ import { VideoDetails } from '../../../shared/video/video-details.model'
|
||||||
export class VideoDownloadComponent implements OnInit {
|
export class VideoDownloadComponent implements OnInit {
|
||||||
@Input() video: VideoDetails = null
|
@Input() video: VideoDetails = null
|
||||||
|
|
||||||
@ViewChild('modal') modal: ModalDirective
|
@ViewChild('modal') modal: ElementRef
|
||||||
|
|
||||||
downloadType: 'direct' | 'torrent' | 'magnet' = 'torrent'
|
downloadType: 'direct' | 'torrent' | 'magnet' = 'torrent'
|
||||||
resolutionId: number | string = -1
|
resolutionId: number | string = -1
|
||||||
|
|
||||||
constructor () {
|
constructor (private modalService: NgbModal) {
|
||||||
// empty
|
// empty
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -24,11 +24,7 @@ export class VideoDownloadComponent implements OnInit {
|
||||||
}
|
}
|
||||||
|
|
||||||
show () {
|
show () {
|
||||||
this.modal.show()
|
this.modalService.open(this.modal)
|
||||||
}
|
|
||||||
|
|
||||||
hide () {
|
|
||||||
this.modal.hide()
|
|
||||||
}
|
}
|
||||||
|
|
||||||
download () {
|
download () {
|
||||||
|
|
|
@ -1,36 +1,31 @@
|
||||||
<div bsModal #modal="bs-modal" class="modal" tabindex="-1">
|
<ng-template #modal>
|
||||||
<div class="modal-dialog">
|
<div class="modal-header">
|
||||||
<div class="modal-content">
|
<h4 i18n class="modal-title">Report video</h4>
|
||||||
|
<span class="close" aria-label="Close" role="button" (click)="hide()"></span>
|
||||||
<div class="modal-header">
|
|
||||||
<span class="close" aria-hidden="true" (click)="hide()"></span>
|
|
||||||
<h4 i18n class="modal-title">Report video</h4>
|
|
||||||
</div>
|
|
||||||
|
|
||||||
<div class="modal-body">
|
|
||||||
|
|
||||||
<form novalidate [formGroup]="form" (ngSubmit)="report()">
|
|
||||||
<div class="form-group">
|
|
||||||
<textarea i18n-placeholder placeholder="Reason..." formControlName="reason" [ngClass]="{ 'input-error': formErrors['reason'] }">
|
|
||||||
</textarea>
|
|
||||||
<div *ngIf="formErrors.reason" class="form-error">
|
|
||||||
{{ formErrors.reason }}
|
|
||||||
</div>
|
|
||||||
</div>
|
|
||||||
|
|
||||||
<div class="form-group inputs">
|
|
||||||
<span i18n class="action-button action-button-cancel" (click)="hide()">
|
|
||||||
Cancel
|
|
||||||
</span>
|
|
||||||
|
|
||||||
<input
|
|
||||||
type="submit" i18n-value value="Submit" class="action-button-submit"
|
|
||||||
[disabled]="!form.valid"
|
|
||||||
>
|
|
||||||
</div>
|
|
||||||
</form>
|
|
||||||
|
|
||||||
</div>
|
|
||||||
</div>
|
|
||||||
</div>
|
</div>
|
||||||
</div>
|
|
||||||
|
<div class="modal-body">
|
||||||
|
|
||||||
|
<form novalidate [formGroup]="form" (ngSubmit)="report()">
|
||||||
|
<div class="form-group">
|
||||||
|
<textarea i18n-placeholder placeholder="Reason..." formControlName="reason" [ngClass]="{ 'input-error': formErrors['reason'] }">
|
||||||
|
</textarea>
|
||||||
|
<div *ngIf="formErrors.reason" class="form-error">
|
||||||
|
{{ formErrors.reason }}
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
|
||||||
|
<div class="form-group inputs">
|
||||||
|
<span i18n class="action-button action-button-cancel" (click)="hide()">
|
||||||
|
Cancel
|
||||||
|
</span>
|
||||||
|
|
||||||
|
<input
|
||||||
|
type="submit" i18n-value value="Submit" class="action-button-submit"
|
||||||
|
[disabled]="!form.valid"
|
||||||
|
>
|
||||||
|
</div>
|
||||||
|
</form>
|
||||||
|
|
||||||
|
</div>
|
||||||
|
</ng-template>
|
||||||
|
|
|
@ -1,11 +1,12 @@
|
||||||
import { Component, Input, OnInit, ViewChild } from '@angular/core'
|
import { Component, Input, OnInit, ViewChild } from '@angular/core'
|
||||||
import { NotificationsService } from 'angular2-notifications'
|
import { NotificationsService } from 'angular2-notifications'
|
||||||
import { ModalDirective } from 'ngx-bootstrap/modal'
|
|
||||||
import { FormReactive, VideoAbuseService } from '../../../shared/index'
|
import { FormReactive, VideoAbuseService } from '../../../shared/index'
|
||||||
import { VideoDetails } from '../../../shared/video/video-details.model'
|
import { VideoDetails } from '../../../shared/video/video-details.model'
|
||||||
import { I18n } from '@ngx-translate/i18n-polyfill'
|
import { I18n } from '@ngx-translate/i18n-polyfill'
|
||||||
import { FormValidatorService } from '@app/shared/forms/form-validators/form-validator.service'
|
import { FormValidatorService } from '@app/shared/forms/form-validators/form-validator.service'
|
||||||
import { VideoAbuseValidatorsService } from '@app/shared/forms/form-validators/video-abuse-validators.service'
|
import { VideoAbuseValidatorsService } from '@app/shared/forms/form-validators/video-abuse-validators.service'
|
||||||
|
import { NgbModal } from '@ng-bootstrap/ng-bootstrap'
|
||||||
|
import { NgbModalRef } from '@ng-bootstrap/ng-bootstrap/modal/modal-ref'
|
||||||
|
|
||||||
@Component({
|
@Component({
|
||||||
selector: 'my-video-report',
|
selector: 'my-video-report',
|
||||||
|
@ -15,12 +16,15 @@ import { VideoAbuseValidatorsService } from '@app/shared/forms/form-validators/v
|
||||||
export class VideoReportComponent extends FormReactive implements OnInit {
|
export class VideoReportComponent extends FormReactive implements OnInit {
|
||||||
@Input() video: VideoDetails = null
|
@Input() video: VideoDetails = null
|
||||||
|
|
||||||
@ViewChild('modal') modal: ModalDirective
|
@ViewChild('modal') modal: NgbModal
|
||||||
|
|
||||||
error: string = null
|
error: string = null
|
||||||
|
|
||||||
|
private openedModal: NgbModalRef
|
||||||
|
|
||||||
constructor (
|
constructor (
|
||||||
protected formValidatorService: FormValidatorService,
|
protected formValidatorService: FormValidatorService,
|
||||||
|
private modalService: NgbModal,
|
||||||
private videoAbuseValidatorsService: VideoAbuseValidatorsService,
|
private videoAbuseValidatorsService: VideoAbuseValidatorsService,
|
||||||
private videoAbuseService: VideoAbuseService,
|
private videoAbuseService: VideoAbuseService,
|
||||||
private notificationsService: NotificationsService,
|
private notificationsService: NotificationsService,
|
||||||
|
@ -36,11 +40,12 @@ export class VideoReportComponent extends FormReactive implements OnInit {
|
||||||
}
|
}
|
||||||
|
|
||||||
show () {
|
show () {
|
||||||
this.modal.show()
|
this.openedModal = this.modalService.open(this.modal, { keyboard: false })
|
||||||
}
|
}
|
||||||
|
|
||||||
hide () {
|
hide () {
|
||||||
this.modal.hide()
|
this.openedModal.close()
|
||||||
|
this.openedModal = null
|
||||||
}
|
}
|
||||||
|
|
||||||
report () {
|
report () {
|
||||||
|
|
|
@ -1,52 +1,46 @@
|
||||||
<div bsModal #modal="bs-modal" class="modal" tabindex="-1">
|
<ng-template #modal let-hide="close">
|
||||||
<div class="modal-dialog">
|
<div class="modal-header">
|
||||||
<div class="modal-content">
|
<h4 i18n class="modal-title">Share</h4>
|
||||||
|
<span class="close" aria-hidden="true" (click)="hide()"></span>
|
||||||
|
</div>
|
||||||
|
|
||||||
<div class="modal-header">
|
<div class="modal-body">
|
||||||
<span class="close" aria-hidden="true" (click)="hide()"></span>
|
<div class="form-group">
|
||||||
<h4 i18n class="modal-title">Share</h4>
|
<label i18n>URL</label>
|
||||||
</div>
|
<div class="input-group input-group-sm">
|
||||||
|
<input #urlInput (click)="urlInput.select()" type="text" class="form-control input-sm readonly" readonly [value]="getVideoUrl()" />
|
||||||
<div class="modal-body">
|
<div class="input-group-append">
|
||||||
<div class="form-group">
|
<button [ngxClipboard]="urlInput" (click)="activateCopiedMessage()" type="button" class="btn btn-outline-secondary">
|
||||||
<label i18n>URL</label>
|
<span class="glyphicon glyphicon-copy"></span>
|
||||||
<div class="input-group input-group-sm">
|
</button>
|
||||||
<input #urlInput (click)="urlInput.select()" type="text" class="form-control input-sm readonly" readonly [value]="getVideoUrl()" />
|
|
||||||
<div class="input-group-btn" placement="bottom right">
|
|
||||||
<button [ngxClipboard]="urlInput" (click)="activateCopiedMessage()" type="button" class="btn btn-default btn-search">
|
|
||||||
<span class="glyphicon glyphicon-copy"></span>
|
|
||||||
</button>
|
|
||||||
</div>
|
|
||||||
</div>
|
|
||||||
</div>
|
|
||||||
|
|
||||||
<div class="form-group">
|
|
||||||
<label i18n>Embed</label>
|
|
||||||
<div class="input-group input-group-sm">
|
|
||||||
<input #shareInput (click)="shareInput.select()" type="text" class="form-control input-sm readonly" readonly [value]="getVideoIframeCode()" />
|
|
||||||
<div class="input-group-btn" placement="bottom right">
|
|
||||||
<button [ngxClipboard]="shareInput" (click)="activateCopiedMessage()" type="button" class="btn btn-default btn-search">
|
|
||||||
<span class="glyphicon glyphicon-copy"></span>
|
|
||||||
</button>
|
|
||||||
</div>
|
|
||||||
</div>
|
|
||||||
</div>
|
|
||||||
|
|
||||||
<div i18n *ngIf="notSecure()" class="alert alert-warning">
|
|
||||||
The url is not secured (no HTTPS), so the embed video won't work on HTTPS websites (web browsers block non secured HTTP requests on HTTPS websites).
|
|
||||||
</div>
|
|
||||||
|
|
||||||
<div class="form-group qr-code-group">
|
|
||||||
<label i18n>QR-Code</label>
|
|
||||||
<ngx-qrcode qrc-element-type="url" [qrc-value]="getVideoUrl()" qrc-errorCorrectionLevel="Q"></ngx-qrcode>
|
|
||||||
</div>
|
|
||||||
|
|
||||||
<div class="form-group inputs">
|
|
||||||
<span i18n class="action-button action-button-cancel" (click)="hide()">
|
|
||||||
Cancel
|
|
||||||
</span>
|
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
|
|
||||||
|
<div class="form-group">
|
||||||
|
<label i18n>Embed</label>
|
||||||
|
<div class="input-group input-group-sm">
|
||||||
|
<input #shareInput (click)="shareInput.select()" type="text" class="form-control input-sm readonly" readonly [value]="getVideoIframeCode()" />
|
||||||
|
<div class="input-group-append">
|
||||||
|
<button [ngxClipboard]="shareInput" (click)="activateCopiedMessage()" type="button" class="btn btn-outline-secondary">
|
||||||
|
<span class="glyphicon glyphicon-copy"></span>
|
||||||
|
</button>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
|
||||||
|
<div i18n *ngIf="notSecure()" class="alert alert-warning">
|
||||||
|
The url is not secured (no HTTPS), so the embed video won't work on HTTPS websites (web browsers block non secured HTTP requests on HTTPS websites).
|
||||||
|
</div>
|
||||||
|
|
||||||
|
<div class="form-group qr-code-group">
|
||||||
|
<label i18n>QR-Code</label>
|
||||||
|
<ngx-qrcode qrc-element-type="url" [qrc-value]="getVideoUrl()" qrc-errorCorrectionLevel="Q"></ngx-qrcode>
|
||||||
|
</div>
|
||||||
</div>
|
</div>
|
||||||
</div>
|
|
||||||
|
<div class="modal-footer inputs">
|
||||||
|
<span i18n class="action-button action-button-cancel" (click)="hide()">Cancel</span>
|
||||||
|
</div>
|
||||||
|
|
||||||
|
</ng-template>
|
||||||
|
|
|
@ -1,7 +1,14 @@
|
||||||
|
@import '~bootstrap/scss/functions';
|
||||||
|
@import '~bootstrap/scss/variables';
|
||||||
|
|
||||||
.action-button-cancel {
|
.action-button-cancel {
|
||||||
margin-right: 0 !important;
|
margin-right: 0 !important;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
.btn-outline-secondary {
|
||||||
|
border-color: $input-border-color;
|
||||||
|
}
|
||||||
|
|
||||||
.qr-code-group {
|
.qr-code-group {
|
||||||
text-align: center;
|
text-align: center;
|
||||||
}
|
}
|
||||||
|
|
|
@ -1,11 +1,9 @@
|
||||||
import { Component, Input, ViewChild } from '@angular/core'
|
import { Component, ElementRef, Input, ViewChild } from '@angular/core'
|
||||||
|
|
||||||
import { NotificationsService } from 'angular2-notifications'
|
import { NotificationsService } from 'angular2-notifications'
|
||||||
|
|
||||||
import { ModalDirective } from 'ngx-bootstrap/modal'
|
|
||||||
import { VideoDetails } from '../../../shared/video/video-details.model'
|
import { VideoDetails } from '../../../shared/video/video-details.model'
|
||||||
import { buildVideoEmbed } from '../../../../assets/player/utils'
|
import { buildVideoEmbed } from '../../../../assets/player/utils'
|
||||||
import { I18n } from '@ngx-translate/i18n-polyfill'
|
import { I18n } from '@ngx-translate/i18n-polyfill'
|
||||||
|
import { NgbModal } from '@ng-bootstrap/ng-bootstrap'
|
||||||
|
|
||||||
@Component({
|
@Component({
|
||||||
selector: 'my-video-share',
|
selector: 'my-video-share',
|
||||||
|
@ -15,9 +13,10 @@ import { I18n } from '@ngx-translate/i18n-polyfill'
|
||||||
export class VideoShareComponent {
|
export class VideoShareComponent {
|
||||||
@Input() video: VideoDetails = null
|
@Input() video: VideoDetails = null
|
||||||
|
|
||||||
@ViewChild('modal') modal: ModalDirective
|
@ViewChild('modal') modal: ElementRef
|
||||||
|
|
||||||
constructor (
|
constructor (
|
||||||
|
private modalService: NgbModal,
|
||||||
private notificationsService: NotificationsService,
|
private notificationsService: NotificationsService,
|
||||||
private i18n: I18n
|
private i18n: I18n
|
||||||
) {
|
) {
|
||||||
|
@ -25,11 +24,7 @@ export class VideoShareComponent {
|
||||||
}
|
}
|
||||||
|
|
||||||
show () {
|
show () {
|
||||||
this.modal.show()
|
this.modalService.open(this.modal)
|
||||||
}
|
|
||||||
|
|
||||||
hide () {
|
|
||||||
this.modal.hide()
|
|
||||||
}
|
}
|
||||||
|
|
||||||
getVideoIframeCode () {
|
getVideoIframeCode () {
|
||||||
|
|
|
@ -1,22 +1,12 @@
|
||||||
<div bsModal #modal="bs-modal" class="modal" tabindex="-1">
|
<ng-template #modal let-hide="close">
|
||||||
<div class="modal-dialog">
|
<div class="modal-header">
|
||||||
<div class="modal-content">
|
<h4 i18n class="modal-title">Support</h4>
|
||||||
|
<span class="close" aria-label="Close" role="button" (click)="hide()"></span>
|
||||||
<div class="modal-header">
|
|
||||||
<span class="close" aria-hidden="true" (click)="hide()"></span>
|
|
||||||
<h4 i18n class="modal-title">Support</h4>
|
|
||||||
</div>
|
|
||||||
|
|
||||||
<div class="modal-body">
|
|
||||||
|
|
||||||
<div [innerHTML]="videoHTMLSupport"></div>
|
|
||||||
|
|
||||||
<div class="form-group inputs">
|
|
||||||
<span i18n class="action-button action-button-cancel" (click)="hide()">
|
|
||||||
Cancel
|
|
||||||
</span>
|
|
||||||
</div>
|
|
||||||
</div>
|
|
||||||
</div>
|
|
||||||
</div>
|
</div>
|
||||||
</div>
|
|
||||||
|
<div class="modal-body" [innerHTML]="videoHTMLSupport"></div>
|
||||||
|
|
||||||
|
<div class="modal-footer inputs">
|
||||||
|
<span i18n class="action-button action-button-cancel" (click)="hide()">Cancel</span>
|
||||||
|
</div>
|
||||||
|
</ng-template>
|
||||||
|
|
|
@ -1,8 +1,8 @@
|
||||||
import { Component, Input, ViewChild } from '@angular/core'
|
import { Component, Input, ViewChild } from '@angular/core'
|
||||||
import { MarkdownService } from '@app/videos/shared'
|
import { MarkdownService } from '@app/videos/shared'
|
||||||
|
|
||||||
import { ModalDirective } from 'ngx-bootstrap/modal'
|
|
||||||
import { VideoDetails } from '../../../shared/video/video-details.model'
|
import { VideoDetails } from '../../../shared/video/video-details.model'
|
||||||
|
import { NgbModal } from '@ng-bootstrap/ng-bootstrap'
|
||||||
|
|
||||||
@Component({
|
@Component({
|
||||||
selector: 'my-video-support',
|
selector: 'my-video-support',
|
||||||
|
@ -12,21 +12,19 @@ import { VideoDetails } from '../../../shared/video/video-details.model'
|
||||||
export class VideoSupportComponent {
|
export class VideoSupportComponent {
|
||||||
@Input() video: VideoDetails = null
|
@Input() video: VideoDetails = null
|
||||||
|
|
||||||
@ViewChild('modal') modal: ModalDirective
|
@ViewChild('modal') modal: NgbModal
|
||||||
|
|
||||||
videoHTMLSupport = ''
|
videoHTMLSupport = ''
|
||||||
|
|
||||||
constructor (private markdownService: MarkdownService) {
|
constructor (
|
||||||
|
private markdownService: MarkdownService,
|
||||||
|
private modalService: NgbModal
|
||||||
|
) {
|
||||||
// empty
|
// empty
|
||||||
}
|
}
|
||||||
|
|
||||||
show () {
|
show () {
|
||||||
this.modal.show()
|
|
||||||
|
|
||||||
this.videoHTMLSupport = this.markdownService.enhancedMarkdownToHTML(this.video.support)
|
this.videoHTMLSupport = this.markdownService.enhancedMarkdownToHTML(this.video.support)
|
||||||
}
|
this.modalService.open(this.modal)
|
||||||
|
|
||||||
hide () {
|
|
||||||
this.modal.hide()
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
@ -76,48 +76,38 @@
|
||||||
<span class="icon-text" i18n>Share</span>
|
<span class="icon-text" i18n>Share</span>
|
||||||
</div>
|
</div>
|
||||||
|
|
||||||
<div class="action-more" dropdown dropup="true" placement="right" role="button">
|
<div class="action-more" ngbDropdown placement="top" role="button">
|
||||||
<div class="action-button" dropdownToggle>
|
<div class="action-button" ngbDropdownToggle role="button">
|
||||||
<span class="icon icon-more"></span>
|
<span class="icon icon-more"></span>
|
||||||
</div>
|
</div>
|
||||||
|
|
||||||
<ul *dropdownMenu class="dropdown-menu" id="more-menu" role="menu" aria-labelledby="single-button">
|
<div ngbDropdownMenu>
|
||||||
<li role="menuitem">
|
<a class="dropdown-item" i18n-title title="Download the video" href="#" (click)="showDownloadModal($event)">
|
||||||
<a class="dropdown-item" i18n-title title="Download the video" href="#" (click)="showDownloadModal($event)">
|
<span class="icon icon-download"></span> <ng-container i18n>Download</ng-container>
|
||||||
<span class="icon icon-download"></span> <ng-container i18n>Download</ng-container>
|
</a>
|
||||||
</a>
|
|
||||||
</li>
|
|
||||||
|
|
||||||
<li *ngIf="isUserLoggedIn()" role="menuitem">
|
<a *ngIf="isUserLoggedIn()" class="dropdown-item" i18n-title title="Report this video" href="#" (click)="showReportModal($event)">
|
||||||
<a class="dropdown-item" i18n-title title="Report this video" href="#" (click)="showReportModal($event)">
|
<span class="icon icon-alert"></span> <ng-container i18n>Report</ng-container>
|
||||||
<span class="icon icon-alert"></span> <ng-container i18n>Report</ng-container>
|
</a>
|
||||||
</a>
|
|
||||||
</li>
|
|
||||||
|
|
||||||
<li *ngIf="isVideoBlacklistable()" role="menuitem">
|
<a *ngIf="isVideoBlacklistable()" class="dropdown-item" i18n-title title="Blacklist this video" href="#" (click)="blacklistVideo($event)">
|
||||||
<a class="dropdown-item" i18n-title title="Blacklist this video" href="#" (click)="blacklistVideo($event)">
|
<span class="icon icon-blacklist"></span> <ng-container i18n>Blacklist</ng-container>
|
||||||
<span class="icon icon-blacklist"></span> <ng-container i18n>Blacklist</ng-container>
|
</a>
|
||||||
</a>
|
|
||||||
</li>
|
|
||||||
|
|
||||||
<li *ngIf="isVideoUpdatable()" role="menuitem">
|
<a *ngIf="isVideoUpdatable()" class="dropdown-item" i18n-title title="Update this video" href="#" [routerLink]="[ '/videos/update', video.uuid ]">
|
||||||
<a class="dropdown-item" i18n-title title="Update this video" href="#" [routerLink]="[ '/videos/update', video.uuid ]">
|
<span class="icon icon-edit"></span> <ng-container i18n>Update</ng-container>
|
||||||
<span class="icon icon-edit"></span> <ng-container i18n>Update</ng-container>
|
</a>
|
||||||
</a>
|
|
||||||
</li>
|
|
||||||
|
|
||||||
<li *ngIf="isVideoRemovable()" role="menuitem">
|
<a *ngIf="isVideoRemovable()" class="dropdown-item" i18n-title title="Delete this video" href="#" (click)="removeVideo($event)">
|
||||||
<a class="dropdown-item" i18n-title title="Delete this video" href="#" (click)="removeVideo($event)">
|
<span class="icon icon-blacklist"></span> <ng-container i18n>Delete</ng-container>
|
||||||
<span class="icon icon-blacklist"></span> <ng-container i18n>Delete</ng-container>
|
</a>
|
||||||
</a>
|
</div>
|
||||||
</li>
|
|
||||||
</ul>
|
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
|
|
||||||
<div
|
<div
|
||||||
class="video-info-likes-dislikes-bar"
|
class="video-info-likes-dislikes-bar"
|
||||||
*ngIf="video.likes !== 0 || video.dislikes !== 0" [tooltip]="likesBarTooltipText">
|
*ngIf="video.likes !== 0 || video.dislikes !== 0" [ngbTooltip]="likesBarTooltipText">
|
||||||
<div class="likes-bar" [ngStyle]="{ 'width.%': video.likesPercent }"></div>
|
<div class="likes-bar" [ngStyle]="{ 'width.%': video.likesPercent }"></div>
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
|
|
|
@ -177,6 +177,10 @@
|
||||||
padding: 0 10px 0 10px;
|
padding: 0 10px 0 10px;
|
||||||
white-space: nowrap;
|
white-space: nowrap;
|
||||||
|
|
||||||
|
&::after {
|
||||||
|
display: none;
|
||||||
|
}
|
||||||
|
|
||||||
.icon {
|
.icon {
|
||||||
@include icon(21px);
|
@include icon(21px);
|
||||||
|
|
||||||
|
|
|
@ -1,7 +1,6 @@
|
||||||
import { NgModule } from '@angular/core'
|
import { NgModule } from '@angular/core'
|
||||||
import { LinkifierService } from '@app/videos/+video-watch/comment/linkifier.service'
|
import { LinkifierService } from '@app/videos/+video-watch/comment/linkifier.service'
|
||||||
import { VideoSupportComponent } from '@app/videos/+video-watch/modal/video-support.component'
|
import { VideoSupportComponent } from '@app/videos/+video-watch/modal/video-support.component'
|
||||||
import { TooltipModule } from 'ngx-bootstrap/tooltip'
|
|
||||||
import { ClipboardModule } from 'ngx-clipboard'
|
import { ClipboardModule } from 'ngx-clipboard'
|
||||||
import { SharedModule } from '../../shared'
|
import { SharedModule } from '../../shared'
|
||||||
import { MarkdownService } from '../shared'
|
import { MarkdownService } from '../shared'
|
||||||
|
@ -12,18 +11,17 @@ import { VideoCommentsComponent } from './comment/video-comments.component'
|
||||||
import { VideoDownloadComponent } from './modal/video-download.component'
|
import { VideoDownloadComponent } from './modal/video-download.component'
|
||||||
import { VideoReportComponent } from './modal/video-report.component'
|
import { VideoReportComponent } from './modal/video-report.component'
|
||||||
import { VideoShareComponent } from './modal/video-share.component'
|
import { VideoShareComponent } from './modal/video-share.component'
|
||||||
|
|
||||||
import { VideoWatchRoutingModule } from './video-watch-routing.module'
|
import { VideoWatchRoutingModule } from './video-watch-routing.module'
|
||||||
|
|
||||||
import { VideoWatchComponent } from './video-watch.component'
|
import { VideoWatchComponent } from './video-watch.component'
|
||||||
import { NgxQRCodeModule } from 'ngx-qrcode2'
|
import { NgxQRCodeModule } from 'ngx-qrcode2'
|
||||||
|
import { NgbTooltipModule } from '@ng-bootstrap/ng-bootstrap'
|
||||||
|
|
||||||
@NgModule({
|
@NgModule({
|
||||||
imports: [
|
imports: [
|
||||||
VideoWatchRoutingModule,
|
VideoWatchRoutingModule,
|
||||||
SharedModule,
|
SharedModule,
|
||||||
ClipboardModule,
|
ClipboardModule,
|
||||||
TooltipModule.forRoot(),
|
NgbTooltipModule.forRoot(),
|
||||||
NgxQRCodeModule
|
NgxQRCodeModule
|
||||||
],
|
],
|
||||||
|
|
||||||
|
|
|
@ -42,6 +42,10 @@ input.readonly {
|
||||||
background-color: #fff !important;
|
background-color: #fff !important;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
input, textarea {
|
||||||
|
outline: none;
|
||||||
|
}
|
||||||
|
|
||||||
label {
|
label {
|
||||||
font-weight: $font-bold;
|
font-weight: $font-bold;
|
||||||
font-size: 15px;
|
font-size: 15px;
|
||||||
|
@ -174,9 +178,13 @@ label {
|
||||||
@include icon(24px);
|
@include icon(24px);
|
||||||
|
|
||||||
position: relative;
|
position: relative;
|
||||||
right: -1px;
|
top: 3px;
|
||||||
float: right;
|
float: right;
|
||||||
background-image: url('../assets/images/global/cross.svg');
|
background-image: url('../assets/images/global/cross.svg');
|
||||||
|
|
||||||
|
margin: 0;
|
||||||
|
padding: 0;
|
||||||
|
opacity: 1;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -200,47 +208,35 @@ label {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
tabset:not(.bootstrap) {
|
// Nav customizations
|
||||||
.nav {
|
.nav .nav-link {
|
||||||
font-size: 16px !important;
|
display: flex !important;
|
||||||
border: none !important;
|
align-items: center;
|
||||||
|
height: 30px !important;
|
||||||
|
padding: 10px 15px !important;
|
||||||
|
}
|
||||||
|
|
||||||
.nav-item .nav-link {
|
.nav.nav-pills {
|
||||||
margin-right: 30px;
|
font-size: 16px !important;
|
||||||
padding: 0;
|
|
||||||
border-radius: 3px;
|
|
||||||
border: none !important;
|
|
||||||
|
|
||||||
.tab-link {
|
.nav-link.active {
|
||||||
display: flex !important;
|
font-weight: $font-semibold !important;
|
||||||
align-items: center;
|
}
|
||||||
min-height: 30px !important;
|
|
||||||
padding: 0 15px;
|
|
||||||
}
|
|
||||||
|
|
||||||
&, & a {
|
a {
|
||||||
color: #000 !important;
|
@include disable-default-a-behaviour;
|
||||||
@include disable-default-a-behaviour;
|
|
||||||
}
|
|
||||||
|
|
||||||
&.active, &:hover {
|
color: #000;
|
||||||
background-color: #F0F0F0;
|
|
||||||
}
|
|
||||||
|
|
||||||
&.active {
|
|
||||||
font-weight: $font-semibold !important;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
tabset.bootstrap {
|
ngb-tabset.bootstrap {
|
||||||
margin-left: 0;
|
|
||||||
|
|
||||||
.nav-item .nav-link {
|
.nav-link {
|
||||||
&, & a {
|
&, & a {
|
||||||
color: #000;
|
|
||||||
@include disable-default-a-behaviour;
|
@include disable-default-a-behaviour;
|
||||||
|
|
||||||
|
color: #000 !important;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
@ -1,37 +1,51 @@
|
||||||
@import "~bootstrap/scss/functions";
|
$dropdown-link-active-bg: inherit;
|
||||||
@import "~bootstrap/scss/variables";
|
|
||||||
@import "~bootstrap/scss/mixins";
|
|
||||||
@import "~bootstrap/scss/root";
|
|
||||||
@import "~bootstrap/scss/reboot";
|
|
||||||
@import "~bootstrap/scss/type";
|
|
||||||
//@import "~bootstrap/scss/images";
|
|
||||||
//@import "~bootstrap/scss/code";
|
|
||||||
@import "~bootstrap/scss/grid";
|
|
||||||
//@import "~bootstrap/scss/tables";
|
|
||||||
@import "~bootstrap/scss/forms";
|
|
||||||
@import "~bootstrap/scss/buttons";
|
|
||||||
//@import "~bootstrap/scss/transitions";
|
|
||||||
@import "~bootstrap/scss/dropdown";
|
|
||||||
//@import "~bootstrap/scss/button-group";
|
|
||||||
@import "~bootstrap/scss/input-group";
|
|
||||||
//@import "~bootstrap/scss/custom-forms";
|
|
||||||
@import "~bootstrap/scss/nav";
|
|
||||||
//@import "~bootstrap/scss/navbar";
|
|
||||||
//@import "~bootstrap/scss/card";
|
|
||||||
//@import "~bootstrap/scss/breadcrumb";
|
|
||||||
//@import "~bootstrap/scss/pagination";
|
|
||||||
//@import "~bootstrap/scss/badge";
|
|
||||||
//@import "~bootstrap/scss/jumbotron";
|
|
||||||
@import "~bootstrap/scss/alert";
|
|
||||||
//@import "~bootstrap/scss/progress";
|
|
||||||
//@import "~bootstrap/scss/media";
|
|
||||||
//@import "~bootstrap/scss/list-group";
|
|
||||||
@import "~bootstrap/scss/close";
|
|
||||||
@import "~bootstrap/scss/modal";
|
|
||||||
@import "~bootstrap/scss/tooltip";
|
|
||||||
@import "~bootstrap/scss/popover";
|
|
||||||
//@import "~bootstrap/scss/carousel";
|
|
||||||
//@import "~bootstrap/scss/utilities";
|
|
||||||
//@import "~bootstrap/scss/print";
|
|
||||||
|
|
||||||
@import "~@neos21/bootstrap3-glyphicons/assets/stylesheets/bootstrap3-glyphicons";
|
$zindex-modal: 10005;
|
||||||
|
$modal-footer-border-width: 0;
|
||||||
|
$modal-md: 600px;
|
||||||
|
|
||||||
|
$input-btn-focus-width: 0;
|
||||||
|
$input-btn-focus-color: inherit;
|
||||||
|
$input-focus-border-color: #ced4da;
|
||||||
|
|
||||||
|
$nav-pills-link-active-bg: #F0F0F0;
|
||||||
|
$nav-pills-link-active-color: #000;
|
||||||
|
|
||||||
|
@import '~bootstrap/scss/functions';
|
||||||
|
@import '~bootstrap/scss/variables';
|
||||||
|
|
||||||
|
@import '~bootstrap/scss/mixins';
|
||||||
|
@import '~bootstrap/scss/root';
|
||||||
|
@import '~bootstrap/scss/reboot';
|
||||||
|
@import '~bootstrap/scss/type';
|
||||||
|
//@import '~bootstrap/scss/images';
|
||||||
|
//@import '~bootstrap/scss/code';
|
||||||
|
@import '~bootstrap/scss/grid';
|
||||||
|
//@import '~bootstrap/scss/tables';
|
||||||
|
@import '~bootstrap/scss/forms';
|
||||||
|
@import '~bootstrap/scss/buttons';
|
||||||
|
//@import '~bootstrap/scss/transitions';
|
||||||
|
@import '~bootstrap/scss/dropdown';
|
||||||
|
//@import '~bootstrap/scss/button-group';
|
||||||
|
@import '~bootstrap/scss/input-group';
|
||||||
|
//@import '~bootstrap/scss/custom-forms';
|
||||||
|
@import '~bootstrap/scss/nav';
|
||||||
|
//@import '~bootstrap/scss/navbar';
|
||||||
|
//@import '~bootstrap/scss/card';
|
||||||
|
//@import '~bootstrap/scss/breadcrumb';
|
||||||
|
//@import '~bootstrap/scss/pagination';
|
||||||
|
//@import '~bootstrap/scss/badge';
|
||||||
|
//@import '~bootstrap/scss/jumbotron';
|
||||||
|
@import '~bootstrap/scss/alert';
|
||||||
|
//@import '~bootstrap/scss/progress';
|
||||||
|
//@import '~bootstrap/scss/media';
|
||||||
|
//@import '~bootstrap/scss/list-group';
|
||||||
|
@import '~bootstrap/scss/close';
|
||||||
|
@import '~bootstrap/scss/modal';
|
||||||
|
@import '~bootstrap/scss/tooltip';
|
||||||
|
@import '~bootstrap/scss/popover';
|
||||||
|
//@import '~bootstrap/scss/carousel';
|
||||||
|
@import '~bootstrap/scss/utilities';
|
||||||
|
//@import '~bootstrap/scss/print';
|
||||||
|
|
||||||
|
@import '~@neos21/bootstrap3-glyphicons/assets/stylesheets/bootstrap3-glyphicons';
|
||||||
|
|
|
@ -191,6 +191,10 @@
|
||||||
version "1.0.1"
|
version "1.0.1"
|
||||||
resolved "https://registry.yarnpkg.com/@neos21/bootstrap3-glyphicons/-/bootstrap3-glyphicons-1.0.1.tgz#e5eeec43e0153d4b51effd9ecb58cdf7029924d7"
|
resolved "https://registry.yarnpkg.com/@neos21/bootstrap3-glyphicons/-/bootstrap3-glyphicons-1.0.1.tgz#e5eeec43e0153d4b51effd9ecb58cdf7029924d7"
|
||||||
|
|
||||||
|
"@ng-bootstrap/ng-bootstrap@^2.2.2":
|
||||||
|
version "2.2.2"
|
||||||
|
resolved "https://registry.yarnpkg.com/@ng-bootstrap/ng-bootstrap/-/ng-bootstrap-2.2.2.tgz#07c64badd48b563140eb5a6327b5516bf2226834"
|
||||||
|
|
||||||
"@ngtools/webpack@6.1.1":
|
"@ngtools/webpack@6.1.1":
|
||||||
version "6.1.1"
|
version "6.1.1"
|
||||||
resolved "https://registry.yarnpkg.com/@ngtools/webpack/-/webpack-6.1.1.tgz#dcfea287c0c1358f3e123621c65b0e3ccaab5b70"
|
resolved "https://registry.yarnpkg.com/@ngtools/webpack/-/webpack-6.1.1.tgz#dcfea287c0c1358f3e123621c65b0e3ccaab5b70"
|
||||||
|
@ -5350,10 +5354,6 @@ ng2-material-dropdown@0.10.1:
|
||||||
dependencies:
|
dependencies:
|
||||||
tslib "^1.9.0"
|
tslib "^1.9.0"
|
||||||
|
|
||||||
ngx-bootstrap@3.0.1:
|
|
||||||
version "3.0.1"
|
|
||||||
resolved "https://registry.yarnpkg.com/ngx-bootstrap/-/ngx-bootstrap-3.0.1.tgz#e98d2fc6340f32a9d358cd08e8fda7dcb23bdab3"
|
|
||||||
|
|
||||||
ngx-chips@1.9.3:
|
ngx-chips@1.9.3:
|
||||||
version "1.9.3"
|
version "1.9.3"
|
||||||
resolved "https://registry.yarnpkg.com/ngx-chips/-/ngx-chips-1.9.3.tgz#0ebc13b4868d9cd480478ed93fd56bcc3b68ea66"
|
resolved "https://registry.yarnpkg.com/ngx-chips/-/ngx-chips-1.9.3.tgz#0ebc13b4868d9cd480478ed93fd56bcc3b68ea66"
|
||||||
|
|
Loading…
Reference in New Issue
Block a user