aboutsummaryrefslogtreecommitdiffhomepage
path: root/client/src/assets/player/settings-menu-item.ts
diff options
context:
space:
mode:
authorChocobozzz <me@florianbigard.com>2019-01-23 15:36:45 +0100
committerChocobozzz <chocobozzz@cpy.re>2019-02-11 09:13:02 +0100
commit2adfc7ea9a1f858db874df9fe322e7ae833db77c (patch)
treee27c6ebe01b7c96ea0e053839a38fc1f824d1284 /client/src/assets/player/settings-menu-item.ts
parent7eeb6a0ba4028d0e20847b846332dd0b7747c7f8 (diff)
downloadPeerTube-2adfc7ea9a1f858db874df9fe322e7ae833db77c.tar.gz
PeerTube-2adfc7ea9a1f858db874df9fe322e7ae833db77c.tar.zst
PeerTube-2adfc7ea9a1f858db874df9fe322e7ae833db77c.zip
Refractor videojs player
Add fake p2p-media-loader plugin
Diffstat (limited to 'client/src/assets/player/settings-menu-item.ts')
-rw-r--r--client/src/assets/player/settings-menu-item.ts332
1 files changed, 0 insertions, 332 deletions
diff --git a/client/src/assets/player/settings-menu-item.ts b/client/src/assets/player/settings-menu-item.ts
deleted file mode 100644
index 2a3460ae5..000000000
--- a/client/src/assets/player/settings-menu-item.ts
+++ /dev/null
@@ -1,332 +0,0 @@
1// Author: Yanko Shterev
2// Thanks https://github.com/yshterev/videojs-settings-menu
3
4// FIXME: something weird with our path definition in tsconfig and typings
5// @ts-ignore
6import * as videojs from 'video.js'
7
8import { toTitleCase } from './utils'
9import { VideoJSComponentInterface, videojsUntyped } from './peertube-videojs-typings'
10
11const MenuItem: VideoJSComponentInterface = videojsUntyped.getComponent('MenuItem')
12const component: VideoJSComponentInterface = videojsUntyped.getComponent('Component')
13
14class SettingsMenuItem extends MenuItem {
15
16 constructor (player: videojs.Player, options: any, entry: string, menuButton: VideoJSComponentInterface) {
17 super(player, options)
18
19 this.settingsButton = menuButton
20 this.dialog = this.settingsButton.dialog
21 this.mainMenu = this.settingsButton.menu
22 this.panel = this.dialog.getChild('settingsPanel')
23 this.panelChild = this.panel.getChild('settingsPanelChild')
24 this.panelChildEl = this.panelChild.el_
25
26 this.size = null
27
28 // keep state of what menu type is loading next
29 this.menuToLoad = 'mainmenu'
30
31 const subMenuName = toTitleCase(entry)
32 const SubMenuComponent = videojsUntyped.getComponent(subMenuName)
33
34 if (!SubMenuComponent) {
35 throw new Error(`Component ${subMenuName} does not exist`)
36 }
37 this.subMenu = new SubMenuComponent(this.player(), options, menuButton, this)
38 const subMenuClass = this.subMenu.buildCSSClass().split(' ')[0]
39 this.settingsSubMenuEl_.className += ' ' + subMenuClass
40
41 this.eventHandlers()
42
43 player.ready(() => {
44 // Voodoo magic for IOS
45 setTimeout(() => {
46 this.build()
47
48 // Update on rate change
49 player.on('ratechange', this.submenuClickHandler)
50
51 if (subMenuName === 'CaptionsButton') {
52 // Hack to regenerate captions on HTTP fallback
53 player.on('captionsChanged', () => {
54 setTimeout(() => {
55 this.settingsSubMenuEl_.innerHTML = ''
56 this.settingsSubMenuEl_.appendChild(this.subMenu.menu.el_)
57 this.update()
58 this.bindClickEvents()
59
60 }, 0)
61 })
62 }
63
64 this.reset()
65 }, 0)
66 })
67 }
68
69 eventHandlers () {
70 this.submenuClickHandler = this.onSubmenuClick.bind(this)
71 this.transitionEndHandler = this.onTransitionEnd.bind(this)
72 }
73
74 onSubmenuClick (event: any) {
75 let target = null
76
77 if (event.type === 'tap') {
78 target = event.target
79 } else {
80 target = event.currentTarget
81 }
82
83 if (target && target.classList.contains('vjs-back-button')) {
84 this.loadMainMenu()
85 return
86 }
87
88 // To update the sub menu value on click, setTimeout is needed because
89 // updating the value is not instant
90 setTimeout(() => this.update(event), 0)
91 }
92
93 /**
94 * Create the component's DOM element
95 *
96 * @return {Element}
97 * @method createEl
98 */
99 createEl () {
100 const el = videojsUntyped.dom.createEl('li', {
101 className: 'vjs-menu-item'
102 })
103
104 this.settingsSubMenuTitleEl_ = videojsUntyped.dom.createEl('div', {
105 className: 'vjs-settings-sub-menu-title'
106 })
107
108 el.appendChild(this.settingsSubMenuTitleEl_)
109
110 this.settingsSubMenuValueEl_ = videojsUntyped.dom.createEl('div', {
111 className: 'vjs-settings-sub-menu-value'
112 })
113
114 el.appendChild(this.settingsSubMenuValueEl_)
115
116 this.settingsSubMenuEl_ = videojsUntyped.dom.createEl('div', {
117 className: 'vjs-settings-sub-menu'
118 })
119
120 return el
121 }
122
123 /**
124 * Handle click on menu item
125 *
126 * @method handleClick
127 */
128 handleClick () {
129 this.menuToLoad = 'submenu'
130 // Remove open class to ensure only the open submenu gets this class
131 videojsUntyped.dom.removeClass(this.el_, 'open')
132
133 super.handleClick()
134
135 this.mainMenu.el_.style.opacity = '0'
136 // Whether to add or remove vjs-hidden class on the settingsSubMenuEl element
137 if (videojsUntyped.dom.hasClass(this.settingsSubMenuEl_, 'vjs-hidden')) {
138 videojsUntyped.dom.removeClass(this.settingsSubMenuEl_, 'vjs-hidden')
139
140 // animation not played without timeout
141 setTimeout(() => {
142 this.settingsSubMenuEl_.style.opacity = '1'
143 this.settingsSubMenuEl_.style.marginRight = '0px'
144 }, 0)
145
146 this.settingsButton.setDialogSize(this.size)
147 } else {
148 videojsUntyped.dom.addClass(this.settingsSubMenuEl_, 'vjs-hidden')
149 }
150 }
151
152 /**
153 * Create back button
154 *
155 * @method createBackButton
156 */
157 createBackButton () {
158 const button = this.subMenu.menu.addChild('MenuItem', {}, 0)
159 button.name_ = 'BackButton'
160 button.addClass('vjs-back-button')
161 button.el_.innerHTML = this.player_.localize(this.subMenu.controlText_)
162 }
163
164 /**
165 * Add/remove prefixed event listener for CSS Transition
166 *
167 * @method PrefixedEvent
168 */
169 PrefixedEvent (element: any, type: any, callback: any, action = 'addEvent') {
170 let prefix = ['webkit', 'moz', 'MS', 'o', '']
171
172 for (let p = 0; p < prefix.length; p++) {
173 if (!prefix[p]) {
174 type = type.toLowerCase()
175 }
176
177 if (action === 'addEvent') {
178 element.addEventListener(prefix[p] + type, callback, false)
179 } else if (action === 'removeEvent') {
180 element.removeEventListener(prefix[p] + type, callback, false)
181 }
182 }
183 }
184
185 onTransitionEnd (event: any) {
186 if (event.propertyName !== 'margin-right') {
187 return
188 }
189
190 if (this.menuToLoad === 'mainmenu') {
191 // hide submenu
192 videojsUntyped.dom.addClass(this.settingsSubMenuEl_, 'vjs-hidden')
193
194 // reset opacity to 0
195 this.settingsSubMenuEl_.style.opacity = '0'
196 }
197 }
198
199 reset () {
200 videojsUntyped.dom.addClass(this.settingsSubMenuEl_, 'vjs-hidden')
201 this.settingsSubMenuEl_.style.opacity = '0'
202 this.setMargin()
203 }
204
205 loadMainMenu () {
206 this.menuToLoad = 'mainmenu'
207 this.mainMenu.show()
208 this.mainMenu.el_.style.opacity = '0'
209
210 // back button will always take you to main menu, so set dialog sizes
211 this.settingsButton.setDialogSize([this.mainMenu.width, this.mainMenu.height])
212
213 // animation not triggered without timeout (some async stuff ?!?)
214 setTimeout(() => {
215 // animate margin and opacity before hiding the submenu
216 // this triggers CSS Transition event
217 this.setMargin()
218 this.mainMenu.el_.style.opacity = '1'
219 }, 0)
220 }
221
222 build () {
223 const saveUpdateLabel = this.subMenu.updateLabel
224 this.subMenu.updateLabel = () => {
225 this.update()
226
227 saveUpdateLabel.call(this.subMenu)
228 }
229
230 this.settingsSubMenuTitleEl_.innerHTML = this.player_.localize(this.subMenu.controlText_)
231 this.settingsSubMenuEl_.appendChild(this.subMenu.menu.el_)
232 this.panelChildEl.appendChild(this.settingsSubMenuEl_)
233 this.update()
234
235 this.createBackButton()
236 this.getSize()
237 this.bindClickEvents()
238
239 // prefixed event listeners for CSS TransitionEnd
240 this.PrefixedEvent(
241 this.settingsSubMenuEl_,
242 'TransitionEnd',
243 this.transitionEndHandler,
244 'addEvent'
245 )
246 }
247
248 update (event?: any) {
249 let target: HTMLElement = null
250 let subMenu = this.subMenu.name()
251
252 if (event && event.type === 'tap') {
253 target = event.target
254 } else if (event) {
255 target = event.currentTarget
256 }
257
258 // Playback rate menu button doesn't get a vjs-selected class
259 // or sets options_['selected'] on the selected playback rate.
260 // Thus we get the submenu value based on the labelEl of playbackRateMenuButton
261 if (subMenu === 'PlaybackRateMenuButton') {
262 setTimeout(() => this.settingsSubMenuValueEl_.innerHTML = this.subMenu.labelEl_.innerHTML, 250)
263 } else {
264 // Loop trough the submenu items to find the selected child
265 for (let subMenuItem of this.subMenu.menu.children_) {
266 if (!(subMenuItem instanceof component)) {
267 continue
268 }
269
270 if (subMenuItem.hasClass('vjs-selected')) {
271 // Prefer to use the function
272 if (typeof subMenuItem.getLabel === 'function') {
273 this.settingsSubMenuValueEl_.innerHTML = subMenuItem.getLabel()
274 break
275 }
276
277 this.settingsSubMenuValueEl_.innerHTML = subMenuItem.options_.label
278 }
279 }
280 }
281
282 if (target && !target.classList.contains('vjs-back-button')) {
283 this.settingsButton.hideDialog()
284 }
285 }
286
287 bindClickEvents () {
288 for (let item of this.subMenu.menu.children()) {
289 if (!(item instanceof component)) {
290 continue
291 }
292 item.on(['tap', 'click'], this.submenuClickHandler)
293 }
294 }
295
296 // save size of submenus on first init
297 // if number of submenu items change dynamically more logic will be needed
298 getSize () {
299 this.dialog.removeClass('vjs-hidden')
300 this.size = this.settingsButton.getComponentSize(this.settingsSubMenuEl_)
301 this.setMargin()
302 this.dialog.addClass('vjs-hidden')
303 videojsUntyped.dom.addClass(this.settingsSubMenuEl_, 'vjs-hidden')
304 }
305
306 setMargin () {
307 let [width] = this.size
308
309 this.settingsSubMenuEl_.style.marginRight = `-${width}px`
310 }
311
312 /**
313 * Hide the sub menu
314 */
315 hideSubMenu () {
316 // after removing settings item this.el_ === null
317 if (!this.el_) {
318 return
319 }
320
321 if (videojsUntyped.dom.hasClass(this.el_, 'open')) {
322 videojsUntyped.dom.addClass(this.settingsSubMenuEl_, 'vjs-hidden')
323 videojsUntyped.dom.removeClass(this.el_, 'open')
324 }
325 }
326
327}
328
329SettingsMenuItem.prototype.contentElType = 'button'
330videojsUntyped.registerComponent('SettingsMenuItem', SettingsMenuItem)
331
332export { SettingsMenuItem }