mirror of https://github.com/Chocobozzz/PeerTube
Add params to share modal
parent
011e1e6b37
commit
2f4c784a92
|
@ -20,7 +20,7 @@
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
|
|
||||||
<div class="results-filter" [ngbCollapse]="isSearchFilterCollapsed">
|
<div class="results-filter collapse-transition" [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>
|
||||||
|
|
|
@ -35,18 +35,6 @@
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
.results-filter {
|
|
||||||
// Animation when we show/hide the filters
|
|
||||||
transition: max-height 0.3s;
|
|
||||||
display: block !important;
|
|
||||||
overflow: hidden !important;
|
|
||||||
max-height: 0;
|
|
||||||
|
|
||||||
&.show {
|
|
||||||
max-height: 1500px;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
.entry {
|
.entry {
|
||||||
|
|
|
@ -4,14 +4,11 @@ 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 { NgbCollapseModule } from '@ng-bootstrap/ng-bootstrap'
|
|
||||||
|
|
||||||
@NgModule({
|
@NgModule({
|
||||||
imports: [
|
imports: [
|
||||||
SearchRoutingModule,
|
SearchRoutingModule,
|
||||||
SharedModule,
|
SharedModule
|
||||||
|
|
||||||
NgbCollapseModule
|
|
||||||
],
|
],
|
||||||
|
|
||||||
declarations: [
|
declarations: [
|
||||||
|
|
|
@ -53,7 +53,14 @@ 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'
|
import {
|
||||||
|
NgbCollapseModule,
|
||||||
|
NgbDropdownModule,
|
||||||
|
NgbModalModule,
|
||||||
|
NgbPopoverModule,
|
||||||
|
NgbTabsetModule,
|
||||||
|
NgbTooltipModule
|
||||||
|
} from '@ng-bootstrap/ng-bootstrap'
|
||||||
import { RemoteSubscribeComponent, SubscribeButtonComponent, UserSubscriptionService } from '@app/shared/user-subscription'
|
import { RemoteSubscribeComponent, SubscribeButtonComponent, UserSubscriptionService } from '@app/shared/user-subscription'
|
||||||
import { InstanceFeaturesTableComponent } from '@app/shared/instance/instance-features-table.component'
|
import { InstanceFeaturesTableComponent } from '@app/shared/instance/instance-features-table.component'
|
||||||
import { OverviewService } from '@app/shared/overview'
|
import { OverviewService } from '@app/shared/overview'
|
||||||
|
@ -100,6 +107,7 @@ import { FollowService } from '@app/shared/instance/follow.service'
|
||||||
NgbPopoverModule,
|
NgbPopoverModule,
|
||||||
NgbTabsetModule,
|
NgbTabsetModule,
|
||||||
NgbTooltipModule,
|
NgbTooltipModule,
|
||||||
|
NgbCollapseModule,
|
||||||
|
|
||||||
ClipboardModule,
|
ClipboardModule,
|
||||||
|
|
||||||
|
@ -170,6 +178,7 @@ import { FollowService } from '@app/shared/instance/follow.service'
|
||||||
NgbPopoverModule,
|
NgbPopoverModule,
|
||||||
NgbTabsetModule,
|
NgbTabsetModule,
|
||||||
NgbTooltipModule,
|
NgbTooltipModule,
|
||||||
|
NgbCollapseModule,
|
||||||
|
|
||||||
ClipboardModule,
|
ClipboardModule,
|
||||||
|
|
||||||
|
|
|
@ -5,26 +5,14 @@
|
||||||
</div>
|
</div>
|
||||||
|
|
||||||
<div class="modal-body">
|
<div class="modal-body">
|
||||||
|
<ngb-tabset class="root-tabset bootstrap" (tabChange)="onTabChange($event)">
|
||||||
|
|
||||||
<div class="start-at">
|
<ngb-tab i18n-title title="URL" id="url">
|
||||||
<my-peertube-checkbox
|
<ng-template ngbTabContent>
|
||||||
inputName="startAt" [(ngModel)]="startAtCheckbox"
|
|
||||||
i18n-labelText labelText="Start at"
|
|
||||||
></my-peertube-checkbox>
|
|
||||||
|
|
||||||
<my-timestamp-input
|
<div class="tab-content">
|
||||||
[timestamp]="currentVideoTimestamp"
|
<div class="input-group">
|
||||||
[maxTimestamp]="video.duration"
|
<input #urlInput (click)="urlInput.select()" type="text" class="form-control readonly" readonly [value]="getVideoUrl()" />
|
||||||
[disabled]="!startAtCheckbox"
|
|
||||||
[(ngModel)]="currentVideoTimestamp"
|
|
||||||
>
|
|
||||||
</my-timestamp-input>
|
|
||||||
</div>
|
|
||||||
|
|
||||||
<div class="form-group">
|
|
||||||
<label i18n>URL</label>
|
|
||||||
<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="input-group-append">
|
<div class="input-group-append">
|
||||||
<button [ngxClipboard]="urlInput" (click)="activateCopiedMessage()" type="button" class="btn btn-outline-secondary">
|
<button [ngxClipboard]="urlInput" (click)="activateCopiedMessage()" type="button" class="btn btn-outline-secondary">
|
||||||
<span class="glyphicon glyphicon-copy"></span>
|
<span class="glyphicon glyphicon-copy"></span>
|
||||||
|
@ -33,27 +21,153 @@
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
|
|
||||||
<div class="form-group qr-code-group">
|
</ng-template>
|
||||||
<label i18n>QR-Code</label>
|
</ngb-tab>
|
||||||
|
|
||||||
|
<ngb-tab i18n-title title="QR-Code" id="qrcode">
|
||||||
|
<ng-template ngbTabContent>
|
||||||
|
<div class="tab-content">
|
||||||
<ngx-qrcode qrc-element-type="url" [qrc-value]="getVideoUrl()" qrc-errorCorrectionLevel="Q"></ngx-qrcode>
|
<ngx-qrcode qrc-element-type="url" [qrc-value]="getVideoUrl()" qrc-errorCorrectionLevel="Q"></ngx-qrcode>
|
||||||
</div>
|
</div>
|
||||||
|
</ng-template>
|
||||||
|
</ngb-tab>
|
||||||
|
|
||||||
<div class="form-group">
|
<ngb-tab i18n-title title="Embed" id="embed">
|
||||||
<label i18n>Embed</label>
|
<ng-template ngbTabContent>
|
||||||
<div class="input-group input-group-sm">
|
<div class="tab-content">
|
||||||
<input #shareInput (click)="shareInput.select()" type="text" class="form-control input-sm readonly" readonly [value]="getVideoIframeCode()" />
|
<div class="input-group">
|
||||||
|
<input #shareInput (click)="shareInput.select()" type="text" class="form-control readonly" readonly [value]="getVideoIframeCode()" />
|
||||||
<div class="input-group-append">
|
<div class="input-group-append">
|
||||||
<button [ngxClipboard]="shareInput" (click)="activateCopiedMessage()" type="button" class="btn btn-outline-secondary">
|
<button [ngxClipboard]="shareInput" (click)="activateCopiedMessage()" type="button" class="btn btn-outline-secondary">
|
||||||
<span class="glyphicon glyphicon-copy"></span>
|
<span class="glyphicon glyphicon-copy"></span>
|
||||||
</button>
|
</button>
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
</div>
|
|
||||||
|
|
||||||
<div i18n *ngIf="notSecure()" class="alert alert-warning">
|
<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).
|
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>
|
||||||
</div>
|
</div>
|
||||||
|
</ng-template>
|
||||||
|
</ngb-tab>
|
||||||
|
|
||||||
|
</ngb-tabset>
|
||||||
|
|
||||||
|
<div class="filters">
|
||||||
|
<div>
|
||||||
|
<div class="form-group start-at">
|
||||||
|
<my-peertube-checkbox
|
||||||
|
inputName="startAt" [(ngModel)]="customizations.startAtCheckbox"
|
||||||
|
i18n-labelText labelText="Start at"
|
||||||
|
></my-peertube-checkbox>
|
||||||
|
|
||||||
|
<my-timestamp-input
|
||||||
|
[timestamp]="customizations.startAt"
|
||||||
|
[maxTimestamp]="video.duration"
|
||||||
|
[disabled]="!customizations.startAtCheckbox"
|
||||||
|
[(ngModel)]="customizations.startAt"
|
||||||
|
>
|
||||||
|
</my-timestamp-input>
|
||||||
|
</div>
|
||||||
|
|
||||||
|
<div *ngIf="videoCaptions.length !== 0" class="form-group video-caption-block">
|
||||||
|
<my-peertube-checkbox
|
||||||
|
inputName="subtitleCheckbox" [(ngModel)]="customizations.subtitleCheckbox"
|
||||||
|
i18n-labelText labelText="Auto select subtitle"
|
||||||
|
></my-peertube-checkbox>
|
||||||
|
|
||||||
|
<div class="peertube-select-container" [ngClass]="{ disabled: !customizations.subtitleCheckbox }">
|
||||||
|
<select [(ngModel)]="customizations.subtitle" [disabled]="!customizations.subtitleCheckbox">
|
||||||
|
<option *ngFor="let caption of videoCaptions" [value]="caption.language.id">{{ caption.language.label }}</option>
|
||||||
|
</select>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
|
||||||
|
<div (click)="isAdvancedCustomizationCollapsed = !isAdvancedCustomizationCollapsed" role="button" class="advanced-filters-button"
|
||||||
|
[attr.aria-expanded]="!isAdvancedCustomizationCollapsed" aria-controls="collapseBasic">
|
||||||
|
|
||||||
|
<ng-container *ngIf="isAdvancedCustomizationCollapsed">
|
||||||
|
<span class="glyphicon glyphicon-menu-down"></span>
|
||||||
|
|
||||||
|
<ng-container i18n>
|
||||||
|
More customization
|
||||||
|
</ng-container>
|
||||||
|
</ng-container>
|
||||||
|
|
||||||
|
<ng-container *ngIf="!isAdvancedCustomizationCollapsed">
|
||||||
|
<span class="glyphicon glyphicon-menu-up"></span>
|
||||||
|
|
||||||
|
<ng-container i18n>
|
||||||
|
Less customization
|
||||||
|
</ng-container>
|
||||||
|
</ng-container>
|
||||||
|
</div>
|
||||||
|
|
||||||
|
<div class="advanced-filters collapse-transition" [ngbCollapse]="isAdvancedCustomizationCollapsed">
|
||||||
|
<div>
|
||||||
|
<div class="form-group stop-at">
|
||||||
|
<my-peertube-checkbox
|
||||||
|
inputName="stopAt" [(ngModel)]="customizations.stopAtCheckbox"
|
||||||
|
i18n-labelText labelText="Stop at"
|
||||||
|
></my-peertube-checkbox>
|
||||||
|
|
||||||
|
<my-timestamp-input
|
||||||
|
[timestamp]="customizations.stopAt"
|
||||||
|
[maxTimestamp]="video.duration"
|
||||||
|
[disabled]="!customizations.stopAtCheckbox"
|
||||||
|
[(ngModel)]="customizations.stopAt"
|
||||||
|
>
|
||||||
|
</my-timestamp-input>
|
||||||
|
</div>
|
||||||
|
|
||||||
|
<div class="form-group">
|
||||||
|
<my-peertube-checkbox
|
||||||
|
inputName="autoplay" [(ngModel)]="customizations.autoplay"
|
||||||
|
i18n-labelText labelText="Autoplay"
|
||||||
|
></my-peertube-checkbox>
|
||||||
|
</div>
|
||||||
|
|
||||||
|
<div class="form-group">
|
||||||
|
<my-peertube-checkbox
|
||||||
|
inputName="muted" [(ngModel)]="customizations.muted"
|
||||||
|
i18n-labelText labelText="Muted"
|
||||||
|
></my-peertube-checkbox>
|
||||||
|
</div>
|
||||||
|
|
||||||
|
<div class="form-group">
|
||||||
|
<my-peertube-checkbox
|
||||||
|
inputName="loop" [(ngModel)]="customizations.loop"
|
||||||
|
i18n-labelText labelText="Loop"
|
||||||
|
></my-peertube-checkbox>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
|
||||||
|
<ng-container *ngIf="isInEmbedTab()">
|
||||||
|
<div class="form-group">
|
||||||
|
<my-peertube-checkbox
|
||||||
|
inputName="title" [(ngModel)]="customizations.title"
|
||||||
|
i18n-labelText labelText="Display video title"
|
||||||
|
></my-peertube-checkbox>
|
||||||
|
</div>
|
||||||
|
|
||||||
|
<div class="form-group">
|
||||||
|
<my-peertube-checkbox
|
||||||
|
inputName="warningTitle" [(ngModel)]="customizations.warningTitle"
|
||||||
|
i18n-labelText labelText="Display privacy warning"
|
||||||
|
></my-peertube-checkbox>
|
||||||
|
</div>
|
||||||
|
|
||||||
|
<div class="form-group">
|
||||||
|
<my-peertube-checkbox
|
||||||
|
inputName="controls" [(ngModel)]="customizations.controls"
|
||||||
|
i18n-labelText labelText="Display player controls"
|
||||||
|
></my-peertube-checkbox>
|
||||||
|
</div>
|
||||||
|
</ng-container>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
|
||||||
<div class="modal-footer inputs">
|
<div class="modal-footer inputs">
|
||||||
<span i18n class="action-button action-button-cancel" (click)="hide()">Close</span>
|
<span i18n class="action-button action-button-cancel" (click)="hide()">Close</span>
|
||||||
|
|
|
@ -1,5 +1,9 @@
|
||||||
@import '~bootstrap/scss/functions';
|
@import '_mixins';
|
||||||
@import '~bootstrap/scss/variables';
|
@import '_variables';
|
||||||
|
|
||||||
|
.peertube-select-container {
|
||||||
|
@include peertube-select-container(200px);
|
||||||
|
}
|
||||||
|
|
||||||
.action-button-cancel {
|
.action-button-cancel {
|
||||||
margin-right: 0 !important;
|
margin-right: 0 !important;
|
||||||
|
@ -9,13 +13,65 @@
|
||||||
text-align: center;
|
text-align: center;
|
||||||
}
|
}
|
||||||
|
|
||||||
.start-at {
|
.tab-content {
|
||||||
|
margin-top: 30px;
|
||||||
display: flex;
|
display: flex;
|
||||||
justify-content: center;
|
justify-content: center;
|
||||||
margin-top: 10px;
|
align-items: center;
|
||||||
|
flex-direction: column;
|
||||||
|
}
|
||||||
|
|
||||||
|
.alert {
|
||||||
|
margin-top: 20px;
|
||||||
|
}
|
||||||
|
|
||||||
|
input.readonly {
|
||||||
|
font-size: 15px;
|
||||||
|
}
|
||||||
|
|
||||||
|
.filters {
|
||||||
|
margin-top: 30px;
|
||||||
|
padding-top: 30px;
|
||||||
|
border-top: 1px solid $separator-border-color;
|
||||||
|
|
||||||
|
.advanced-filters-button {
|
||||||
|
display: flex;
|
||||||
|
justify-content: center;
|
||||||
|
align-items: center;
|
||||||
|
margin-top: 30px;
|
||||||
|
font-size: 16px;
|
||||||
|
font-weight: $font-semibold;
|
||||||
|
cursor: pointer;
|
||||||
|
|
||||||
|
.glyphicon {
|
||||||
|
margin-right: 5px;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
.form-group {
|
||||||
|
margin-bottom: 0;
|
||||||
|
height: 34px;
|
||||||
|
display: flex;
|
||||||
|
align-items: center;
|
||||||
|
}
|
||||||
|
|
||||||
|
.video-caption-block {
|
||||||
|
display: flex;
|
||||||
|
align-items: center;
|
||||||
|
|
||||||
|
.peertube-select-container {
|
||||||
|
margin-left: 10px;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
.start-at,
|
||||||
|
.stop-at {
|
||||||
|
width: 300px;
|
||||||
|
display: flex;
|
||||||
align-items: center;
|
align-items: center;
|
||||||
|
|
||||||
my-timestamp-input {
|
my-timestamp-input {
|
||||||
margin-left: 10px;
|
margin-left: 10px;
|
||||||
}
|
}
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
|
@ -3,8 +3,26 @@ import { Notifier } from '@app/core'
|
||||||
import { VideoDetails } from '../../../shared/video/video-details.model'
|
import { VideoDetails } from '../../../shared/video/video-details.model'
|
||||||
import { buildVideoEmbed, buildVideoLink } from '../../../../assets/player/utils'
|
import { buildVideoEmbed, buildVideoLink } 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'
|
import { NgbModal, NgbTabChangeEvent } from '@ng-bootstrap/ng-bootstrap'
|
||||||
import { durationToString } from '@app/shared/misc/utils'
|
import { VideoCaption } from '@shared/models'
|
||||||
|
|
||||||
|
type Customizations = {
|
||||||
|
startAtCheckbox: boolean
|
||||||
|
startAt: number
|
||||||
|
|
||||||
|
stopAtCheckbox: boolean
|
||||||
|
stopAt: number
|
||||||
|
|
||||||
|
subtitleCheckbox: boolean
|
||||||
|
subtitle: string
|
||||||
|
|
||||||
|
loop: boolean
|
||||||
|
autoplay: boolean
|
||||||
|
muted: boolean
|
||||||
|
title: boolean
|
||||||
|
warningTitle: boolean
|
||||||
|
controls: boolean
|
||||||
|
}
|
||||||
|
|
||||||
@Component({
|
@Component({
|
||||||
selector: 'my-video-share',
|
selector: 'my-video-share',
|
||||||
|
@ -15,9 +33,13 @@ export class VideoShareComponent {
|
||||||
@ViewChild('modal') modal: ElementRef
|
@ViewChild('modal') modal: ElementRef
|
||||||
|
|
||||||
@Input() video: VideoDetails = null
|
@Input() video: VideoDetails = null
|
||||||
|
@Input() videoCaptions: VideoCaption[] = []
|
||||||
|
|
||||||
currentVideoTimestamp: number
|
activeId: 'url' | 'qrcode' | 'embed'
|
||||||
startAtCheckbox = false
|
customizations: Customizations
|
||||||
|
isAdvancedCustomizationCollapsed = true
|
||||||
|
|
||||||
|
private currentVideoTimestamp: number
|
||||||
|
|
||||||
constructor (
|
constructor (
|
||||||
private modalService: NgbModal,
|
private modalService: NgbModal,
|
||||||
|
@ -26,19 +48,47 @@ export class VideoShareComponent {
|
||||||
) { }
|
) { }
|
||||||
|
|
||||||
show (currentVideoTimestamp?: number) {
|
show (currentVideoTimestamp?: number) {
|
||||||
this.currentVideoTimestamp = currentVideoTimestamp ? Math.floor(currentVideoTimestamp) : 0
|
this.currentVideoTimestamp = currentVideoTimestamp
|
||||||
|
|
||||||
|
let subtitle: string
|
||||||
|
if (this.videoCaptions.length !== 0) {
|
||||||
|
subtitle = this.videoCaptions[0].language.id
|
||||||
|
}
|
||||||
|
|
||||||
|
this.customizations = {
|
||||||
|
startAtCheckbox: false,
|
||||||
|
startAt: currentVideoTimestamp ? Math.floor(currentVideoTimestamp) : 0,
|
||||||
|
|
||||||
|
stopAtCheckbox: false,
|
||||||
|
stopAt: this.video.duration,
|
||||||
|
|
||||||
|
subtitleCheckbox: false,
|
||||||
|
subtitle,
|
||||||
|
|
||||||
|
loop: false,
|
||||||
|
autoplay: false,
|
||||||
|
muted: false,
|
||||||
|
|
||||||
|
// Embed options
|
||||||
|
title: true,
|
||||||
|
warningTitle: true,
|
||||||
|
controls: true
|
||||||
|
}
|
||||||
|
|
||||||
this.modalService.open(this.modal)
|
this.modalService.open(this.modal)
|
||||||
}
|
}
|
||||||
|
|
||||||
getVideoIframeCode () {
|
getVideoIframeCode () {
|
||||||
const embedUrl = buildVideoLink(this.getVideoTimestampIfEnabled(), this.video.embedUrl)
|
const options = this.getOptions(this.video.embedUrl)
|
||||||
|
|
||||||
|
const embedUrl = buildVideoLink(options)
|
||||||
return buildVideoEmbed(embedUrl)
|
return buildVideoEmbed(embedUrl)
|
||||||
}
|
}
|
||||||
|
|
||||||
getVideoUrl () {
|
getVideoUrl () {
|
||||||
return buildVideoLink(this.getVideoTimestampIfEnabled())
|
const options = this.getOptions()
|
||||||
|
|
||||||
|
return buildVideoLink(options)
|
||||||
}
|
}
|
||||||
|
|
||||||
notSecure () {
|
notSecure () {
|
||||||
|
@ -49,9 +99,30 @@ export class VideoShareComponent {
|
||||||
this.notifier.success(this.i18n('Copied'))
|
this.notifier.success(this.i18n('Copied'))
|
||||||
}
|
}
|
||||||
|
|
||||||
private getVideoTimestampIfEnabled () {
|
onTabChange (event: NgbTabChangeEvent) {
|
||||||
if (this.startAtCheckbox === true) return this.currentVideoTimestamp
|
this.activeId = event.nextId as any
|
||||||
|
}
|
||||||
|
|
||||||
return undefined
|
isInEmbedTab () {
|
||||||
|
return this.activeId === 'embed'
|
||||||
|
}
|
||||||
|
|
||||||
|
private getOptions (baseUrl?: string) {
|
||||||
|
return {
|
||||||
|
baseUrl,
|
||||||
|
|
||||||
|
startTime: this.customizations.startAtCheckbox ? this.customizations.startAt : undefined,
|
||||||
|
stopTime: this.customizations.stopAtCheckbox ? this.customizations.stopAt : undefined,
|
||||||
|
|
||||||
|
subtitle: this.customizations.subtitleCheckbox ? this.customizations.subtitle : undefined,
|
||||||
|
|
||||||
|
loop: this.customizations.loop,
|
||||||
|
autoplay: this.customizations.autoplay,
|
||||||
|
muted: this.customizations.muted,
|
||||||
|
|
||||||
|
title: this.customizations.title,
|
||||||
|
warningTitle: this.customizations.warningTitle,
|
||||||
|
controls: this.customizations.controls
|
||||||
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
@ -219,5 +219,5 @@
|
||||||
|
|
||||||
<ng-template [ngIf]="video !== null">
|
<ng-template [ngIf]="video !== null">
|
||||||
<my-video-support #videoSupportModal [video]="video"></my-video-support>
|
<my-video-support #videoSupportModal [video]="video"></my-video-support>
|
||||||
<my-video-share #videoShareModal [video]="video"></my-video-share>
|
<my-video-share #videoShareModal [video]="video" [videoCaptions]="videoCaptions"></my-video-share>
|
||||||
</ng-template>
|
</ng-template>
|
||||||
|
|
|
@ -50,9 +50,11 @@ export class VideoWatchComponent implements OnInit, OnDestroy {
|
||||||
playerElement: HTMLVideoElement
|
playerElement: HTMLVideoElement
|
||||||
theaterEnabled = false
|
theaterEnabled = false
|
||||||
userRating: UserVideoRateType = null
|
userRating: UserVideoRateType = null
|
||||||
video: VideoDetails = null
|
|
||||||
descriptionLoading = false
|
descriptionLoading = false
|
||||||
|
|
||||||
|
video: VideoDetails = null
|
||||||
|
videoCaptions: VideoCaption[] = []
|
||||||
|
|
||||||
playlist: VideoPlaylist = null
|
playlist: VideoPlaylist = null
|
||||||
|
|
||||||
completeDescriptionShown = false
|
completeDescriptionShown = false
|
||||||
|
@ -339,6 +341,7 @@ export class VideoWatchComponent implements OnInit, OnDestroy {
|
||||||
urlOptions: CustomizationOptions & { playerMode: PlayerMode }
|
urlOptions: CustomizationOptions & { playerMode: PlayerMode }
|
||||||
) {
|
) {
|
||||||
this.video = video
|
this.video = video
|
||||||
|
this.videoCaptions = videoCaptions
|
||||||
|
|
||||||
// Re init attributes
|
// Re init attributes
|
||||||
this.descriptionLoading = false
|
this.descriptionLoading = false
|
||||||
|
|
|
@ -446,7 +446,7 @@ export class PeertubePlayerManager {
|
||||||
label: player.localize('Copy the video URL at the current time'),
|
label: player.localize('Copy the video URL at the current time'),
|
||||||
listener: function () {
|
listener: function () {
|
||||||
const player = this as videojs.Player
|
const player = this as videojs.Player
|
||||||
copyToClipboard(buildVideoLink(player.currentTime()))
|
copyToClipboard(buildVideoLink({ startTime: player.currentTime() }))
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
|
|
|
@ -27,18 +27,55 @@ function isMobile () {
|
||||||
return /iPhone|iPad|iPod|Android/i.test(navigator.userAgent)
|
return /iPhone|iPad|iPod|Android/i.test(navigator.userAgent)
|
||||||
}
|
}
|
||||||
|
|
||||||
function buildVideoLink (time?: number, url?: string) {
|
function buildVideoLink (options: {
|
||||||
if (!url) url = window.location.origin + window.location.pathname.replace('/embed/', '/watch/')
|
baseUrl?: string,
|
||||||
|
|
||||||
if (time) {
|
startTime?: number,
|
||||||
const timeInt = Math.floor(time)
|
stopTime?: number,
|
||||||
|
|
||||||
|
subtitle?: string,
|
||||||
|
|
||||||
|
loop?: boolean,
|
||||||
|
autoplay?: boolean,
|
||||||
|
muted?: boolean,
|
||||||
|
|
||||||
|
// Embed options
|
||||||
|
title?: boolean,
|
||||||
|
warningTitle?: boolean,
|
||||||
|
controls?: boolean
|
||||||
|
} = {}) {
|
||||||
|
const { baseUrl } = options
|
||||||
|
|
||||||
|
const url = baseUrl
|
||||||
|
? baseUrl
|
||||||
|
: window.location.origin + window.location.pathname.replace('/embed/', '/watch/')
|
||||||
|
|
||||||
const params = new URLSearchParams(window.location.search)
|
const params = new URLSearchParams(window.location.search)
|
||||||
params.set('start', secondsToTime(timeInt))
|
|
||||||
|
|
||||||
return url + '?' + params.toString()
|
if (options.startTime) {
|
||||||
|
const startTimeInt = Math.floor(options.startTime)
|
||||||
|
params.set('start', secondsToTime(startTimeInt))
|
||||||
}
|
}
|
||||||
|
|
||||||
|
if (options.stopTime) {
|
||||||
|
const stopTimeInt = Math.floor(options.stopTime)
|
||||||
|
params.set('stop', secondsToTime(stopTimeInt))
|
||||||
|
}
|
||||||
|
|
||||||
|
if (options.subtitle) params.set('subtitle', options.subtitle)
|
||||||
|
|
||||||
|
if (options.loop === true) params.set('loop', '1')
|
||||||
|
if (options.autoplay === true) params.set('autoplay', '1')
|
||||||
|
if (options.muted === true) params.set('muted', '1')
|
||||||
|
if (options.title === false) params.set('title', '0')
|
||||||
|
if (options.warningTitle === false) params.set('warningTitle', '0')
|
||||||
|
if (options.controls === false) params.set('controls', '0')
|
||||||
|
|
||||||
|
let hasParams = false
|
||||||
|
params.forEach(() => hasParams = true)
|
||||||
|
|
||||||
|
if (hasParams) return url + '?' + params.toString()
|
||||||
|
|
||||||
return url
|
return url
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
@ -16,7 +16,7 @@ class PeerTubeLinkButton extends Button {
|
||||||
}
|
}
|
||||||
|
|
||||||
updateHref () {
|
updateHref () {
|
||||||
this.el().setAttribute('href', buildVideoLink(this.player().currentTime()))
|
this.el().setAttribute('href', buildVideoLink({ startTime: this.player().currentTime() }))
|
||||||
}
|
}
|
||||||
|
|
||||||
handleClick () {
|
handleClick () {
|
||||||
|
|
|
@ -12,6 +12,7 @@ $assets-path: '../assets/';
|
||||||
@import './player/index';
|
@import './player/index';
|
||||||
@import './loading-bar';
|
@import './loading-bar';
|
||||||
|
|
||||||
|
@import './bootstrap';
|
||||||
@import './primeng-custom';
|
@import './primeng-custom';
|
||||||
|
|
||||||
[hidden] {
|
[hidden] {
|
||||||
|
@ -181,128 +182,11 @@ label {
|
||||||
font-weight: bold;
|
font-weight: bold;
|
||||||
}
|
}
|
||||||
|
|
||||||
// Thanks https://gist.github.com/alexandrevicenzi/680147013e902a4eaa5d
|
|
||||||
.glyphicon-refresh-animate {
|
|
||||||
animation: spin .7s infinite linear;
|
|
||||||
}
|
|
||||||
|
|
||||||
@keyframes spin {
|
@keyframes spin {
|
||||||
from { transform: scale(1) rotate(0deg);}
|
from { transform: scale(1) rotate(0deg);}
|
||||||
to { transform: scale(1) rotate(360deg);}
|
to { transform: scale(1) rotate(360deg);}
|
||||||
}
|
}
|
||||||
|
|
||||||
// Bootstrap customizations
|
|
||||||
.dropdown-menu {
|
|
||||||
border-radius: 3px;
|
|
||||||
box-shadow: 0 3px 6px;
|
|
||||||
font-size: 15px;
|
|
||||||
|
|
||||||
.dropdown-item {
|
|
||||||
padding: 3px 15px;
|
|
||||||
|
|
||||||
&:active {
|
|
||||||
color: #000 !important;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
button {
|
|
||||||
@include disable-default-a-behaviour;
|
|
||||||
}
|
|
||||||
|
|
||||||
a {
|
|
||||||
@include disable-default-a-behaviour;
|
|
||||||
color: #000 !important;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
.modal {
|
|
||||||
.modal-content {
|
|
||||||
background-color: var(--mainBackgroundColor);
|
|
||||||
}
|
|
||||||
|
|
||||||
.modal-header {
|
|
||||||
border-bottom: none;
|
|
||||||
margin-bottom: 5px;
|
|
||||||
|
|
||||||
.modal-title {
|
|
||||||
font-size: 20px;
|
|
||||||
font-weight: $font-semibold;
|
|
||||||
}
|
|
||||||
|
|
||||||
my-global-icon {
|
|
||||||
@include icon(24px);
|
|
||||||
|
|
||||||
position: relative;
|
|
||||||
top: 3px;
|
|
||||||
float: right;
|
|
||||||
|
|
||||||
margin: 0;
|
|
||||||
padding: 0;
|
|
||||||
opacity: 1;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
.inputs {
|
|
||||||
margin-bottom: 0;
|
|
||||||
text-align: right;
|
|
||||||
|
|
||||||
.action-button-cancel {
|
|
||||||
@include peertube-button;
|
|
||||||
@include grey-button;
|
|
||||||
|
|
||||||
display: inline-block;
|
|
||||||
margin-right: 10px;
|
|
||||||
}
|
|
||||||
|
|
||||||
.action-button-submit {
|
|
||||||
@include peertube-button;
|
|
||||||
@include orange-button;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
// Nav customizations
|
|
||||||
.nav .nav-link {
|
|
||||||
display: flex !important;
|
|
||||||
align-items: center;
|
|
||||||
height: 30px !important;
|
|
||||||
padding: 10px 15px !important;
|
|
||||||
}
|
|
||||||
|
|
||||||
.nav.nav-pills {
|
|
||||||
font-size: 16px !important;
|
|
||||||
|
|
||||||
.nav-link.active {
|
|
||||||
font-weight: $font-semibold !important;
|
|
||||||
}
|
|
||||||
|
|
||||||
a {
|
|
||||||
@include disable-default-a-behaviour;
|
|
||||||
|
|
||||||
color: var(--mainForegroundColor);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
ngb-tabset.bootstrap {
|
|
||||||
|
|
||||||
.nav-link {
|
|
||||||
&, & a {
|
|
||||||
@include disable-default-a-behaviour;
|
|
||||||
|
|
||||||
color: var(--mainForegroundColor) !important;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
.nav-pills .nav-link.active {
|
|
||||||
color: #000 !important;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
.nav-tabs .nav-link.active {
|
|
||||||
background-color: var(--mainBackgroundColor) !important;
|
|
||||||
border-bottom: none;
|
|
||||||
}
|
|
||||||
|
|
||||||
.orange-button {
|
.orange-button {
|
||||||
@include peertube-button;
|
@include peertube-button;
|
||||||
@include orange-button;
|
@include orange-button;
|
||||||
|
|
|
@ -0,0 +1,138 @@
|
||||||
|
$icon-font-path: '~@neos21/bootstrap3-glyphicons/assets/fonts/';
|
||||||
|
@import '_bootstrap';
|
||||||
|
|
||||||
|
@import '_variables';
|
||||||
|
@import '_mixins';
|
||||||
|
|
||||||
|
// Thanks https://gist.github.com/alexandrevicenzi/680147013e902a4eaa5d
|
||||||
|
.glyphicon-refresh-animate {
|
||||||
|
animation: spin .7s infinite linear;
|
||||||
|
}
|
||||||
|
|
||||||
|
@keyframes spin {
|
||||||
|
from { transform: scale(1) rotate(0deg);}
|
||||||
|
to { transform: scale(1) rotate(360deg);}
|
||||||
|
}
|
||||||
|
|
||||||
|
.dropdown-menu {
|
||||||
|
border-radius: 3px;
|
||||||
|
box-shadow: 0 3px 6px;
|
||||||
|
font-size: 15px;
|
||||||
|
|
||||||
|
.dropdown-item {
|
||||||
|
padding: 3px 15px;
|
||||||
|
|
||||||
|
&:active {
|
||||||
|
color: #000 !important;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
button {
|
||||||
|
@include disable-default-a-behaviour;
|
||||||
|
}
|
||||||
|
|
||||||
|
a {
|
||||||
|
@include disable-default-a-behaviour;
|
||||||
|
color: #000 !important;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
.modal {
|
||||||
|
.modal-content {
|
||||||
|
background-color: var(--mainBackgroundColor);
|
||||||
|
}
|
||||||
|
|
||||||
|
.modal-header {
|
||||||
|
border-bottom: none;
|
||||||
|
margin-bottom: 5px;
|
||||||
|
|
||||||
|
.modal-title {
|
||||||
|
font-size: 20px;
|
||||||
|
font-weight: $font-semibold;
|
||||||
|
}
|
||||||
|
|
||||||
|
my-global-icon {
|
||||||
|
@include icon(24px);
|
||||||
|
|
||||||
|
position: relative;
|
||||||
|
top: 3px;
|
||||||
|
float: right;
|
||||||
|
|
||||||
|
margin: 0;
|
||||||
|
padding: 0;
|
||||||
|
opacity: 1;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
.inputs {
|
||||||
|
margin-bottom: 0;
|
||||||
|
text-align: right;
|
||||||
|
|
||||||
|
.action-button-cancel {
|
||||||
|
@include peertube-button;
|
||||||
|
@include grey-button;
|
||||||
|
|
||||||
|
display: inline-block;
|
||||||
|
margin-right: 10px;
|
||||||
|
}
|
||||||
|
|
||||||
|
.action-button-submit {
|
||||||
|
@include peertube-button;
|
||||||
|
@include orange-button;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// Nav customizations
|
||||||
|
.nav .nav-link {
|
||||||
|
display: flex !important;
|
||||||
|
align-items: center;
|
||||||
|
height: 30px !important;
|
||||||
|
padding: 10px 15px !important;
|
||||||
|
}
|
||||||
|
|
||||||
|
.nav.nav-pills {
|
||||||
|
font-size: 16px !important;
|
||||||
|
|
||||||
|
.nav-link.active {
|
||||||
|
font-weight: $font-semibold !important;
|
||||||
|
}
|
||||||
|
|
||||||
|
a {
|
||||||
|
@include disable-default-a-behaviour;
|
||||||
|
|
||||||
|
color: var(--mainForegroundColor);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
ngb-tabset.bootstrap {
|
||||||
|
|
||||||
|
.nav-link {
|
||||||
|
&, & a {
|
||||||
|
@include disable-default-a-behaviour;
|
||||||
|
|
||||||
|
color: var(--mainForegroundColor) !important;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
.nav-pills .nav-link.active {
|
||||||
|
color: #000 !important;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
.nav-tabs .nav-link.active {
|
||||||
|
background-color: var(--mainBackgroundColor) !important;
|
||||||
|
border-bottom: none;
|
||||||
|
}
|
||||||
|
|
||||||
|
.collapse-transition {
|
||||||
|
// Animation when we show/hide the filters
|
||||||
|
transition: max-height 0.3s;
|
||||||
|
display: block !important;
|
||||||
|
overflow: hidden !important;
|
||||||
|
max-height: 0;
|
||||||
|
|
||||||
|
&.show {
|
||||||
|
max-height: 1500px;
|
||||||
|
}
|
||||||
|
}
|
|
@ -235,6 +235,14 @@
|
||||||
position: relative;
|
position: relative;
|
||||||
font-size: 15px;
|
font-size: 15px;
|
||||||
|
|
||||||
|
&.disabled {
|
||||||
|
background-color: #E5E5E5;
|
||||||
|
|
||||||
|
select {
|
||||||
|
cursor: default;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
@media screen and (max-width: $width) {
|
@media screen and (max-width: $width) {
|
||||||
width: 100%;
|
width: 100%;
|
||||||
}
|
}
|
||||||
|
@ -282,16 +290,6 @@
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@mixin peertube-select-disabled-container ($width) {
|
|
||||||
@include peertube-select-container($width);
|
|
||||||
|
|
||||||
background-color: #E5E5E5;
|
|
||||||
|
|
||||||
select {
|
|
||||||
cursor: default;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
// Thanks: https://codepen.io/triss90/pen/XNEdRe/
|
// Thanks: https://codepen.io/triss90/pen/XNEdRe/
|
||||||
@mixin peertube-radio-container {
|
@mixin peertube-radio-container {
|
||||||
input[type="radio"] {
|
input[type="radio"] {
|
||||||
|
|
Loading…
Reference in New Issue