// ========================================================================== // Plyr controls // ========================================================================== import captions from './captions'; import html5 from './html5'; import i18n from './i18n'; import support from './support'; import ui from './ui'; import utils from './utils'; // Sniff out the browser const browser = utils.getBrowser(); const controls = { // Webkit polyfill for lower fill range updateRangeFill(target) { // Get range from event if event passed const range = utils.is.event(target) ? target.target : target; // Needs to be a valid if (!utils.is.element(range) || range.getAttribute('type') !== 'range') { return; } // Set aria value for https://github.com/sampotts/plyr/issues/905 range.setAttribute('aria-valuenow', range.value); // WebKit only if (!browser.isWebkit) { return; } // Set CSS custom property range.style.setProperty('--value', `${range.value / range.max * 100}%`); }, // Get icon URL getIconUrl() { const url = new URL(this.config.iconUrl, window.location); const cors = url.host !== window.location.host || (browser.isIE && !window.svg4everybody); return { url: this.config.iconUrl, cors, }; }, // Find the UI controls and store references in custom controls // TODO: Allow settings menus with custom controls findElements() { try { this.elements.controls = utils.getElement.call(this, this.config.selectors.controls.wrapper); // Buttons this.elements.buttons = { play: utils.getElements.call(this, this.config.selectors.buttons.play), pause: utils.getElement.call(this, this.config.selectors.buttons.pause), restart: utils.getElement.call(this, this.config.selectors.buttons.restart), rewind: utils.getElement.call(this, this.config.selectors.buttons.rewind), fastForward: utils.getElement.call(this, this.config.selectors.buttons.fastForward), mute: utils.getElement.call(this, this.config.selectors.buttons.mute), pip: utils.getElement.call(this, this.config.selectors.buttons.pip), airplay: utils.getElement.call(this, this.config.selectors.buttons.airplay), settings: utils.getElement.call(this, this.config.selectors.buttons.settings), captions: utils.getElement.call(this, this.config.selectors.buttons.captions), fullscreen: utils.getElement.call(this, this.config.selectors.buttons.fullscreen), }; // Progress this.elements.progress = utils.getElement.call(this, this.config.selectors.progress); // Inputs this.elements.inputs = { seek: utils.getElement.call(this, this.config.selectors.inputs.seek), volume: utils.getElement.call(this, this.config.selectors.inputs.volume), }; // Display this.elements.display = { buffer: utils.getElement.call(this, this.config.selectors.display.buffer), currentTime: utils.getElement.call(this, this.config.selectors.display.currentTime), duration: utils.getElement.call(this, this.config.selectors.display.duration), }; // Seek tooltip if (utils.is.element(this.elements.progress)) { this.elements.display.seekTooltip = this.elements.progress.querySelector(`.${this.config.classNames.tooltip}`); } return true; } catch (error) { // Log it this.debug.warn('It looks like there is a problem with your custom controls HTML', error); // Restore native video controls this.toggleNativeControls(true); return false; } }, // Create icon createIcon(type, attributes) { const namespace = 'http://www.w3.org/2000/svg'; const iconUrl = controls.getIconUrl.call(this); const iconPath = `${!iconUrl.cors ? iconUrl.url : ''}#${this.config.iconPrefix}`; // Create const icon = document.createElementNS(namespace, 'svg'); utils.setAttributes( icon, utils.extend(attributes, { role: 'presentation', focusable: 'false', }), ); // Create the to reference sprite const use = document.createElementNS(namespace, 'use'); const path = `${iconPath}-${type}`; // Set `href` attributes // https://github.com/sampotts/plyr/issues/460 // https://developer.mozilla.org/en-US/docs/Web/SVG/Attribute/xlink:href if ('href' in use) { use.setAttributeNS('http://www.w3.org/1999/xlink', 'href', path); } else { use.setAttributeNS('http://www.w3.org/1999/xlink', 'xlink:href', path); } // Add to icon.appendChild(use); return icon; }, // Create hidden text label createLabel(type, attr) { let text = i18n.get(type, this.config); const attributes = Object.assign({}, attr); switch (type) { case 'pip': text = 'PIP'; break; case 'airplay': text = 'AirPlay'; break; default: break; } if ('class' in attributes) { attributes.class += ` ${this.config.classNames.hidden}`; } else { attributes.class = this.config.classNames.hidden; } return utils.createElement('span', attributes, text); }, // Create a badge createBadge(text) { if (utils.is.empty(text)) { return null; } const badge = utils.createElement('span', { class: this.config.classNames.menu.value, }); badge.appendChild( utils.createElement( 'span', { class: this.config.classNames.menu.badge, }, text, ), ); return badge; }, // Create a