Source: ui/text_style.js

/*! @license
 * Shaka Player
 * Copyright 2016 Google LLC
 * SPDX-License-Identifier: Apache-2.0
 */


goog.provide('shaka.ui.TextStyleMenu');

goog.require('shaka.ui.SettingsMenu');
goog.require('shaka.ui.Utils');
goog.require('shaka.util.Dom');
goog.requireType('shaka.ui.Controls');
goog.requireType('shaka.ui.TextStylePreview');


/**
 * Abstract base for text style configuration menus (position, size, etc.).
 * Subclasses implement the template methods getItems / getLabelForItem /
 * onItemSelected / getPreviewConfigForItem / getCurrentValueLabel.
 *
 * @extends {shaka.ui.SettingsMenu}
 * @template T
 * @abstract
 * @export
 */
shaka.ui.TextStyleMenu = class extends shaka.ui.SettingsMenu {
  /**
   * @param {!HTMLElement} parent
   * @param {!shaka.ui.Controls} controls
   * @param {string} icon
   */
  constructor(parent, controls, icon) {
    super(parent, controls, icon);

    this.eventManager.listenMulti(
        this.player,
        [
          'loading',
          'unloading',
          'configurationchanged',
          'trackschanged',
        ], () => {
          this.updateCurrentSelection_();
          this.checkAvailability();
        });
  }

  /** @override */
  checkAvailability() {
    const tracks = this.player.getTextTracks() || [];
    const hasTrack = tracks.some((track) => track.active);
    const available = hasTrack && !this.isSubMenuOpened &&
        this.controls.getConfig().captionsStyles;
    shaka.ui.Utils.setDisplay(this.button, available);
    this.button.ariaPressed = available ? 'true' : 'false';
  }

  /** @override */
  onMenuOpen() {
    this.controls.showTextStylePreview();
  }

  /** @override */
  onMenuClose() {
    this.controls.hideTextStylePreview();
  }

  /**
   * @return {!Array<T>}
   * @protected
   */
  getItems() { return []; }

  /**
   * @param {T} item
   * @return {string}
   * @protected
   */
  getLabelForItem(item) { return ''; }

  /**
   * @param {T} item
   * @protected
   */
  onItemSelected(item) {}

  /**
   * @param {T} item
   * @return {!shaka.ui.TextStylePreview.Configuration}
   * @protected
   */
  getPreviewConfigForItem(item) { return {}; }

  /**
   * @return {string}
   * @protected
   */
  getCurrentValueLabel() { return ''; }

  /**
   * Clears and rebuilds the menu items, then refreshes the selection indicator.
   * Call from the subclass constructor and from updateLocalizedStrings() when
   * item labels are localized strings.
   * @protected
   */
  rebuildMenu() {
    const backButton = shaka.ui.Utils.getFirstDescendantWithClassName(
        this.menu, 'shaka-back-to-overflow-button');
    shaka.util.Dom.removeAllChildren(this.menu);
    this.menu.appendChild(backButton);

    for (const item of this.getItems()) {
      const button = shaka.util.Dom.createButton();
      button.setAttribute('role', 'menuitemradio');
      button.setAttribute('aria-checked', 'false');
      const span = shaka.util.Dom.createHTMLElement('span');
      span.textContent = this.getLabelForItem(item);
      button.appendChild(span);

      this.eventManager.listen(button, 'click', () => {
        this.onItemSelected(item);
        this.updateCurrentSelection_();
      });

      shaka.ui.Utils.addHoverAndFocusListeners(
          this.eventManager, button,
          () => this.controls.updateTextStylePreview(
              this.getPreviewConfigForItem(item)),
          () => this.controls.resetTextStylePreview());

      this.menu.appendChild(button);
    }

    this.updateCurrentSelection_();
    shaka.ui.Utils.focusOnTheChosenItem(this.menu);
  }

  /** @private */
  updateCurrentSelection_() {
    const checkmarkIcon = shaka.ui.Utils.getDescendantIfExists(
        this.menu, 'shaka-ui-icon shaka-chosen-item');
    if (checkmarkIcon) {
      const prevButton = checkmarkIcon.parentElement;
      prevButton.setAttribute('aria-checked', 'false');
      const prevSpan = prevButton.getElementsByTagName('span')[0];
      if (prevSpan) {
        prevSpan.classList.remove('shaka-chosen-item');
      }
      prevButton.removeChild(checkmarkIcon);
    }

    const currentLabel = this.getCurrentValueLabel();
    const span = Array.from(this.menu.querySelectorAll('span'))
        .find((el) => el.textContent === currentLabel);
    if (span) {
      const button = span.parentElement;
      button.appendChild(shaka.ui.Utils.checkmarkIcon());
      shaka.ui.Utils.setChosenItem(button, span);
    }
    this.currentSelection.textContent = currentLabel;
  }
};