]>
Commit | Line | Data |
---|---|---|
3bcb4fd7 RK |
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> | |
22 | ` | |
23 | } | |
24 | ||
25 | // @ts-ignore-start | |
26 | const Component = videojs.getComponent('Component') | |
27 | class EndCard extends Component { | |
28 | options_: any | |
29 | getTitle: Function | |
30 | next: Function | |
31 | condition: Function | |
32 | dashOffsetTotal = 586 | |
33 | dashOffsetStart = 293 | |
34 | interval = 50 | |
35 | upNextEvents = new videojs.EventTarget() | |
36 | chunkSize: number | |
37 | ||
38 | container: HTMLElement | |
39 | title: HTMLElement | |
40 | autoplayRing: HTMLElement | |
41 | cancelButton: HTMLElement | |
42 | nextButton: HTMLElement | |
43 | ||
44 | constructor (player: videojs.Player, options: any) { | |
45 | super(player, options) | |
46 | this.options_ = options | |
47 | ||
48 | this.getTitle = this.options_.getTitle | |
49 | this.next = this.options_.next | |
50 | this.condition = this.options_.condition | |
51 | ||
52 | this.chunkSize = (this.dashOffsetTotal - this.dashOffsetStart) / (this.options_.timeout / this.interval) | |
53 | ||
54 | player.on('ended', (_: any) => { | |
55 | if (!this.condition()) return | |
56 | ||
57 | player.addClass('vjs-upnext--showing') | |
58 | this.showCard((canceled: boolean) => { | |
59 | player.removeClass('vjs-upnext--showing') | |
60 | this.container.style.display = 'none' | |
61 | if (!canceled) { | |
62 | this.next() | |
63 | } | |
64 | }) | |
65 | }) | |
66 | ||
67 | player.on('playing', () => { | |
68 | this.upNextEvents.trigger('playing') | |
69 | }) | |
70 | } | |
71 | ||
72 | createEl () { | |
73 | const container = super.createEl('div', { | |
74 | className: 'vjs-upnext-content', | |
75 | innerHTML: getMainTemplate(this.options_) | |
76 | }) | |
77 | ||
78 | this.container = container | |
79 | container.style.display = 'none' | |
80 | ||
81 | this.autoplayRing = container.getElementsByClassName('vjs-upnext-svg-autoplay-ring')[0] | |
82 | this.title = container.getElementsByClassName('vjs-upnext-title')[0] | |
83 | this.cancelButton = container.getElementsByClassName('vjs-upnext-cancel-button')[0] | |
84 | this.nextButton = container.getElementsByClassName('vjs-upnext-autoplay-icon')[0] | |
85 | ||
86 | this.cancelButton.onclick = () => { | |
87 | this.upNextEvents.trigger('cancel') | |
88 | } | |
89 | ||
90 | this.nextButton.onclick = () => { | |
91 | this.upNextEvents.trigger('next') | |
92 | } | |
93 | ||
94 | return container | |
95 | } | |
96 | ||
97 | showCard (cb: Function) { | |
98 | let timeout: any | |
99 | let start: number | |
100 | let now: number | |
101 | let newOffset: number | |
102 | ||
103 | this.autoplayRing.setAttribute('stroke-dasharray', this.dashOffsetStart) | |
104 | this.autoplayRing.setAttribute('stroke-dashoffset', -this.dashOffsetStart) | |
105 | ||
106 | this.title.innerHTML = this.getTitle() | |
107 | ||
108 | this.upNextEvents.one('cancel', () => { | |
109 | clearTimeout(timeout) | |
110 | cb(true) | |
111 | }) | |
112 | ||
113 | this.upNextEvents.one('playing', () => { | |
114 | clearTimeout(timeout) | |
115 | cb(true) | |
116 | }) | |
117 | ||
118 | this.upNextEvents.one('next', () => { | |
119 | clearTimeout(timeout) | |
120 | cb(false) | |
121 | }) | |
122 | ||
123 | const update = () => { | |
124 | now = this.options_.timeout - (new Date().getTime() - start) | |
125 | ||
126 | if (now <= 0) { | |
127 | clearTimeout(timeout) | |
128 | cb(false) | |
129 | } else { | |
130 | newOffset = Math.max(-this.dashOffsetTotal, this.autoplayRing.getAttribute('stroke-dashoffset') - this.chunkSize) | |
131 | this.autoplayRing.setAttribute('stroke-dashoffset', newOffset) | |
132 | timeout = setTimeout(update.bind(this), this.interval) | |
133 | } | |
134 | ||
135 | } | |
136 | ||
137 | this.container.style.display = 'block' | |
138 | start = new Date().getTime() | |
139 | timeout = setTimeout(update.bind(this), this.interval) | |
140 | } | |
141 | } | |
142 | // @ts-ignore-end | |
143 | ||
144 | videojs.registerComponent('EndCard', EndCard) | |
145 | ||
146 | const Plugin: VideoJSComponentInterface = videojs.getPlugin('plugin') | |
147 | class UpNextPlugin extends Plugin { | |
148 | constructor (player: videojs.Player, options: any = {}) { | |
149 | const settings = { | |
150 | next: options.next, | |
151 | getTitle: options.getTitle, | |
152 | timeout: options.timeout || 5000, | |
153 | cancelText: options.cancelText || 'Cancel', | |
154 | headText: options.headText || 'Up Next', | |
155 | condition: options.condition | |
156 | } | |
157 | ||
158 | super(player, settings) | |
159 | ||
160 | this.player.ready(() => { | |
161 | player.addClass('vjs-upnext') | |
162 | }) | |
163 | ||
164 | player.addChild('EndCard', settings) | |
165 | } | |
166 | } | |
167 | ||
168 | videojs.registerPlugin('upnext', UpNextPlugin) | |
169 | export { UpNextPlugin } |