X-Git-Url: https://git.immae.eu/?a=blobdiff_plain;f=client%2Fsrc%2Fassets%2Fplayer%2Fvideojs-components%2Fsettings-menu-item.ts;h=f1342f1792ed5a2da9f4835df5a37d6cf81d1002;hb=d6d951ddc0c492f3261065b5dcb4df0534d252fc;hp=f14959f9cf4e0b958933cd0ff9e7fd3d63364796;hpb=28f3d1b36a70426795240c9370e47b6c4ba847f8;p=github%2FChocobozzz%2FPeerTube.git diff --git a/client/src/assets/player/videojs-components/settings-menu-item.ts b/client/src/assets/player/videojs-components/settings-menu-item.ts index f14959f9c..f1342f179 100644 --- a/client/src/assets/player/videojs-components/settings-menu-item.ts +++ b/client/src/assets/player/videojs-components/settings-menu-item.ts @@ -1,41 +1,63 @@ -// Author: Yanko Shterev -// Thanks https://github.com/yshterev/videojs-settings-menu - -// FIXME: something weird with our path definition in tsconfig and typings -// @ts-ignore -import * as videojs from 'video.js' - +// Thanks to Yanko Shterev: https://github.com/yshterev/videojs-settings-menu import { toTitleCase } from '../utils' -import { VideoJSComponentInterface, videojsUntyped } from '../peertube-videojs-typings' - -const MenuItem: VideoJSComponentInterface = videojsUntyped.getComponent('MenuItem') -const component: VideoJSComponentInterface = videojsUntyped.getComponent('Component') +import videojs from 'video.js' +import { SettingsButton } from './settings-menu-button' +import { SettingsDialog } from './settings-dialog' +import { SettingsPanel } from './settings-panel' +import { SettingsPanelChild } from './settings-panel-child' + +const MenuItem = videojs.getComponent('MenuItem') +const component = videojs.getComponent('Component') + +export interface SettingsMenuItemOptions extends videojs.MenuItemOptions { + entry: string + menuButton: SettingsButton +} class SettingsMenuItem extends MenuItem { - - constructor (player: videojs.Player, options: any, entry: string, menuButton: VideoJSComponentInterface) { + settingsButton: SettingsButton + dialog: SettingsDialog + mainMenu: videojs.Menu + panel: SettingsPanel + panelChild: SettingsPanelChild + panelChildEl: HTMLElement + size: number[] + menuToLoad: string + subMenu: SettingsButton + + submenuClickHandler: typeof SettingsMenuItem.prototype.onSubmenuClick + transitionEndHandler: typeof SettingsMenuItem.prototype.onTransitionEnd + + settingsSubMenuTitleEl_: HTMLElement + settingsSubMenuValueEl_: HTMLElement + settingsSubMenuEl_: HTMLElement + + constructor (player: videojs.Player, options?: SettingsMenuItemOptions) { super(player, options) - this.settingsButton = menuButton + this.settingsButton = options.menuButton this.dialog = this.settingsButton.dialog this.mainMenu = this.settingsButton.menu this.panel = this.dialog.getChild('settingsPanel') this.panelChild = this.panel.getChild('settingsPanelChild') - this.panelChildEl = this.panelChild.el_ + this.panelChildEl = this.panelChild.el() as HTMLElement this.size = null // keep state of what menu type is loading next this.menuToLoad = 'mainmenu' - const subMenuName = toTitleCase(entry) - const SubMenuComponent = videojsUntyped.getComponent(subMenuName) + const subMenuName = toTitleCase(options.entry) + const SubMenuComponent = videojs.getComponent(subMenuName) if (!SubMenuComponent) { throw new Error(`Component ${subMenuName} does not exist`) } - this.subMenu = new SubMenuComponent(this.player(), options, menuButton, this) - const subMenuClass = this.subMenu.buildCSSClass().split(' ')[0] + + const newOptions = Object.assign({}, options, { entry: options.menuButton, menuButton: this }) + + this.subMenu = new SubMenuComponent(this.player(), newOptions) as any // FIXME: typings + const subMenuClass = this.subMenu.buildCSSClass().split(' ')[ 0 ] this.settingsSubMenuEl_.className += ' ' + subMenuClass this.eventHandlers() @@ -43,6 +65,9 @@ class SettingsMenuItem extends MenuItem { player.ready(() => { // Voodoo magic for IOS setTimeout(() => { + // Player was destroyed + if (!this.player_) return + this.build() // Update on rate change @@ -53,10 +78,9 @@ class SettingsMenuItem extends MenuItem { player.on('captionsChanged', () => { setTimeout(() => { this.settingsSubMenuEl_.innerHTML = '' - this.settingsSubMenuEl_.appendChild(this.subMenu.menu.el_) + this.settingsSubMenuEl_.appendChild(this.subMenu.menu.el()) this.update() this.bindClickEvents() - }, 0) }) } @@ -88,6 +112,10 @@ class SettingsMenuItem extends MenuItem { // To update the sub menu value on click, setTimeout is needed because // updating the value is not instant setTimeout(() => this.update(event), 0) + + // Seems like videojs adds a vjs-hidden class on the caption menu after a click + // We don't need it + this.subMenu.menu.removeClass('vjs-hidden') } /** @@ -97,27 +125,27 @@ class SettingsMenuItem extends MenuItem { * @method createEl */ createEl () { - const el = videojsUntyped.dom.createEl('li', { + const el = videojs.dom.createEl('li', { className: 'vjs-menu-item' }) - this.settingsSubMenuTitleEl_ = videojsUntyped.dom.createEl('div', { + this.settingsSubMenuTitleEl_ = videojs.dom.createEl('div', { className: 'vjs-settings-sub-menu-title' - }) + }) as HTMLElement el.appendChild(this.settingsSubMenuTitleEl_) - this.settingsSubMenuValueEl_ = videojsUntyped.dom.createEl('div', { + this.settingsSubMenuValueEl_ = videojs.dom.createEl('div', { className: 'vjs-settings-sub-menu-value' - }) + }) as HTMLElement el.appendChild(this.settingsSubMenuValueEl_) - this.settingsSubMenuEl_ = videojsUntyped.dom.createEl('div', { + this.settingsSubMenuEl_ = videojs.dom.createEl('div', { className: 'vjs-settings-sub-menu' - }) + }) as HTMLElement - return el + return el as HTMLLIElement } /** @@ -125,17 +153,17 @@ class SettingsMenuItem extends MenuItem { * * @method handleClick */ - handleClick () { + handleClick (event: videojs.EventTarget.Event) { this.menuToLoad = 'submenu' // Remove open class to ensure only the open submenu gets this class - videojsUntyped.dom.removeClass(this.el_, 'open') + videojs.dom.removeClass(this.el(), 'open') - super.handleClick() + super.handleClick(event); - this.mainMenu.el_.style.opacity = '0' + (this.mainMenu.el() as HTMLElement).style.opacity = '0' // Whether to add or remove vjs-hidden class on the settingsSubMenuEl element - if (videojsUntyped.dom.hasClass(this.settingsSubMenuEl_, 'vjs-hidden')) { - videojsUntyped.dom.removeClass(this.settingsSubMenuEl_, 'vjs-hidden') + if (videojs.dom.hasClass(this.settingsSubMenuEl_, 'vjs-hidden')) { + videojs.dom.removeClass(this.settingsSubMenuEl_, 'vjs-hidden') // animation not played without timeout setTimeout(() => { @@ -145,7 +173,7 @@ class SettingsMenuItem extends MenuItem { this.settingsButton.setDialogSize(this.size) } else { - videojsUntyped.dom.addClass(this.settingsSubMenuEl_, 'vjs-hidden') + videojs.dom.addClass(this.settingsSubMenuEl_, 'vjs-hidden') } } @@ -156,9 +184,9 @@ class SettingsMenuItem extends MenuItem { */ createBackButton () { const button = this.subMenu.menu.addChild('MenuItem', {}, 0) - button.name_ = 'BackButton' - button.addClass('vjs-back-button') - button.el_.innerHTML = this.player_.localize(this.subMenu.controlText_) + + button.addClass('vjs-back-button'); + (button.el() as HTMLElement).innerHTML = this.player().localize(this.subMenu.controlText()) } /** @@ -167,17 +195,17 @@ class SettingsMenuItem extends MenuItem { * @method PrefixedEvent */ PrefixedEvent (element: any, type: any, callback: any, action = 'addEvent') { - let prefix = ['webkit', 'moz', 'MS', 'o', ''] + const prefix = [ 'webkit', 'moz', 'MS', 'o', '' ] for (let p = 0; p < prefix.length; p++) { - if (!prefix[p]) { + if (!prefix[ p ]) { type = type.toLowerCase() } if (action === 'addEvent') { - element.addEventListener(prefix[p] + type, callback, false) + element.addEventListener(prefix[ p ] + type, callback, false) } else if (action === 'removeEvent') { - element.removeEventListener(prefix[p] + type, callback, false) + element.removeEventListener(prefix[ p ] + type, callback, false) } } } @@ -189,7 +217,7 @@ class SettingsMenuItem extends MenuItem { if (this.menuToLoad === 'mainmenu') { // hide submenu - videojsUntyped.dom.addClass(this.settingsSubMenuEl_, 'vjs-hidden') + videojs.dom.addClass(this.settingsSubMenuEl_, 'vjs-hidden') // reset opacity to 0 this.settingsSubMenuEl_.style.opacity = '0' @@ -197,25 +225,27 @@ class SettingsMenuItem extends MenuItem { } reset () { - videojsUntyped.dom.addClass(this.settingsSubMenuEl_, 'vjs-hidden') + videojs.dom.addClass(this.settingsSubMenuEl_, 'vjs-hidden') this.settingsSubMenuEl_.style.opacity = '0' this.setMargin() } loadMainMenu () { + const mainMenuEl = this.mainMenu.el() as HTMLElement this.menuToLoad = 'mainmenu' this.mainMenu.show() - this.mainMenu.el_.style.opacity = '0' + mainMenuEl.style.opacity = '0' // back button will always take you to main menu, so set dialog sizes - this.settingsButton.setDialogSize([this.mainMenu.width, this.mainMenu.height]) + const mainMenuAny = this.mainMenu as any + this.settingsButton.setDialogSize([ mainMenuAny.width, mainMenuAny.height ]) // animation not triggered without timeout (some async stuff ?!?) setTimeout(() => { // animate margin and opacity before hiding the submenu // this triggers CSS Transition event this.setMargin() - this.mainMenu.el_.style.opacity = '1' + mainMenuEl.style.opacity = '1' }, 0) } @@ -229,8 +259,8 @@ class SettingsMenuItem extends MenuItem { this.update() }) - this.settingsSubMenuTitleEl_.innerHTML = this.player_.localize(this.subMenu.controlText_) - this.settingsSubMenuEl_.appendChild(this.subMenu.menu.el_) + this.settingsSubMenuTitleEl_.innerHTML = this.player().localize(this.subMenu.controlText()) + this.settingsSubMenuEl_.appendChild(this.subMenu.menu.el()) this.panelChildEl.appendChild(this.settingsSubMenuEl_) this.update() @@ -249,7 +279,7 @@ class SettingsMenuItem extends MenuItem { update (event?: any) { let target: HTMLElement = null - let subMenu = this.subMenu.name() + const subMenu = this.subMenu.name() if (event && event.type === 'tap') { target = event.target @@ -261,22 +291,25 @@ class SettingsMenuItem extends MenuItem { // or sets options_['selected'] on the selected playback rate. // Thus we get the submenu value based on the labelEl of playbackRateMenuButton if (subMenu === 'PlaybackRateMenuButton') { - setTimeout(() => this.settingsSubMenuValueEl_.innerHTML = this.subMenu.labelEl_.innerHTML, 250) + const html = (this.subMenu as any).labelEl_.innerHTML + setTimeout(() => this.settingsSubMenuValueEl_.innerHTML = html, 250) } else { // Loop trough the submenu items to find the selected child - for (let subMenuItem of this.subMenu.menu.children_) { + for (const subMenuItem of this.subMenu.menu.children_) { if (!(subMenuItem instanceof component)) { continue } if (subMenuItem.hasClass('vjs-selected')) { + const subMenuItemUntyped = subMenuItem as any + // Prefer to use the function - if (typeof subMenuItem.getLabel === 'function') { - this.settingsSubMenuValueEl_.innerHTML = subMenuItem.getLabel() + if (typeof subMenuItemUntyped.getLabel === 'function') { + this.settingsSubMenuValueEl_.innerHTML = subMenuItemUntyped.getLabel() break } - this.settingsSubMenuValueEl_.innerHTML = subMenuItem.options_.label + this.settingsSubMenuValueEl_.innerHTML = subMenuItemUntyped.options_.label } } } @@ -287,11 +320,11 @@ class SettingsMenuItem extends MenuItem { } bindClickEvents () { - for (let item of this.subMenu.menu.children()) { + for (const item of this.subMenu.menu.children()) { if (!(item instanceof component)) { continue } - item.on(['tap', 'click'], this.submenuClickHandler) + item.on([ 'tap', 'click' ], this.submenuClickHandler) } } @@ -299,15 +332,17 @@ class SettingsMenuItem extends MenuItem { // if number of submenu items change dynamically more logic will be needed setSize () { this.dialog.removeClass('vjs-hidden') - videojsUntyped.dom.removeClass(this.settingsSubMenuEl_, 'vjs-hidden') + videojs.dom.removeClass(this.settingsSubMenuEl_, 'vjs-hidden') this.size = this.settingsButton.getComponentSize(this.settingsSubMenuEl_) this.setMargin() this.dialog.addClass('vjs-hidden') - videojsUntyped.dom.addClass(this.settingsSubMenuEl_, 'vjs-hidden') + videojs.dom.addClass(this.settingsSubMenuEl_, 'vjs-hidden') } setMargin () { - let [width] = this.size + if (!this.size) return + + const [ width ] = this.size this.settingsSubMenuEl_.style.marginRight = `-${width}px` } @@ -317,19 +352,19 @@ class SettingsMenuItem extends MenuItem { */ hideSubMenu () { // after removing settings item this.el_ === null - if (!this.el_) { + if (!this.el()) { return } - if (videojsUntyped.dom.hasClass(this.el_, 'open')) { - videojsUntyped.dom.addClass(this.settingsSubMenuEl_, 'vjs-hidden') - videojsUntyped.dom.removeClass(this.el_, 'open') + if (videojs.dom.hasClass(this.el(), 'open')) { + videojs.dom.addClass(this.settingsSubMenuEl_, 'vjs-hidden') + videojs.dom.removeClass(this.el(), 'open') } } } -SettingsMenuItem.prototype.contentElType = 'button' -videojsUntyped.registerComponent('SettingsMenuItem', SettingsMenuItem) +(SettingsMenuItem as any).prototype.contentElType = 'button' +videojs.registerComponent('SettingsMenuItem', SettingsMenuItem) export { SettingsMenuItem }