mirror of
https://github.com/videojs/video.js.git
synced 2025-04-13 11:50:49 +02:00
262 lines
6.6 KiB
JavaScript
262 lines
6.6 KiB
JavaScript
/**
|
|
* @file clickable-component.js
|
|
*/
|
|
import Component from './component';
|
|
import * as Dom from './utils/dom.js';
|
|
import log from './utils/log.js';
|
|
import keycode from 'keycode';
|
|
|
|
/**
|
|
* @typedef { import('./player').default } Player
|
|
*/
|
|
|
|
/**
|
|
* Component which is clickable or keyboard actionable, but is not a
|
|
* native HTML button.
|
|
*
|
|
* @extends Component
|
|
*/
|
|
class ClickableComponent extends Component {
|
|
|
|
/**
|
|
* Creates an instance of this class.
|
|
*
|
|
* @param {Player} player
|
|
* The `Player` that this class should be attached to.
|
|
*
|
|
* @param {Object} [options]
|
|
* The key/value store of component options.
|
|
*
|
|
* @param {function} [options.clickHandler]
|
|
* The function to call when the button is clicked / activated
|
|
*
|
|
* @param {string} [options.controlText]
|
|
* The text to set on the button
|
|
*
|
|
* @param {string} [options.className]
|
|
* A class or space separated list of classes to add the component
|
|
*
|
|
*/
|
|
constructor(player, options) {
|
|
|
|
super(player, options);
|
|
|
|
if (this.options_.controlText) {
|
|
this.controlText(this.options_.controlText);
|
|
}
|
|
|
|
this.handleMouseOver_ = (e) => this.handleMouseOver(e);
|
|
this.handleMouseOut_ = (e) => this.handleMouseOut(e);
|
|
this.handleClick_ = (e) => this.handleClick(e);
|
|
this.handleKeyDown_ = (e) => this.handleKeyDown(e);
|
|
|
|
this.emitTapEvents();
|
|
|
|
this.enable();
|
|
}
|
|
|
|
/**
|
|
* Create the `ClickableComponent`s DOM element.
|
|
*
|
|
* @param {string} [tag=div]
|
|
* The element's node type.
|
|
*
|
|
* @param {Object} [props={}]
|
|
* An object of properties that should be set on the element.
|
|
*
|
|
* @param {Object} [attributes={}]
|
|
* An object of attributes that should be set on the element.
|
|
*
|
|
* @return {Element}
|
|
* The element that gets created.
|
|
*/
|
|
createEl(tag = 'div', props = {}, attributes = {}) {
|
|
props = Object.assign({
|
|
className: this.buildCSSClass(),
|
|
tabIndex: 0
|
|
}, props);
|
|
|
|
if (tag === 'button') {
|
|
log.error(`Creating a ClickableComponent with an HTML element of ${tag} is not supported; use a Button instead.`);
|
|
}
|
|
|
|
// Add ARIA attributes for clickable element which is not a native HTML button
|
|
attributes = Object.assign({
|
|
role: 'button'
|
|
}, attributes);
|
|
|
|
this.tabIndex_ = props.tabIndex;
|
|
|
|
const el = Dom.createEl(tag, props, attributes);
|
|
|
|
el.appendChild(Dom.createEl('span', {
|
|
className: 'vjs-icon-placeholder'
|
|
}, {
|
|
'aria-hidden': true
|
|
}));
|
|
|
|
this.createControlTextEl(el);
|
|
|
|
return el;
|
|
}
|
|
|
|
dispose() {
|
|
// remove controlTextEl_ on dispose
|
|
this.controlTextEl_ = null;
|
|
|
|
super.dispose();
|
|
}
|
|
|
|
/**
|
|
* Create a control text element on this `ClickableComponent`
|
|
*
|
|
* @param {Element} [el]
|
|
* Parent element for the control text.
|
|
*
|
|
* @return {Element}
|
|
* The control text element that gets created.
|
|
*/
|
|
createControlTextEl(el) {
|
|
this.controlTextEl_ = Dom.createEl('span', {
|
|
className: 'vjs-control-text'
|
|
}, {
|
|
// let the screen reader user know that the text of the element may change
|
|
'aria-live': 'polite'
|
|
});
|
|
|
|
if (el) {
|
|
el.appendChild(this.controlTextEl_);
|
|
}
|
|
|
|
this.controlText(this.controlText_, el);
|
|
|
|
return this.controlTextEl_;
|
|
}
|
|
|
|
/**
|
|
* Get or set the localize text to use for the controls on the `ClickableComponent`.
|
|
*
|
|
* @param {string} [text]
|
|
* Control text for element.
|
|
*
|
|
* @param {Element} [el=this.el()]
|
|
* Element to set the title on.
|
|
*
|
|
* @return {string}
|
|
* - The control text when getting
|
|
*/
|
|
controlText(text, el = this.el()) {
|
|
if (text === undefined) {
|
|
return this.controlText_ || 'Need Text';
|
|
}
|
|
|
|
const localizedText = this.localize(text);
|
|
|
|
/** @protected */
|
|
this.controlText_ = text;
|
|
Dom.textContent(this.controlTextEl_, localizedText);
|
|
if (!this.nonIconControl && !this.player_.options_.noUITitleAttributes) {
|
|
// Set title attribute if only an icon is shown
|
|
el.setAttribute('title', localizedText);
|
|
}
|
|
}
|
|
|
|
/**
|
|
* Builds the default DOM `className`.
|
|
*
|
|
* @return {string}
|
|
* The DOM `className` for this object.
|
|
*/
|
|
buildCSSClass() {
|
|
return `vjs-control vjs-button ${super.buildCSSClass()}`;
|
|
}
|
|
|
|
/**
|
|
* Enable this `ClickableComponent`
|
|
*/
|
|
enable() {
|
|
if (!this.enabled_) {
|
|
this.enabled_ = true;
|
|
this.removeClass('vjs-disabled');
|
|
this.el_.setAttribute('aria-disabled', 'false');
|
|
if (typeof this.tabIndex_ !== 'undefined') {
|
|
this.el_.setAttribute('tabIndex', this.tabIndex_);
|
|
}
|
|
this.on(['tap', 'click'], this.handleClick_);
|
|
this.on('keydown', this.handleKeyDown_);
|
|
}
|
|
}
|
|
|
|
/**
|
|
* Disable this `ClickableComponent`
|
|
*/
|
|
disable() {
|
|
this.enabled_ = false;
|
|
this.addClass('vjs-disabled');
|
|
this.el_.setAttribute('aria-disabled', 'true');
|
|
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_);
|
|
}
|
|
|
|
/**
|
|
* Handles language change in ClickableComponent for the player in components
|
|
*
|
|
*
|
|
*/
|
|
handleLanguagechange() {
|
|
this.controlText(this.controlText_);
|
|
}
|
|
|
|
/**
|
|
* Event handler that is called when a `ClickableComponent` receives a
|
|
* `click` or `tap` event.
|
|
*
|
|
* @param {Event} event
|
|
* The `tap` or `click` event that caused this function to be called.
|
|
*
|
|
* @listens tap
|
|
* @listens click
|
|
* @abstract
|
|
*/
|
|
handleClick(event) {
|
|
if (this.options_.clickHandler) {
|
|
this.options_.clickHandler.call(this, arguments);
|
|
}
|
|
}
|
|
|
|
/**
|
|
* Event handler that is called when a `ClickableComponent` receives a
|
|
* `keydown` event.
|
|
*
|
|
* By default, if the key is Space or Enter, it will trigger a `click` event.
|
|
*
|
|
* @param {Event} event
|
|
* The `keydown` event that caused this function to be called.
|
|
*
|
|
* @listens keydown
|
|
*/
|
|
handleKeyDown(event) {
|
|
|
|
// Support Space or Enter key operation to fire a click event. Also,
|
|
// prevent the event from propagating through the DOM and triggering
|
|
// Player hotkeys.
|
|
if (keycode.isEventKey(event, 'Space') || keycode.isEventKey(event, 'Enter')) {
|
|
event.preventDefault();
|
|
event.stopPropagation();
|
|
this.trigger('click');
|
|
} else {
|
|
|
|
// Pass keypress handling up for unsupported keys
|
|
super.handleKeyDown(event);
|
|
}
|
|
}
|
|
}
|
|
|
|
Component.registerComponent('ClickableComponent', ClickableComponent);
|
|
export default ClickableComponent;
|