1
0
mirror of https://github.com/videojs/video.js.git synced 2025-02-12 12:16:27 +02:00

fix: make 'Esc' works for a vertical volume bar and menus (#6046)

Improve player accessibility by adding 'Esc' functionality to the volume panel and menu popups.

Fixes #6004.
This commit is contained in:
Grzegorz Blaszczyk 2019-08-21 20:24:35 +02:00 committed by Gary Katsevman
parent 51b9861d5b
commit 62465b841e
5 changed files with 128 additions and 9 deletions

View File

@ -32,35 +32,33 @@
width: 1px;
height: 1px;
margin-left: -1px;
}
.video-js .vjs-volume-panel {
&:hover .vjs-volume-control,
&.vjs-hover .vjs-volume-control,
&:active .vjs-volume-control,
&:focus .vjs-volume-control,
& .vjs-volume-control:hover ,
& .vjs-volume-control:active ,
& .vjs-mute-control:hover ~ .vjs-volume-control,
& .vjs-volume-control:active,
&.vjs-hover .vjs-mute-control ~ .vjs-volume-control,
& .vjs-volume-control.vjs-slider-active {
&.vjs-volume-horizontal {
width: 5em;
height: 3em;
}
visibility: visible;
opacity: 1;
position: relative;
&.vjs-volume-vertical {
left: -3.5em;
@include transition(left 0s);
}
$transition-property: visibility 0.1s, opacity 0.1s, height 0.1s, width 0.1s, left 0s, top 0s;
@include transition($transition-property);
}
&.vjs-volume-panel-horizontal {
&:hover,
&.vjs-hover,
&:active,
&.vjs-slider-active {
width: 9em;
@ -83,6 +81,7 @@
$transition-property: visibility 1s, opacity 1s, height 1s 1s, width 1s 1s, left 1s 1s, top 1s 1s;
@include transition($transition-property)
}
.video-js .vjs-volume-panel .vjs-volume-control.vjs-volume-horizontal {
$transition-property: visibility 1s, opacity 1s, height 1s 1s, width 1s, left 1s 1s, top 1s 1s;
@include transition($transition-property)

View File

@ -38,7 +38,7 @@
max-height: 25em;
}
.vjs-workinghover .vjs-menu-button-popup:hover .vjs-menu,
.vjs-workinghover .vjs-menu-button-popup.vjs-hover .vjs-menu,
.vjs-menu-button-popup .vjs-menu.vjs-lock-showing {
display: block;
}

View File

@ -168,6 +168,8 @@ class ClickableComponent extends Component {
if (typeof this.tabIndex_ !== 'undefined') {
this.el_.removeAttribute('tabIndex');
}
this.off('mouseover', this.handleMouseOver);
this.off('mouseout', this.handleMouseOut);
this.off(['tap', 'click'], this.handleClick);
this.off('keydown', this.handleKeyDown);
}

View File

@ -3,6 +3,10 @@
*/
import Component from '../component.js';
import {isPlain} from '../utils/obj';
import * as Events from '../utils/events.js';
import * as Fn from '../utils/fn.js';
import keycode from 'keycode';
import document from 'global/document';
// Required children
import './volume-control/volume-control.js';
@ -42,6 +46,11 @@ class VolumePanel extends Component {
super(player, options);
this.on(player, ['loadstart'], this.volumePanelState_);
this.on(this.muteToggle, 'keyup', this.handleKeyPress);
this.on(this.volumeControl, 'keyup', this.handleVolumeControlKeyUp);
this.on('keydown', this.handleKeyPress);
this.on('mouseover', this.handleMouseOver);
this.on('mouseout', this.handleMouseOut);
// while the slider is active (the mouse has been pressed down and
// is dragging) we do not want to hide the VolumeBar
@ -109,6 +118,73 @@ class VolumePanel extends Component {
});
}
/**
* Dispose of the `volume-panel` and all child components.
*/
dispose() {
this.handleMouseOut();
super.dispose();
}
/**
* Handles `keyup` events on the `VolumeControl`, looking for ESC, which closes
* the volume panel and sets focus on `MuteToggle`.
*
* @param {EventTarget~Event} event
* The `keyup` event that caused this function to be called.
*
* @listens keyup
*/
handleVolumeControlKeyUp(event) {
if (keycode.isEventKey(event, 'Esc')) {
this.muteToggle.focus();
}
}
/**
* This gets called when a `VolumePanel` gains hover via a `mouseover` event.
* Turns on listening for `mouseover` event. When they happen it
* calls `this.handleMouseOver`.
*
* @param {EventTarget~Event} event
* The `mouseover` event that caused this function to be called.
*
* @listens mouseover
*/
handleMouseOver(event) {
this.addClass('vjs-hover');
Events.on(document, 'keyup', Fn.bind(this, this.handleKeyPress));
}
/**
* This gets called when a `VolumePanel` gains hover via a `mouseout` event.
* Turns on listening for `mouseout` event. When they happen it
* calls `this.handleMouseOut`.
*
* @param {EventTarget~Event} event
* The `mouseout` event that caused this function to be called.
*
* @listens mouseout
*/
handleMouseOut(event) {
this.removeClass('vjs-hover');
Events.off(document, 'keyup', Fn.bind(this, this.handleKeyPress));
}
/**
* Handles `keyup` event on the document or `keydown` event on the `VolumePanel`,
* looking for ESC, which hides the `VolumeControl`.
*
* @param {EventTarget~Event} event
* The keypress that triggered this event.
*
* @listens keydown | keyup
*/
handleKeyPress(event) {
if (keycode.isEventKey(event, 'Esc')) {
this.handleMouseOut();
}
}
}
/**

View File

@ -5,8 +5,11 @@ import Button from '../button.js';
import Component from '../component.js';
import Menu from './menu.js';
import * as Dom from '../utils/dom.js';
import * as Fn from '../utils/fn.js';
import * as Events from '../utils/events.js';
import {toTitleCase} from '../utils/string-cases.js';
import { IS_IOS } from '../utils/browser.js';
import document from 'global/document';
import keycode from 'keycode';
/**
@ -49,9 +52,11 @@ class MenuButton extends Component {
this.on(this.menuButton_, 'click', this.handleClick);
this.on(this.menuButton_, 'keydown', this.handleKeyDown);
this.on(this.menuButton_, 'mouseenter', () => {
this.addClass('vjs-hover');
this.menu.show();
Events.on(document, 'keyup', Fn.bind(this, this.handleMenuKeyUp));
});
this.on('mouseleave', this.handleMouseLeave);
this.on('keydown', this.handleSubmenuKeyDown);
}
@ -210,6 +215,14 @@ class MenuButton extends Component {
return this.menuButton_.controlText(text, el);
}
/**
* Dispose of the `menu-button` and all child components.
*/
dispose() {
this.handleMouseLeave();
super.dispose();
}
/**
* Handle a click on a `MenuButton`.
* See {@link ClickableComponent#handleClick} for instances where this is called.
@ -229,6 +242,19 @@ class MenuButton extends Component {
}
}
/**
* Handle `mouseleave` for `MenuButton`.
*
* @param {EventTarget~Event} event
* The `mouseleave` event that caused this function to be called.
*
* @listens mouseleave
*/
handleMouseLeave(event) {
this.removeClass('vjs-hover');
Events.off(document, 'keyup', Fn.bind(this, this.handleMenuKeyUp));
}
/**
* Set the focus to the actual button, not to this element
*/
@ -275,6 +301,22 @@ class MenuButton extends Component {
}
}
/**
* Handle a `keyup` event on a `MenuButton`. The listener for this is added in
* the constructor.
*
* @param {EventTarget~Event} event
* Key press event
*
* @listens keyup
*/
handleMenuKeyUp(event) {
// Escape hides popup menu
if (keycode.isEventKey(event, 'Esc') || keycode.isEventKey(event, 'Tab')) {
this.removeClass('vjs-hover');
}
}
/**
* This method name now delegates to `handleSubmenuKeyDown`. This means
* anyone calling `handleSubmenuKeyPress` will not see their method calls