Source: ui/text_style_preview.js

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


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

goog.require('shaka.ui.Locales');
goog.require('shaka.ui.Localization');
goog.require('shaka.util.EventManager');
goog.requireType('shaka.config.PositionArea');
goog.requireType('shaka.Player');


/**
 * Manages the temporary subtitle style preview shown while subtitle style
 * settings are hovered or focused.
 *
 * @final
 */
shaka.ui.TextStylePreview = class {
  /**
   * @param {!shaka.Player} player
   * @param {!shaka.ui.Localization} localization
   */
  constructor(player, localization) {
    /** @private {?shaka.Player} */
    this.player_ = player;

    /** @private {?shaka.ui.Localization} */
    this.localization_ = localization;

    /** @private {?shaka.extern.TextDisplayerConfiguration} */
    this.baseConfig_ = null;

    /** @private {!shaka.ui.TextStylePreview.Configuration} */
    this.previewConfig_ = {};

    /** @private {boolean} */
    this.shown_ = false;

    /** @private {?shaka.util.EventManager} */
    this.eventManager_ = new shaka.util.EventManager();

    this.eventManager_.listen(player, 'configurationchanged', () => {
      this.updateBaseConfig_();
    });

    this.eventManager_.listenMulti(
        localization,
        [
          shaka.ui.Localization.LOCALE_UPDATED,
          shaka.ui.Localization.LOCALE_CHANGED,
        ], () => {
          this.apply_();
        });
  }

  /** Releases all resources owned by this preview. */
  release() {
    this.hide();
    this.eventManager_?.release();
    this.eventManager_ = null;
    this.player_ = null;
    this.localization_ = null;
  }

  /** Shows a temporary subtitle with the current text displayer style. */
  show() {
    if (!this.player_) {
      return;
    }

    this.shown_ = true;
    this.previewConfig_ = {};
    this.updateBaseConfig_();
  }

  /**
   * Updates the temporary subtitle style without changing player config.
   *
   * @param {!shaka.ui.TextStylePreview.Configuration=} config
   */
  update(config = {}) {
    if (!this.player_) {
      return;
    }

    if (!this.shown_) {
      this.show();
    }

    this.previewConfig_ = Object.assign({}, config);
    this.apply_();
  }

  /** Reverts the temporary subtitle to the style captured when shown. */
  reset() {
    if (!this.shown_) {
      return;
    }

    this.previewConfig_ = {};
    this.apply_();
  }

  /** Removes the temporary subtitle style preview. */
  hide() {
    if (!this.shown_) {
      return;
    }

    this.shown_ = false;
    this.baseConfig_ = null;
    this.previewConfig_ = {};
    const displayer = this.getTextDisplayer_();
    if (displayer &&
        typeof displayer['clearTextStylePreview'] == 'function') {
      displayer['clearTextStylePreview']();
    }
  }

  /** @private */
  updateBaseConfig_() {
    if (!this.shown_ || !this.player_) {
      return;
    }

    this.baseConfig_ = this.getCurrentTextDisplayerConfig_();
    this.apply_();
  }

  /**
   * @return {!shaka.extern.TextDisplayerConfiguration}
   * @private
   */
  getCurrentTextDisplayerConfig_() {
    const player = /** @type {!shaka.Player} */(this.player_);
    return /** @type {!shaka.extern.TextDisplayerConfiguration} */(
      Object.assign({}, player.getConfiguration().textDisplayer));
  }

  /** @private */
  apply_() {
    if (!this.shown_ || !this.player_ || !this.baseConfig_) {
      return;
    }

    const previewConfig =
    /** @type {!shaka.extern.TextDisplayerConfiguration} */(
        Object.assign({}, this.baseConfig_, this.previewConfig_));
    const displayer = this.getTextDisplayer_();
    if (displayer && typeof displayer['setTextStylePreview'] == 'function') {
      displayer['setTextStylePreview'](
          previewConfig, this.getLocalizedExampleText_());
    }
  }

  /**
   * @return {?}
   * @private
   */
  getTextDisplayer_() {
    const player = /** @type {?} */(this.player_);
    if (!player || typeof player.getTextDisplayer != 'function') {
      return null;
    }

    return player.getTextDisplayer();
  }

  /**
   * @return {string}
   * @private
   */
  getLocalizedExampleText_() {
    if (!this.localization_) {
      return '';
    }

    return this.localization_.resolve(
        shaka.ui.Locales.Ids.SUBTITLES_EXAMPLE);
  }
};


/**
 * @typedef {{
 *   fontScaleFactor: (number|undefined),
 *   positionArea: (shaka.config.PositionArea|undefined),
 * }}
 *
 * @description
 *   Text displayer fields that the style preview can temporarily override.
 */
shaka.ui.TextStylePreview.Configuration;