UNPKG

@haxtheweb/a11y-media-player

Version:

A feature rich, highly accessible video player

194 lines (181 loc) 5.3 kB
/** * Copyright 2018 The Pennsylvania State University * @license Apache-2.0, see License.md for full text. */ import { LitElement } from "lit"; // register globally so we can make sure there is only one globalThis.A11yMediaStateManager = globalThis.A11yMediaStateManager || {}; // request if this exists. This helps invoke the element existing in the dom // as well as that there is only one of them. That way we can ensure everything // is rendered through the same modal globalThis.A11yMediaStateManager.requestAvailability = () => { if (!globalThis.A11yMediaStateManager.instance && globalThis.document) { globalThis.A11yMediaStateManager.instance = globalThis.document.createElement("a11y-media-state-manager"); globalThis.document.body.appendChild( globalThis.A11yMediaStateManager.instance, ); } return globalThis.A11yMediaStateManager.instance; }; /** * `a11y-media-state-manager` * A utility that manages the state of multiple a11y-media-players on a single page. * */ class A11yMediaStateManager extends LitElement { /** * Store the tag name to make it easier to obtain directly. */ static get tag() { return "a11y-media-state-manager"; } // properties available to the custom element for data binding static get properties() { return { ...super.properties, /** * Stores an array of all the players on the page. */ players: { type: Array, }, /** * Manages which player is currently active. */ activePlayer: { type: Object, }, }; } /** * Makes sure there is a utility ready and listening for elements. */ constructor() { super(); this.windowControllers = new AbortController(); this.players = []; this.__stickyManager = (e) => this.setStickyPlayer(e.detail); this.__fullscreenManager = (e) => this._handleFullscreen(e.detail); this.__playerLoader = (e) => this.players.push(e.detail); // sets the instance to the current instance if (!globalThis.A11yMediaStateManager.instance) { globalThis.A11yMediaStateManager.instance = this; } } /** * if a player disallows concurrent players, pauses other players */ checkConcurrentPlayers() { let active = this.activePlayer; this.players.forEach((player) => { if (!!active && player !== active) { if (player.fullscreen) player.toggleFullscreen(false); if ( !player.allowConcurrent || !active.allowConcurrent || active.fullscreen ) player.pause(); } }); } /** * sets the active player * * @param {object} the player to set stickiness */ setActivePlayer(player) { this.activePlayer = player; this.checkConcurrentPlayers(); if (this.observer) this.observer.disconnect(); this.observer.observe(this.activePlayer); } /** * active player observer * * @readonly * @memberof A11yMediaStateManager */ get observer() { let handleIntersect = (entries, observer) => { globalThis.A11yMediaStateManager.instance._handleIntersect( entries, observer, ); }; this._observer = this._observer || new IntersectionObserver(handleIntersect, { root: null, rootMargin: "0px", threshold: [0.25, 0.75], }); return this._observer; } /** * * handles when active player is out of range and sets stickiness accordingly * @param {array} entries * @param {object} observer */ _handleIntersect(entries, observer) { entries.forEach((entry) => { if (!this.activePlayer || this.activePlayer.fullscreen) { } else if (!this.activePlayer.__playing) { this.activePlayer.toggleSticky(false); } else { this.activePlayer.toggleSticky(!entry.isIntersecting); } }); } /** * stops all other players on the page * * @param {object} the player to set stickiness */ setStickyPlayer(player) { if ( player !== this.activePlayer && this.activePlayer !== undefined && this.activePlayer !== null ) { this.activePlayer.toggleSticky(false); } this.setActivePlayer(player); } _handleFullscreen(player) { if (player && player.fullscreen) this.setActivePlayer(player); } connectedCallback() { super.connectedCallback(); // listen for a player that starts playing globalThis.addEventListener( "a11y-player-playing", this.__stickyManager.bind(this), { signal: this.windowControllers.signal }, ); // listen for a player toggling fullscreen mode globalThis.addEventListener( "fullscreen-toggle", this._handleFullscreen.bind(this), { signal: this.windowControllers.signal }, ); // listen for a players added to the page globalThis.addEventListener("a11y-player", this.__playerLoader.bind(this), { signal: this.windowControllers.signal, }); } /** * life cycle, element is removed from the DOM */ disconnectedCallback() { this.windowControllers.abort(); super.disconnectedCallback(); } } globalThis.customElements.define( A11yMediaStateManager.tag, A11yMediaStateManager, ); export { A11yMediaStateManager };