96 lines
3 KiB
JavaScript
96 lines
3 KiB
JavaScript
|
import videojs from 'video.js';
|
||
|
|
||
|
const IS_DEV = process.env.NODE_ENV !== 'production';
|
||
|
const CONTROL_BAR = 'ControlBar';
|
||
|
const PLAYBACK_RATE_MENU_BUTTON = 'PlaybackRateMenuButton';
|
||
|
const MENU = 'Menu';
|
||
|
|
||
|
const Menu = videojs.getComponent(MENU);
|
||
|
const PlaybackRateMenuButton = videojs.getComponent(PLAYBACK_RATE_MENU_BUTTON);
|
||
|
|
||
|
class LbryPlaybackRateMenuButton extends PlaybackRateMenuButton {
|
||
|
static replaceExisting(player) {
|
||
|
try {
|
||
|
const controlBar = player.getChild(CONTROL_BAR);
|
||
|
const playbackRateMenuButton = controlBar.getChild(PLAYBACK_RATE_MENU_BUTTON);
|
||
|
controlBar.removeChild(playbackRateMenuButton);
|
||
|
controlBar.addChild(new LbryPlaybackRateMenuButton(player));
|
||
|
} catch (error) {
|
||
|
if (IS_DEV) throw Error('\n\nvideojs.jsx: Playback rate hierarchy changed?\n\n' + error);
|
||
|
}
|
||
|
}
|
||
|
|
||
|
constructor(player, options = {}) {
|
||
|
super(player, options);
|
||
|
}
|
||
|
|
||
|
/**
|
||
|
* The default behavior cycles through the selection, while the popup is
|
||
|
* invoked by hover. We have removed the hover behavior (1637) since it is
|
||
|
* annoying when accidentally hovered, and it's also needed to address a
|
||
|
* z-order issue.
|
||
|
*
|
||
|
* With the hover behavior gone, we need to override the default click
|
||
|
* behavior to invoke the popup instead of cycling through the settings.
|
||
|
*
|
||
|
* Ref: https://github.com/videojs/video.js/issues/3394#issuecomment-230793773
|
||
|
* @param event
|
||
|
*/
|
||
|
handleClick(event) {
|
||
|
if (this.buttonPressed_) {
|
||
|
this.unpressButton();
|
||
|
} else {
|
||
|
this.pressButton();
|
||
|
}
|
||
|
}
|
||
|
|
||
|
/**
|
||
|
* The default menu behavior is to dismiss the popup when losing focus, unless
|
||
|
* the new focus is on the associated button. The associated button is
|
||
|
* specifically defined as the first child, but PlaybackRateMenuButton
|
||
|
* implements it as the second child.
|
||
|
*
|
||
|
* Fixed by reversing the check to use `relatedTarget.parentElement` instead.
|
||
|
* It shouldn't matter which sub-element was clicked, as long as it's part of
|
||
|
* the button.
|
||
|
*
|
||
|
* @param event
|
||
|
* @param menu
|
||
|
*/
|
||
|
handleMenuBlur(event, menu) {
|
||
|
const relatedTarget = event.relatedTarget || document.activeElement;
|
||
|
|
||
|
if (
|
||
|
!menu.children().some((element) => {
|
||
|
return element.el() === relatedTarget;
|
||
|
})
|
||
|
) {
|
||
|
const btn = menu.menuButton_;
|
||
|
if (btn && btn.buttonPressed_ && relatedTarget.parentElement !== btn.el()) {
|
||
|
btn.unpressButton();
|
||
|
}
|
||
|
}
|
||
|
}
|
||
|
|
||
|
createMenu() {
|
||
|
const menu = new Menu(this.player_, { menuButton: this });
|
||
|
|
||
|
// Override the original with ours. Must be done after the constructor
|
||
|
// is called, as that is where `boundHandleBlur_` is originally set.
|
||
|
menu.boundHandleBlur_ = (e) => this.handleMenuBlur(e, menu);
|
||
|
|
||
|
this.hideThreshold_ = 0; // Must reset. See `MenuButton::createMenu` notes.
|
||
|
this.items = this.createItems();
|
||
|
|
||
|
if (this.items) {
|
||
|
for (let i = 0; i < this.items.length; ++i) {
|
||
|
menu.addItem(this.items[i]);
|
||
|
}
|
||
|
}
|
||
|
|
||
|
return menu;
|
||
|
}
|
||
|
}
|
||
|
|
||
|
export default LbryPlaybackRateMenuButton;
|