import { FakeEvent } from '../event/fake-event'; import { FakeEventTarget } from '../event/fake-event-target'; import { CustomEventType } from '../event/event-type'; /** * A Factory class to create a resize observer for the player. */ class ResizeWatcher extends FakeEventTarget { private _observer?: ResizeObserver | IFrameObserver; private _el?: HTMLElement; constructor() { super(); } /** * Removes resize listeners. * @returns {void} */ public destroy(): void { if (this._observer) { this._observer.disconnect(); } this._observer = undefined; this._el = undefined; } /** * Start listening to a resize of the element. * @param {HTMLElement} el - the element to listen to. * @returns {void} */ public init(el: HTMLElement): void { if (this._observer) return; this._el = el; window.ResizeObserver ? this._createNativeObserver() : this._createIframeObserver(); if (this._el instanceof HTMLElement && this._observer) { (this._observer as ResizeObserver | IFrameObserver).observe(this._el); } } private _createNativeObserver(): void { this._observer = new ResizeObserver((entries) => { entries.forEach(() => { this._triggerResize(); }); }); } private _createIframeObserver(): void { this._observer = new IFrameObserver(this._triggerResize.bind(this)); } private _triggerResize(): void { this.dispatchEvent(new FakeEvent(CustomEventType.RESIZE)); } } const IFRAME_CLASS_NAME: string = 'playkit-size-iframe'; /** * This class mimics the API of the ResizeObserver API (currently available only in Chrome). * Creates an empty iFrame next to the player container, which gets the dimensions of it's parent and listens to * the iframes resize event. * @param {Function} callback - the function to be called when a resize event is detected. */ class IFrameObserver { private _observersStore: { [id: number]: HTMLIFrameElement } = {}; private _onChangeCallback: () => void; constructor(callback: () => void) { this._onChangeCallback = callback; } /** * start detecting resize event * @param {HTMLElement} el - The element that is going to be resized. * @returns {void} */ public observe(el: HTMLElement): void { const iframe = this._createIframe(); const playerId = el.getAttribute('id'); this._observersStore[playerId!] = iframe; el.appendChild(iframe); // eslint-disable-next-line @typescript-eslint/ban-ts-comment // @ts-ignore iframe.contentWindow.onresize = (): void => this._onChangeCallback(); } /** * remove all resize listeners * @returns {void} */ public disconnect(): void { for (const target in this._observersStore) { const el = document.getElementById(target); const iframe = this._observersStore[target]; iframe.onresize = null; if (el) { el.removeChild(iframe); // eslint-disable-next-line @typescript-eslint/ban-ts-comment // @ts-ignore delete this._observersStore[el.getAttribute('id')]; } } } private _createIframe(): HTMLIFrameElement { const iframe = document.createElement('iframe'); iframe.className = IFRAME_CLASS_NAME; return iframe; } } export { ResizeWatcher };