Support playlists in share modal
This commit is contained in:
parent
689a4f6946
commit
3a1fed11c5
|
@ -0,0 +1,9 @@
|
||||||
|
<div class="input-group">
|
||||||
|
<input #urlInput (click)="urlInput.select()" type="text" class="form-control readonly" readonly [value]="value" />
|
||||||
|
|
||||||
|
<div class="input-group-append">
|
||||||
|
<button [ngxClipboard]="urlInput" (click)="activateCopiedMessage()" type="button" class="btn btn-outline-secondary">
|
||||||
|
<span class="glyphicon glyphicon-copy"></span>
|
||||||
|
</button>
|
||||||
|
</div>
|
||||||
|
</div>
|
|
@ -0,0 +1,3 @@
|
||||||
|
input.readonly {
|
||||||
|
font-size: 15px;
|
||||||
|
}
|
|
@ -0,0 +1,21 @@
|
||||||
|
import { Component, Input } from '@angular/core'
|
||||||
|
import { Notifier } from '@app/core'
|
||||||
|
import { I18n } from '@ngx-translate/i18n-polyfill'
|
||||||
|
|
||||||
|
@Component({
|
||||||
|
selector: 'my-input-readonly-copy',
|
||||||
|
templateUrl: './input-readonly-copy.component.html',
|
||||||
|
styleUrls: [ './input-readonly-copy.component.scss' ]
|
||||||
|
})
|
||||||
|
export class InputReadonlyCopyComponent {
|
||||||
|
@Input() value = ''
|
||||||
|
|
||||||
|
constructor (
|
||||||
|
private notifier: Notifier,
|
||||||
|
private i18n: I18n
|
||||||
|
) { }
|
||||||
|
|
||||||
|
activateCopiedMessage () {
|
||||||
|
this.notifier.success(this.i18n('Copied'))
|
||||||
|
}
|
||||||
|
}
|
|
@ -95,6 +95,7 @@ import { ClipboardModule } from 'ngx-clipboard'
|
||||||
import { FollowService } from '@app/shared/instance/follow.service'
|
import { FollowService } from '@app/shared/instance/follow.service'
|
||||||
import { MultiSelectModule } from 'primeng/multiselect'
|
import { MultiSelectModule } from 'primeng/multiselect'
|
||||||
import { FeatureBooleanComponent } from '@app/shared/instance/feature-boolean.component'
|
import { FeatureBooleanComponent } from '@app/shared/instance/feature-boolean.component'
|
||||||
|
import { InputReadonlyCopyComponent } from '@app/shared/forms/input-readonly-copy.component'
|
||||||
|
|
||||||
@NgModule({
|
@NgModule({
|
||||||
imports: [
|
imports: [
|
||||||
|
@ -155,6 +156,7 @@ import { FeatureBooleanComponent } from '@app/shared/instance/feature-boolean.co
|
||||||
ReactiveFileComponent,
|
ReactiveFileComponent,
|
||||||
PeertubeCheckboxComponent,
|
PeertubeCheckboxComponent,
|
||||||
TimestampInputComponent,
|
TimestampInputComponent,
|
||||||
|
InputReadonlyCopyComponent,
|
||||||
|
|
||||||
SubscribeButtonComponent,
|
SubscribeButtonComponent,
|
||||||
RemoteSubscribeComponent,
|
RemoteSubscribeComponent,
|
||||||
|
@ -220,6 +222,7 @@ import { FeatureBooleanComponent } from '@app/shared/instance/feature-boolean.co
|
||||||
InfiniteScrollerDirective,
|
InfiniteScrollerDirective,
|
||||||
TextareaAutoResizeDirective,
|
TextareaAutoResizeDirective,
|
||||||
HelpComponent,
|
HelpComponent,
|
||||||
|
InputReadonlyCopyComponent,
|
||||||
|
|
||||||
ReactiveFileComponent,
|
ReactiveFileComponent,
|
||||||
PeertubeCheckboxComponent,
|
PeertubeCheckboxComponent,
|
||||||
|
|
|
@ -4,21 +4,36 @@
|
||||||
<my-global-icon iconName="cross" aria-label="Close" role="button" (click)="hide()"></my-global-icon>
|
<my-global-icon iconName="cross" aria-label="Close" role="button" (click)="hide()"></my-global-icon>
|
||||||
</div>
|
</div>
|
||||||
|
|
||||||
|
|
||||||
<div class="modal-body">
|
<div class="modal-body">
|
||||||
|
<div class="playlist" *ngIf="hasPlaylist()">
|
||||||
|
<div class="title-page title-page-single" i18n>Share the playlist</div>
|
||||||
|
|
||||||
|
<my-input-readonly-copy [value]="getPlaylistUrl()"></my-input-readonly-copy>
|
||||||
|
|
||||||
|
<div class="filters">
|
||||||
|
|
||||||
|
<div class="form-group">
|
||||||
|
<my-peertube-checkbox
|
||||||
|
inputName="includeVideoInPlaylist" [(ngModel)]="includeVideoInPlaylist"
|
||||||
|
i18n-labelText labelText="Share the playlist at this video position"
|
||||||
|
></my-peertube-checkbox>
|
||||||
|
</div>
|
||||||
|
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
|
||||||
|
|
||||||
|
<div class="video">
|
||||||
|
<div class="title-page title-page-single" *ngIf="hasPlaylist()" i18n>Share the video</div>
|
||||||
|
|
||||||
<ngb-tabset class="root-tabset bootstrap" (tabChange)="onTabChange($event)">
|
<ngb-tabset class="root-tabset bootstrap" (tabChange)="onTabChange($event)">
|
||||||
|
|
||||||
<ngb-tab i18n-title title="URL" id="url">
|
<ngb-tab i18n-title title="URL" id="url">
|
||||||
<ng-template ngbTabContent>
|
<ng-template ngbTabContent>
|
||||||
|
|
||||||
<div class="tab-content">
|
<div class="tab-content">
|
||||||
<div class="input-group">
|
<my-input-readonly-copy [value]="getVideoUrl()"></my-input-readonly-copy>
|
||||||
<input #urlInput (click)="urlInput.select()" type="text" class="form-control readonly" readonly [value]="getVideoUrl()" />
|
|
||||||
<div class="input-group-append">
|
|
||||||
<button [ngxClipboard]="urlInput" (click)="activateCopiedMessage()" type="button" class="btn btn-outline-secondary">
|
|
||||||
<span class="glyphicon glyphicon-copy"></span>
|
|
||||||
</button>
|
|
||||||
</div>
|
|
||||||
</div>
|
|
||||||
</div>
|
</div>
|
||||||
|
|
||||||
</ng-template>
|
</ng-template>
|
||||||
|
@ -35,14 +50,7 @@
|
||||||
<ngb-tab i18n-title title="Embed" id="embed">
|
<ngb-tab i18n-title title="Embed" id="embed">
|
||||||
<ng-template ngbTabContent>
|
<ng-template ngbTabContent>
|
||||||
<div class="tab-content">
|
<div class="tab-content">
|
||||||
<div class="input-group">
|
<my-input-readonly-copy [value]="getVideoIframeCode()"></my-input-readonly-copy>
|
||||||
<input #shareInput (click)="shareInput.select()" type="text" class="form-control 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 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).
|
||||||
|
@ -168,6 +176,7 @@
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
</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,6 +1,18 @@
|
||||||
@import '_mixins';
|
@import '_mixins';
|
||||||
@import '_variables';
|
@import '_variables';
|
||||||
|
|
||||||
|
my-input-readonly-copy {
|
||||||
|
width: 100%;
|
||||||
|
}
|
||||||
|
|
||||||
|
.title-page.title-page-single {
|
||||||
|
margin-top: 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
.playlist {
|
||||||
|
margin-bottom: 50px;
|
||||||
|
}
|
||||||
|
|
||||||
.peertube-select-container {
|
.peertube-select-container {
|
||||||
@include peertube-select-container(200px);
|
@include peertube-select-container(200px);
|
||||||
}
|
}
|
||||||
|
@ -25,10 +37,6 @@
|
||||||
margin-top: 20px;
|
margin-top: 20px;
|
||||||
}
|
}
|
||||||
|
|
||||||
input.readonly {
|
|
||||||
font-size: 15px;
|
|
||||||
}
|
|
||||||
|
|
||||||
.filters {
|
.filters {
|
||||||
margin-top: 30px;
|
margin-top: 30px;
|
||||||
padding-top: 30px;
|
padding-top: 30px;
|
||||||
|
|
|
@ -5,6 +5,7 @@ import { buildVideoEmbed, buildVideoLink } from '../../../../assets/player/utils
|
||||||
import { I18n } from '@ngx-translate/i18n-polyfill'
|
import { I18n } from '@ngx-translate/i18n-polyfill'
|
||||||
import { NgbModal, NgbTabChangeEvent } from '@ng-bootstrap/ng-bootstrap'
|
import { NgbModal, NgbTabChangeEvent } from '@ng-bootstrap/ng-bootstrap'
|
||||||
import { VideoCaption } from '@shared/models'
|
import { VideoCaption } from '@shared/models'
|
||||||
|
import { VideoPlaylist } from '@app/shared/video-playlist/video-playlist.model'
|
||||||
|
|
||||||
type Customizations = {
|
type Customizations = {
|
||||||
startAtCheckbox: boolean
|
startAtCheckbox: boolean
|
||||||
|
@ -34,18 +35,16 @@ export class VideoShareComponent {
|
||||||
|
|
||||||
@Input() video: VideoDetails = null
|
@Input() video: VideoDetails = null
|
||||||
@Input() videoCaptions: VideoCaption[] = []
|
@Input() videoCaptions: VideoCaption[] = []
|
||||||
|
@Input() playlist: VideoPlaylist = null
|
||||||
|
|
||||||
activeId: 'url' | 'qrcode' | 'embed'
|
activeId: 'url' | 'qrcode' | 'embed'
|
||||||
customizations: Customizations
|
customizations: Customizations
|
||||||
isAdvancedCustomizationCollapsed = true
|
isAdvancedCustomizationCollapsed = true
|
||||||
|
includeVideoInPlaylist = false
|
||||||
|
|
||||||
private currentVideoTimestamp: number
|
private currentVideoTimestamp: number
|
||||||
|
|
||||||
constructor (
|
constructor (private modalService: NgbModal) { }
|
||||||
private modalService: NgbModal,
|
|
||||||
private notifier: Notifier,
|
|
||||||
private i18n: I18n
|
|
||||||
) { }
|
|
||||||
|
|
||||||
show (currentVideoTimestamp?: number) {
|
show (currentVideoTimestamp?: number) {
|
||||||
this.currentVideoTimestamp = currentVideoTimestamp
|
this.currentVideoTimestamp = currentVideoTimestamp
|
||||||
|
@ -86,17 +85,22 @@ export class VideoShareComponent {
|
||||||
}
|
}
|
||||||
|
|
||||||
getVideoUrl () {
|
getVideoUrl () {
|
||||||
const options = this.getOptions()
|
const baseUrl = window.location.origin + '/videos/watch/' + this.video.uuid
|
||||||
|
const options = this.getOptions(baseUrl)
|
||||||
|
|
||||||
return buildVideoLink(options)
|
return buildVideoLink(options)
|
||||||
}
|
}
|
||||||
|
|
||||||
notSecure () {
|
getPlaylistUrl () {
|
||||||
return window.location.protocol === 'http:'
|
const base = window.location.origin + '/videos/watch/playlist/' + this.playlist.uuid
|
||||||
|
|
||||||
|
if (!this.includeVideoInPlaylist) return base
|
||||||
|
|
||||||
|
return base + '?videoId=' + this.video.uuid
|
||||||
}
|
}
|
||||||
|
|
||||||
activateCopiedMessage () {
|
notSecure () {
|
||||||
this.notifier.success(this.i18n('Copied'))
|
return window.location.protocol === 'http:'
|
||||||
}
|
}
|
||||||
|
|
||||||
onTabChange (event: NgbTabChangeEvent) {
|
onTabChange (event: NgbTabChangeEvent) {
|
||||||
|
@ -107,6 +111,10 @@ export class VideoShareComponent {
|
||||||
return this.activeId === 'embed'
|
return this.activeId === 'embed'
|
||||||
}
|
}
|
||||||
|
|
||||||
|
hasPlaylist () {
|
||||||
|
return !!this.playlist
|
||||||
|
}
|
||||||
|
|
||||||
private getOptions (baseUrl?: string) {
|
private getOptions (baseUrl?: string) {
|
||||||
return {
|
return {
|
||||||
baseUrl,
|
baseUrl,
|
||||||
|
|
|
@ -224,5 +224,5 @@
|
||||||
|
|
||||||
<ng-container *ngIf="video !== null">
|
<ng-container *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" [videoCaptions]="videoCaptions"></my-video-share>
|
<my-video-share #videoShareModal [video]="video" [videoCaptions]="videoCaptions" [playlist]="playlist"></my-video-share>
|
||||||
</ng-container>
|
</ng-container>
|
||||||
|
|
|
@ -51,6 +51,8 @@ function buildVideoLink (options: {
|
||||||
: window.location.origin + window.location.pathname.replace('/embed/', '/watch/')
|
: window.location.origin + window.location.pathname.replace('/embed/', '/watch/')
|
||||||
|
|
||||||
const params = new URLSearchParams(window.location.search)
|
const params = new URLSearchParams(window.location.search)
|
||||||
|
// Remove this unused parameter when we are on a playlist page
|
||||||
|
params.delete('videoId')
|
||||||
|
|
||||||
if (options.startTime) {
|
if (options.startTime) {
|
||||||
const startTimeInt = Math.floor(options.startTime)
|
const startTimeInt = Math.floor(options.startTime)
|
||||||
|
|
Loading…
Reference in New Issue