Files
shaka-player/ui/overflow_menu.js
T
Joey Parrish c1d849bc9b Fix UI button types
The compiler is very picky about the use of the "disabled" property on
HTMLElement, since it is only defined on certain subclasses of that.
This adds a method to create a button with the correct type to satisfy
the compiler.

Issue #2528

Change-Id: I31cacd62a35acc87b245ab362dbab55d791cf34d
2020-04-28 21:40:53 +00:00

247 lines
7.0 KiB
JavaScript

/** @license
* Copyright 2016 Google LLC
* SPDX-License-Identifier: Apache-2.0
*/
goog.provide('shaka.ui.OverflowMenu');
goog.require('goog.asserts');
goog.require('shaka.log');
goog.require('shaka.ui.Constants');
goog.require('shaka.ui.Controls');
goog.require('shaka.ui.Element');
goog.require('shaka.ui.Enums');
goog.require('shaka.ui.Locales');
goog.require('shaka.ui.Localization');
goog.require('shaka.ui.Utils');
goog.require('shaka.util.Dom');
/**
* @extends {shaka.ui.Element}
* @final
* @export
*/
shaka.ui.OverflowMenu = class extends shaka.ui.Element {
/**
* @param {!HTMLElement} parent
* @param {!shaka.ui.Controls} controls
*/
constructor(parent, controls) {
super(parent, controls);
/** @private {!shaka.extern.UIConfiguration} */
this.config_ = this.controls.getConfig();
/** @private {HTMLElement} */
this.controlsContainer_ = this.controls.getControlsContainer();
/** @private {!Array.<shaka.extern.IUIElement>} */
this.children_ = [];
this.addOverflowMenuButton_();
this.addOverflowMenu_();
this.createChildren_();
const backToOverflowMenuButtons =
this.controls.getVideoContainer().getElementsByClassName(
'shaka-back-to-overflow-button');
for (const button of backToOverflowMenuButtons) {
this.eventManager.listen(button, 'click', () => {
// Hide the submenus, display the overflow menu
this.controls.hideSettingsMenus();
shaka.ui.Utils.setDisplay(this.overflowMenu_, true);
// If there are back to overflow menu buttons, there must be
// overflow menu buttons, but oh well
if (this.overflowMenu_.childNodes.length) {
/** @type {!HTMLElement} */ (this.overflowMenu_.childNodes[0])
.focus();
}
// Make sure controls are displayed
this.controls.computeOpacity();
});
}
this.eventManager.listen(
this.localization, shaka.ui.Localization.LOCALE_UPDATED, () => {
this.updateAriaLabel_();
});
this.eventManager.listen(
this.localization, shaka.ui.Localization.LOCALE_CHANGED, () => {
this.updateAriaLabel_();
});
this.eventManager.listen(
this.adManager, shaka.ads.AdManager.AD_STARTED, () => {
shaka.ui.Utils.setDisplay(this.overflowMenuButton_, false);
});
this.eventManager.listen(
this.adManager, shaka.ads.AdManager.AD_STOPPED, () => {
shaka.ui.Utils.setDisplay(this.overflowMenuButton_, true);
});
this.eventManager.listen(
this.controls, 'submenuopen', () => {
// Hide the main overflow menu if one of the sub menus has
// been opened.
shaka.ui.Utils.setDisplay(this.overflowMenu_, false);
});
this.eventManager.listen(
this.overflowMenu_, 'touchstart', (event) => {
this.controls.setLastTouchEventTime(Date.now());
event.stopPropagation();
});
this.eventManager.listen(this.overflowMenuButton_, 'click', () => {
this.onOverflowMenuButtonClick_();
});
this.eventManager.listen(
this.controlsContainer_, 'touchstart', (event) => {
// If the overflow menu is showing, hide it on a touch event
if (!this.overflowMenu_.classList.contains('shaka-hidden')) {
shaka.ui.Utils.setDisplay(this.overflowMenu_, false);
// Stop this event from becoming a click event.
event.preventDefault();
}
});
this.updateAriaLabel_();
}
/** @override */
release() {
this.controlsContainer_ = null;
for (const element of this.children_) {
element.release();
}
this.children_ = [];
super.release();
}
/**
* @param {string} name
* @param {!shaka.extern.IUIElement.Factory} factory
* @export
*/
static registerElement(name, factory) {
shaka.ui.OverflowMenu.elementNamesToFactories_.set(name, factory);
}
/**
* @private
*/
addOverflowMenu_() {
/** @private {!HTMLElement} */
this.overflowMenu_ = shaka.util.Dom.createHTMLElement('div');
this.overflowMenu_.classList.add('shaka-overflow-menu');
this.overflowMenu_.classList.add('shaka-no-propagation');
this.overflowMenu_.classList.add('shaka-show-controls-on-mouse-over');
this.overflowMenu_.classList.add('shaka-settings-menu');
this.overflowMenu_.classList.add('shaka-hidden');
this.controlsContainer_.appendChild(this.overflowMenu_);
}
/**
* @private
*/
addOverflowMenuButton_() {
/** @private {!HTMLButtonElement} */
this.overflowMenuButton_ = shaka.util.Dom.createButton();
this.overflowMenuButton_.classList.add('shaka-overflow-menu-button');
this.overflowMenuButton_.classList.add('shaka-no-propagation');
this.overflowMenuButton_.classList.add('material-icons');
this.overflowMenuButton_.textContent =
shaka.ui.Enums.MaterialDesignIcons.OPEN_OVERFLOW;
this.parent.appendChild(this.overflowMenuButton_);
}
/**
* @private
*/
createChildren_() {
for (const name of this.config_.overflowMenuButtons) {
if (shaka.ui.OverflowMenu.elementNamesToFactories_.get(name)) {
const factory =
shaka.ui.OverflowMenu.elementNamesToFactories_.get(name);
goog.asserts.assert(this.controls, 'Controls should not be null!');
this.children_.push(factory.create(this.overflowMenu_, this.controls));
} else {
shaka.log.alwaysWarn('Unrecognized overflow menu element requested:',
name);
}
}
}
/** @private */
onOverflowMenuButtonClick_() {
if (this.controls.anySettingsMenusAreOpen()) {
this.controls.hideSettingsMenus();
} else {
shaka.ui.Utils.setDisplay(this.overflowMenu_, true);
this.controls.computeOpacity();
// If overflow menu has currently visible buttons, focus on the
// first one, when the menu opens.
const isDisplayed =
(element) => element.classList.contains('shaka-hidden') == false;
const Iterables = shaka.util.Iterables;
if (Iterables.some(this.overflowMenu_.childNodes, isDisplayed)) {
// Focus on the first visible child of the overflow menu
const visibleElements =
Iterables.filter(this.overflowMenu_.childNodes, isDisplayed);
/** @type {!HTMLElement} */ (visibleElements[0]).focus();
}
}
}
/**
* @private
*/
updateAriaLabel_() {
const LocIds = shaka.ui.Locales.Ids;
this.overflowMenuButton_.setAttribute(shaka.ui.Constants.ARIA_LABEL,
this.localization.resolve(LocIds.MORE_SETTINGS));
}
};
/**
* @implements {shaka.extern.IUIElement.Factory}
* @final
*/
shaka.ui.OverflowMenu.Factory = class {
/** @override */
create(rootElement, controls) {
return new shaka.ui.OverflowMenu(rootElement, controls);
}
};
shaka.ui.Controls.registerElement(
'overflow_menu', new shaka.ui.OverflowMenu.Factory());
/** @private {!Map.<string, !shaka.extern.IUIElement.Factory>} */
shaka.ui.OverflowMenu.elementNamesToFactories_ = new Map();