Playback-rate: fix popup behavior (#1650)

* Playback-rate: fix popup behavior

- Part of 1637 - invokes the popup menu when clicked.
- This also makes the button consistent with other `MenuButton`s, i.e. to invoke a menu popup when clicked instead of hovered.

* Adjust CSS

Co-authored-by: Raphael Wickihalder <raphael.wickihalder@odysee.com>
This commit is contained in:
infinite-persistence 2022-06-13 21:55:05 +08:00 committed by GitHub
parent d5b7f25191
commit d3365d69f9
No known key found for this signature in database
GPG key ID: 4AEE18F83AFDEB23
3 changed files with 119 additions and 1 deletions

View file

@ -0,0 +1,95 @@
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;

View file

@ -16,6 +16,7 @@ import eventTracking from 'videojs-event-tracking';
import functions from './videojs-functions'; import functions from './videojs-functions';
import hlsQualitySelector from './plugins/videojs-hls-quality-selector/plugin'; import hlsQualitySelector from './plugins/videojs-hls-quality-selector/plugin';
import keyboardShorcuts from './videojs-shortcuts'; import keyboardShorcuts from './videojs-shortcuts';
import LbryPlaybackRateMenuButton from './lbry-playback-rate';
import LbryVolumeBarClass from './lbry-volume-bar'; import LbryVolumeBarClass from './lbry-volume-bar';
import Chromecast from './chromecast'; import Chromecast from './chromecast';
import playerjs from 'player.js'; import playerjs from 'player.js';
@ -278,8 +279,8 @@ export default React.memo<Props>(function VideoJs(props: Props) {
// runAds(internalFeatureEnabled, allowPreRoll, player, embedded); // runAds(internalFeatureEnabled, allowPreRoll, player, embedded);
// Replace volume bar with custom LBRY volume bar
LbryVolumeBarClass.replaceExisting(player); LbryVolumeBarClass.replaceExisting(player);
LbryPlaybackRateMenuButton.replaceExisting(player);
// Add reloadSourceOnError plugin // Add reloadSourceOnError plugin
player.reloadSourceOnError({ errorInterval: 10 }); player.reloadSourceOnError({ errorInterval: 10 });

View file

@ -205,6 +205,16 @@ $control-bar-popup-font-size: 0.8rem;
opacity: 1; opacity: 1;
} }
.vjs-lock-showing {
@media (max-width: $breakpoint-small) {
width: 8em !important;
// overflow-y:scroll;
.vjs-menu-content {
max-height: 176px !important;
}
}
}
[dir] .vjs-menu-button-popup .vjs-menu .vjs-menu-content { [dir] .vjs-menu-button-popup .vjs-menu .vjs-menu-content {
//background-color: rgba(43, 51, 63); //background-color: rgba(43, 51, 63);
background-color: rgba(var(--color-header-button-base), 0.9); background-color: rgba(var(--color-header-button-base), 0.9);
@ -239,6 +249,18 @@ $control-bar-popup-font-size: 0.8rem;
background-color: var(--color-primary); background-color: var(--color-primary);
border-radius: var(--border-radius); border-radius: var(--border-radius);
} }
@media (max-width: $breakpoint-small) {
padding: 0.1em 0;
margin-left: var(--spacing-xxs);
margin-right: var(--spacing-xxs);
&:first-child {
margin-top: var(--spacing-xxs);
}
&:last-child {
margin-bottom: var(--spacing-xxs);
}
}
} }
.vjs-selected { .vjs-selected {
background-color: var(--color-primary); background-color: var(--color-primary);