This commit is contained in:
Sam Potts 2020-04-24 01:05:58 +10:00
parent e48b1d11ce
commit 66c5780616
19 changed files with 998 additions and 346 deletions

View File

@ -1,6 +1,22 @@
## v3.6.0 ## v3.6.0
- You can now easily change colors using CSS Custom Properties. - You can now easily change colors using CSS Custom Properties. See the [README](README.md#customizing-the-css).
- Bug fix for Vimeo fullscreen.
- Various typos (thanks @likev)
- Preload TextTracks as per default video element (thanks @theprojectsomething)
- Features/fullscreen container (thanks @theprojectsomething)
- Ignore internal play promises (thanks @ydylla)
- Ads plugin fixes to allow multiple VAST requests (thanks @Steejo)
- Fix shadowroot (thanks @jnoordsij)
- Add financial contributors for Open Collective (thanks @monkeywithacupcake)
- Update the gitpod setup description to be more precise. (thanks @nisarhassan12)
- Completely hide SVG icons to screen readers (thanks @LeBenLeBen)
- Preview thumbnails via src:callback() (thanks @doublex)
- Add missing Typescripts types and options (thanks @hug963)
- Use number instead of string in TS quality definitions (thanks @mogzol)
- Fix Vimeo playback rate (thanks @hug963)
- Fix issue when controls config is string or element (thanks @CzBiX)
- Simplify contributions by fully automating the dev setup with gitpod (thanks @nisarhassan12)
### v3.5.10 ### v3.5.10

2
demo/dist/demo.css vendored

File diff suppressed because one or more lines are too long

232
demo/dist/demo.js vendored
View File

@ -4380,6 +4380,42 @@ typeof navigator === "object" && (function () {
return 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) { function _slicedToArray(arr, i) {
return _arrayWithHoles(arr) || _iterableToArrayLimit(arr, i) || _unsupportedIterableToArray(arr, i) || _nonIterableRest(); return _arrayWithHoles(arr) || _iterableToArrayLimit(arr, i) || _unsupportedIterableToArray(arr, i) || _nonIterableRest();
} }
@ -14612,7 +14648,7 @@ typeof navigator === "object" && (function () {
(module.exports = function (key, value) { (module.exports = function (key, value) {
return sharedStore$1[key] || (sharedStore$1[key] = value !== undefined ? value : {}); return sharedStore$1[key] || (sharedStore$1[key] = value !== undefined ? value : {});
})('versions', []).push({ })('versions', []).push({
version: '3.6.4', version: '3.6.5',
mode: 'global', mode: 'global',
copyright: '© 2020 Denis Pushkarev (zloirock.ru)' copyright: '© 2020 Denis Pushkarev (zloirock.ru)'
}); });
@ -17622,7 +17658,7 @@ typeof navigator === "object" && (function () {
var INVALID_PORT$1 = 'Invalid port'; var INVALID_PORT$1 = 'Invalid port';
var ALPHA$1 = /[A-Za-z]/; var ALPHA$1 = /[A-Za-z]/;
var ALPHANUMERIC$1 = /[\d+\-.A-Za-z]/; var ALPHANUMERIC$1 = /[\d+-.A-Za-z]/;
var DIGIT$1 = /\d/; var DIGIT$1 = /\d/;
var HEX_START$1 = /^(0x|0X)/; var HEX_START$1 = /^(0x|0X)/;
var OCT$1 = /^[0-7]+$/; var OCT$1 = /^[0-7]+$/;
@ -19629,7 +19665,13 @@ typeof navigator === "object" && (function () {
defer$1 = functionBindContext$1(port$1.postMessage, port$1, 1); defer$1 = functionBindContext$1(port$1.postMessage, port$1, 1);
// Browsers with postMessage, skip WebWorkers // Browsers with postMessage, skip WebWorkers
// IE8 has postMessage, but it's sync & typeof its postMessage is 'object' // IE8 has postMessage, but it's sync & typeof its postMessage is 'object'
} else if (global_1$1.addEventListener && typeof postMessage == 'function' && !global_1$1.importScripts && !fails$1(post$1)) { } else if (
global_1$1.addEventListener &&
typeof postMessage == 'function' &&
!global_1$1.importScripts &&
!fails$1(post$1) &&
location$1.protocol !== 'file:'
) {
defer$1 = post$1; defer$1 = post$1;
global_1$1.addEventListener('message', listener$1, false); global_1$1.addEventListener('message', listener$1, false);
// IE8- // IE8-
@ -20639,6 +20681,25 @@ typeof navigator === "object" && (function () {
var method = prototype.matches || prototype.webkitMatchesSelector || prototype.mozMatchesSelector || prototype.msMatchesSelector || match; var method = prototype.matches || prototype.webkitMatchesSelector || prototype.mozMatchesSelector || prototype.msMatchesSelector || match;
return method.call(element, selector); 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$2.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 } // Find all elements
function getElements(selector) { function getElements(selector) {
@ -20990,8 +21051,8 @@ typeof navigator === "object" && (function () {
var padding = 100 / w * h; var padding = 100 / w * h;
wrapper.style.paddingBottom = "".concat(padding, "%"); // For Vimeo we have an extra <div> to hide the standard controls and UI 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) { if (this.isVimeo && !this.config.vimeo.premium && this.supported.ui) {
var height = 240; var height = 100 / this.media.offsetWidth * parseInt(window.getComputedStyle(this.media).paddingBottom, 10);
var offset = (height - padding) / (height / 50); var offset = (height - padding) / (height / 50);
this.media.style.transform = "translateY(-".concat(offset, "%)"); this.media.style.transform = "translateY(-".concat(offset, "%)");
} else if (this.isHTML5) { } else if (this.isHTML5) {
@ -21144,7 +21205,7 @@ typeof navigator === "object" && (function () {
}); });
} // Get the closest value in an array } // Get the closest value in an array
function closest(array, value) { function closest$1(array, value) {
if (!is$2.array(array) || !array.length) { if (!is$2.array(array) || !array.length) {
return null; return null;
} }
@ -23252,9 +23313,15 @@ typeof navigator === "object" && (function () {
meta.set(track, { meta.set(track, {
default: track.mode === 'showing' default: track.mode === 'showing'
}); // Turn off native caption rendering to avoid double captions }); // 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 // 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 () { on.call(_this, track, 'cuechange', function () {
return captions.updateCues.call(_this); return captions.updateCues.call(_this);
@ -23278,6 +23345,8 @@ typeof navigator === "object" && (function () {
// Toggle captions display // Toggle captions display
// Used internally for the toggleCaptions method, with the passive option forced to false // Used internally for the toggleCaptions method, with the passive option forced to false
toggle: function toggle(input) { toggle: function toggle(input) {
var _this2 = this;
var passive = arguments.length > 1 && arguments[1] !== undefined ? arguments[1] : true; var passive = arguments.length > 1 && arguments[1] !== undefined ? arguments[1] : true;
// If there's no full support // If there's no full support
@ -23324,7 +23393,15 @@ typeof navigator === "object" && (function () {
controls.updateSetting.call(this, 'captions'); // Trigger event (not used internally) controls.updateSetting.call(this, 'captions'); // Trigger event (not used internally)
triggerEvent.call(this, this.media, active ? 'captionsenabled' : 'captionsdisabled'); 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 // Set captions by track index
// Used internally for the currentTrack setter with the passive option forced to false // Used internally for the currentTrack setter with the passive option forced to false
@ -23405,7 +23482,7 @@ typeof navigator === "object" && (function () {
// If update is false it will also ignore tracks without metadata // If update is false it will also ignore tracks without metadata
// This is used to "freeze" the language options when captions.update is false // This is used to "freeze" the language options when captions.update is false
getTracks: function getTracks() { getTracks: function getTracks() {
var _this2 = this; var _this3 = this;
var update = arguments.length > 0 && arguments[0] !== undefined ? arguments[0] : false; var update = arguments.length > 0 && arguments[0] !== undefined ? arguments[0] : false;
// Handle media or textTracks missing or null // Handle media or textTracks missing or null
@ -23413,20 +23490,20 @@ typeof navigator === "object" && (function () {
// Filter out removed tracks and tracks that aren't captions/subtitles (for example metadata) // Filter out removed tracks and tracks that aren't captions/subtitles (for example metadata)
return tracks.filter(function (track) { 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) { }).filter(function (track) {
return ['captions', 'subtitles'].includes(track.kind); return ['captions', 'subtitles'].includes(track.kind);
}); });
}, },
// Match tracks based on languages and get the first // Match tracks based on languages and get the first
findTrack: function findTrack(languages) { findTrack: function findTrack(languages) {
var _this3 = this; var _this4 = this;
var force = arguments.length > 1 && arguments[1] !== undefined ? arguments[1] : false; var force = arguments.length > 1 && arguments[1] !== undefined ? arguments[1] : false;
var tracks = captions.getTracks.call(this); var tracks = captions.getTracks.call(this);
var sortIsDefault = function sortIsDefault(track) { 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) { var sorted = Array.from(tracks).sort(function (a, b) {
@ -23607,6 +23684,9 @@ typeof navigator === "object" && (function () {
fallback: true, fallback: true,
// Fallback using full viewport/window // Fallback using full viewport/window
iosNative: false // Use the native fullscreen in iOS (disables custom controls) 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 // Local storage
@ -23844,16 +23924,16 @@ typeof navigator === "object" && (function () {
title: false, title: false,
speed: true, speed: true,
transparent: false, transparent: false,
// These settings require a pro or premium account to work // Whether the owner of the video has a Pro or Business account
sidedock: false, // (which allows us to properly hide controls without CSS hacks, etc)
controls: false, premium: false,
// Custom settings from Plyr // Custom settings from Plyr
referrerPolicy: null // https://developer.mozilla.org/en-US/docs/Web/API/HTMLIFrameElement/referrerPolicy referrerPolicy: null // https://developer.mozilla.org/en-US/docs/Web/API/HTMLIFrameElement/referrerPolicy
}, },
// YouTube plugin // YouTube plugin
youtube: { youtube: {
noCookie: false, noCookie: true,
// Whether to use an alternative version of YouTube without cookies // Whether to use an alternative version of YouTube without cookies
rel: 0, rel: 0,
// No related vids // No related vids
@ -23963,7 +24043,10 @@ typeof navigator === "object" && (function () {
y: 0 y: 0
}; // Force the use of 'full window/browser' rather than fullscreen }; // 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) // Handle event (incase user presses escape etc)
on.call(this.player, document, this.prefix === 'ms' ? 'MSFullscreenChange' : "".concat(this.prefix, "fullscreenchange"), function () { on.call(this.player, document, this.prefix === 'ms' ? 'MSFullscreenChange' : "".concat(this.prefix, "fullscreenchange"), function () {
@ -24189,7 +24272,7 @@ typeof navigator === "object" && (function () {
}, { }, {
key: "target", key: "target",
get: function get() { 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", key: "native",
@ -24398,12 +24481,7 @@ typeof navigator === "object" && (function () {
} // Set property synchronously to respect the call order } // Set property synchronously to respect the call order
this.media.setAttribute('poster', poster); // HTML5 uses native poster attribute this.media.setAttribute('data-poster', poster); // Wait until ui is ready
if (this.isHTML5) {
return Promise.resolve(poster);
} // Wait until ui is ready
return ready.call(this) // Load image return ready.call(this) // Load image
.then(function () { .then(function () {
@ -24479,6 +24557,26 @@ typeof navigator === "object" && (function () {
this.toggleControls(Boolean(force || this.loading || this.paused || controlsElement.pressed || controlsElement.hover || recentTouchSeek)); 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$2.empty(this.media.style)) {
this.media.removeAttribute('style');
}
} }
}; };
@ -24687,6 +24785,7 @@ typeof navigator === "object" && (function () {
removeCurrent(); // Delay the adding of classname until the focus has changed removeCurrent(); // Delay the adding of classname until the focus has changed
// This event fires before the focusin event // This event fires before the focusin event
if (event.type !== 'focusout') {
this.focusTimer = setTimeout(function () { this.focusTimer = setTimeout(function () {
var focused = document.activeElement; // Ignore if current focus element isn't inside the player var focused = document.activeElement; // Ignore if current focus element isn't inside the player
@ -24696,6 +24795,7 @@ typeof navigator === "object" && (function () {
toggleClass(document.activeElement, player.config.classNames.tabFocus, true); toggleClass(document.activeElement, player.config.classNames.tabFocus, true);
}, 10); }, 10);
}
} // Global window & document listeners } // Global window & document listeners
}, { }, {
@ -24713,7 +24813,7 @@ typeof navigator === "object" && (function () {
once.call(player, document.body, 'touchstart', this.firstTouch); // Tab focus detection 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 } // Container listeners
}, { }, {
@ -24756,7 +24856,7 @@ typeof navigator === "object" && (function () {
}); // Set a gutter for Vimeo }); // Set a gutter for Vimeo
var setGutter = function setGutter(ratio, padding, toggle) { var setGutter = function setGutter(ratio, padding, toggle) {
if (!player.isVimeo) { if (!player.isVimeo || player.config.vimeo.premium) {
return; return;
} }
@ -24813,7 +24913,7 @@ typeof navigator === "object" && (function () {
ratio = _setPlayerSize.ratio; // Set Vimeo gutter 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 (!usingNative) {
if (isEnter) { if (isEnter) {
@ -25192,7 +25292,18 @@ typeof navigator === "object" && (function () {
this.bind(elements.controls, 'mouseenter mouseleave', function (event) { this.bind(elements.controls, 'mouseenter mouseleave', function (event) {
elements.controls.hover = !player.touch && event.type === 'mouseenter'; 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) { this.bind(elements.controls, 'mousedown mouseup touchstart touchend touchcancel', function (event) {
elements.controls.pressed = ['mousedown', 'touchstart'].includes(event.type); elements.controls.pressed = ['mousedown', 'touchstart'].includes(event.type);
@ -25661,15 +25772,28 @@ typeof navigator === "object" && (function () {
var _this = this; var _this = this;
var player = this; var player = this;
var config = player.config.vimeo; // Get Vimeo params for the iframe var config = player.config.vimeo;
var params = buildUrlParams(extend$1({}, { 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(_objectSpread2({
loop: player.config.loop.active, loop: player.config.loop.active,
autoplay: player.autoplay, autoplay: player.autoplay,
muted: player.muted, muted: player.muted,
gesture: 'media', gesture: 'media',
playsinline: !this.config.fullscreen.iosNative 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 var source = player.media.getAttribute('src'); // Get from <div> if needed
@ -25683,22 +25807,27 @@ typeof navigator === "object" && (function () {
var src = format(player.config.urls.vimeo.iframe, id, params); var src = format(player.config.urls.vimeo.iframe, id, params);
iframe.setAttribute('src', src); iframe.setAttribute('src', src);
iframe.setAttribute('allowfullscreen', ''); iframe.setAttribute('allowfullscreen', '');
iframe.setAttribute('allowtransparency', ''); iframe.setAttribute('allow', 'autoplay,fullscreen,picture-in-picture'); // Set the referrer policy if required
iframe.setAttribute('allow', 'autoplay'); // Set the referrer policy if required
if (!is$2.empty(config.referrerPolicy)) { if (!is$2.empty(referrerPolicy)) {
iframe.setAttribute('referrerPolicy', config.referrerPolicy); iframe.setAttribute('referrerPolicy', referrerPolicy);
} // Get poster, if already set } // 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$1('div', { var wrapper = createElement$1('div', {
poster: poster, class: player.config.classNames.embedContainer,
class: player.config.classNames.embedContainer 'data-poster': poster
}); });
wrapper.appendChild(iframe); wrapper.appendChild(iframe);
player.media = replaceElement(wrapper, player.media); // Get poster image player.media = replaceElement(wrapper, player.media);
} // Get poster image
fetch(format(player.config.urls.vimeo.api, id), 'json').then(function (response) { fetch(format(player.config.urls.vimeo.api, id), 'json').then(function (response) {
if (is$2.empty(response)) { if (is$2.empty(response)) {
@ -26069,7 +26198,7 @@ typeof navigator === "object" && (function () {
var container = createElement$1('div', { var container = createElement$1('div', {
id: id, id: id,
poster: poster 'data-poster': poster
}); });
player.media = replaceElement(container, player.media); // Id to poster wrapper player.media = replaceElement(container, player.media); // Id to poster wrapper
@ -26387,15 +26516,13 @@ typeof navigator === "object" && (function () {
class: this.config.classNames.video class: this.config.classNames.video
}); // Wrap the video in a container }); // Wrap the video in a container
wrap$4(this.media, this.elements.wrapper); // Faux poster container wrap$4(this.media, this.elements.wrapper); // Poster image container
if (this.isEmbed) {
this.elements.poster = createElement$1('div', { this.elements.poster = createElement$1('div', {
class: this.config.classNames.poster class: this.config.classNames.poster
}); });
this.elements.wrapper.appendChild(this.elements.poster); this.elements.wrapper.appendChild(this.elements.poster);
} }
}
if (this.isHTML5) { if (this.isHTML5) {
html5.setup.call(this); html5.setup.call(this);
@ -28051,6 +28178,7 @@ typeof navigator === "object" && (function () {
this.elements = { this.elements = {
container: null, container: null,
fullscreen: null,
captions: null, captions: null,
buttons: {}, buttons: {},
display: {}, display: {},
@ -28225,9 +28353,11 @@ typeof navigator === "object" && (function () {
tabindex: 0 tabindex: 0
}); });
wrap$4(this.media, this.elements.container); wrap$4(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 ui.addStyleHook.call(this); // Setup media
media.setup.call(this); // Listen for events if debugging media.setup.call(this); // Listen for events if debugging
@ -28236,10 +28366,12 @@ typeof navigator === "object" && (function () {
on.call(this, this.elements.container, this.config.events.join(' '), function (event) { on.call(this, this.elements.container, this.config.events.join(' '), function (event) {
_this.debug.log("event: ".concat(event.type)); _this.debug.log("event: ".concat(event.type));
}); });
} // Setup interface } // Setup fullscreen
// If embed but not fully supported, build interface now to avoid flash of controls
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) { if (this.isHTML5 || this.isEmbed && !this.supported.ui) {
ui.build.call(this); ui.build.call(this);
} // Container listeners } // Container listeners
@ -28247,9 +28379,7 @@ typeof navigator === "object" && (function () {
this.listeners.container(); // Global listeners this.listeners.container(); // Global listeners
this.listeners.global(); // Setup fullscreen this.listeners.global(); // Setup ads if provided
this.fullscreen = new Fullscreen(this); // Setup ads if provided
if (this.config.ads.enabled) { if (this.config.ads.enabled) {
this.ads = new Ads(this); this.ads = new Ads(this);
@ -28948,7 +29078,7 @@ typeof navigator === "object" && (function () {
var updateStorage = true; var updateStorage = true;
if (!options.includes(quality)) { 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")); this.debug.warn("Unsupported quality option: ".concat(quality, ", using ").concat(value, " instead"));
quality = value; // Don't update storage if quality is not supported quality = value; // Don't update storage if quality is not supported
@ -29093,7 +29223,7 @@ typeof navigator === "object" && (function () {
return null; return null;
} }
return this.media.getAttribute('poster'); return this.media.getAttribute('poster') || this.media.getAttribute('data-poster');
} }
/** /**
* Get the current aspect ratio in use * Get the current aspect ratio in use

File diff suppressed because one or more lines are too long

File diff suppressed because one or more lines are too long

2
dist/plyr.css vendored

File diff suppressed because one or more lines are too long

221
dist/plyr.js vendored
View File

@ -75,6 +75,42 @@ typeof navigator === "object" && (function (global, factory) {
return 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) { function _slicedToArray(arr, i) {
return _arrayWithHoles(arr) || _iterableToArrayLimit(arr, i) || _unsupportedIterableToArray(arr, i) || _nonIterableRest(); return _arrayWithHoles(arr) || _iterableToArrayLimit(arr, i) || _unsupportedIterableToArray(arr, i) || _nonIterableRest();
} }
@ -788,6 +824,25 @@ typeof navigator === "object" && (function (global, factory) {
var method = prototype.matches || prototype.webkitMatchesSelector || prototype.mozMatchesSelector || prototype.msMatchesSelector || match; var method = prototype.matches || prototype.webkitMatchesSelector || prototype.mozMatchesSelector || prototype.msMatchesSelector || match;
return method.call(element, selector); 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 } // Find all elements
function getElements(selector) { function getElements(selector) {
@ -1139,8 +1194,8 @@ typeof navigator === "object" && (function (global, factory) {
var padding = 100 / w * h; var padding = 100 / w * h;
wrapper.style.paddingBottom = "".concat(padding, "%"); // For Vimeo we have an extra <div> to hide the standard controls and UI 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) { if (this.isVimeo && !this.config.vimeo.premium && this.supported.ui) {
var height = 240; var height = 100 / this.media.offsetWidth * parseInt(window.getComputedStyle(this.media).paddingBottom, 10);
var offset = (height - padding) / (height / 50); var offset = (height - padding) / (height / 50);
this.media.style.transform = "translateY(-".concat(offset, "%)"); this.media.style.transform = "translateY(-".concat(offset, "%)");
} else if (this.isHTML5) { } else if (this.isHTML5) {
@ -1296,7 +1351,7 @@ typeof navigator === "object" && (function (global, factory) {
}); });
} // Get the closest value in an array } // Get the closest value in an array
function closest(array, value) { function closest$1(array, value) {
if (!is$1.array(array) || !array.length) { if (!is$1.array(array) || !array.length) {
return null; return null;
} }
@ -3278,9 +3333,15 @@ typeof navigator === "object" && (function (global, factory) {
meta.set(track, { meta.set(track, {
default: track.mode === 'showing' default: track.mode === 'showing'
}); // Turn off native caption rendering to avoid double captions }); // 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 // 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 () { on.call(_this, track, 'cuechange', function () {
return captions.updateCues.call(_this); return captions.updateCues.call(_this);
@ -3304,6 +3365,8 @@ typeof navigator === "object" && (function (global, factory) {
// Toggle captions display // Toggle captions display
// Used internally for the toggleCaptions method, with the passive option forced to false // Used internally for the toggleCaptions method, with the passive option forced to false
toggle: function toggle(input) { toggle: function toggle(input) {
var _this2 = this;
var passive = arguments.length > 1 && arguments[1] !== undefined ? arguments[1] : true; var passive = arguments.length > 1 && arguments[1] !== undefined ? arguments[1] : true;
// If there's no full support // If there's no full support
@ -3350,7 +3413,15 @@ typeof navigator === "object" && (function (global, factory) {
controls.updateSetting.call(this, 'captions'); // Trigger event (not used internally) controls.updateSetting.call(this, 'captions'); // Trigger event (not used internally)
triggerEvent.call(this, this.media, active ? 'captionsenabled' : 'captionsdisabled'); 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 // Set captions by track index
// Used internally for the currentTrack setter with the passive option forced to false // Used internally for the currentTrack setter with the passive option forced to false
@ -3431,7 +3502,7 @@ typeof navigator === "object" && (function (global, factory) {
// If update is false it will also ignore tracks without metadata // If update is false it will also ignore tracks without metadata
// This is used to "freeze" the language options when captions.update is false // This is used to "freeze" the language options when captions.update is false
getTracks: function getTracks() { getTracks: function getTracks() {
var _this2 = this; var _this3 = this;
var update = arguments.length > 0 && arguments[0] !== undefined ? arguments[0] : false; var update = arguments.length > 0 && arguments[0] !== undefined ? arguments[0] : false;
// Handle media or textTracks missing or null // Handle media or textTracks missing or null
@ -3439,20 +3510,20 @@ typeof navigator === "object" && (function (global, factory) {
// Filter out removed tracks and tracks that aren't captions/subtitles (for example metadata) // Filter out removed tracks and tracks that aren't captions/subtitles (for example metadata)
return tracks.filter(function (track) { 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) { }).filter(function (track) {
return ['captions', 'subtitles'].includes(track.kind); return ['captions', 'subtitles'].includes(track.kind);
}); });
}, },
// Match tracks based on languages and get the first // Match tracks based on languages and get the first
findTrack: function findTrack(languages) { findTrack: function findTrack(languages) {
var _this3 = this; var _this4 = this;
var force = arguments.length > 1 && arguments[1] !== undefined ? arguments[1] : false; var force = arguments.length > 1 && arguments[1] !== undefined ? arguments[1] : false;
var tracks = captions.getTracks.call(this); var tracks = captions.getTracks.call(this);
var sortIsDefault = function sortIsDefault(track) { 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) { var sorted = Array.from(tracks).sort(function (a, b) {
@ -3633,6 +3704,9 @@ typeof navigator === "object" && (function (global, factory) {
fallback: true, fallback: true,
// Fallback using full viewport/window // Fallback using full viewport/window
iosNative: false // Use the native fullscreen in iOS (disables custom controls) 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 // Local storage
@ -3870,16 +3944,16 @@ typeof navigator === "object" && (function (global, factory) {
title: false, title: false,
speed: true, speed: true,
transparent: false, transparent: false,
// These settings require a pro or premium account to work // Whether the owner of the video has a Pro or Business account
sidedock: false, // (which allows us to properly hide controls without CSS hacks, etc)
controls: false, premium: false,
// Custom settings from Plyr // Custom settings from Plyr
referrerPolicy: null // https://developer.mozilla.org/en-US/docs/Web/API/HTMLIFrameElement/referrerPolicy referrerPolicy: null // https://developer.mozilla.org/en-US/docs/Web/API/HTMLIFrameElement/referrerPolicy
}, },
// YouTube plugin // YouTube plugin
youtube: { youtube: {
noCookie: false, noCookie: true,
// Whether to use an alternative version of YouTube without cookies // Whether to use an alternative version of YouTube without cookies
rel: 0, rel: 0,
// No related vids // No related vids
@ -3989,7 +4063,10 @@ typeof navigator === "object" && (function (global, factory) {
y: 0 y: 0
}; // Force the use of 'full window/browser' rather than fullscreen }; // 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) // Handle event (incase user presses escape etc)
on.call(this.player, document, this.prefix === 'ms' ? 'MSFullscreenChange' : "".concat(this.prefix, "fullscreenchange"), function () { on.call(this.player, document, this.prefix === 'ms' ? 'MSFullscreenChange' : "".concat(this.prefix, "fullscreenchange"), function () {
@ -4215,7 +4292,7 @@ typeof navigator === "object" && (function (global, factory) {
}, { }, {
key: "target", key: "target",
get: function get() { 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", key: "native",
@ -4277,7 +4354,6 @@ typeof navigator === "object" && (function (global, factory) {
}); });
} }
// ==========================================================================
var ui = { var ui = {
addStyleHook: function addStyleHook() { addStyleHook: function addStyleHook() {
toggleClass(this.elements.container, this.config.selectors.container.replace('.', ''), true); toggleClass(this.elements.container, this.config.selectors.container.replace('.', ''), true);
@ -4412,12 +4488,7 @@ typeof navigator === "object" && (function (global, factory) {
} // Set property synchronously to respect the call order } // Set property synchronously to respect the call order
this.media.setAttribute('poster', poster); // HTML5 uses native poster attribute this.media.setAttribute('data-poster', poster); // Wait until ui is ready
if (this.isHTML5) {
return Promise.resolve(poster);
} // Wait until ui is ready
return ready.call(this) // Load image return ready.call(this) // Load image
.then(function () { .then(function () {
@ -4493,6 +4564,26 @@ typeof navigator === "object" && (function (global, factory) {
this.toggleControls(Boolean(force || this.loading || this.paused || controlsElement.pressed || controlsElement.hover || recentTouchSeek)); 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');
}
} }
}; };
@ -4701,6 +4792,7 @@ typeof navigator === "object" && (function (global, factory) {
removeCurrent(); // Delay the adding of classname until the focus has changed removeCurrent(); // Delay the adding of classname until the focus has changed
// This event fires before the focusin event // This event fires before the focusin event
if (event.type !== 'focusout') {
this.focusTimer = setTimeout(function () { this.focusTimer = setTimeout(function () {
var focused = document.activeElement; // Ignore if current focus element isn't inside the player var focused = document.activeElement; // Ignore if current focus element isn't inside the player
@ -4710,6 +4802,7 @@ typeof navigator === "object" && (function (global, factory) {
toggleClass(document.activeElement, player.config.classNames.tabFocus, true); toggleClass(document.activeElement, player.config.classNames.tabFocus, true);
}, 10); }, 10);
}
} // Global window & document listeners } // Global window & document listeners
}, { }, {
@ -4727,7 +4820,7 @@ typeof navigator === "object" && (function (global, factory) {
once.call(player, document.body, 'touchstart', this.firstTouch); // Tab focus detection 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 } // Container listeners
}, { }, {
@ -4770,7 +4863,7 @@ typeof navigator === "object" && (function (global, factory) {
}); // Set a gutter for Vimeo }); // Set a gutter for Vimeo
var setGutter = function setGutter(ratio, padding, toggle) { var setGutter = function setGutter(ratio, padding, toggle) {
if (!player.isVimeo) { if (!player.isVimeo || player.config.vimeo.premium) {
return; return;
} }
@ -4827,7 +4920,7 @@ typeof navigator === "object" && (function (global, factory) {
ratio = _setPlayerSize.ratio; // Set Vimeo gutter 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 (!usingNative) {
if (isEnter) { if (isEnter) {
@ -5206,7 +5299,18 @@ typeof navigator === "object" && (function (global, factory) {
this.bind(elements.controls, 'mouseenter mouseleave', function (event) { this.bind(elements.controls, 'mouseenter mouseleave', function (event) {
elements.controls.hover = !player.touch && event.type === 'mouseenter'; 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) { this.bind(elements.controls, 'mousedown mouseup touchstart touchend touchcancel', function (event) {
elements.controls.pressed = ['mousedown', 'touchstart'].includes(event.type); elements.controls.pressed = ['mousedown', 'touchstart'].includes(event.type);
@ -5622,15 +5726,28 @@ typeof navigator === "object" && (function (global, factory) {
var _this = this; var _this = this;
var player = this; var player = this;
var config = player.config.vimeo; // Get Vimeo params for the iframe var config = player.config.vimeo;
var params = buildUrlParams(extend({}, { 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(_objectSpread2({
loop: player.config.loop.active, loop: player.config.loop.active,
autoplay: player.autoplay, autoplay: player.autoplay,
muted: player.muted, muted: player.muted,
gesture: 'media', gesture: 'media',
playsinline: !this.config.fullscreen.iosNative 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 var source = player.media.getAttribute('src'); // Get from <div> if needed
@ -5644,22 +5761,27 @@ typeof navigator === "object" && (function (global, factory) {
var src = format(player.config.urls.vimeo.iframe, id, params); var src = format(player.config.urls.vimeo.iframe, id, params);
iframe.setAttribute('src', src); iframe.setAttribute('src', src);
iframe.setAttribute('allowfullscreen', ''); iframe.setAttribute('allowfullscreen', '');
iframe.setAttribute('allowtransparency', ''); iframe.setAttribute('allow', 'autoplay,fullscreen,picture-in-picture'); // Set the referrer policy if required
iframe.setAttribute('allow', 'autoplay'); // Set the referrer policy if required
if (!is$1.empty(config.referrerPolicy)) { if (!is$1.empty(referrerPolicy)) {
iframe.setAttribute('referrerPolicy', config.referrerPolicy); iframe.setAttribute('referrerPolicy', referrerPolicy);
} // Get poster, if already set } // 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', { var wrapper = createElement('div', {
poster: poster, class: player.config.classNames.embedContainer,
class: player.config.classNames.embedContainer 'data-poster': poster
}); });
wrapper.appendChild(iframe); wrapper.appendChild(iframe);
player.media = replaceElement(wrapper, player.media); // Get poster image player.media = replaceElement(wrapper, player.media);
} // Get poster image
fetch(format(player.config.urls.vimeo.api, id), 'json').then(function (response) { fetch(format(player.config.urls.vimeo.api, id), 'json').then(function (response) {
if (is$1.empty(response)) { if (is$1.empty(response)) {
@ -6032,7 +6154,7 @@ typeof navigator === "object" && (function (global, factory) {
var container = createElement('div', { var container = createElement('div', {
id: id, id: id,
poster: poster 'data-poster': poster
}); });
player.media = replaceElement(container, player.media); // Id to poster wrapper player.media = replaceElement(container, player.media); // Id to poster wrapper
@ -6351,15 +6473,13 @@ typeof navigator === "object" && (function (global, factory) {
class: this.config.classNames.video class: this.config.classNames.video
}); // Wrap the video in a container }); // 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', { this.elements.poster = createElement('div', {
class: this.config.classNames.poster class: this.config.classNames.poster
}); });
this.elements.wrapper.appendChild(this.elements.poster); this.elements.wrapper.appendChild(this.elements.poster);
} }
}
if (this.isHTML5) { if (this.isHTML5) {
html5.setup.call(this); html5.setup.call(this);
@ -7964,6 +8084,7 @@ typeof navigator === "object" && (function (global, factory) {
this.elements = { this.elements = {
container: null, container: null,
fullscreen: null,
captions: null, captions: null,
buttons: {}, buttons: {},
display: {}, display: {},
@ -8138,9 +8259,11 @@ typeof navigator === "object" && (function (global, factory) {
tabindex: 0 tabindex: 0
}); });
wrap(this.media, this.elements.container); 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 ui.addStyleHook.call(this); // Setup media
media.setup.call(this); // Listen for events if debugging media.setup.call(this); // Listen for events if debugging
@ -8149,10 +8272,12 @@ typeof navigator === "object" && (function (global, factory) {
on.call(this, this.elements.container, this.config.events.join(' '), function (event) { on.call(this, this.elements.container, this.config.events.join(' '), function (event) {
_this.debug.log("event: ".concat(event.type)); _this.debug.log("event: ".concat(event.type));
}); });
} // Setup interface } // Setup fullscreen
// If embed but not fully supported, build interface now to avoid flash of controls
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) { if (this.isHTML5 || this.isEmbed && !this.supported.ui) {
ui.build.call(this); ui.build.call(this);
} // Container listeners } // Container listeners
@ -8160,9 +8285,7 @@ typeof navigator === "object" && (function (global, factory) {
this.listeners.container(); // Global listeners this.listeners.container(); // Global listeners
this.listeners.global(); // Setup fullscreen this.listeners.global(); // Setup ads if provided
this.fullscreen = new Fullscreen(this); // Setup ads if provided
if (this.config.ads.enabled) { if (this.config.ads.enabled) {
this.ads = new Ads(this); this.ads = new Ads(this);
@ -8861,7 +8984,7 @@ typeof navigator === "object" && (function (global, factory) {
var updateStorage = true; var updateStorage = true;
if (!options.includes(quality)) { 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")); this.debug.warn("Unsupported quality option: ".concat(quality, ", using ").concat(value, " instead"));
quality = value; // Don't update storage if quality is not supported quality = value; // Don't update storage if quality is not supported
@ -9006,7 +9129,7 @@ typeof navigator === "object" && (function (global, factory) {
return null; return null;
} }
return this.media.getAttribute('poster'); return this.media.getAttribute('poster') || this.media.getAttribute('data-poster');
} }
/** /**
* Get the current aspect ratio in use * Get the current aspect ratio in use

4
dist/plyr.min.js vendored

File diff suppressed because one or more lines are too long

File diff suppressed because one or more lines are too long

4
dist/plyr.min.mjs vendored

File diff suppressed because one or more lines are too long

File diff suppressed because one or more lines are too long

221
dist/plyr.mjs vendored
View File

@ -69,6 +69,42 @@ function _objectSpread2(target) {
return 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) { function _slicedToArray(arr, i) {
return _arrayWithHoles(arr) || _iterableToArrayLimit(arr, i) || _unsupportedIterableToArray(arr, i) || _nonIterableRest(); 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; var method = prototype.matches || prototype.webkitMatchesSelector || prototype.mozMatchesSelector || prototype.msMatchesSelector || match;
return method.call(element, selector); 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 } // Find all elements
function getElements(selector) { function getElements(selector) {
@ -1133,8 +1188,8 @@ function setAspectRatio(input) {
var padding = 100 / w * h; var padding = 100 / w * h;
wrapper.style.paddingBottom = "".concat(padding, "%"); // For Vimeo we have an extra <div> to hide the standard controls and UI 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) { if (this.isVimeo && !this.config.vimeo.premium && this.supported.ui) {
var height = 240; var height = 100 / this.media.offsetWidth * parseInt(window.getComputedStyle(this.media).paddingBottom, 10);
var offset = (height - padding) / (height / 50); var offset = (height - padding) / (height / 50);
this.media.style.transform = "translateY(-".concat(offset, "%)"); this.media.style.transform = "translateY(-".concat(offset, "%)");
} else if (this.isHTML5) { } else if (this.isHTML5) {
@ -1290,7 +1345,7 @@ function dedupe(array) {
}); });
} // Get the closest value in an array } // Get the closest value in an array
function closest(array, value) { function closest$1(array, value) {
if (!is$1.array(array) || !array.length) { if (!is$1.array(array) || !array.length) {
return null; return null;
} }
@ -3272,9 +3327,15 @@ var captions = {
meta.set(track, { meta.set(track, {
default: track.mode === 'showing' default: track.mode === 'showing'
}); // Turn off native caption rendering to avoid double captions }); // 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 // 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 () { on.call(_this, track, 'cuechange', function () {
return captions.updateCues.call(_this); return captions.updateCues.call(_this);
@ -3298,6 +3359,8 @@ var captions = {
// Toggle captions display // Toggle captions display
// Used internally for the toggleCaptions method, with the passive option forced to false // Used internally for the toggleCaptions method, with the passive option forced to false
toggle: function toggle(input) { toggle: function toggle(input) {
var _this2 = this;
var passive = arguments.length > 1 && arguments[1] !== undefined ? arguments[1] : true; var passive = arguments.length > 1 && arguments[1] !== undefined ? arguments[1] : true;
// If there's no full support // If there's no full support
@ -3344,7 +3407,15 @@ var captions = {
controls.updateSetting.call(this, 'captions'); // Trigger event (not used internally) controls.updateSetting.call(this, 'captions'); // Trigger event (not used internally)
triggerEvent.call(this, this.media, active ? 'captionsenabled' : 'captionsdisabled'); 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 // Set captions by track index
// Used internally for the currentTrack setter with the passive option forced to false // 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 // If update is false it will also ignore tracks without metadata
// This is used to "freeze" the language options when captions.update is false // This is used to "freeze" the language options when captions.update is false
getTracks: function getTracks() { getTracks: function getTracks() {
var _this2 = this; var _this3 = this;
var update = arguments.length > 0 && arguments[0] !== undefined ? arguments[0] : false; var update = arguments.length > 0 && arguments[0] !== undefined ? arguments[0] : false;
// Handle media or textTracks missing or null // 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) // Filter out removed tracks and tracks that aren't captions/subtitles (for example metadata)
return tracks.filter(function (track) { 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) { }).filter(function (track) {
return ['captions', 'subtitles'].includes(track.kind); return ['captions', 'subtitles'].includes(track.kind);
}); });
}, },
// Match tracks based on languages and get the first // Match tracks based on languages and get the first
findTrack: function findTrack(languages) { findTrack: function findTrack(languages) {
var _this3 = this; var _this4 = this;
var force = arguments.length > 1 && arguments[1] !== undefined ? arguments[1] : false; var force = arguments.length > 1 && arguments[1] !== undefined ? arguments[1] : false;
var tracks = captions.getTracks.call(this); var tracks = captions.getTracks.call(this);
var sortIsDefault = function sortIsDefault(track) { 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) { var sorted = Array.from(tracks).sort(function (a, b) {
@ -3627,6 +3698,9 @@ var defaults$1 = {
fallback: true, fallback: true,
// Fallback using full viewport/window // Fallback using full viewport/window
iosNative: false // Use the native fullscreen in iOS (disables custom controls) 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 // Local storage
@ -3864,16 +3938,16 @@ var defaults$1 = {
title: false, title: false,
speed: true, speed: true,
transparent: false, transparent: false,
// These settings require a pro or premium account to work // Whether the owner of the video has a Pro or Business account
sidedock: false, // (which allows us to properly hide controls without CSS hacks, etc)
controls: false, premium: false,
// Custom settings from Plyr // Custom settings from Plyr
referrerPolicy: null // https://developer.mozilla.org/en-US/docs/Web/API/HTMLIFrameElement/referrerPolicy referrerPolicy: null // https://developer.mozilla.org/en-US/docs/Web/API/HTMLIFrameElement/referrerPolicy
}, },
// YouTube plugin // YouTube plugin
youtube: { youtube: {
noCookie: false, noCookie: true,
// Whether to use an alternative version of YouTube without cookies // Whether to use an alternative version of YouTube without cookies
rel: 0, rel: 0,
// No related vids // No related vids
@ -3983,7 +4057,10 @@ var Fullscreen = /*#__PURE__*/function () {
y: 0 y: 0
}; // Force the use of 'full window/browser' rather than fullscreen }; // 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) // Handle event (incase user presses escape etc)
on.call(this.player, document, this.prefix === 'ms' ? 'MSFullscreenChange' : "".concat(this.prefix, "fullscreenchange"), function () { on.call(this.player, document, this.prefix === 'ms' ? 'MSFullscreenChange' : "".concat(this.prefix, "fullscreenchange"), function () {
@ -4209,7 +4286,7 @@ var Fullscreen = /*#__PURE__*/function () {
}, { }, {
key: "target", key: "target",
get: function get() { 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", key: "native",
@ -4271,7 +4348,6 @@ function loadImage(src) {
}); });
} }
// ==========================================================================
var ui = { var ui = {
addStyleHook: function addStyleHook() { addStyleHook: function addStyleHook() {
toggleClass(this.elements.container, this.config.selectors.container.replace('.', ''), true); toggleClass(this.elements.container, this.config.selectors.container.replace('.', ''), true);
@ -4406,12 +4482,7 @@ var ui = {
} // Set property synchronously to respect the call order } // Set property synchronously to respect the call order
this.media.setAttribute('poster', poster); // HTML5 uses native poster attribute this.media.setAttribute('data-poster', poster); // Wait until ui is ready
if (this.isHTML5) {
return Promise.resolve(poster);
} // Wait until ui is ready
return ready.call(this) // Load image return ready.call(this) // Load image
.then(function () { .then(function () {
@ -4487,6 +4558,26 @@ var ui = {
this.toggleControls(Boolean(force || this.loading || this.paused || controlsElement.pressed || controlsElement.hover || recentTouchSeek)); 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,6 +4786,7 @@ var Listeners = /*#__PURE__*/function () {
removeCurrent(); // Delay the adding of classname until the focus has changed removeCurrent(); // Delay the adding of classname until the focus has changed
// This event fires before the focusin event // This event fires before the focusin event
if (event.type !== 'focusout') {
this.focusTimer = setTimeout(function () { this.focusTimer = setTimeout(function () {
var focused = document.activeElement; // Ignore if current focus element isn't inside the player var focused = document.activeElement; // Ignore if current focus element isn't inside the player
@ -4704,6 +4796,7 @@ var Listeners = /*#__PURE__*/function () {
toggleClass(document.activeElement, player.config.classNames.tabFocus, true); toggleClass(document.activeElement, player.config.classNames.tabFocus, true);
}, 10); }, 10);
}
} // Global window & document listeners } // Global window & document listeners
}, { }, {
@ -4721,7 +4814,7 @@ var Listeners = /*#__PURE__*/function () {
once.call(player, document.body, 'touchstart', this.firstTouch); // Tab focus detection 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 } // Container listeners
}, { }, {
@ -4764,7 +4857,7 @@ var Listeners = /*#__PURE__*/function () {
}); // Set a gutter for Vimeo }); // Set a gutter for Vimeo
var setGutter = function setGutter(ratio, padding, toggle) { var setGutter = function setGutter(ratio, padding, toggle) {
if (!player.isVimeo) { if (!player.isVimeo || player.config.vimeo.premium) {
return; return;
} }
@ -4821,7 +4914,7 @@ var Listeners = /*#__PURE__*/function () {
ratio = _setPlayerSize.ratio; // Set Vimeo gutter 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 (!usingNative) {
if (isEnter) { if (isEnter) {
@ -5200,7 +5293,18 @@ var Listeners = /*#__PURE__*/function () {
this.bind(elements.controls, 'mouseenter mouseleave', function (event) { this.bind(elements.controls, 'mouseenter mouseleave', function (event) {
elements.controls.hover = !player.touch && event.type === 'mouseenter'; 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) { this.bind(elements.controls, 'mousedown mouseup touchstart touchend touchcancel', function (event) {
elements.controls.pressed = ['mousedown', 'touchstart'].includes(event.type); elements.controls.pressed = ['mousedown', 'touchstart'].includes(event.type);
@ -5616,15 +5720,28 @@ var vimeo = {
var _this = this; var _this = this;
var player = this; var player = this;
var config = player.config.vimeo; // Get Vimeo params for the iframe var config = player.config.vimeo;
var params = buildUrlParams(extend({}, { 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(_objectSpread2({
loop: player.config.loop.active, loop: player.config.loop.active,
autoplay: player.autoplay, autoplay: player.autoplay,
muted: player.muted, muted: player.muted,
gesture: 'media', gesture: 'media',
playsinline: !this.config.fullscreen.iosNative 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 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); var src = format(player.config.urls.vimeo.iframe, id, params);
iframe.setAttribute('src', src); iframe.setAttribute('src', src);
iframe.setAttribute('allowfullscreen', ''); iframe.setAttribute('allowfullscreen', '');
iframe.setAttribute('allowtransparency', ''); iframe.setAttribute('allow', 'autoplay,fullscreen,picture-in-picture'); // Set the referrer policy if required
iframe.setAttribute('allow', 'autoplay'); // Set the referrer policy if required
if (!is$1.empty(config.referrerPolicy)) { if (!is$1.empty(referrerPolicy)) {
iframe.setAttribute('referrerPolicy', config.referrerPolicy); iframe.setAttribute('referrerPolicy', referrerPolicy);
} // Get poster, if already set } // 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', { var wrapper = createElement('div', {
poster: poster, class: player.config.classNames.embedContainer,
class: player.config.classNames.embedContainer 'data-poster': poster
}); });
wrapper.appendChild(iframe); wrapper.appendChild(iframe);
player.media = replaceElement(wrapper, player.media); // Get poster image player.media = replaceElement(wrapper, player.media);
} // Get poster image
fetch(format(player.config.urls.vimeo.api, id), 'json').then(function (response) { fetch(format(player.config.urls.vimeo.api, id), 'json').then(function (response) {
if (is$1.empty(response)) { if (is$1.empty(response)) {
@ -6026,7 +6148,7 @@ var youtube = {
var container = createElement('div', { var container = createElement('div', {
id: id, id: id,
poster: poster 'data-poster': poster
}); });
player.media = replaceElement(container, player.media); // Id to poster wrapper player.media = replaceElement(container, player.media); // Id to poster wrapper
@ -6345,15 +6467,13 @@ var media = {
class: this.config.classNames.video class: this.config.classNames.video
}); // Wrap the video in a container }); // 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', { this.elements.poster = createElement('div', {
class: this.config.classNames.poster class: this.config.classNames.poster
}); });
this.elements.wrapper.appendChild(this.elements.poster); this.elements.wrapper.appendChild(this.elements.poster);
} }
}
if (this.isHTML5) { if (this.isHTML5) {
html5.setup.call(this); html5.setup.call(this);
@ -7958,6 +8078,7 @@ var Plyr = /*#__PURE__*/function () {
this.elements = { this.elements = {
container: null, container: null,
fullscreen: null,
captions: null, captions: null,
buttons: {}, buttons: {},
display: {}, display: {},
@ -8132,9 +8253,11 @@ var Plyr = /*#__PURE__*/function () {
tabindex: 0 tabindex: 0
}); });
wrap(this.media, this.elements.container); 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 ui.addStyleHook.call(this); // Setup media
media.setup.call(this); // Listen for events if debugging media.setup.call(this); // Listen for events if debugging
@ -8143,10 +8266,12 @@ var Plyr = /*#__PURE__*/function () {
on.call(this, this.elements.container, this.config.events.join(' '), function (event) { on.call(this, this.elements.container, this.config.events.join(' '), function (event) {
_this.debug.log("event: ".concat(event.type)); _this.debug.log("event: ".concat(event.type));
}); });
} // Setup interface } // Setup fullscreen
// If embed but not fully supported, build interface now to avoid flash of controls
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) { if (this.isHTML5 || this.isEmbed && !this.supported.ui) {
ui.build.call(this); ui.build.call(this);
} // Container listeners } // Container listeners
@ -8154,9 +8279,7 @@ var Plyr = /*#__PURE__*/function () {
this.listeners.container(); // Global listeners this.listeners.container(); // Global listeners
this.listeners.global(); // Setup fullscreen this.listeners.global(); // Setup ads if provided
this.fullscreen = new Fullscreen(this); // Setup ads if provided
if (this.config.ads.enabled) { if (this.config.ads.enabled) {
this.ads = new Ads(this); this.ads = new Ads(this);
@ -8855,7 +8978,7 @@ var Plyr = /*#__PURE__*/function () {
var updateStorage = true; var updateStorage = true;
if (!options.includes(quality)) { 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")); this.debug.warn("Unsupported quality option: ".concat(quality, ", using ").concat(value, " instead"));
quality = value; // Don't update storage if quality is not supported quality = value; // Don't update storage if quality is not supported
@ -9000,7 +9123,7 @@ var Plyr = /*#__PURE__*/function () {
return null; return null;
} }
return this.media.getAttribute('poster'); return this.media.getAttribute('poster') || this.media.getAttribute('data-poster');
} }
/** /**
* Get the current aspect ratio in use * Get the current aspect ratio in use

View File

@ -269,7 +269,7 @@ typeof navigator === "object" && (function (global, factory) {
(module.exports = function (key, value) { (module.exports = function (key, value) {
return sharedStore[key] || (sharedStore[key] = value !== undefined ? value : {}); return sharedStore[key] || (sharedStore[key] = value !== undefined ? value : {});
})('versions', []).push({ })('versions', []).push({
version: '3.6.4', version: '3.6.5',
mode: 'global', mode: 'global',
copyright: '© 2020 Denis Pushkarev (zloirock.ru)' copyright: '© 2020 Denis Pushkarev (zloirock.ru)'
}); });
@ -3061,7 +3061,7 @@ typeof navigator === "object" && (function (global, factory) {
var INVALID_PORT = 'Invalid port'; var INVALID_PORT = 'Invalid port';
var ALPHA = /[A-Za-z]/; var ALPHA = /[A-Za-z]/;
var ALPHANUMERIC = /[\d+\-.A-Za-z]/; var ALPHANUMERIC = /[\d+-.A-Za-z]/;
var DIGIT = /\d/; var DIGIT = /\d/;
var HEX_START = /^(0x|0X)/; var HEX_START = /^(0x|0X)/;
var OCT = /^[0-7]+$/; var OCT = /^[0-7]+$/;
@ -4123,6 +4123,42 @@ typeof navigator === "object" && (function (global, factory) {
return 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) { function _slicedToArray(arr, i) {
return _arrayWithHoles(arr) || _iterableToArrayLimit(arr, i) || _unsupportedIterableToArray(arr, i) || _nonIterableRest(); return _arrayWithHoles(arr) || _iterableToArrayLimit(arr, i) || _unsupportedIterableToArray(arr, i) || _nonIterableRest();
} }
@ -6008,7 +6044,13 @@ typeof navigator === "object" && (function (global, factory) {
defer = functionBindContext(port.postMessage, port, 1); defer = functionBindContext(port.postMessage, port, 1);
// Browsers with postMessage, skip WebWorkers // Browsers with postMessage, skip WebWorkers
// IE8 has postMessage, but it's sync & typeof its postMessage is 'object' // IE8 has postMessage, but it's sync & typeof its postMessage is 'object'
} else if (global_1.addEventListener && typeof postMessage == 'function' && !global_1.importScripts && !fails(post)) { } else if (
global_1.addEventListener &&
typeof postMessage == 'function' &&
!global_1.importScripts &&
!fails(post) &&
location.protocol !== 'file:'
) {
defer = post; defer = post;
global_1.addEventListener('message', listener, false); global_1.addEventListener('message', listener, false);
// IE8- // IE8-
@ -7018,6 +7060,25 @@ typeof navigator === "object" && (function (global, factory) {
var method = prototype.matches || prototype.webkitMatchesSelector || prototype.mozMatchesSelector || prototype.msMatchesSelector || match; var method = prototype.matches || prototype.webkitMatchesSelector || prototype.mozMatchesSelector || prototype.msMatchesSelector || match;
return method.call(element, selector); 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 } // Find all elements
function getElements(selector) { function getElements(selector) {
@ -7369,8 +7430,8 @@ typeof navigator === "object" && (function (global, factory) {
var padding = 100 / w * h; var padding = 100 / w * h;
wrapper.style.paddingBottom = "".concat(padding, "%"); // For Vimeo we have an extra <div> to hide the standard controls and UI 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) { if (this.isVimeo && !this.config.vimeo.premium && this.supported.ui) {
var height = 240; var height = 100 / this.media.offsetWidth * parseInt(window.getComputedStyle(this.media).paddingBottom, 10);
var offset = (height - padding) / (height / 50); var offset = (height - padding) / (height / 50);
this.media.style.transform = "translateY(-".concat(offset, "%)"); this.media.style.transform = "translateY(-".concat(offset, "%)");
} else if (this.isHTML5) { } else if (this.isHTML5) {
@ -7523,7 +7584,7 @@ typeof navigator === "object" && (function (global, factory) {
}); });
} // Get the closest value in an array } // Get the closest value in an array
function closest(array, value) { function closest$1(array, value) {
if (!is$1.array(array) || !array.length) { if (!is$1.array(array) || !array.length) {
return null; return null;
} }
@ -9593,9 +9654,15 @@ typeof navigator === "object" && (function (global, factory) {
meta.set(track, { meta.set(track, {
default: track.mode === 'showing' default: track.mode === 'showing'
}); // Turn off native caption rendering to avoid double captions }); // 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 // 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 () { on.call(_this, track, 'cuechange', function () {
return captions.updateCues.call(_this); return captions.updateCues.call(_this);
@ -9619,6 +9686,8 @@ typeof navigator === "object" && (function (global, factory) {
// Toggle captions display // Toggle captions display
// Used internally for the toggleCaptions method, with the passive option forced to false // Used internally for the toggleCaptions method, with the passive option forced to false
toggle: function toggle(input) { toggle: function toggle(input) {
var _this2 = this;
var passive = arguments.length > 1 && arguments[1] !== undefined ? arguments[1] : true; var passive = arguments.length > 1 && arguments[1] !== undefined ? arguments[1] : true;
// If there's no full support // If there's no full support
@ -9665,7 +9734,15 @@ typeof navigator === "object" && (function (global, factory) {
controls.updateSetting.call(this, 'captions'); // Trigger event (not used internally) controls.updateSetting.call(this, 'captions'); // Trigger event (not used internally)
triggerEvent.call(this, this.media, active ? 'captionsenabled' : 'captionsdisabled'); 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 // Set captions by track index
// Used internally for the currentTrack setter with the passive option forced to false // Used internally for the currentTrack setter with the passive option forced to false
@ -9746,7 +9823,7 @@ typeof navigator === "object" && (function (global, factory) {
// If update is false it will also ignore tracks without metadata // If update is false it will also ignore tracks without metadata
// This is used to "freeze" the language options when captions.update is false // This is used to "freeze" the language options when captions.update is false
getTracks: function getTracks() { getTracks: function getTracks() {
var _this2 = this; var _this3 = this;
var update = arguments.length > 0 && arguments[0] !== undefined ? arguments[0] : false; var update = arguments.length > 0 && arguments[0] !== undefined ? arguments[0] : false;
// Handle media or textTracks missing or null // Handle media or textTracks missing or null
@ -9754,20 +9831,20 @@ typeof navigator === "object" && (function (global, factory) {
// Filter out removed tracks and tracks that aren't captions/subtitles (for example metadata) // Filter out removed tracks and tracks that aren't captions/subtitles (for example metadata)
return tracks.filter(function (track) { 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) { }).filter(function (track) {
return ['captions', 'subtitles'].includes(track.kind); return ['captions', 'subtitles'].includes(track.kind);
}); });
}, },
// Match tracks based on languages and get the first // Match tracks based on languages and get the first
findTrack: function findTrack(languages) { findTrack: function findTrack(languages) {
var _this3 = this; var _this4 = this;
var force = arguments.length > 1 && arguments[1] !== undefined ? arguments[1] : false; var force = arguments.length > 1 && arguments[1] !== undefined ? arguments[1] : false;
var tracks = captions.getTracks.call(this); var tracks = captions.getTracks.call(this);
var sortIsDefault = function sortIsDefault(track) { 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) { var sorted = Array.from(tracks).sort(function (a, b) {
@ -9948,6 +10025,9 @@ typeof navigator === "object" && (function (global, factory) {
fallback: true, fallback: true,
// Fallback using full viewport/window // Fallback using full viewport/window
iosNative: false // Use the native fullscreen in iOS (disables custom controls) 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 // Local storage
@ -10185,16 +10265,16 @@ typeof navigator === "object" && (function (global, factory) {
title: false, title: false,
speed: true, speed: true,
transparent: false, transparent: false,
// These settings require a pro or premium account to work // Whether the owner of the video has a Pro or Business account
sidedock: false, // (which allows us to properly hide controls without CSS hacks, etc)
controls: false, premium: false,
// Custom settings from Plyr // Custom settings from Plyr
referrerPolicy: null // https://developer.mozilla.org/en-US/docs/Web/API/HTMLIFrameElement/referrerPolicy referrerPolicy: null // https://developer.mozilla.org/en-US/docs/Web/API/HTMLIFrameElement/referrerPolicy
}, },
// YouTube plugin // YouTube plugin
youtube: { youtube: {
noCookie: false, noCookie: true,
// Whether to use an alternative version of YouTube without cookies // Whether to use an alternative version of YouTube without cookies
rel: 0, rel: 0,
// No related vids // No related vids
@ -10304,7 +10384,10 @@ typeof navigator === "object" && (function (global, factory) {
y: 0 y: 0
}; // Force the use of 'full window/browser' rather than fullscreen }; // 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) // Handle event (incase user presses escape etc)
on.call(this.player, document, this.prefix === 'ms' ? 'MSFullscreenChange' : "".concat(this.prefix, "fullscreenchange"), function () { on.call(this.player, document, this.prefix === 'ms' ? 'MSFullscreenChange' : "".concat(this.prefix, "fullscreenchange"), function () {
@ -10530,7 +10613,7 @@ typeof navigator === "object" && (function (global, factory) {
}, { }, {
key: "target", key: "target",
get: function get() { 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", key: "native",
@ -10739,12 +10822,7 @@ typeof navigator === "object" && (function (global, factory) {
} // Set property synchronously to respect the call order } // Set property synchronously to respect the call order
this.media.setAttribute('poster', poster); // HTML5 uses native poster attribute this.media.setAttribute('data-poster', poster); // Wait until ui is ready
if (this.isHTML5) {
return Promise.resolve(poster);
} // Wait until ui is ready
return ready.call(this) // Load image return ready.call(this) // Load image
.then(function () { .then(function () {
@ -10820,6 +10898,26 @@ typeof navigator === "object" && (function (global, factory) {
this.toggleControls(Boolean(force || this.loading || this.paused || controlsElement.pressed || controlsElement.hover || recentTouchSeek)); 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');
}
} }
}; };
@ -11028,6 +11126,7 @@ typeof navigator === "object" && (function (global, factory) {
removeCurrent(); // Delay the adding of classname until the focus has changed removeCurrent(); // Delay the adding of classname until the focus has changed
// This event fires before the focusin event // This event fires before the focusin event
if (event.type !== 'focusout') {
this.focusTimer = setTimeout(function () { this.focusTimer = setTimeout(function () {
var focused = document.activeElement; // Ignore if current focus element isn't inside the player var focused = document.activeElement; // Ignore if current focus element isn't inside the player
@ -11037,6 +11136,7 @@ typeof navigator === "object" && (function (global, factory) {
toggleClass(document.activeElement, player.config.classNames.tabFocus, true); toggleClass(document.activeElement, player.config.classNames.tabFocus, true);
}, 10); }, 10);
}
} // Global window & document listeners } // Global window & document listeners
}, { }, {
@ -11054,7 +11154,7 @@ typeof navigator === "object" && (function (global, factory) {
once.call(player, document.body, 'touchstart', this.firstTouch); // Tab focus detection 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 } // Container listeners
}, { }, {
@ -11097,7 +11197,7 @@ typeof navigator === "object" && (function (global, factory) {
}); // Set a gutter for Vimeo }); // Set a gutter for Vimeo
var setGutter = function setGutter(ratio, padding, toggle) { var setGutter = function setGutter(ratio, padding, toggle) {
if (!player.isVimeo) { if (!player.isVimeo || player.config.vimeo.premium) {
return; return;
} }
@ -11154,7 +11254,7 @@ typeof navigator === "object" && (function (global, factory) {
ratio = _setPlayerSize.ratio; // Set Vimeo gutter 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 (!usingNative) {
if (isEnter) { if (isEnter) {
@ -11533,7 +11633,18 @@ typeof navigator === "object" && (function (global, factory) {
this.bind(elements.controls, 'mouseenter mouseleave', function (event) { this.bind(elements.controls, 'mouseenter mouseleave', function (event) {
elements.controls.hover = !player.touch && event.type === 'mouseenter'; 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) { this.bind(elements.controls, 'mousedown mouseup touchstart touchend touchcancel', function (event) {
elements.controls.pressed = ['mousedown', 'touchstart'].includes(event.type); elements.controls.pressed = ['mousedown', 'touchstart'].includes(event.type);
@ -12002,15 +12113,28 @@ typeof navigator === "object" && (function (global, factory) {
var _this = this; var _this = this;
var player = this; var player = this;
var config = player.config.vimeo; // Get Vimeo params for the iframe var config = player.config.vimeo;
var params = buildUrlParams(extend({}, { 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(_objectSpread2({
loop: player.config.loop.active, loop: player.config.loop.active,
autoplay: player.autoplay, autoplay: player.autoplay,
muted: player.muted, muted: player.muted,
gesture: 'media', gesture: 'media',
playsinline: !this.config.fullscreen.iosNative 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 var source = player.media.getAttribute('src'); // Get from <div> if needed
@ -12024,22 +12148,27 @@ typeof navigator === "object" && (function (global, factory) {
var src = format(player.config.urls.vimeo.iframe, id, params); var src = format(player.config.urls.vimeo.iframe, id, params);
iframe.setAttribute('src', src); iframe.setAttribute('src', src);
iframe.setAttribute('allowfullscreen', ''); iframe.setAttribute('allowfullscreen', '');
iframe.setAttribute('allowtransparency', ''); iframe.setAttribute('allow', 'autoplay,fullscreen,picture-in-picture'); // Set the referrer policy if required
iframe.setAttribute('allow', 'autoplay'); // Set the referrer policy if required
if (!is$1.empty(config.referrerPolicy)) { if (!is$1.empty(referrerPolicy)) {
iframe.setAttribute('referrerPolicy', config.referrerPolicy); iframe.setAttribute('referrerPolicy', referrerPolicy);
} // Get poster, if already set } // 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', { var wrapper = createElement('div', {
poster: poster, class: player.config.classNames.embedContainer,
class: player.config.classNames.embedContainer 'data-poster': poster
}); });
wrapper.appendChild(iframe); wrapper.appendChild(iframe);
player.media = replaceElement(wrapper, player.media); // Get poster image player.media = replaceElement(wrapper, player.media);
} // Get poster image
fetch(format(player.config.urls.vimeo.api, id), 'json').then(function (response) { fetch(format(player.config.urls.vimeo.api, id), 'json').then(function (response) {
if (is$1.empty(response)) { if (is$1.empty(response)) {
@ -12410,7 +12539,7 @@ typeof navigator === "object" && (function (global, factory) {
var container = createElement('div', { var container = createElement('div', {
id: id, id: id,
poster: poster 'data-poster': poster
}); });
player.media = replaceElement(container, player.media); // Id to poster wrapper player.media = replaceElement(container, player.media); // Id to poster wrapper
@ -12728,15 +12857,13 @@ typeof navigator === "object" && (function (global, factory) {
class: this.config.classNames.video class: this.config.classNames.video
}); // Wrap the video in a container }); // Wrap the video in a container
wrap$1(this.media, this.elements.wrapper); // Faux poster container wrap$1(this.media, this.elements.wrapper); // Poster image container
if (this.isEmbed) {
this.elements.poster = createElement('div', { this.elements.poster = createElement('div', {
class: this.config.classNames.poster class: this.config.classNames.poster
}); });
this.elements.wrapper.appendChild(this.elements.poster); this.elements.wrapper.appendChild(this.elements.poster);
} }
}
if (this.isHTML5) { if (this.isHTML5) {
html5.setup.call(this); html5.setup.call(this);
@ -14392,6 +14519,7 @@ typeof navigator === "object" && (function (global, factory) {
this.elements = { this.elements = {
container: null, container: null,
fullscreen: null,
captions: null, captions: null,
buttons: {}, buttons: {},
display: {}, display: {},
@ -14566,9 +14694,11 @@ typeof navigator === "object" && (function (global, factory) {
tabindex: 0 tabindex: 0
}); });
wrap$1(this.media, this.elements.container); wrap$1(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 ui.addStyleHook.call(this); // Setup media
media.setup.call(this); // Listen for events if debugging media.setup.call(this); // Listen for events if debugging
@ -14577,10 +14707,12 @@ typeof navigator === "object" && (function (global, factory) {
on.call(this, this.elements.container, this.config.events.join(' '), function (event) { on.call(this, this.elements.container, this.config.events.join(' '), function (event) {
_this.debug.log("event: ".concat(event.type)); _this.debug.log("event: ".concat(event.type));
}); });
} // Setup interface } // Setup fullscreen
// If embed but not fully supported, build interface now to avoid flash of controls
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) { if (this.isHTML5 || this.isEmbed && !this.supported.ui) {
ui.build.call(this); ui.build.call(this);
} // Container listeners } // Container listeners
@ -14588,9 +14720,7 @@ typeof navigator === "object" && (function (global, factory) {
this.listeners.container(); // Global listeners this.listeners.container(); // Global listeners
this.listeners.global(); // Setup fullscreen this.listeners.global(); // Setup ads if provided
this.fullscreen = new Fullscreen(this); // Setup ads if provided
if (this.config.ads.enabled) { if (this.config.ads.enabled) {
this.ads = new Ads(this); this.ads = new Ads(this);
@ -15289,7 +15419,7 @@ typeof navigator === "object" && (function (global, factory) {
var updateStorage = true; var updateStorage = true;
if (!options.includes(quality)) { 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")); this.debug.warn("Unsupported quality option: ".concat(quality, ", using ").concat(value, " instead"));
quality = value; // Don't update storage if quality is not supported quality = value; // Don't update storage if quality is not supported
@ -15434,7 +15564,7 @@ typeof navigator === "object" && (function (global, factory) {
return null; return null;
} }
return this.media.getAttribute('poster'); return this.media.getAttribute('poster') || this.media.getAttribute('data-poster');
} }
/** /**
* Get the current aspect ratio in use * Get the current aspect ratio in use

File diff suppressed because one or more lines are too long

File diff suppressed because one or more lines are too long

File diff suppressed because one or more lines are too long

File diff suppressed because one or more lines are too long

View File

@ -263,7 +263,7 @@ var shared = createCommonjsModule(function (module) {
(module.exports = function (key, value) { (module.exports = function (key, value) {
return sharedStore[key] || (sharedStore[key] = value !== undefined ? value : {}); return sharedStore[key] || (sharedStore[key] = value !== undefined ? value : {});
})('versions', []).push({ })('versions', []).push({
version: '3.6.4', version: '3.6.5',
mode: 'global', mode: 'global',
copyright: '© 2020 Denis Pushkarev (zloirock.ru)' copyright: '© 2020 Denis Pushkarev (zloirock.ru)'
}); });
@ -3055,7 +3055,7 @@ var INVALID_HOST = 'Invalid host';
var INVALID_PORT = 'Invalid port'; var INVALID_PORT = 'Invalid port';
var ALPHA = /[A-Za-z]/; var ALPHA = /[A-Za-z]/;
var ALPHANUMERIC = /[\d+\-.A-Za-z]/; var ALPHANUMERIC = /[\d+-.A-Za-z]/;
var DIGIT = /\d/; var DIGIT = /\d/;
var HEX_START = /^(0x|0X)/; var HEX_START = /^(0x|0X)/;
var OCT = /^[0-7]+$/; var OCT = /^[0-7]+$/;
@ -4117,6 +4117,42 @@ function _objectSpread2(target) {
return 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) { function _slicedToArray(arr, i) {
return _arrayWithHoles(arr) || _iterableToArrayLimit(arr, i) || _unsupportedIterableToArray(arr, i) || _nonIterableRest(); return _arrayWithHoles(arr) || _iterableToArrayLimit(arr, i) || _unsupportedIterableToArray(arr, i) || _nonIterableRest();
} }
@ -6002,7 +6038,13 @@ if (!set$1 || !clear) {
defer = functionBindContext(port.postMessage, port, 1); defer = functionBindContext(port.postMessage, port, 1);
// Browsers with postMessage, skip WebWorkers // Browsers with postMessage, skip WebWorkers
// IE8 has postMessage, but it's sync & typeof its postMessage is 'object' // IE8 has postMessage, but it's sync & typeof its postMessage is 'object'
} else if (global_1.addEventListener && typeof postMessage == 'function' && !global_1.importScripts && !fails(post)) { } else if (
global_1.addEventListener &&
typeof postMessage == 'function' &&
!global_1.importScripts &&
!fails(post) &&
location.protocol !== 'file:'
) {
defer = post; defer = post;
global_1.addEventListener('message', listener, false); global_1.addEventListener('message', listener, false);
// IE8- // IE8-
@ -7012,6 +7054,25 @@ function matches$1(element, selector) {
var method = prototype.matches || prototype.webkitMatchesSelector || prototype.mozMatchesSelector || prototype.msMatchesSelector || match; var method = prototype.matches || prototype.webkitMatchesSelector || prototype.mozMatchesSelector || prototype.msMatchesSelector || match;
return method.call(element, selector); 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 } // Find all elements
function getElements(selector) { function getElements(selector) {
@ -7363,8 +7424,8 @@ function setAspectRatio(input) {
var padding = 100 / w * h; var padding = 100 / w * h;
wrapper.style.paddingBottom = "".concat(padding, "%"); // For Vimeo we have an extra <div> to hide the standard controls and UI 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) { if (this.isVimeo && !this.config.vimeo.premium && this.supported.ui) {
var height = 240; var height = 100 / this.media.offsetWidth * parseInt(window.getComputedStyle(this.media).paddingBottom, 10);
var offset = (height - padding) / (height / 50); var offset = (height - padding) / (height / 50);
this.media.style.transform = "translateY(-".concat(offset, "%)"); this.media.style.transform = "translateY(-".concat(offset, "%)");
} else if (this.isHTML5) { } else if (this.isHTML5) {
@ -7517,7 +7578,7 @@ function dedupe(array) {
}); });
} // Get the closest value in an array } // Get the closest value in an array
function closest(array, value) { function closest$1(array, value) {
if (!is$1.array(array) || !array.length) { if (!is$1.array(array) || !array.length) {
return null; return null;
} }
@ -9587,9 +9648,15 @@ var captions = {
meta.set(track, { meta.set(track, {
default: track.mode === 'showing' default: track.mode === 'showing'
}); // Turn off native caption rendering to avoid double captions }); // 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 // 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 () { on.call(_this, track, 'cuechange', function () {
return captions.updateCues.call(_this); return captions.updateCues.call(_this);
@ -9613,6 +9680,8 @@ var captions = {
// Toggle captions display // Toggle captions display
// Used internally for the toggleCaptions method, with the passive option forced to false // Used internally for the toggleCaptions method, with the passive option forced to false
toggle: function toggle(input) { toggle: function toggle(input) {
var _this2 = this;
var passive = arguments.length > 1 && arguments[1] !== undefined ? arguments[1] : true; var passive = arguments.length > 1 && arguments[1] !== undefined ? arguments[1] : true;
// If there's no full support // If there's no full support
@ -9659,7 +9728,15 @@ var captions = {
controls.updateSetting.call(this, 'captions'); // Trigger event (not used internally) controls.updateSetting.call(this, 'captions'); // Trigger event (not used internally)
triggerEvent.call(this, this.media, active ? 'captionsenabled' : 'captionsdisabled'); 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 // Set captions by track index
// Used internally for the currentTrack setter with the passive option forced to false // Used internally for the currentTrack setter with the passive option forced to false
@ -9740,7 +9817,7 @@ var captions = {
// If update is false it will also ignore tracks without metadata // If update is false it will also ignore tracks without metadata
// This is used to "freeze" the language options when captions.update is false // This is used to "freeze" the language options when captions.update is false
getTracks: function getTracks() { getTracks: function getTracks() {
var _this2 = this; var _this3 = this;
var update = arguments.length > 0 && arguments[0] !== undefined ? arguments[0] : false; var update = arguments.length > 0 && arguments[0] !== undefined ? arguments[0] : false;
// Handle media or textTracks missing or null // Handle media or textTracks missing or null
@ -9748,20 +9825,20 @@ var captions = {
// Filter out removed tracks and tracks that aren't captions/subtitles (for example metadata) // Filter out removed tracks and tracks that aren't captions/subtitles (for example metadata)
return tracks.filter(function (track) { 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) { }).filter(function (track) {
return ['captions', 'subtitles'].includes(track.kind); return ['captions', 'subtitles'].includes(track.kind);
}); });
}, },
// Match tracks based on languages and get the first // Match tracks based on languages and get the first
findTrack: function findTrack(languages) { findTrack: function findTrack(languages) {
var _this3 = this; var _this4 = this;
var force = arguments.length > 1 && arguments[1] !== undefined ? arguments[1] : false; var force = arguments.length > 1 && arguments[1] !== undefined ? arguments[1] : false;
var tracks = captions.getTracks.call(this); var tracks = captions.getTracks.call(this);
var sortIsDefault = function sortIsDefault(track) { 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) { var sorted = Array.from(tracks).sort(function (a, b) {
@ -9942,6 +10019,9 @@ var defaults$1 = {
fallback: true, fallback: true,
// Fallback using full viewport/window // Fallback using full viewport/window
iosNative: false // Use the native fullscreen in iOS (disables custom controls) 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 // Local storage
@ -10179,16 +10259,16 @@ var defaults$1 = {
title: false, title: false,
speed: true, speed: true,
transparent: false, transparent: false,
// These settings require a pro or premium account to work // Whether the owner of the video has a Pro or Business account
sidedock: false, // (which allows us to properly hide controls without CSS hacks, etc)
controls: false, premium: false,
// Custom settings from Plyr // Custom settings from Plyr
referrerPolicy: null // https://developer.mozilla.org/en-US/docs/Web/API/HTMLIFrameElement/referrerPolicy referrerPolicy: null // https://developer.mozilla.org/en-US/docs/Web/API/HTMLIFrameElement/referrerPolicy
}, },
// YouTube plugin // YouTube plugin
youtube: { youtube: {
noCookie: false, noCookie: true,
// Whether to use an alternative version of YouTube without cookies // Whether to use an alternative version of YouTube without cookies
rel: 0, rel: 0,
// No related vids // No related vids
@ -10298,7 +10378,10 @@ var Fullscreen = /*#__PURE__*/function () {
y: 0 y: 0
}; // Force the use of 'full window/browser' rather than fullscreen }; // 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) // Handle event (incase user presses escape etc)
on.call(this.player, document, this.prefix === 'ms' ? 'MSFullscreenChange' : "".concat(this.prefix, "fullscreenchange"), function () { on.call(this.player, document, this.prefix === 'ms' ? 'MSFullscreenChange' : "".concat(this.prefix, "fullscreenchange"), function () {
@ -10524,7 +10607,7 @@ var Fullscreen = /*#__PURE__*/function () {
}, { }, {
key: "target", key: "target",
get: function get() { 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", key: "native",
@ -10733,12 +10816,7 @@ var ui = {
} // Set property synchronously to respect the call order } // Set property synchronously to respect the call order
this.media.setAttribute('poster', poster); // HTML5 uses native poster attribute this.media.setAttribute('data-poster', poster); // Wait until ui is ready
if (this.isHTML5) {
return Promise.resolve(poster);
} // Wait until ui is ready
return ready.call(this) // Load image return ready.call(this) // Load image
.then(function () { .then(function () {
@ -10814,6 +10892,26 @@ var ui = {
this.toggleControls(Boolean(force || this.loading || this.paused || controlsElement.pressed || controlsElement.hover || recentTouchSeek)); 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');
}
} }
}; };
@ -11022,6 +11120,7 @@ var Listeners = /*#__PURE__*/function () {
removeCurrent(); // Delay the adding of classname until the focus has changed removeCurrent(); // Delay the adding of classname until the focus has changed
// This event fires before the focusin event // This event fires before the focusin event
if (event.type !== 'focusout') {
this.focusTimer = setTimeout(function () { this.focusTimer = setTimeout(function () {
var focused = document.activeElement; // Ignore if current focus element isn't inside the player var focused = document.activeElement; // Ignore if current focus element isn't inside the player
@ -11031,6 +11130,7 @@ var Listeners = /*#__PURE__*/function () {
toggleClass(document.activeElement, player.config.classNames.tabFocus, true); toggleClass(document.activeElement, player.config.classNames.tabFocus, true);
}, 10); }, 10);
}
} // Global window & document listeners } // Global window & document listeners
}, { }, {
@ -11048,7 +11148,7 @@ var Listeners = /*#__PURE__*/function () {
once.call(player, document.body, 'touchstart', this.firstTouch); // Tab focus detection 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 } // Container listeners
}, { }, {
@ -11091,7 +11191,7 @@ var Listeners = /*#__PURE__*/function () {
}); // Set a gutter for Vimeo }); // Set a gutter for Vimeo
var setGutter = function setGutter(ratio, padding, toggle) { var setGutter = function setGutter(ratio, padding, toggle) {
if (!player.isVimeo) { if (!player.isVimeo || player.config.vimeo.premium) {
return; return;
} }
@ -11148,7 +11248,7 @@ var Listeners = /*#__PURE__*/function () {
ratio = _setPlayerSize.ratio; // Set Vimeo gutter 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 (!usingNative) {
if (isEnter) { if (isEnter) {
@ -11527,7 +11627,18 @@ var Listeners = /*#__PURE__*/function () {
this.bind(elements.controls, 'mouseenter mouseleave', function (event) { this.bind(elements.controls, 'mouseenter mouseleave', function (event) {
elements.controls.hover = !player.touch && event.type === 'mouseenter'; 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) { this.bind(elements.controls, 'mousedown mouseup touchstart touchend touchcancel', function (event) {
elements.controls.pressed = ['mousedown', 'touchstart'].includes(event.type); elements.controls.pressed = ['mousedown', 'touchstart'].includes(event.type);
@ -11996,15 +12107,28 @@ var vimeo = {
var _this = this; var _this = this;
var player = this; var player = this;
var config = player.config.vimeo; // Get Vimeo params for the iframe var config = player.config.vimeo;
var params = buildUrlParams(extend({}, { 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(_objectSpread2({
loop: player.config.loop.active, loop: player.config.loop.active,
autoplay: player.autoplay, autoplay: player.autoplay,
muted: player.muted, muted: player.muted,
gesture: 'media', gesture: 'media',
playsinline: !this.config.fullscreen.iosNative 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 var source = player.media.getAttribute('src'); // Get from <div> if needed
@ -12018,22 +12142,27 @@ var vimeo = {
var src = format(player.config.urls.vimeo.iframe, id, params); var src = format(player.config.urls.vimeo.iframe, id, params);
iframe.setAttribute('src', src); iframe.setAttribute('src', src);
iframe.setAttribute('allowfullscreen', ''); iframe.setAttribute('allowfullscreen', '');
iframe.setAttribute('allowtransparency', ''); iframe.setAttribute('allow', 'autoplay,fullscreen,picture-in-picture'); // Set the referrer policy if required
iframe.setAttribute('allow', 'autoplay'); // Set the referrer policy if required
if (!is$1.empty(config.referrerPolicy)) { if (!is$1.empty(referrerPolicy)) {
iframe.setAttribute('referrerPolicy', config.referrerPolicy); iframe.setAttribute('referrerPolicy', referrerPolicy);
} // Get poster, if already set } // 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', { var wrapper = createElement('div', {
poster: poster, class: player.config.classNames.embedContainer,
class: player.config.classNames.embedContainer 'data-poster': poster
}); });
wrapper.appendChild(iframe); wrapper.appendChild(iframe);
player.media = replaceElement(wrapper, player.media); // Get poster image player.media = replaceElement(wrapper, player.media);
} // Get poster image
fetch(format(player.config.urls.vimeo.api, id), 'json').then(function (response) { fetch(format(player.config.urls.vimeo.api, id), 'json').then(function (response) {
if (is$1.empty(response)) { if (is$1.empty(response)) {
@ -12404,7 +12533,7 @@ var youtube = {
var container = createElement('div', { var container = createElement('div', {
id: id, id: id,
poster: poster 'data-poster': poster
}); });
player.media = replaceElement(container, player.media); // Id to poster wrapper player.media = replaceElement(container, player.media); // Id to poster wrapper
@ -12722,15 +12851,13 @@ var media = {
class: this.config.classNames.video class: this.config.classNames.video
}); // Wrap the video in a container }); // Wrap the video in a container
wrap$1(this.media, this.elements.wrapper); // Faux poster container wrap$1(this.media, this.elements.wrapper); // Poster image container
if (this.isEmbed) {
this.elements.poster = createElement('div', { this.elements.poster = createElement('div', {
class: this.config.classNames.poster class: this.config.classNames.poster
}); });
this.elements.wrapper.appendChild(this.elements.poster); this.elements.wrapper.appendChild(this.elements.poster);
} }
}
if (this.isHTML5) { if (this.isHTML5) {
html5.setup.call(this); html5.setup.call(this);
@ -14386,6 +14513,7 @@ var Plyr = /*#__PURE__*/function () {
this.elements = { this.elements = {
container: null, container: null,
fullscreen: null,
captions: null, captions: null,
buttons: {}, buttons: {},
display: {}, display: {},
@ -14560,9 +14688,11 @@ var Plyr = /*#__PURE__*/function () {
tabindex: 0 tabindex: 0
}); });
wrap$1(this.media, this.elements.container); wrap$1(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 ui.addStyleHook.call(this); // Setup media
media.setup.call(this); // Listen for events if debugging media.setup.call(this); // Listen for events if debugging
@ -14571,10 +14701,12 @@ var Plyr = /*#__PURE__*/function () {
on.call(this, this.elements.container, this.config.events.join(' '), function (event) { on.call(this, this.elements.container, this.config.events.join(' '), function (event) {
_this.debug.log("event: ".concat(event.type)); _this.debug.log("event: ".concat(event.type));
}); });
} // Setup interface } // Setup fullscreen
// If embed but not fully supported, build interface now to avoid flash of controls
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) { if (this.isHTML5 || this.isEmbed && !this.supported.ui) {
ui.build.call(this); ui.build.call(this);
} // Container listeners } // Container listeners
@ -14582,9 +14714,7 @@ var Plyr = /*#__PURE__*/function () {
this.listeners.container(); // Global listeners this.listeners.container(); // Global listeners
this.listeners.global(); // Setup fullscreen this.listeners.global(); // Setup ads if provided
this.fullscreen = new Fullscreen(this); // Setup ads if provided
if (this.config.ads.enabled) { if (this.config.ads.enabled) {
this.ads = new Ads(this); this.ads = new Ads(this);
@ -15283,7 +15413,7 @@ var Plyr = /*#__PURE__*/function () {
var updateStorage = true; var updateStorage = true;
if (!options.includes(quality)) { 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")); this.debug.warn("Unsupported quality option: ".concat(quality, ", using ").concat(value, " instead"));
quality = value; // Don't update storage if quality is not supported quality = value; // Don't update storage if quality is not supported
@ -15428,7 +15558,7 @@ var Plyr = /*#__PURE__*/function () {
return null; return null;
} }
return this.media.getAttribute('poster'); return this.media.getAttribute('poster') || this.media.getAttribute('data-poster');
} }
/** /**
* Get the current aspect ratio in use * Get the current aspect ratio in use

View File

@ -1,6 +1,6 @@
{ {
"name": "plyr", "name": "plyr",
"version": "3.5.10", "version": "3.6.0",
"description": "A simple, accessible and customizable HTML5, YouTube and Vimeo media player", "description": "A simple, accessible and customizable HTML5, YouTube and Vimeo media player",
"homepage": "https://plyr.io", "homepage": "https://plyr.io",
"author": "Sam Potts <sam@potts.es>", "author": "Sam Potts <sam@potts.es>",