PeerTube/client/src/assets/player/shared/upnext/end-card.ts

180 lines
5.4 KiB
TypeScript
Raw Normal View History

2020-04-21 11:02:28 +02:00
import videojs from 'video.js'
2023-06-29 15:55:00 +02:00
import { UpNextPluginOptions } from '../../types'
2020-01-28 17:29:50 +01:00
2023-06-29 15:55:00 +02:00
function getMainTemplate (options: EndCardOptions) {
2020-01-28 17:29:50 +01:00
return `
<div class="vjs-upnext-top">
<span class="vjs-upnext-headtext">${options.headText}</span>
<div class="vjs-upnext-title"></div>
</div>
<div class="vjs-upnext-autoplay-icon">
<svg height="100%" version="1.1" viewbox="0 0 98 98" width="100%">
<circle class="vjs-upnext-svg-autoplay-circle" cx="49" cy="49" fill="#000" fill-opacity="0.8" r="48"></circle>
2021-08-17 14:42:53 +02:00
<circle class="vjs-upnext-svg-autoplay-ring" cx="-49" cy="49" fill-opacity="0" r="46.5"
stroke="#FFFFFF" stroke-width="4" transform="rotate(-90)"
></circle>
2020-01-28 17:29:50 +01:00
<polygon class="vjs-upnext-svg-autoplay-triangle" fill="#fff" points="32,27 72,49 32,71"></polygon></svg>
</div>
<span class="vjs-upnext-bottom">
<span class="vjs-upnext-cancel">
<button class="vjs-upnext-cancel-button" tabindex="0" aria-label="Cancel autoplay">${options.cancelText}</button>
</span>
<span class="vjs-upnext-suspended">${options.suspendedText}</span>
</span>
`
}
2023-06-29 15:55:00 +02:00
export interface EndCardOptions extends videojs.ComponentOptions, UpNextPluginOptions {
2020-01-28 17:29:50 +01:00
cancelText: string
headText: string
suspendedText: string
}
const Component = videojs.getComponent('Component')
2023-07-27 14:49:49 +02:00
export class EndCard extends Component {
2020-01-28 17:29:50 +01:00
options_: EndCardOptions
dashOffsetTotal = 586
dashOffsetStart = 293
interval = 50
upNextEvents = new videojs.EventTarget()
ticks = 0
totalTicks: number
container: HTMLDivElement
title: HTMLElement
autoplayRing: HTMLElement
cancelButton: HTMLElement
suspendedMessage: HTMLElement
nextButton: HTMLElement
private timeout: any
2023-06-29 15:55:00 +02:00
private onEndedHandler: () => void
private onPlayingHandler: () => void
2020-04-17 11:20:12 +02:00
constructor (player: videojs.Player, options: EndCardOptions) {
2020-01-28 17:29:50 +01:00
super(player, options)
this.totalTicks = this.options_.timeout / this.interval
2023-06-29 15:55:00 +02:00
this.onEndedHandler = () => {
if (!this.options_.isDisplayed()) return
2020-01-28 17:29:50 +01:00
player.addClass('vjs-upnext--showing')
2023-06-29 15:55:00 +02:00
this.showCard(canceled => {
2020-01-28 17:29:50 +01:00
player.removeClass('vjs-upnext--showing')
2023-06-29 15:55:00 +02:00
2020-01-28 17:29:50 +01:00
this.container.style.display = 'none'
2023-06-29 15:55:00 +02:00
2020-01-28 17:29:50 +01:00
if (!canceled) {
this.options_.next()
}
})
2023-06-29 15:55:00 +02:00
}
2020-01-28 17:29:50 +01:00
2023-06-29 15:55:00 +02:00
this.onPlayingHandler = () => {
2020-01-28 17:29:50 +01:00
this.upNextEvents.trigger('playing')
2023-06-29 15:55:00 +02:00
}
player.on([ 'auto-stopped', 'ended' ], this.onEndedHandler)
player.on('playing', this.onPlayingHandler)
}
dispose () {
if (this.onEndedHandler) this.player().off([ 'auto-stopped', 'ended' ], this.onEndedHandler)
if (this.onPlayingHandler) this.player().off('playing', this.onPlayingHandler)
if (this.timeout) clearTimeout(this.timeout)
2023-06-29 15:55:00 +02:00
super.dispose()
2020-01-28 17:29:50 +01:00
}
createEl () {
const container = super.createEl('div', {
className: 'vjs-upnext-content',
innerHTML: getMainTemplate(this.options_)
}) as HTMLDivElement
this.container = container
container.style.display = 'none'
this.autoplayRing = container.getElementsByClassName('vjs-upnext-svg-autoplay-ring')[0] as HTMLElement
this.title = container.getElementsByClassName('vjs-upnext-title')[0] as HTMLElement
this.cancelButton = container.getElementsByClassName('vjs-upnext-cancel-button')[0] as HTMLElement
this.suspendedMessage = container.getElementsByClassName('vjs-upnext-suspended')[0] as HTMLElement
this.nextButton = container.getElementsByClassName('vjs-upnext-autoplay-icon')[0] as HTMLElement
this.cancelButton.onclick = () => {
this.upNextEvents.trigger('cancel')
}
this.nextButton.onclick = () => {
this.upNextEvents.trigger('next')
}
return container
}
2023-06-29 15:55:00 +02:00
showCard (cb: (canceled: boolean) => void) {
2021-08-17 14:42:53 +02:00
this.autoplayRing.setAttribute('stroke-dasharray', `${this.dashOffsetStart}`)
this.autoplayRing.setAttribute('stroke-dashoffset', `${-this.dashOffsetStart}`)
2020-01-28 17:29:50 +01:00
this.title.innerText = this.options_.getTitle()
2020-01-28 17:29:50 +01:00
2023-06-29 15:55:00 +02:00
if (this.totalTicks === 0) {
return cb(false)
}
2020-01-28 17:29:50 +01:00
this.upNextEvents.one('cancel', () => {
clearTimeout(this.timeout)
this.timeout = undefined
2020-01-28 17:29:50 +01:00
cb(true)
})
this.upNextEvents.one('playing', () => {
clearTimeout(this.timeout)
this.timeout = undefined
2020-01-28 17:29:50 +01:00
cb(true)
})
this.upNextEvents.one('next', () => {
clearTimeout(this.timeout)
this.timeout = undefined
2020-01-28 17:29:50 +01:00
cb(false)
})
const goToPercent = (percent: number) => {
2021-08-17 14:42:53 +02:00
const newOffset = Math.max(-this.dashOffsetTotal, -this.dashOffsetStart - percent * this.dashOffsetTotal / 2 / 100)
2020-01-28 17:29:50 +01:00
this.autoplayRing.setAttribute('stroke-dashoffset', '' + newOffset)
}
const tick = () => {
goToPercent((this.ticks++) * 100 / this.totalTicks)
}
const update = () => {
2023-06-29 15:55:00 +02:00
if (this.options_.isSuspended()) {
2020-01-28 17:29:50 +01:00
this.suspendedMessage.innerText = this.options_.suspendedText
goToPercent(0)
this.ticks = 0
this.timeout = setTimeout(update.bind(this), 300) // checks once supsended can be a bit longer
2020-01-28 17:29:50 +01:00
} else if (this.ticks >= this.totalTicks) {
clearTimeout(this.timeout)
this.timeout = undefined
2020-01-28 17:29:50 +01:00
cb(false)
} else {
this.suspendedMessage.innerText = ''
tick()
this.timeout = setTimeout(update.bind(this), this.interval)
2020-01-28 17:29:50 +01:00
}
}
this.container.style.display = 'block'
this.timeout = setTimeout(update.bind(this), this.interval)
2020-01-28 17:29:50 +01:00
}
}
videojs.registerComponent('EndCard', EndCard)