import { queryOne } from '@ecl/dom-utils';import EventManager from '@ecl/event-manager';/** * @param {HTMLElement} element DOM element for component instantiation and scope * @param {Object} options * @param {String} options.iframeSelector Selector for iframe element * @param {boolean} options.useAutomaticRatio Toggle automatic ratio calculus * @param {String} options.videoTitleSelector Selector for video title * @param {String} options.videoPlay Selector for the video play button * @param {String} options.videoPause Selector for the video pause button */export class MediaContainer { /** * @static * Shorthand for instance creation and initialisation. * * @param {HTMLElement} root DOM element for component instantiation and scope * * @return {MediaContainer} An instance of MediaContainer. */ static autoInit(root, { MEDIA_CONTAINER: defaultOptions = {} } = {}) { const mediaContainer = new MediaContainer(root, defaultOptions); mediaContainer.init(); root.ECLMediaContainer = mediaContainer; return mediaContainer; } /** * An array of supported events for this component. * * @type {Array<string>} * @event MediaContainer#onPlayClick * @event MediaContainer#onPauseClick * @memberof Media container */ supportedEvents = ['onPlayClick', 'onPauseClick']; constructor( element, { iframeSelector = 'iframe', useAutomaticRatio = true, videoTitleSelector = 'data-ecl-media-container-video-title', videoPlay = '[data-ecl-media-container-play]', videoPause = '[data-ecl-media-container-pause]', mediaVideo = '[data-ecl-media-container-video]', } = {}, ) { // Check element if (!element || element.nodeType !== Node.ELEMENT_NODE) { throw new TypeError( 'DOM element should be given to initialize this widget.', ); } this.element = element; this.eventManager = new EventManager(); // Options this.iframeSelector = iframeSelector; this.useAutomaticRatio = useAutomaticRatio; this.videoTitleSelector = videoTitleSelector; this.mediaVideo = queryOne(mediaVideo, this.element); this.videoPlay = queryOne(videoPlay, this.element); this.videoPause = queryOne(videoPause, this.element); // Private variables this.iframe = null; this.videoTitle = ''; // Bind `this` for use in callbacks this.calculateRatio = this.calculateRatio.bind(this); this.handleParameters = this.handleParameters.bind(this); this.handlePauseClick = this.handlePauseClick.bind(this); this.handlePlayClick = this.handlePlayClick.bind(this); } /** * Initialise component. */ init() { if (!ECL) { throw new TypeError('Called init but ECL is not present'); } ECL.components = ECL.components || new Map(); // Get elements this.videoTitle = this.element.getAttribute(this.videoTitleSelector); // Check if a ratio has been set manually const media = queryOne('.ecl-media-container__media', this.element); if (media && !/ecl-media-container__media--ratio/.test(media.className)) { // Get the iframe this.iframe = queryOne(this.iframeSelector, this.element); // Check if there is an iframe to handle if (this.iframe) { this.handleParameters(); if (this.useAutomaticRatio) this.calculateRatio(); } } if (this.videoPlay) { this.videoPlay.addEventListener('click', (e) => this.handlePlayClick(e)); this.videoPlay.style.display = 'none'; } if (this.videoPause) { this.videoPause.addEventListener('click', (e) => this.handlePauseClick(e), ); this.videoPause.style.display = 'flex'; } // Set ecl initialized attribute this.element.setAttribute('data-ecl-auto-initialized', 'true'); ECL.components.set(this.element, this); } /** * Register a callback function for a specific event. * * @param {string} eventName - The name of the event to listen for. * @param {Function} callback - The callback function to be invoked when the event occurs. * @returns {void} * @memberof Banner * @instance * * @example * // Registering a callback for the 'onPauseClick' event * mediaContainer.on('onPauseClick', (event) => { * console.log('The pause button was clicked', event); * }); */ on(eventName, callback) { this.eventManager.on(eventName, callback); } /** * Trigger a component event. * * @param {string} eventName - The name of the event to trigger. * @param {any} eventData - Data associated with the event. * * @memberof Banner */ trigger(eventName, eventData) { this.eventManager.trigger(eventName, eventData); } /** * Destroy component. */ destroy() { if (this.element) { this.element.removeAttribute('data-ecl-auto-initialized'); ECL.components.delete(this.element); } if (this.videoPlay) { this.videoPlay.removeEventListener('click', this.handlePlayClick); this.videoPlay.style.display = 'none'; } if (this.videoPause) { this.videoPause.remveEventListener('click', this.handlePauseClick); this.videoPause.style.display = 'flex'; } } /** * Handle the parameters of the iframe video. */ handleParameters() { const iframeUrl = new URL(this.iframe.src); // Youtube if (iframeUrl.host.includes('youtube')) { this.iframe.src = iframeUrl; } // Update iframe title if (this.videoTitle) { this.iframe.setAttribute('title', this.videoTitle); } } /** * Calculate the ratio of the iframe video. */ calculateRatio() { // Get dimension if they are provided let iframeWidth = this.iframe.width; let iframeHeight = this.iframe.height; // If at least one dimension in not provided, calculate them (less reliable) if (!iframeWidth || !iframeHeight) { iframeWidth = this.iframe.offsetWidth; iframeHeight = this.iframe.offsetHeight; } // Set aspect ratio this.iframe.style.aspectRatio = `${iframeWidth}/${iframeHeight}`; } /** * Triggers a custom event when clicking on the play button. * * @param {e} Event * @fires MediaContainer#onPlayClick */ handlePlayClick(e) { if (this.mediaVideo) { this.mediaVideo.play(); } this.videoPlay.style.display = 'none'; if (this.videoPause) { this.videoPause.style.display = 'flex'; this.videoPause.focus(); } const eventData = { ...e, status: 'Playing' }; this.trigger('onPlayClick', eventData); } /** * Triggers a custom event when clicking on the pause button. * * @param {e} Event * @fires MediaContainer#onPauseClick */ handlePauseClick(e) { if (this.mediaVideo) { this.mediaVideo.pause(); } this.videoPause.style.display = 'none'; if (this.videoPlay) { this.videoPlay.style.display = 'flex'; this.videoPlay.focus(); } const eventData = { ...e, status: 'Paused' }; this.trigger('onPauseClick', eventData); }}export default MediaContainer;