From 392dfd024c505f5ae1bbb2f0d3e0793c251a1f35 Mon Sep 17 00:00:00 2001 From: Sam Potts Date: Wed, 13 Jun 2018 00:02:55 +1000 Subject: Utils broken down into seperate files and exports --- src/js/ui.js | 70 ++++++++++++++++++++++++++++++------------------------------ 1 file changed, 35 insertions(+), 35 deletions(-) (limited to 'src/js/ui.js') diff --git a/src/js/ui.js b/src/js/ui.js index d6ab0e59..e3faf42f 100644 --- a/src/js/ui.js +++ b/src/js/ui.js @@ -6,15 +6,16 @@ import captions from './captions'; import controls from './controls'; import i18n from './i18n'; import support from './support'; -import utils from './utils'; - -// Sniff out the browser -const browser = utils.getBrowser(); +import browser from './utils/browser'; +import { getElement, toggleClass, toggleState } from './utils/elements'; +import { trigger } from './utils/events'; +import is from './utils/is'; +import loadImage from './utils/loadImage'; const ui = { addStyleHook() { - utils.toggleClass(this.elements.container, this.config.selectors.container.replace('.', ''), true); - utils.toggleClass(this.elements.container, this.config.classNames.uiSupported, this.supported.ui); + toggleClass(this.elements.container, this.config.selectors.container.replace('.', ''), true); + toggleClass(this.elements.container, this.config.classNames.uiSupported, this.supported.ui); }, // Toggle native HTML5 media controls @@ -44,7 +45,7 @@ const ui = { } // Inject custom controls if not present - if (!utils.is.element(this.elements.controls)) { + if (!is.element(this.elements.controls)) { // Inject custom controls controls.inject.call(this); @@ -85,23 +86,23 @@ const ui = { ui.checkPlaying.call(this); // Check for picture-in-picture support - utils.toggleClass(this.elements.container, this.config.classNames.pip.supported, support.pip && this.isHTML5 && this.isVideo); + toggleClass(this.elements.container, this.config.classNames.pip.supported, support.pip && this.isHTML5 && this.isVideo); // Check for airplay support - utils.toggleClass(this.elements.container, this.config.classNames.airplay.supported, support.airplay && this.isHTML5); + toggleClass(this.elements.container, this.config.classNames.airplay.supported, support.airplay && this.isHTML5); // Add iOS class - utils.toggleClass(this.elements.container, this.config.classNames.isIos, browser.isIos); + toggleClass(this.elements.container, this.config.classNames.isIos, browser.isIos); // Add touch class - utils.toggleClass(this.elements.container, this.config.classNames.isTouch, this.touch); + toggleClass(this.elements.container, this.config.classNames.isTouch, this.touch); // Ready for API calls this.ready = true; // Ready event at end of execution stack setTimeout(() => { - utils.dispatchEvent.call(this, this.media, 'ready'); + trigger.call(this, this.media, 'ready'); }, 0); // Set the title @@ -125,7 +126,7 @@ const ui = { let label = i18n.get('play', this.config); // If there's a media title set, use that for the label - if (utils.is.string(this.config.title) && !utils.is.empty(this.config.title)) { + if (is.string(this.config.title) && !is.empty(this.config.title)) { label += `, ${this.config.title}`; // Set container label @@ -133,7 +134,7 @@ const ui = { } // If there's a play button, set label - if (utils.is.nodeList(this.elements.buttons.play)) { + if (is.nodeList(this.elements.buttons.play)) { Array.from(this.elements.buttons.play).forEach(button => { button.setAttribute('aria-label', label); }); @@ -142,14 +143,14 @@ const ui = { // Set iframe title // https://github.com/sampotts/plyr/issues/124 if (this.isEmbed) { - const iframe = utils.getElement.call(this, 'iframe'); + const iframe = getElement.call(this, 'iframe'); - if (!utils.is.element(iframe)) { + if (!is.element(iframe)) { return; } // Default to media type - const title = !utils.is.empty(this.config.title) ? this.config.title : 'video'; + const title = !is.empty(this.config.title) ? this.config.title : 'video'; const format = i18n.get('frameTitle', this.config); iframe.setAttribute('title', format.replace('{title}', title)); @@ -158,7 +159,7 @@ const ui = { // Toggle poster togglePoster(enable) { - utils.toggleClass(this.elements.container, this.config.classNames.posterEnabled, enable); + toggleClass(this.elements.container, this.config.classNames.posterEnabled, enable); }, // Set the poster image (async) @@ -167,22 +168,21 @@ const ui = { this.media.setAttribute('poster', poster); // Bail if element is missing - if (!utils.is.element(this.elements.poster)) { + if (!is.element(this.elements.poster)) { return Promise.reject(); } // Load the image, and set poster if successful - const loadPromise = utils.loadImage(poster) - .then(() => { - this.elements.poster.style.backgroundImage = `url('${poster}')`; - Object.assign(this.elements.poster.style, { - backgroundImage: `url('${poster}')`, - // Reset backgroundSize as well (since it can be set to "cover" for padded thumbnails for youtube) - backgroundSize: '', - }); - ui.togglePoster.call(this, true); - return poster; + const loadPromise = loadImage(poster).then(() => { + this.elements.poster.style.backgroundImage = `url('${poster}')`; + Object.assign(this.elements.poster.style, { + backgroundImage: `url('${poster}')`, + // Reset backgroundSize as well (since it can be set to "cover" for padded thumbnails for youtube) + backgroundSize: '', }); + ui.togglePoster.call(this, true); + return poster; + }); // Hide the element if the poster can't be loaded (otherwise it will just be a black element covering the video) loadPromise.catch(() => ui.togglePoster.call(this, false)); @@ -194,15 +194,15 @@ const ui = { // Check playing state checkPlaying(event) { // Class hooks - utils.toggleClass(this.elements.container, this.config.classNames.playing, this.playing); - utils.toggleClass(this.elements.container, this.config.classNames.paused, this.paused); - utils.toggleClass(this.elements.container, this.config.classNames.stopped, this.stopped); + toggleClass(this.elements.container, this.config.classNames.playing, this.playing); + toggleClass(this.elements.container, this.config.classNames.paused, this.paused); + toggleClass(this.elements.container, this.config.classNames.stopped, this.stopped); // Set ARIA state - utils.toggleState(this.elements.buttons.play, this.playing); + toggleState(this.elements.buttons.play, this.playing); // Only update controls on non timeupdate events - if (utils.is.event(event) && event.type === 'timeupdate') { + if (is.event(event) && event.type === 'timeupdate') { return; } @@ -223,7 +223,7 @@ const ui = { // Timer to prevent flicker when seeking this.timers.loading = setTimeout(() => { // Update progress bar loading class state - utils.toggleClass(this.elements.container, this.config.classNames.loading, this.loading); + toggleClass(this.elements.container, this.config.classNames.loading, this.loading); // Update controls visibility ui.toggleControls.call(this); -- cgit v1.2.3 From 6bff6b317d6adcd9f94c8d4d8ee225d39f784e0f Mon Sep 17 00:00:00 2001 From: Albin Larsson Date: Wed, 13 Jun 2018 22:18:57 +0200 Subject: Remove line breaks in arrays --- src/js/ui.js | 5 +---- 1 file changed, 1 insertion(+), 4 deletions(-) (limited to 'src/js/ui.js') diff --git a/src/js/ui.js b/src/js/ui.js index d3d86124..285739a7 100644 --- a/src/js/ui.js +++ b/src/js/ui.js @@ -212,10 +212,7 @@ const ui = { // Check if media is loading checkLoading(event) { - this.loading = [ - 'stalled', - 'waiting', - ].includes(event.type); + this.loading = ['stalled', 'waiting'].includes(event.type); // Clear timer clearTimeout(this.timers.loading); -- cgit v1.2.3 From 115f352ade7fbe133a42fd434dbcc1fca13287a7 Mon Sep 17 00:00:00 2001 From: Albin Larsson Date: Fri, 15 Jun 2018 23:56:47 +0200 Subject: Respect call order and prioritize public API calls for setting poster, in order to avoid race conditions --- src/js/ui.js | 63 +++++++++++++++++++++++++++++++++++------------------------- 1 file changed, 37 insertions(+), 26 deletions(-) (limited to 'src/js/ui.js') diff --git a/src/js/ui.js b/src/js/ui.js index 285739a7..5d7a6ae3 100644 --- a/src/js/ui.js +++ b/src/js/ui.js @@ -8,7 +8,7 @@ import i18n from './i18n'; import support from './support'; import browser from './utils/browser'; import { getElement, toggleClass, toggleState } from './utils/elements'; -import { triggerEvent } from './utils/events'; +import { ready, triggerEvent } from './utils/events'; import is from './utils/is'; import loadImage from './utils/loadImage'; @@ -109,8 +109,8 @@ const ui = { ui.setTitle.call(this); // Assure the poster image is set, if the property was added before the element was created - if (this.poster && this.elements.poster && !this.elements.poster.style.backgroundImage) { - ui.setPoster.call(this, this.poster); + if (this.poster) { + ui.setPoster.call(this, this.poster, false).catch(() => {}); } // Manually set the duration if user has overridden it. @@ -163,32 +163,43 @@ const ui = { }, // Set the poster image (async) - setPoster(poster) { - // Set property regardless of validity - this.media.setAttribute('poster', poster); - - // Bail if element is missing - if (!is.element(this.elements.poster)) { - return Promise.reject(); + // Used internally for the poster setter, with the passive option forced to false + setPoster(poster, passive = true) { + // Don't override if call is passive + if (passive && this.poster) { + return Promise.reject(new Error('Poster already set')); } - // Load the image, and set poster if successful - const loadPromise = loadImage(poster).then(() => { - this.elements.poster.style.backgroundImage = `url('${poster}')`; - Object.assign(this.elements.poster.style, { - backgroundImage: `url('${poster}')`, - // Reset backgroundSize as well (since it can be set to "cover" for padded thumbnails for youtube) - backgroundSize: '', - }); - ui.togglePoster.call(this, true); - return poster; - }); - - // Hide the element if the poster can't be loaded (otherwise it will just be a black element covering the video) - loadPromise.catch(() => ui.togglePoster.call(this, false)); + // Set property synchronously to respect the call order + this.media.setAttribute('poster', poster); - // Return the promise so the caller can use it as well - return loadPromise; + // Wait until ui is ready + return ready.call(this) + // Load image + .then(() => loadImage(poster)) + .catch(err => { + // Hide poster on error unless it's been set by another call + if (poster === this.poster) { + ui.togglePoster.call(this, false); + } + // Rethrow + throw err; + }) + .then(() => { + // Prevent race conditions + if (poster !== this.poster) { + throw new Error('setPoster cancelled by later call to setPoster'); + } + }) + .then(() => { + Object.assign(this.elements.poster.style, { + backgroundImage: `url('${poster}')`, + // Reset backgroundSize as well (since it can be set to "cover" for padded thumbnails for youtube) + backgroundSize: '', + }); + ui.togglePoster.call(this, true); + return poster; + }); }, // Check playing state -- cgit v1.2.3 From d4abb4b1438cb316aacae480e7b7e9b055a60b24 Mon Sep 17 00:00:00 2001 From: Sam Potts Date: Sun, 17 Jun 2018 01:04:55 +1000 Subject: 120 line width, package upgrade --- src/js/ui.js | 61 +++++++++++++++++++++++++++++++++--------------------------- 1 file changed, 34 insertions(+), 27 deletions(-) (limited to 'src/js/ui.js') diff --git a/src/js/ui.js b/src/js/ui.js index 5d7a6ae3..e0d7c6ae 100644 --- a/src/js/ui.js +++ b/src/js/ui.js @@ -86,7 +86,11 @@ const ui = { ui.checkPlaying.call(this); // Check for picture-in-picture support - toggleClass(this.elements.container, this.config.classNames.pip.supported, support.pip && this.isHTML5 && this.isVideo); + toggleClass( + this.elements.container, + this.config.classNames.pip.supported, + support.pip && this.isHTML5 && this.isVideo, + ); // Check for airplay support toggleClass(this.elements.container, this.config.classNames.airplay.supported, support.airplay && this.isHTML5); @@ -174,32 +178,35 @@ const ui = { this.media.setAttribute('poster', poster); // Wait until ui is ready - return ready.call(this) - // Load image - .then(() => loadImage(poster)) - .catch(err => { - // Hide poster on error unless it's been set by another call - if (poster === this.poster) { - ui.togglePoster.call(this, false); - } - // Rethrow - throw err; - }) - .then(() => { - // Prevent race conditions - if (poster !== this.poster) { - throw new Error('setPoster cancelled by later call to setPoster'); - } - }) - .then(() => { - Object.assign(this.elements.poster.style, { - backgroundImage: `url('${poster}')`, - // Reset backgroundSize as well (since it can be set to "cover" for padded thumbnails for youtube) - backgroundSize: '', - }); - ui.togglePoster.call(this, true); - return poster; - }); + return ( + ready + .call(this) + // Load image + .then(() => loadImage(poster)) + .catch(err => { + // Hide poster on error unless it's been set by another call + if (poster === this.poster) { + ui.togglePoster.call(this, false); + } + // Rethrow + throw err; + }) + .then(() => { + // Prevent race conditions + if (poster !== this.poster) { + throw new Error('setPoster cancelled by later call to setPoster'); + } + }) + .then(() => { + Object.assign(this.elements.poster.style, { + backgroundImage: `url('${poster}')`, + // Reset backgroundSize as well (since it can be set to "cover" for padded thumbnails for youtube) + backgroundSize: '', + }); + ui.togglePoster.call(this, true); + return poster; + }) + ); }, // Check playing state -- cgit v1.2.3