]>
Commit | Line | Data |
---|---|---|
1 | // @ts-ignore | |
2 | import * as videojs from 'video.js' | |
3 | import { VideoJSComponentInterface } from '../peertube-videojs-typings' | |
4 | ||
5 | function getMainTemplate (options: any) { | |
6 | return ` | |
7 | <div class="vjs-upnext-top"> | |
8 | <span class="vjs-upnext-headtext">${options.headText}</span> | |
9 | <div class="vjs-upnext-title"></div> | |
10 | </div> | |
11 | <div class="vjs-upnext-autoplay-icon"> | |
12 | <svg height="100%" version="1.1" viewbox="0 0 98 98" width="100%"> | |
13 | <circle class="vjs-upnext-svg-autoplay-circle" cx="49" cy="49" fill="#000" fill-opacity="0.8" r="48"></circle> | |
14 | <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> | |
15 | <polygon class="vjs-upnext-svg-autoplay-triangle" fill="#fff" points="32,27 72,49 32,71"></polygon></svg> | |
16 | </div> | |
17 | <span class="vjs-upnext-bottom"> | |
18 | <span class="vjs-upnext-cancel"> | |
19 | <button class="vjs-upnext-cancel-button" tabindex="0" aria-label="Cancel autoplay">${options.cancelText}</button> | |
20 | </span> | |
21 | <span class="vjs-upnext-suspended">${options.suspendedText}</span> | |
22 | </span> | |
23 | ` | |
24 | } | |
25 | ||
26 | // @ts-ignore-start | |
27 | const Component = videojs.getComponent('Component') | |
28 | class EndCard extends Component { | |
29 | options_: any | |
30 | dashOffsetTotal = 586 | |
31 | dashOffsetStart = 293 | |
32 | interval = 50 | |
33 | upNextEvents = new videojs.EventTarget() | |
34 | ticks = 0 | |
35 | totalTicks: number | |
36 | ||
37 | container: HTMLElement | |
38 | title: HTMLElement | |
39 | autoplayRing: HTMLElement | |
40 | cancelButton: HTMLElement | |
41 | suspendedMessage: HTMLElement | |
42 | nextButton: HTMLElement | |
43 | ||
44 | constructor (player: videojs.Player, options: any) { | |
45 | super(player, options) | |
46 | ||
47 | this.totalTicks = this.options_.timeout / this.interval | |
48 | ||
49 | player.on('ended', (_: any) => { | |
50 | if (!this.options_.condition()) return | |
51 | ||
52 | player.addClass('vjs-upnext--showing') | |
53 | this.showCard((canceled: boolean) => { | |
54 | player.removeClass('vjs-upnext--showing') | |
55 | this.container.style.display = 'none' | |
56 | if (!canceled) { | |
57 | this.options_.next() | |
58 | } | |
59 | }) | |
60 | }) | |
61 | ||
62 | player.on('playing', () => { | |
63 | this.upNextEvents.trigger('playing') | |
64 | }) | |
65 | } | |
66 | ||
67 | createEl () { | |
68 | const container = super.createEl('div', { | |
69 | className: 'vjs-upnext-content', | |
70 | innerHTML: getMainTemplate(this.options_) | |
71 | }) | |
72 | ||
73 | this.container = container | |
74 | container.style.display = 'none' | |
75 | ||
76 | this.autoplayRing = container.getElementsByClassName('vjs-upnext-svg-autoplay-ring')[0] | |
77 | this.title = container.getElementsByClassName('vjs-upnext-title')[0] | |
78 | this.cancelButton = container.getElementsByClassName('vjs-upnext-cancel-button')[0] | |
79 | this.suspendedMessage = container.getElementsByClassName('vjs-upnext-suspended')[0] | |
80 | this.nextButton = container.getElementsByClassName('vjs-upnext-autoplay-icon')[0] | |
81 | ||
82 | this.cancelButton.onclick = () => { | |
83 | this.upNextEvents.trigger('cancel') | |
84 | } | |
85 | ||
86 | this.nextButton.onclick = () => { | |
87 | this.upNextEvents.trigger('next') | |
88 | } | |
89 | ||
90 | return container | |
91 | } | |
92 | ||
93 | showCard (cb: Function) { | |
94 | let timeout: any | |
95 | ||
96 | this.autoplayRing.setAttribute('stroke-dasharray', '' + this.dashOffsetStart) | |
97 | this.autoplayRing.setAttribute('stroke-dashoffset', '' + -this.dashOffsetStart) | |
98 | ||
99 | this.title.innerHTML = this.options_.getTitle() | |
100 | ||
101 | this.upNextEvents.one('cancel', () => { | |
102 | clearTimeout(timeout) | |
103 | cb(true) | |
104 | }) | |
105 | ||
106 | this.upNextEvents.one('playing', () => { | |
107 | clearTimeout(timeout) | |
108 | cb(true) | |
109 | }) | |
110 | ||
111 | this.upNextEvents.one('next', () => { | |
112 | clearTimeout(timeout) | |
113 | cb(false) | |
114 | }) | |
115 | ||
116 | const goToPercent = (percent: number) => { | |
117 | const newOffset = Math.max(-this.dashOffsetTotal, - this.dashOffsetStart - percent * this.dashOffsetTotal / 2 / 100) | |
118 | this.autoplayRing.setAttribute('stroke-dashoffset', '' + newOffset) | |
119 | } | |
120 | ||
121 | const tick = () => { | |
122 | goToPercent((this.ticks++) * 100 / this.totalTicks) | |
123 | } | |
124 | ||
125 | const update = () => { | |
126 | if (this.options_.suspended()) { | |
127 | this.suspendedMessage.innerText = this.options_.suspendedText | |
128 | goToPercent(0) | |
129 | this.ticks = 0 | |
130 | timeout = setTimeout(update.bind(this), 300) // checks once supsended can be a bit longer | |
131 | } else if (this.ticks >= this.totalTicks) { | |
132 | clearTimeout(timeout) | |
133 | cb(false) | |
134 | } else { | |
135 | this.suspendedMessage.innerText = '' | |
136 | tick() | |
137 | timeout = setTimeout(update.bind(this), this.interval) | |
138 | } | |
139 | } | |
140 | ||
141 | this.container.style.display = 'block' | |
142 | timeout = setTimeout(update.bind(this), this.interval) | |
143 | } | |
144 | } | |
145 | // @ts-ignore-end | |
146 | ||
147 | videojs.registerComponent('EndCard', EndCard) | |
148 | ||
149 | const Plugin: VideoJSComponentInterface = videojs.getPlugin('plugin') | |
150 | class UpNextPlugin extends Plugin { | |
151 | constructor (player: videojs.Player, options: any = {}) { | |
152 | const settings = { | |
153 | next: options.next, | |
154 | getTitle: options.getTitle, | |
155 | timeout: options.timeout || 5000, | |
156 | cancelText: options.cancelText || 'Cancel', | |
157 | headText: options.headText || 'Up Next', | |
158 | suspendedText: options.suspendedText || 'Autoplay is suspended', | |
159 | condition: options.condition, | |
160 | suspended: options.suspended | |
161 | } | |
162 | ||
163 | super(player, settings) | |
164 | ||
165 | this.player.ready(() => { | |
166 | player.addClass('vjs-upnext') | |
167 | }) | |
168 | ||
169 | player.addChild('EndCard', settings) | |
170 | } | |
171 | } | |
172 | ||
173 | videojs.registerPlugin('upnext', UpNextPlugin) | |
174 | export { UpNextPlugin } |