aboutsummaryrefslogtreecommitdiffstats
path: root/dist/plyr.mjs
diff options
context:
space:
mode:
authorSam Potts <sam@potts.es>2020-04-24 01:05:58 +1000
committerSam Potts <sam@potts.es>2020-04-24 01:05:58 +1000
commit66c57806166e3f760b7c13d02d0025f929dcd2d9 (patch)
treef46fc0424ea20a0a253bef175e35962538d72115 /dist/plyr.mjs
parente48b1d11ce37960bc5803056561ec2b3996258c3 (diff)
downloadplyr-66c57806166e3f760b7c13d02d0025f929dcd2d9.tar.lz
plyr-66c57806166e3f760b7c13d02d0025f929dcd2d9.tar.xz
plyr-66c57806166e3f760b7c13d02d0025f929dcd2d9.zip
v3.6.0
Diffstat (limited to 'dist/plyr.mjs')
-rw-r--r--dist/plyr.mjs251
1 files changed, 187 insertions, 64 deletions
diff --git a/dist/plyr.mjs b/dist/plyr.mjs
index 32b4cf15..7b700992 100644
--- a/dist/plyr.mjs
+++ b/dist/plyr.mjs
@@ -69,6 +69,42 @@ function _objectSpread2(target) {
return target;
}
+function _objectWithoutPropertiesLoose(source, excluded) {
+ if (source == null) return {};
+ var target = {};
+ var sourceKeys = Object.keys(source);
+ var key, i;
+
+ for (i = 0; i < sourceKeys.length; i++) {
+ key = sourceKeys[i];
+ if (excluded.indexOf(key) >= 0) continue;
+ target[key] = source[key];
+ }
+
+ return target;
+}
+
+function _objectWithoutProperties(source, excluded) {
+ if (source == null) return {};
+
+ var target = _objectWithoutPropertiesLoose(source, excluded);
+
+ var key, i;
+
+ if (Object.getOwnPropertySymbols) {
+ var sourceSymbolKeys = Object.getOwnPropertySymbols(source);
+
+ for (i = 0; i < sourceSymbolKeys.length; i++) {
+ key = sourceSymbolKeys[i];
+ if (excluded.indexOf(key) >= 0) continue;
+ if (!Object.prototype.propertyIsEnumerable.call(source, key)) continue;
+ target[key] = source[key];
+ }
+ }
+
+ return target;
+}
+
function _slicedToArray(arr, i) {
return _arrayWithHoles(arr) || _iterableToArrayLimit(arr, i) || _unsupportedIterableToArray(arr, i) || _nonIterableRest();
}
@@ -782,6 +818,25 @@ function matches$1(element, selector) {
var method = prototype.matches || prototype.webkitMatchesSelector || prototype.mozMatchesSelector || prototype.msMatchesSelector || match;
return method.call(element, selector);
+} // Closest ancestor element matching selector (also tests element itself)
+
+function closest(element, selector) {
+ var _Element2 = Element,
+ prototype = _Element2.prototype; // https://developer.mozilla.org/en-US/docs/Web/API/Element/closest#Polyfill
+
+ function closestElement() {
+ var el = this;
+
+ do {
+ if (matches$1.matches(el, selector)) return el;
+ el = el.parentElement || el.parentNode;
+ } while (el !== null && el.nodeType === 1);
+
+ return null;
+ }
+
+ var method = prototype.closest || closestElement;
+ return method.call(element, selector);
} // Find all elements
function getElements(selector) {
@@ -1133,8 +1188,8 @@ function setAspectRatio(input) {
var padding = 100 / w * h;
wrapper.style.paddingBottom = "".concat(padding, "%"); // For Vimeo we have an extra <div> to hide the standard controls and UI
- if (this.isVimeo && this.supported.ui) {
- var height = 240;
+ if (this.isVimeo && !this.config.vimeo.premium && this.supported.ui) {
+ var height = 100 / this.media.offsetWidth * parseInt(window.getComputedStyle(this.media).paddingBottom, 10);
var offset = (height - padding) / (height / 50);
this.media.style.transform = "translateY(-".concat(offset, "%)");
} else if (this.isHTML5) {
@@ -1290,7 +1345,7 @@ function dedupe(array) {
});
} // Get the closest value in an array
-function closest(array, value) {
+function closest$1(array, value) {
if (!is$1.array(array) || !array.length) {
return null;
}
@@ -3272,9 +3327,15 @@ var captions = {
meta.set(track, {
default: track.mode === 'showing'
}); // Turn off native caption rendering to avoid double captions
+ // Note: mode='hidden' forces a track to download. To ensure every track
+ // isn't downloaded at once, only 'showing' tracks should be reassigned
// eslint-disable-next-line no-param-reassign
- track.mode = 'hidden'; // Add event listener for cue changes
+ if (track.mode === 'showing') {
+ // eslint-disable-next-line no-param-reassign
+ track.mode = 'hidden';
+ } // Add event listener for cue changes
+
on.call(_this, track, 'cuechange', function () {
return captions.updateCues.call(_this);
@@ -3298,6 +3359,8 @@ var captions = {
// Toggle captions display
// Used internally for the toggleCaptions method, with the passive option forced to false
toggle: function toggle(input) {
+ var _this2 = this;
+
var passive = arguments.length > 1 && arguments[1] !== undefined ? arguments[1] : true;
// If there's no full support
@@ -3344,7 +3407,15 @@ var captions = {
controls.updateSetting.call(this, 'captions'); // Trigger event (not used internally)
triggerEvent.call(this, this.media, active ? 'captionsenabled' : 'captionsdisabled');
- }
+ } // Wait for the call stack to clear before setting mode='hidden'
+ // on the active track - forcing the browser to download it
+
+
+ setTimeout(function () {
+ if (active && _this2.captions.toggled) {
+ _this2.captions.currentTrackNode.mode = 'hidden';
+ }
+ });
},
// Set captions by track index
// Used internally for the currentTrack setter with the passive option forced to false
@@ -3425,7 +3496,7 @@ var captions = {
// If update is false it will also ignore tracks without metadata
// This is used to "freeze" the language options when captions.update is false
getTracks: function getTracks() {
- var _this2 = this;
+ var _this3 = this;
var update = arguments.length > 0 && arguments[0] !== undefined ? arguments[0] : false;
// Handle media or textTracks missing or null
@@ -3433,20 +3504,20 @@ var captions = {
// Filter out removed tracks and tracks that aren't captions/subtitles (for example metadata)
return tracks.filter(function (track) {
- return !_this2.isHTML5 || update || _this2.captions.meta.has(track);
+ return !_this3.isHTML5 || update || _this3.captions.meta.has(track);
}).filter(function (track) {
return ['captions', 'subtitles'].includes(track.kind);
});
},
// Match tracks based on languages and get the first
findTrack: function findTrack(languages) {
- var _this3 = this;
+ var _this4 = this;
var force = arguments.length > 1 && arguments[1] !== undefined ? arguments[1] : false;
var tracks = captions.getTracks.call(this);
var sortIsDefault = function sortIsDefault(track) {
- return Number((_this3.captions.meta.get(track) || {}).default);
+ return Number((_this4.captions.meta.get(track) || {}).default);
};
var sorted = Array.from(tracks).sort(function (a, b) {
@@ -3627,6 +3698,9 @@ var defaults$1 = {
fallback: true,
// Fallback using full viewport/window
iosNative: false // Use the native fullscreen in iOS (disables custom controls)
+ // Selector for the fullscreen container so contextual / non-player content can remain visible in fullscreen mode
+ // Non-ancestors of the player element will be ignored
+ // container: null, // defaults to the player element
},
// Local storage
@@ -3864,16 +3938,16 @@ var defaults$1 = {
title: false,
speed: true,
transparent: false,
- // These settings require a pro or premium account to work
- sidedock: false,
- controls: false,
+ // Whether the owner of the video has a Pro or Business account
+ // (which allows us to properly hide controls without CSS hacks, etc)
+ premium: false,
// Custom settings from Plyr
referrerPolicy: null // https://developer.mozilla.org/en-US/docs/Web/API/HTMLIFrameElement/referrerPolicy
},
// YouTube plugin
youtube: {
- noCookie: false,
+ noCookie: true,
// Whether to use an alternative version of YouTube without cookies
rel: 0,
// No related vids
@@ -3983,7 +4057,10 @@ var Fullscreen = /*#__PURE__*/function () {
y: 0
}; // Force the use of 'full window/browser' rather than fullscreen
- this.forceFallback = player.config.fullscreen.fallback === 'force'; // Register event listeners
+ this.forceFallback = player.config.fullscreen.fallback === 'force'; // Get the fullscreen element
+ // Checks container is an ancestor, defaults to null
+
+ this.player.elements.fullscreen = player.config.fullscreen.container && closest(this.player.elements.container, player.config.fullscreen.container); // Register event listeners
// Handle event (incase user presses escape etc)
on.call(this.player, document, this.prefix === 'ms' ? 'MSFullscreenChange' : "".concat(this.prefix, "fullscreenchange"), function () {
@@ -4209,7 +4286,7 @@ var Fullscreen = /*#__PURE__*/function () {
}, {
key: "target",
get: function get() {
- return browser.isIos && this.player.config.fullscreen.iosNative ? this.player.media : this.player.elements.container;
+ return browser.isIos && this.player.config.fullscreen.iosNative ? this.player.media : this.player.elements.fullscreen || this.player.elements.container;
}
}], [{
key: "native",
@@ -4271,7 +4348,6 @@ function loadImage(src) {
});
}
-// ==========================================================================
var ui = {
addStyleHook: function addStyleHook() {
toggleClass(this.elements.container, this.config.selectors.container.replace('.', ''), true);
@@ -4406,12 +4482,7 @@ var ui = {
} // Set property synchronously to respect the call order
- this.media.setAttribute('poster', poster); // HTML5 uses native poster attribute
-
- if (this.isHTML5) {
- return Promise.resolve(poster);
- } // Wait until ui is ready
-
+ this.media.setAttribute('data-poster', poster); // Wait until ui is ready
return ready.call(this) // Load image
.then(function () {
@@ -4487,6 +4558,26 @@ var ui = {
this.toggleControls(Boolean(force || this.loading || this.paused || controlsElement.pressed || controlsElement.hover || recentTouchSeek));
}
+ },
+ // Migrate any custom properties from the media to the parent
+ migrateStyles: function migrateStyles() {
+ var _this5 = this;
+
+ // Loop through values (as they are the keys when the object is spread 🤔)
+ Object.values(_objectSpread2({}, this.media.style)) // We're only fussed about Plyr specific properties
+ .filter(function (key) {
+ return key.startsWith('--plyr');
+ }).forEach(function (key) {
+ // Set on the container
+ _this5.elements.container.style.setProperty(key, _this5.media.style.getPropertyValue(key)); // Clean up from media element
+
+
+ _this5.media.style.removeProperty(key);
+ }); // Remove attribute if empty
+
+ if (is$1.empty(this.media.style)) {
+ this.media.removeAttribute('style');
+ }
}
};
@@ -4695,15 +4786,17 @@ var Listeners = /*#__PURE__*/function () {
removeCurrent(); // Delay the adding of classname until the focus has changed
// This event fires before the focusin event
- this.focusTimer = setTimeout(function () {
- var focused = document.activeElement; // Ignore if current focus element isn't inside the player
+ if (event.type !== 'focusout') {
+ this.focusTimer = setTimeout(function () {
+ var focused = document.activeElement; // Ignore if current focus element isn't inside the player
- if (!elements.container.contains(focused)) {
- return;
- }
+ if (!elements.container.contains(focused)) {
+ return;
+ }
- toggleClass(document.activeElement, player.config.classNames.tabFocus, true);
- }, 10);
+ toggleClass(document.activeElement, player.config.classNames.tabFocus, true);
+ }, 10);
+ }
} // Global window & document listeners
}, {
@@ -4721,7 +4814,7 @@ var Listeners = /*#__PURE__*/function () {
once.call(player, document.body, 'touchstart', this.firstTouch); // Tab focus detection
- toggleListener.call(player, document.body, 'keydown focus blur', this.setTabFocus, toggle, false, true);
+ toggleListener.call(player, document.body, 'keydown focus blur focusout', this.setTabFocus, toggle, false, true);
} // Container listeners
}, {
@@ -4764,7 +4857,7 @@ var Listeners = /*#__PURE__*/function () {
}); // Set a gutter for Vimeo
var setGutter = function setGutter(ratio, padding, toggle) {
- if (!player.isVimeo) {
+ if (!player.isVimeo || player.config.vimeo.premium) {
return;
}
@@ -4821,7 +4914,7 @@ var Listeners = /*#__PURE__*/function () {
ratio = _setPlayerSize.ratio; // Set Vimeo gutter
- setGutter(ratio, padding, isEnter); // If not using native fullscreen, we need to check for resizes of viewport
+ setGutter(ratio, padding, isEnter); // If not using native browser fullscreen API, we need to check for resizes of viewport
if (!usingNative) {
if (isEnter) {
@@ -5200,7 +5293,18 @@ var Listeners = /*#__PURE__*/function () {
this.bind(elements.controls, 'mouseenter mouseleave', function (event) {
elements.controls.hover = !player.touch && event.type === 'mouseenter';
- }); // Update controls.pressed state (used for ui.toggleControls to avoid hiding when interacting)
+ }); // Also update controls.hover state for any non-player children of fullscreen element (as above)
+
+ if (elements.fullscreen) {
+ Array.from(elements.fullscreen.children).filter(function (c) {
+ return !c.contains(elements.container);
+ }).forEach(function (child) {
+ _this3.bind(child, 'mouseenter mouseleave', function (event) {
+ elements.controls.hover = !player.touch && event.type === 'mouseenter';
+ });
+ });
+ } // Update controls.pressed state (used for ui.toggleControls to avoid hiding when interacting)
+
this.bind(elements.controls, 'mousedown mouseup touchstart touchend touchcancel', function (event) {
elements.controls.pressed = ['mousedown', 'touchstart'].includes(event.type);
@@ -5616,15 +5720,28 @@ var vimeo = {
var _this = this;
var player = this;
- var config = player.config.vimeo; // Get Vimeo params for the iframe
+ var config = player.config.vimeo;
+
+ var premium = config.premium,
+ referrerPolicy = config.referrerPolicy,
+ frameParams = _objectWithoutProperties(config, ["premium", "referrerPolicy"]); // If the owner has a pro or premium account then we can hide controls etc
+
+
+ if (premium) {
+ Object.assign(frameParams, {
+ controls: false,
+ sidedock: false
+ });
+ } // Get Vimeo params for the iframe
+
- var params = buildUrlParams(extend({}, {
+ var params = buildUrlParams(_objectSpread2({
loop: player.config.loop.active,
autoplay: player.autoplay,
muted: player.muted,
gesture: 'media',
playsinline: !this.config.fullscreen.iosNative
- }, config)); // Get the source URL or ID
+ }, frameParams)); // Get the source URL or ID
var source = player.media.getAttribute('src'); // Get from <div> if needed
@@ -5638,22 +5755,27 @@ var vimeo = {
var src = format(player.config.urls.vimeo.iframe, id, params);
iframe.setAttribute('src', src);
iframe.setAttribute('allowfullscreen', '');
- iframe.setAttribute('allowtransparency', '');
- iframe.setAttribute('allow', 'autoplay'); // Set the referrer policy if required
+ iframe.setAttribute('allow', 'autoplay,fullscreen,picture-in-picture'); // Set the referrer policy if required
- if (!is$1.empty(config.referrerPolicy)) {
- iframe.setAttribute('referrerPolicy', config.referrerPolicy);
- } // Get poster, if already set
+ if (!is$1.empty(referrerPolicy)) {
+ iframe.setAttribute('referrerPolicy', referrerPolicy);
+ } // Inject the package
- var poster = player.poster; // Inject the package
+ var poster = player.poster;
+
+ if (premium) {
+ iframe.setAttribute('data-poster', poster);
+ player.media = replaceElement(iframe, player.media);
+ } else {
+ var wrapper = createElement('div', {
+ class: player.config.classNames.embedContainer,
+ 'data-poster': poster
+ });
+ wrapper.appendChild(iframe);
+ player.media = replaceElement(wrapper, player.media);
+ } // Get poster image
- var wrapper = createElement('div', {
- poster: poster,
- class: player.config.classNames.embedContainer
- });
- wrapper.appendChild(iframe);
- player.media = replaceElement(wrapper, player.media); // Get poster image
fetch(format(player.config.urls.vimeo.api, id), 'json').then(function (response) {
if (is$1.empty(response)) {
@@ -6026,7 +6148,7 @@ var youtube = {
var container = createElement('div', {
id: id,
- poster: poster
+ 'data-poster': poster
});
player.media = replaceElement(container, player.media); // Id to poster wrapper
@@ -6345,14 +6467,12 @@ var media = {
class: this.config.classNames.video
}); // Wrap the video in a container
- wrap(this.media, this.elements.wrapper); // Faux poster container
+ wrap(this.media, this.elements.wrapper); // Poster image container
- if (this.isEmbed) {
- this.elements.poster = createElement('div', {
- class: this.config.classNames.poster
- });
- this.elements.wrapper.appendChild(this.elements.poster);
- }
+ this.elements.poster = createElement('div', {
+ class: this.config.classNames.poster
+ });
+ this.elements.wrapper.appendChild(this.elements.poster);
}
if (this.isHTML5) {
@@ -7958,6 +8078,7 @@ var Plyr = /*#__PURE__*/function () {
this.elements = {
container: null,
+ fullscreen: null,
captions: null,
buttons: {},
display: {},
@@ -8132,8 +8253,10 @@ var Plyr = /*#__PURE__*/function () {
tabindex: 0
});
wrap(this.media, this.elements.container);
- } // Add style hook
+ } // Migrate custom properties from media to container (so they work 😉)
+
+ ui.migrateStyles.call(this); // Add style hook
ui.addStyleHook.call(this); // Setup media
@@ -8143,9 +8266,11 @@ var Plyr = /*#__PURE__*/function () {
on.call(this, this.elements.container, this.config.events.join(' '), function (event) {
_this.debug.log("event: ".concat(event.type));
});
- } // Setup interface
- // If embed but not fully supported, build interface now to avoid flash of controls
+ } // Setup fullscreen
+
+ this.fullscreen = new Fullscreen(this); // Setup interface
+ // If embed but not fully supported, build interface now to avoid flash of controls
if (this.isHTML5 || this.isEmbed && !this.supported.ui) {
ui.build.call(this);
@@ -8154,9 +8279,7 @@ var Plyr = /*#__PURE__*/function () {
this.listeners.container(); // Global listeners
- this.listeners.global(); // Setup fullscreen
-
- this.fullscreen = new Fullscreen(this); // Setup ads if provided
+ this.listeners.global(); // Setup ads if provided
if (this.config.ads.enabled) {
this.ads = new Ads(this);
@@ -8855,7 +8978,7 @@ var Plyr = /*#__PURE__*/function () {
var updateStorage = true;
if (!options.includes(quality)) {
- var value = closest(options, quality);
+ var value = closest$1(options, quality);
this.debug.warn("Unsupported quality option: ".concat(quality, ", using ").concat(value, " instead"));
quality = value; // Don't update storage if quality is not supported
@@ -9000,7 +9123,7 @@ var Plyr = /*#__PURE__*/function () {
return null;
}
- return this.media.getAttribute('poster');
+ return this.media.getAttribute('poster') || this.media.getAttribute('data-poster');
}
/**
* Get the current aspect ratio in use