Skip to content

Source: src/controller/Play.js

import DomSmith from '../../lib/dom/DomSmith.js';

/**
 * The Play component shows a button which is used to start and pause playing the media.
 * Also listens to the appropriate events should the media be paused or played by other means,
 * and adapts the play button state accordingly (i.e. Showing the 'play' or 'pause' icon).
 * @exports module:src/controller/Play
 * @requires lib/dom/DomSmith
 * @author   Frank Kudermann - alphanull
 * @version  1.0.0
 * @license  MIT
 */
export default class Play {

    /**
     * Reference to the main player instance.
     * @type {module:src/core/Player}
     */
    #player;

    /**
     * Holds tokens of subscriptions to player events, for later unsubscribe.
     * @type {number[]}
     */
    #subscriptions;

    /**
     * Reference to the DomSmith instance of the play button.
     * @type {module:lib/dom/DomSmith}
     */
    #dom;

    /**
     * Creates an instance of the Play component.
     * @param {module:src/core/Player}           player  Reference to the VisionPlayer instance.
     * @param {module:src/controller/Controller} parent  Reference to the parent instance, in this case the controller component.
     */
    constructor(player, parent) {

        if (!player.initConfig('playControl', true)) return [false];

        this.#player = player;

        const playText = this.#player.locale.t('commands.play'),
              pauseText = this.#player.locale.t('commands.pause');

        this.#dom = new DomSmith({
            _tag: 'button',
            _ref: 'playButton',
            className: 'play icon',
            disabled: true,
            'data-sort': 10,
            ariaLabel: playText,
            click: this.#togglePlay,
            $tooltip: { player, text: () => this.#player.getState('media.paused') ? playText : pauseText }
        }, parent.getElement('left'));

        this.#subscriptions = [
            ['data/ready', this.#onDataReady],
            ['media/pause', this.#onPause],
            ['media/play', this.#onPlay],
            ['data/nomedia', this.#disable],
            ['media/error', this.#disable],
            ['media/canplay', this.#enable]
        ].map(([event, handler]) => this.#player.subscribe(event, handler));

    }

    /**
     * Sets up the component as soon as the media data is available.
     * @listens module:src/core/Data#data/ready
     */
    #onDataReady = () => {

        this.#enable();

        if (this.#player.getState('media.paused') === false) this.#onPlay();
        else this.#onPause();

    };

    /**
     * Invoked when the user presses the play button. Toggles between 'play' and 'pause'.
     */
    #togglePlay = () => {

        // this.#dom.playButton.blur();

        if (this.#player.getState('media.paused')) this.#player.media.play();
        else this.#player.media.pause();

    };

    /**
     * This method switches the appearance of the play button to the play state.
     * @listens module:src/core/Media#media/play
     */
    #onPlay = () => {

        this.#dom.playButton.classList.remove('play');
        this.#dom.playButton.classList.add('pause');
        this.#dom.playButton.setAttribute('aria-pressed', 'true');
        this.#dom.playButton.setAttribute('aria-label', this.#player.locale.t('commands.pause'));

    };

    /**
     * This method switches the appearance of the play button to the pause state.
     * @listens module:src/core/Media#media/pause
     */
    #onPause = () => {

        this.#dom.playButton.classList.add('play');
        this.#dom.playButton.classList.remove('pause');
        this.#dom.playButton.setAttribute('aria-pressed', 'false');
        this.#dom.playButton.setAttribute('aria-label', this.#player.locale.t('commands.play'));

    };

    /**
     * Disables the button functionality. This method listens to media error events which cause the button to be disabled.
     * @listens module:src/core/Media#media/error
     * @listens module:src/core/Data#data/nomedia
     */
    #disable = () => {

        this.#dom.playButton.disabled = true;

    };

    /**
     * Enables the play button functionality. This method listens to canplay events in order to restore a usable state again
     * when the player recovered from a media error (for example by loading another file).
     * @listens module:src/core/Media#media/canplay
     */
    #enable = () => {

        this.#dom.playButton.disabled = false;

    };

    /**
     * This method removes all events, subscriptions and DOM nodes created by this component.
     */
    destroy() {

        this.#dom.destroy();
        this.#player.unsubscribe(this.#subscriptions);
        this.#player = this.#dom = null;

    }

}