aboutsummaryrefslogtreecommitdiffstats
path: root/src
diff options
context:
space:
mode:
Diffstat (limited to 'src')
-rw-r--r--src/js/controls.js16
-rw-r--r--src/js/defaults.js3
-rw-r--r--src/js/listeners.js7
-rw-r--r--src/js/media.js5
-rw-r--r--src/js/plugins/vimeo.js7
-rw-r--r--src/js/plugins/youtube.js4
-rw-r--r--src/js/plyr.js62
-rw-r--r--src/js/ui.js6
-rw-r--r--src/js/utils.js134
-rw-r--r--src/less/components/embed.less10
10 files changed, 156 insertions, 98 deletions
diff --git a/src/js/controls.js b/src/js/controls.js
index d40165e1..ac7ba2b6 100644
--- a/src/js/controls.js
+++ b/src/js/controls.js
@@ -6,11 +6,14 @@ import support from './support';
import utils from './utils';
import ui from './ui';
+// Sniff out the browser
+const browser = utils.getBrowser();
+
const controls = {
// Webkit polyfill for lower fill range
updateRangeFill(target) {
// WebKit only
- if (!this.browser.isWebkit) {
+ if (!browser.isWebkit) {
return;
}
@@ -49,7 +52,7 @@ const controls = {
getIconUrl() {
return {
url: this.config.iconUrl,
- absolute: this.config.iconUrl.indexOf('http') === 0 || (this.browser.isIE && !window.svg4everybody),
+ absolute: this.config.iconUrl.indexOf('http') === 0 || (browser.isIE && !window.svg4everybody),
};
},
@@ -1139,14 +1142,11 @@ const controls = {
inject() {
// Sprite
if (this.config.loadSprite) {
- const iconUrl = controls.getIconUrl.call(this);
+ const icon = controls.getIconUrl.call(this);
// Only load external sprite using AJAX
- if (iconUrl.absolute) {
- this.log(`AJAX loading absolute SVG sprite ${this.browser.isIE ? '(due to IE)' : ''}`);
- utils.loadSprite(iconUrl.url, 'sprite-plyr');
- } else {
- this.log('Sprite will be used as external resource directly');
+ if (icon.absolute) {
+ utils.loadSprite(icon.url, 'sprite-plyr');
}
}
diff --git a/src/js/defaults.js b/src/js/defaults.js
index 837b981b..a3d95bb4 100644
--- a/src/js/defaults.js
+++ b/src/js/defaults.js
@@ -45,6 +45,9 @@ const defaults = {
// Pass a custom duration
duration: null,
+ // Aspect ratio (for embeds)
+ ratio: '16:9',
+
// Quality default
quality: {
default: 'default',
diff --git a/src/js/listeners.js b/src/js/listeners.js
index 9b84a729..29038a21 100644
--- a/src/js/listeners.js
+++ b/src/js/listeners.js
@@ -9,6 +9,9 @@ import fullscreen from './fullscreen';
import storage from './storage';
import ui from './ui';
+// Sniff out the browser
+const browser = utils.getBrowser();
+
const listeners = {
// Listen for media events
media() {
@@ -134,7 +137,7 @@ const listeners = {
// Listen for control events
controls() {
// IE doesn't support input event, so we fallback to change
- const inputEvent = this.browser.isIE ? 'change' : 'input';
+ const inputEvent = browser.isIE ? 'change' : 'input';
let last = null;
// Trigger custom and default handlers
@@ -468,7 +471,7 @@ const listeners = {
);
// Polyfill for lower fill in <input type="range"> for webkit
- if (this.browser.isWebkit) {
+ if (browser.isWebkit) {
utils.on(utils.getElements.call(this, 'input[type="range"]'), 'input', event => {
controls.updateRangeFill.call(this, event.target);
});
diff --git a/src/js/media.js b/src/js/media.js
index 9e53f5fc..46e6bec6 100644
--- a/src/js/media.js
+++ b/src/js/media.js
@@ -8,6 +8,9 @@ import youtube from './plugins/youtube';
import vimeo from './plugins/vimeo';
import ui from './ui';
+// Sniff out the browser
+const browser = utils.getBrowser();
+
const media = {
// Setup media
setup() {
@@ -45,7 +48,7 @@ const media = {
utils.toggleClass(this.elements.container, this.config.classNames.stopped, this.config.autoplay);
// Add iOS class
- utils.toggleClass(this.elements.container, this.config.classNames.isIos, this.browser.isIos);
+ utils.toggleClass(this.elements.container, this.config.classNames.isIos, browser.isIos);
// Add touch class
utils.toggleClass(this.elements.container, this.config.classNames.isTouch, support.touch);
diff --git a/src/js/plugins/vimeo.js b/src/js/plugins/vimeo.js
index 0b815fa5..0f6aa4db 100644
--- a/src/js/plugins/vimeo.js
+++ b/src/js/plugins/vimeo.js
@@ -15,6 +15,13 @@ const vimeo = {
// Add embed class for responsive
utils.toggleClass(this.elements.wrapper, this.config.classNames.embed, true);
+ // Set aspect ratio
+ const ratio = this.config.ratio.split(':');
+ const padding = 100 / ratio[0] * ratio[1];
+ const offset = (100 - padding) / 2;
+ this.elements.wrapper.style.paddingBottom = `${padding}%`;
+ this.media.style.transform = `translateY(-${offset}%)`;
+
// Set ID
this.media.setAttribute('id', utils.generateId(this.type));
diff --git a/src/js/plugins/youtube.js b/src/js/plugins/youtube.js
index 38f649a5..2c8557dc 100644
--- a/src/js/plugins/youtube.js
+++ b/src/js/plugins/youtube.js
@@ -17,6 +17,10 @@ const youtube = {
// Add embed class for responsive
utils.toggleClass(this.elements.wrapper, this.config.classNames.embed, true);
+ // Set aspect ratio
+ const ratio = this.config.ratio.split(':');
+ this.elements.wrapper.style.paddingBottom = `${100 / ratio[0] * ratio[1]}%`;
+
// Set ID
this.media.setAttribute('id', utils.generateId(this.type));
diff --git a/src/js/plyr.js b/src/js/plyr.js
index 5c28887e..08711172 100644
--- a/src/js/plyr.js
+++ b/src/js/plyr.js
@@ -192,10 +192,7 @@ class Plyr {
return;
}
- // Sniff out the browser
- this.browser = utils.getBrowser();
-
- // Load saved settings from localStorage
+ // Setup local storage for user settings
storage.setup.call(this);
// Check for support again but with type
@@ -237,17 +234,27 @@ class Plyr {
}
}
+ // ---------------------------------------
// API
// ---------------------------------------
+ /**
+ * If the player is HTML5
+ */
get isHTML5() {
return types.html5.includes(this.type);
}
+
+ /**
+ * If the player is an embed - e.g. YouTube or Vimeo
+ */
get isEmbed() {
return types.embed.includes(this.type);
}
- // Play
+ /**
+ * Play the media
+ */
play() {
if ('play' in this.media) {
this.media.play();
@@ -257,7 +264,9 @@ class Plyr {
return this;
}
- // Pause
+ /**
+ * Pause the media
+ */
pause() {
if ('pause' in this.media) {
this.media.pause();
@@ -267,7 +276,10 @@ class Plyr {
return this;
}
- // Toggle playback
+ /**
+ * Toggle playback based on current status
+ * @param {boolean} toggle
+ */
togglePlay(toggle) {
// True toggle if nothing passed
if ((!utils.is.boolean(toggle) && this.media.paused) || toggle) {
@@ -277,31 +289,43 @@ class Plyr {
return this.pause();
}
- // Stop
+ /**
+ * Stop playback
+ */
stop() {
return this.restart().pause();
}
- // Restart
+ /**
+ * Restart playback
+ */
restart() {
this.currentTime = 0;
return this;
}
- // Rewind
+ /**
+ * Rewind
+ * @param {number} seekTime - how far to rewind in seconds. Defaults to the config.seekTime
+ */
rewind(seekTime) {
this.currentTime = this.currentTime - (utils.is.number(seekTime) ? seekTime : this.config.seekTime);
return this;
}
- // Fast forward
+ /**
+ * Fast forward
+ * @param {number} seekTime - how far to fast forward in seconds. Defaults to the config.seekTime
+ */
forward(seekTime) {
this.currentTime = this.currentTime + (utils.is.number(seekTime) ? seekTime : this.config.seekTime);
return this;
}
- // Seek to time
- // The input parameter can be an event or a number
+ /**
+ * Seek to a time
+ * @param {number} input - where to seek to in seconds. Defaults to 0 (the start)
+ */
set currentTime(input) {
let targetTime = 0;
@@ -327,7 +351,9 @@ class Plyr {
return Number(this.media.currentTime);
}
- // Duration
+ /**
+ * Get the duration of the current media
+ */
get duration() {
// Faux duration set via config
const fauxDuration = parseInt(this.config.duration, 10);
@@ -339,7 +365,10 @@ class Plyr {
return !Number.isNaN(fauxDuration) ? fauxDuration : realDuration;
}
- // Volume
+ /**
+ * Set the player volume
+ * @param {number} value - must be between 0 and 1. Defaults to the value from local storage and config.volume if not set in storage
+ */
set volume(value) {
let volume = value;
const max = 1;
@@ -377,6 +406,9 @@ class Plyr {
}
}
+ /**
+ * Get the current player volume
+ */
get volume() {
return this.media.volume;
}
diff --git a/src/js/ui.js b/src/js/ui.js
index c0448054..aa579d8d 100644
--- a/src/js/ui.js
+++ b/src/js/ui.js
@@ -84,15 +84,17 @@ const ui = {
// Update the UI
ui.checkPlaying.call(this);
+ // Ready for API calls
this.ready = true;
// Ready event at end of execution stack
utils.dispatchEvent.call(this, this.media, 'ready');
// Autoplay
- if (this.config.autoplay) {
+ // TODO: check we still need this?
+ /* if (this.isEmbed && this.config.autoplay) {
this.play();
- }
+ } */
},
// Show the duration on metadataloaded
diff --git a/src/js/utils.js b/src/js/utils.js
index 4296f345..70519fac 100644
--- a/src/js/utils.js
+++ b/src/js/utils.js
@@ -89,6 +89,73 @@ const utils = {
firstScriptTag.parentNode.insertBefore(tag, firstScriptTag);
},
+ // Load an external SVG sprite
+ loadSprite(url, id) {
+ if (typeof url !== 'string') {
+ return;
+ }
+
+ const prefix = 'cache-';
+ const hasId = typeof id === 'string';
+ let isCached = false;
+
+ function updateSprite(data) {
+ // Inject content
+ this.innerHTML = data;
+
+ // Inject the SVG to the body
+ document.body.insertBefore(this, document.body.childNodes[0]);
+ }
+
+ // Only load once
+ if (!hasId || !document.querySelectorAll(`#${id}`).length) {
+ // Create container
+ const container = document.createElement('div');
+ container.setAttribute('hidden', '');
+
+ if (hasId) {
+ container.setAttribute('id', id);
+ }
+
+ // Check in cache
+ if (support.storage) {
+ const cached = window.localStorage.getItem(prefix + id);
+ isCached = cached !== null;
+
+ if (isCached) {
+ const data = JSON.parse(cached);
+ updateSprite.call(container, data.content);
+ }
+ }
+
+ // ReSharper disable once InconsistentNaming
+ const xhr = new XMLHttpRequest();
+
+ // XHR for Chrome/Firefox/Opera/Safari
+ if ('withCredentials' in xhr) {
+ xhr.open('GET', url, true);
+ } else {
+ return;
+ }
+
+ // Once loaded, inject to container and body
+ xhr.onload = () => {
+ if (support.storage) {
+ window.localStorage.setItem(
+ prefix + id,
+ JSON.stringify({
+ content: xhr.responseText,
+ })
+ );
+ }
+
+ updateSprite.call(container, xhr.responseText);
+ };
+
+ xhr.send();
+ }
+ },
+
// Generate a random ID
generateId(prefix) {
return `${prefix}-${Math.floor(Math.random() * 10000)}`;
@@ -564,73 +631,6 @@ const utils = {
return fragment.firstChild.innerText;
},
- // Load an SVG sprite
- loadSprite(url, id) {
- if (typeof url !== 'string') {
- return;
- }
-
- const prefix = 'cache-';
- const hasId = typeof id === 'string';
- let isCached = false;
-
- function updateSprite(data) {
- // Inject content
- this.innerHTML = data;
-
- // Inject the SVG to the body
- document.body.insertBefore(this, document.body.childNodes[0]);
- }
-
- // Only load once
- if (!hasId || !document.querySelectorAll(`#${id}`).length) {
- // Create container
- const container = document.createElement('div');
- container.setAttribute('hidden', '');
-
- if (hasId) {
- container.setAttribute('id', id);
- }
-
- // Check in cache
- if (support.storage) {
- const cached = window.localStorage.getItem(prefix + id);
- isCached = cached !== null;
-
- if (isCached) {
- const data = JSON.parse(cached);
- updateSprite.call(container, data.content);
- }
- }
-
- // ReSharper disable once InconsistentNaming
- const xhr = new XMLHttpRequest();
-
- // XHR for Chrome/Firefox/Opera/Safari
- if ('withCredentials' in xhr) {
- xhr.open('GET', url, true);
- } else {
- return;
- }
-
- // Once loaded, inject to container and body
- xhr.onload = () => {
- if (support.storage) {
- window.localStorage.setItem(
- prefix + id,
- JSON.stringify({
- content: xhr.responseText,
- })
- );
- }
-
- updateSprite.call(container, xhr.responseText);
- };
-
- xhr.send();
- }
- },
-
// Get the transition end event
transitionEnd: (() => {
const element = document.createElement('span');
diff --git a/src/less/components/embed.less b/src/less/components/embed.less
index f6b5b307..dcf889b7 100644
--- a/src/less/components/embed.less
+++ b/src/less/components/embed.less
@@ -4,7 +4,11 @@
// --------------------------------------------------------------
.plyr__video-embed {
- padding-bottom: 56.25%; /* 16:9 */
+ // Default to 16:9 ratio but this is set by JavaScript based on config
+ @padding: ((100 / 16) * 9);
+ @offset: unit((100 - @padding) / 2, ~'%');
+
+ padding-bottom: unit(@padding, ~'%');
height: 0;
iframe {
@@ -20,8 +24,8 @@
// Vimeo hack
> div {
position: relative;
- padding-bottom: 200%;
- transform: translateY(-35.95%);
+ padding-bottom: 100%;
+ transform: translateY(-@offset);
}
}
// To allow mouse events to be captured if full support