mirror of
https://github.com/videojs/video.js.git
synced 2025-02-14 12:20:48 +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:
parent
51b9861d5b
commit
62465b841e
@ -32,35 +32,33 @@
|
|||||||
width: 1px;
|
width: 1px;
|
||||||
height: 1px;
|
height: 1px;
|
||||||
margin-left: -1px;
|
margin-left: -1px;
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
||||||
.video-js .vjs-volume-panel {
|
.video-js .vjs-volume-panel {
|
||||||
&:hover .vjs-volume-control,
|
&.vjs-hover .vjs-volume-control,
|
||||||
&:active .vjs-volume-control,
|
&:active .vjs-volume-control,
|
||||||
&:focus .vjs-volume-control,
|
&:focus .vjs-volume-control,
|
||||||
& .vjs-volume-control:hover ,
|
& .vjs-volume-control:active,
|
||||||
& .vjs-volume-control:active ,
|
&.vjs-hover .vjs-mute-control ~ .vjs-volume-control,
|
||||||
& .vjs-mute-control:hover ~ .vjs-volume-control,
|
|
||||||
& .vjs-volume-control.vjs-slider-active {
|
& .vjs-volume-control.vjs-slider-active {
|
||||||
&.vjs-volume-horizontal {
|
&.vjs-volume-horizontal {
|
||||||
width: 5em;
|
width: 5em;
|
||||||
height: 3em;
|
height: 3em;
|
||||||
}
|
}
|
||||||
|
|
||||||
visibility: visible;
|
visibility: visible;
|
||||||
opacity: 1;
|
opacity: 1;
|
||||||
position: relative;
|
position: relative;
|
||||||
|
|
||||||
&.vjs-volume-vertical {
|
&.vjs-volume-vertical {
|
||||||
left: -3.5em;
|
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;
|
$transition-property: visibility 0.1s, opacity 0.1s, height 0.1s, width 0.1s, left 0s, top 0s;
|
||||||
@include transition($transition-property);
|
@include transition($transition-property);
|
||||||
}
|
}
|
||||||
|
|
||||||
&.vjs-volume-panel-horizontal {
|
&.vjs-volume-panel-horizontal {
|
||||||
&:hover,
|
&.vjs-hover,
|
||||||
&:active,
|
&:active,
|
||||||
&.vjs-slider-active {
|
&.vjs-slider-active {
|
||||||
width: 9em;
|
width: 9em;
|
||||||
@ -83,6 +81,7 @@
|
|||||||
$transition-property: visibility 1s, opacity 1s, height 1s 1s, width 1s 1s, left 1s 1s, top 1s 1s;
|
$transition-property: visibility 1s, opacity 1s, height 1s 1s, width 1s 1s, left 1s 1s, top 1s 1s;
|
||||||
@include transition($transition-property)
|
@include transition($transition-property)
|
||||||
}
|
}
|
||||||
|
|
||||||
.video-js .vjs-volume-panel .vjs-volume-control.vjs-volume-horizontal {
|
.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;
|
$transition-property: visibility 1s, opacity 1s, height 1s 1s, width 1s, left 1s 1s, top 1s 1s;
|
||||||
@include transition($transition-property)
|
@include transition($transition-property)
|
||||||
|
@ -38,7 +38,7 @@
|
|||||||
max-height: 25em;
|
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 {
|
.vjs-menu-button-popup .vjs-menu.vjs-lock-showing {
|
||||||
display: block;
|
display: block;
|
||||||
}
|
}
|
||||||
|
@ -168,6 +168,8 @@ class ClickableComponent extends Component {
|
|||||||
if (typeof this.tabIndex_ !== 'undefined') {
|
if (typeof this.tabIndex_ !== 'undefined') {
|
||||||
this.el_.removeAttribute('tabIndex');
|
this.el_.removeAttribute('tabIndex');
|
||||||
}
|
}
|
||||||
|
this.off('mouseover', this.handleMouseOver);
|
||||||
|
this.off('mouseout', this.handleMouseOut);
|
||||||
this.off(['tap', 'click'], this.handleClick);
|
this.off(['tap', 'click'], this.handleClick);
|
||||||
this.off('keydown', this.handleKeyDown);
|
this.off('keydown', this.handleKeyDown);
|
||||||
}
|
}
|
||||||
|
@ -3,6 +3,10 @@
|
|||||||
*/
|
*/
|
||||||
import Component from '../component.js';
|
import Component from '../component.js';
|
||||||
import {isPlain} from '../utils/obj';
|
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
|
// Required children
|
||||||
import './volume-control/volume-control.js';
|
import './volume-control/volume-control.js';
|
||||||
@ -42,6 +46,11 @@ class VolumePanel extends Component {
|
|||||||
super(player, options);
|
super(player, options);
|
||||||
|
|
||||||
this.on(player, ['loadstart'], this.volumePanelState_);
|
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
|
// while the slider is active (the mouse has been pressed down and
|
||||||
// is dragging) we do not want to hide the VolumeBar
|
// 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();
|
||||||
|
}
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
|
@ -5,8 +5,11 @@ import Button from '../button.js';
|
|||||||
import Component from '../component.js';
|
import Component from '../component.js';
|
||||||
import Menu from './menu.js';
|
import Menu from './menu.js';
|
||||||
import * as Dom from '../utils/dom.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 {toTitleCase} from '../utils/string-cases.js';
|
||||||
import { IS_IOS } from '../utils/browser.js';
|
import { IS_IOS } from '../utils/browser.js';
|
||||||
|
import document from 'global/document';
|
||||||
import keycode from 'keycode';
|
import keycode from 'keycode';
|
||||||
|
|
||||||
/**
|
/**
|
||||||
@ -49,9 +52,11 @@ class MenuButton extends Component {
|
|||||||
this.on(this.menuButton_, 'click', this.handleClick);
|
this.on(this.menuButton_, 'click', this.handleClick);
|
||||||
this.on(this.menuButton_, 'keydown', this.handleKeyDown);
|
this.on(this.menuButton_, 'keydown', this.handleKeyDown);
|
||||||
this.on(this.menuButton_, 'mouseenter', () => {
|
this.on(this.menuButton_, 'mouseenter', () => {
|
||||||
|
this.addClass('vjs-hover');
|
||||||
this.menu.show();
|
this.menu.show();
|
||||||
|
Events.on(document, 'keyup', Fn.bind(this, this.handleMenuKeyUp));
|
||||||
});
|
});
|
||||||
|
this.on('mouseleave', this.handleMouseLeave);
|
||||||
this.on('keydown', this.handleSubmenuKeyDown);
|
this.on('keydown', this.handleSubmenuKeyDown);
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -210,6 +215,14 @@ class MenuButton extends Component {
|
|||||||
return this.menuButton_.controlText(text, el);
|
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`.
|
* Handle a click on a `MenuButton`.
|
||||||
* See {@link ClickableComponent#handleClick} for instances where this is called.
|
* 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
|
* 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
|
* This method name now delegates to `handleSubmenuKeyDown`. This means
|
||||||
* anyone calling `handleSubmenuKeyPress` will not see their method calls
|
* anyone calling `handleSubmenuKeyPress` will not see their method calls
|
||||||
|
Loading…
x
Reference in New Issue
Block a user