update plyr to 3.6.2

This commit is contained in:
Jesús 2020-06-14 23:23:55 -05:00
parent 3c81bce7a4
commit 9fc0b65630
No known key found for this signature in database
GPG Key ID: F6EE7BC59A315766
14 changed files with 1538 additions and 796 deletions

File diff suppressed because one or more lines are too long

View File

@ -75,20 +75,52 @@ typeof navigator === "object" && (function (global, factory) {
return target;
}
function _objectWithoutPropertiesLoose(source, excluded) {
if (source == null) return {};
var target = {};
var sourceKeys = Object.keys(source);
var key, i;
for (i = 0; i < sourceKeys.length; i++) {
key = sourceKeys[i];
if (excluded.indexOf(key) >= 0) continue;
target[key] = source[key];
}
return target;
}
function _objectWithoutProperties(source, excluded) {
if (source == null) return {};
var target = _objectWithoutPropertiesLoose(source, excluded);
var key, i;
if (Object.getOwnPropertySymbols) {
var sourceSymbolKeys = Object.getOwnPropertySymbols(source);
for (i = 0; i < sourceSymbolKeys.length; i++) {
key = sourceSymbolKeys[i];
if (excluded.indexOf(key) >= 0) continue;
if (!Object.prototype.propertyIsEnumerable.call(source, key)) continue;
target[key] = source[key];
}
}
return target;
}
function _slicedToArray(arr, i) {
return _arrayWithHoles(arr) || _iterableToArrayLimit(arr, i) || _nonIterableRest();
return _arrayWithHoles(arr) || _iterableToArrayLimit(arr, i) || _unsupportedIterableToArray(arr, i) || _nonIterableRest();
}
function _toConsumableArray(arr) {
return _arrayWithoutHoles(arr) || _iterableToArray(arr) || _nonIterableSpread();
return _arrayWithoutHoles(arr) || _iterableToArray(arr) || _unsupportedIterableToArray(arr) || _nonIterableSpread();
}
function _arrayWithoutHoles(arr) {
if (Array.isArray(arr)) {
for (var i = 0, arr2 = new Array(arr.length); i < arr.length; i++) arr2[i] = arr[i];
return arr2;
}
if (Array.isArray(arr)) return _arrayLikeToArray(arr);
}
function _arrayWithHoles(arr) {
@ -96,14 +128,11 @@ typeof navigator === "object" && (function (global, factory) {
}
function _iterableToArray(iter) {
if (Symbol.iterator in Object(iter) || Object.prototype.toString.call(iter) === "[object Arguments]") return Array.from(iter);
if (typeof Symbol !== "undefined" && Symbol.iterator in Object(iter)) return Array.from(iter);
}
function _iterableToArrayLimit(arr, i) {
if (!(Symbol.iterator in Object(arr) || Object.prototype.toString.call(arr) === "[object Arguments]")) {
return;
}
if (typeof Symbol === "undefined" || !(Symbol.iterator in Object(arr))) return;
var _arr = [];
var _n = true;
var _d = false;
@ -129,12 +158,29 @@ typeof navigator === "object" && (function (global, factory) {
return _arr;
}
function _unsupportedIterableToArray(o, minLen) {
if (!o) return;
if (typeof o === "string") return _arrayLikeToArray(o, minLen);
var n = Object.prototype.toString.call(o).slice(8, -1);
if (n === "Object" && o.constructor) n = o.constructor.name;
if (n === "Map" || n === "Set") return Array.from(o);
if (n === "Arguments" || /^(?:Ui|I)nt(?:8|16|32)(?:Clamped)?Array$/.test(n)) return _arrayLikeToArray(o, minLen);
}
function _arrayLikeToArray(arr, len) {
if (len == null || len > arr.length) len = arr.length;
for (var i = 0, arr2 = new Array(len); i < len; i++) arr2[i] = arr[i];
return arr2;
}
function _nonIterableSpread() {
throw new TypeError("Invalid attempt to spread non-iterable instance");
throw new TypeError("Invalid attempt to spread non-iterable instance.\nIn order to be iterable, non-array objects must have a [Symbol.iterator]() method.");
}
function _nonIterableRest() {
throw new TypeError("Invalid attempt to destructure non-iterable instance");
throw new TypeError("Invalid attempt to destructure non-iterable instance.\nIn order to be iterable, non-array objects must have a [Symbol.iterator]() method.");
}
function _classCallCheck$1(e, t) {
@ -427,7 +473,7 @@ typeof navigator === "object" && (function (global, factory) {
};
var isPromise = function isPromise(input) {
return instanceOf$1(input, Promise);
return instanceOf$1(input, Promise) && isFunction$1(input.then);
};
var isEmpty$1 = function isEmpty(input) {
@ -769,12 +815,33 @@ typeof navigator === "object" && (function (global, factory) {
} // Element matches selector
function matches$1(element, selector) {
var _Element = Element,
prototype = _Element.prototype;
function match() {
return Array.from(document.querySelectorAll(selector)).includes(this);
}
var method = match;
var method = prototype.matches || prototype.webkitMatchesSelector || prototype.mozMatchesSelector || prototype.msMatchesSelector || match;
return method.call(element, selector);
} // Closest ancestor element matching selector (also tests element itself)
function closest(element, selector) {
var _Element2 = Element,
prototype = _Element2.prototype; // https://developer.mozilla.org/en-US/docs/Web/API/Element/closest#Polyfill
function closestElement() {
var el = this;
do {
if (matches$1.matches(el, selector)) return el;
el = el.parentElement || el.parentNode;
} while (el !== null && el.nodeType === 1);
return null;
}
var method = prototype.closest || closestElement;
return method.call(element, selector);
} // Find all elements
@ -1017,7 +1084,7 @@ typeof navigator === "object" && (function (global, factory) {
var event = new CustomEvent(type, {
bubbles: bubbles,
detail: _objectSpread2({}, detail, {
detail: _objectSpread2(_objectSpread2({}, detail), {}, {
plyr: this
})
}); // Dispatch the event
@ -1046,6 +1113,19 @@ typeof navigator === "object" && (function (global, factory) {
}).then(function () {});
}
/**
* Silence a Promise-like object.
* This is useful for avoiding non-harmful, but potentially confusing "uncaught
* play promise" rejection error messages.
* @param {Object} value An object that may or may not be `Promise`-like.
*/
function silencePromise(value) {
if (is$1.promise(value)) {
value.then(null, function () {});
}
}
function validateRatio(input) {
if (!is$1.array(input) && (!is$1.string(input) || !input.includes(':'))) {
return false;
@ -1114,8 +1194,8 @@ typeof navigator === "object" && (function (global, factory) {
var padding = 100 / w * h;
wrapper.style.paddingBottom = "".concat(padding, "%"); // For Vimeo we have an extra <div> to hide the standard controls and UI
if (this.isVimeo && this.supported.ui) {
var height = 240;
if (this.isVimeo && !this.config.vimeo.premium && this.supported.ui) {
var height = 100 / this.media.offsetWidth * parseInt(window.getComputedStyle(this.media).paddingBottom, 10);
var offset = (height - padding) / (height / 50);
this.media.style.transform = "translateY(-".concat(offset, "%)");
} else if (this.isHTML5) {
@ -1222,7 +1302,7 @@ typeof navigator === "object" && (function (global, factory) {
player.currentTime = currentTime; // Resume playing
if (!paused) {
player.play();
silencePromise(player.play());
}
}); // Load new source
@ -1271,7 +1351,7 @@ typeof navigator === "object" && (function (global, factory) {
});
} // Get the closest value in an array
function closest(array, value) {
function closest$1(array, value) {
if (!is$1.array(array) || !array.length) {
return null;
}
@ -1309,19 +1389,19 @@ typeof navigator === "object" && (function (global, factory) {
return (current / max * 100).toFixed(2);
} // Replace all occurances of a string in a string
function replaceAll() {
var replaceAll = function replaceAll() {
var input = arguments.length > 0 && arguments[0] !== undefined ? arguments[0] : '';
var find = arguments.length > 1 && arguments[1] !== undefined ? arguments[1] : '';
var replace = arguments.length > 2 && arguments[2] !== undefined ? arguments[2] : '';
return input.replace(new RegExp(find.toString().replace(/([.*+?^=!:${}()|[\]/\\])/g, '\\$1'), 'g'), replace.toString());
} // Convert to title case
}; // Convert to title case
function toTitleCase() {
var toTitleCase = function toTitleCase() {
var input = arguments.length > 0 && arguments[0] !== undefined ? arguments[0] : '';
return input.toString().replace(/\w\S*/g, function (text) {
return text.charAt(0).toUpperCase() + text.substr(1).toLowerCase();
});
} // Convert string to pascalCase
}; // Convert string to pascalCase
function toPascalCase() {
var input = arguments.length > 0 && arguments[0] !== undefined ? arguments[0] : '';
@ -1682,7 +1762,7 @@ typeof navigator === "object" && (function (global, factory) {
var icon = document.createElementNS(namespace, 'svg');
setAttributes(icon, extend(attributes, {
role: 'presentation',
'aria-hidden': 'true',
focusable: 'false'
})); // Create the <use> to reference sprite
@ -1706,7 +1786,7 @@ typeof navigator === "object" && (function (global, factory) {
var attr = arguments.length > 1 && arguments[1] !== undefined ? arguments[1] : {};
var text = i18n.get(key, this.config);
var attributes = _objectSpread2({}, attr, {
var attributes = _objectSpread2(_objectSpread2({}, attr), {}, {
class: [attr.class, this.config.classNames.hidden].filter(Boolean).join(' ')
});
@ -2465,7 +2545,7 @@ typeof navigator === "object" && (function (global, factory) {
var type = 'captions';
var list = this.elements.settings.panels.captions.querySelector('[role="menu"]');
var list = this.elements.settings.panels.captions.querySelector('[role="menucaptions"]');
var tracks = captions.getTracks.call(this);
var toggle = Boolean(tracks.length); // Toggle the pane and tab
@ -2706,7 +2786,7 @@ typeof navigator === "object" && (function (global, factory) {
showMenuPanel = controls.showMenuPanel;
this.elements.controls = null; // Larger overlaid play button
if (this.config.controls.includes('play-large')) {
if (is$1.array(this.config.controls) && this.config.controls.includes('play-large')) {
this.elements.container.appendChild(createButton.call(this, 'play-large'));
} // Create the container
@ -2718,7 +2798,7 @@ typeof navigator === "object" && (function (global, factory) {
class: 'plyr__controls__item'
}; // Loop through controls in order
dedupe(this.config.controls).forEach(function (control) {
dedupe(is$1.array(this.config.controls) ? this.config.controls : []).forEach(function (control) {
// Restart button
if (control === 'restart') {
container.appendChild(createButton.call(_this10, 'restart', defaultAttributes));
@ -2907,6 +2987,10 @@ typeof navigator === "object" && (function (global, factory) {
pane.appendChild(createElement('div', {
role: 'menu'
})); // Menu Captions
pane.appendChild(createElement('div', {
role: 'menucaptions'
}));
inner.appendChild(pane);
_this10.elements.settings.buttons[type] = menuItem;
@ -3037,8 +3121,6 @@ typeof navigator === "object" && (function (global, factory) {
if (update) {
if (is$1.string(this.config.controls)) {
container = replace(container);
} else if (is$1.element(container)) {
container.innerHTML = replace(container.innerHTML);
}
} // Controls container
@ -3253,9 +3335,15 @@ typeof navigator === "object" && (function (global, factory) {
meta.set(track, {
default: track.mode === 'showing'
}); // Turn off native caption rendering to avoid double captions
// Note: mode='hidden' forces a track to download. To ensure every track
// isn't downloaded at once, only 'showing' tracks should be reassigned
// eslint-disable-next-line no-param-reassign
track.mode = 'hidden'; // Add event listener for cue changes
if (track.mode === 'showing') {
// eslint-disable-next-line no-param-reassign
track.mode = 'hidden';
} // Add event listener for cue changes
on.call(_this, track, 'cuechange', function () {
return captions.updateCues.call(_this);
@ -3272,13 +3360,15 @@ typeof navigator === "object" && (function (global, factory) {
toggleClass(this.elements.container, this.config.classNames.captions.enabled, !is$1.empty(tracks)); // Update available languages in list
if ((this.config.controls || []).includes('settings') && this.config.settings.includes('captions')) {
if (is$1.array(this.config.controls) && this.config.controls.includes('settings') && this.config.settings.includes('captions')) {
controls.setCaptionsMenu.call(this);
}
},
// Toggle captions display
// Used internally for the toggleCaptions method, with the passive option forced to false
toggle: function toggle(input) {
var _this2 = this;
var passive = arguments.length > 1 && arguments[1] !== undefined ? arguments[1] : true;
// If there's no full support
@ -3325,7 +3415,15 @@ typeof navigator === "object" && (function (global, factory) {
controls.updateSetting.call(this, 'captions'); // Trigger event (not used internally)
triggerEvent.call(this, this.media, active ? 'captionsenabled' : 'captionsdisabled');
} // Wait for the call stack to clear before setting mode='hidden'
// on the active track - forcing the browser to download it
setTimeout(function () {
if (active && _this2.captions.toggled) {
_this2.captions.currentTrackNode.mode = 'hidden';
}
});
},
// Set captions by track index
// Used internally for the currentTrack setter with the passive option forced to false
@ -3406,7 +3504,7 @@ typeof navigator === "object" && (function (global, factory) {
// If update is false it will also ignore tracks without metadata
// This is used to "freeze" the language options when captions.update is false
getTracks: function getTracks() {
var _this2 = this;
var _this3 = this;
var update = arguments.length > 0 && arguments[0] !== undefined ? arguments[0] : false;
// Handle media or textTracks missing or null
@ -3414,20 +3512,20 @@ typeof navigator === "object" && (function (global, factory) {
// Filter out removed tracks and tracks that aren't captions/subtitles (for example metadata)
return tracks.filter(function (track) {
return !_this2.isHTML5 || update || _this2.captions.meta.has(track);
return !_this3.isHTML5 || update || _this3.captions.meta.has(track);
}).filter(function (track) {
return ['captions', 'subtitles'].includes(track.kind);
});
},
// Match tracks based on languages and get the first
findTrack: function findTrack(languages) {
var _this3 = this;
var _this4 = this;
var force = arguments.length > 1 && arguments[1] !== undefined ? arguments[1] : false;
var tracks = captions.getTracks.call(this);
var sortIsDefault = function sortIsDefault(track) {
return Number((_this3.captions.meta.get(track) || {}).default);
return Number((_this4.captions.meta.get(track) || {}).default);
};
var sorted = Array.from(tracks).sort(function (a, b) {
@ -3608,6 +3706,9 @@ typeof navigator === "object" && (function (global, factory) {
fallback: true,
// Fallback using full viewport/window
iosNative: false // Use the native fullscreen in iOS (disables custom controls)
// Selector for the fullscreen container so contextual / non-player content can remain visible in fullscreen mode
// Non-ancestors of the player element will be ignored
// container: null, // defaults to the player element
},
// Local storage
@ -3845,16 +3946,16 @@ typeof navigator === "object" && (function (global, factory) {
title: false,
speed: true,
transparent: false,
// These settings require a pro or premium account to work
sidedock: false,
controls: false,
// Whether the owner of the video has a Pro or Business account
// (which allows us to properly hide controls without CSS hacks, etc)
premium: false,
// Custom settings from Plyr
referrerPolicy: null // https://developer.mozilla.org/en-US/docs/Web/API/HTMLIFrameElement/referrerPolicy
},
// YouTube plugin
youtube: {
noCookie: false,
noCookie: true,
// Whether to use an alternative version of YouTube without cookies
rel: 0,
// No related vids
@ -3964,7 +4065,10 @@ typeof navigator === "object" && (function (global, factory) {
y: 0
}; // Force the use of 'full window/browser' rather than fullscreen
this.forceFallback = player.config.fullscreen.fallback === 'force'; // Register event listeners
this.forceFallback = player.config.fullscreen.fallback === 'force'; // Get the fullscreen element
// Checks container is an ancestor, defaults to null
this.player.elements.fullscreen = player.config.fullscreen.container && closest(this.player.elements.container, player.config.fullscreen.container); // Register event listeners
// Handle event (incase user presses escape etc)
on.call(this.player, document, this.prefix === 'ms' ? 'MSFullscreenChange' : "".concat(this.prefix, "fullscreenchange"), function () {
@ -4137,7 +4241,7 @@ typeof navigator === "object" && (function (global, factory) {
if (browser.isIos && this.player.config.fullscreen.iosNative) {
this.target.webkitExitFullscreen();
this.player.play();
silencePromise(this.player.play());
} else if (!Fullscreen.native || this.forceFallback) {
this.toggleFallback(false);
} else if (!this.prefix) {
@ -4184,13 +4288,13 @@ typeof navigator === "object" && (function (global, factory) {
}
var element = !this.prefix ? document.fullscreenElement : document["".concat(this.prefix).concat(this.property, "Element")];
return element === this.target;
return element && element.shadowRoot ? element === this.target.getRootNode().host : element === this.target;
} // Get target element
}, {
key: "target",
get: function get() {
return browser.isIos && this.player.config.fullscreen.iosNative ? this.player.media : this.player.elements.container;
return browser.isIos && this.player.config.fullscreen.iosNative ? this.player.media : this.player.elements.fullscreen || this.player.elements.container;
}
}], [{
key: "native",
@ -4252,7 +4356,6 @@ typeof navigator === "object" && (function (global, factory) {
});
}
// ==========================================================================
var ui = {
addStyleHook: function addStyleHook() {
toggleClass(this.elements.container, this.config.selectors.container.replace('.', ''), true);
@ -4387,12 +4490,7 @@ typeof navigator === "object" && (function (global, factory) {
} // Set property synchronously to respect the call order
this.media.setAttribute('poster', poster); // HTML5 uses native poster attribute
if (this.isHTML5) {
return Promise.resolve(poster);
} // Wait until ui is ready
this.media.setAttribute('data-poster', poster); // Wait until ui is ready
return ready.call(this) // Load image
.then(function () {
@ -4468,6 +4566,26 @@ typeof navigator === "object" && (function (global, factory) {
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 !is$1.empty(key) && 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');
}
}
};
@ -4562,7 +4680,7 @@ typeof navigator === "object" && (function (global, factory) {
case 75:
// Space and K key
if (!repeat) {
player.togglePlay();
silencePromise(player.togglePlay());
}
break;
@ -4676,6 +4794,7 @@ typeof navigator === "object" && (function (global, factory) {
removeCurrent(); // Delay the adding of classname until the focus has changed
// This event fires before the focusin event
if (event.type !== 'focusout') {
this.focusTimer = setTimeout(function () {
var focused = document.activeElement; // Ignore if current focus element isn't inside the player
@ -4685,6 +4804,7 @@ typeof navigator === "object" && (function (global, factory) {
toggleClass(document.activeElement, player.config.classNames.tabFocus, true);
}, 10);
}
} // Global window & document listeners
}, {
@ -4702,7 +4822,7 @@ typeof navigator === "object" && (function (global, factory) {
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
}, {
@ -4745,7 +4865,7 @@ typeof navigator === "object" && (function (global, factory) {
}); // Set a gutter for Vimeo
var setGutter = function setGutter(ratio, padding, toggle) {
if (!player.isVimeo) {
if (!player.isVimeo || player.config.vimeo.premium) {
return;
}
@ -4802,7 +4922,7 @@ typeof navigator === "object" && (function (global, factory) {
ratio = _setPlayerSize.ratio; // Set Vimeo gutter
setGutter(ratio, padding, isEnter); // If not using native fullscreen, we need to check for resizes of viewport
setGutter(ratio, padding, isEnter); // If not using native browser fullscreen API, we need to check for resizes of viewport
if (!usingNative) {
if (isEnter) {
@ -4880,9 +5000,13 @@ typeof navigator === "object" && (function (global, factory) {
if (player.ended) {
_this.proxy(event, player.restart, 'restart');
_this.proxy(event, player.play, 'play');
_this.proxy(event, function () {
silencePromise(player.play());
}, 'play');
} else {
_this.proxy(event, player.togglePlay, 'play');
_this.proxy(event, function () {
silencePromise(player.togglePlay());
}, 'play');
}
});
} // Disable right click
@ -4980,7 +5104,9 @@ typeof navigator === "object" && (function (global, factory) {
if (elements.buttons.play) {
Array.from(elements.buttons.play).forEach(function (button) {
_this3.bind(button, 'click', player.togglePlay, 'play');
_this3.bind(button, 'click', function () {
silencePromise(player.togglePlay());
}, 'play');
});
} // Pause
@ -5077,7 +5203,7 @@ typeof navigator === "object" && (function (global, factory) {
if (play && done) {
seek.removeAttribute(attribute);
player.play();
silencePromise(player.play());
} else if (!done && player.playing) {
seek.setAttribute(attribute, '');
player.pause();
@ -5175,7 +5301,18 @@ typeof navigator === "object" && (function (global, factory) {
this.bind(elements.controls, 'mouseenter mouseleave', function (event) {
elements.controls.hover = !player.touch && event.type === 'mouseenter';
}); // Update controls.pressed state (used for ui.toggleControls to avoid hiding when interacting)
}); // Also update controls.hover state for any non-player children of fullscreen element (as above)
if (elements.fullscreen) {
Array.from(elements.fullscreen.children).filter(function (c) {
return !c.contains(elements.container);
}).forEach(function (child) {
_this3.bind(child, 'mouseenter mouseleave', function (event) {
elements.controls.hover = !player.touch && event.type === 'mouseenter';
});
});
} // Update controls.pressed state (used for ui.toggleControls to avoid hiding when interacting)
this.bind(elements.controls, 'mousedown mouseup touchstart touchend touchcancel', function (event) {
elements.controls.pressed = ['mousedown', 'touchstart'].includes(event.type);
@ -5591,15 +5728,28 @@ typeof navigator === "object" && (function (global, factory) {
var _this = 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,
autoplay: player.autoplay,
muted: player.muted,
gesture: 'media',
playsinline: !this.config.fullscreen.iosNative
}, config)); // Get the source URL or ID
}, frameParams)); // Get the source URL or ID
var source = player.media.getAttribute('src'); // Get from <div> if needed
@ -5613,22 +5763,27 @@ typeof navigator === "object" && (function (global, factory) {
var src = format(player.config.urls.vimeo.iframe, id, params);
iframe.setAttribute('src', src);
iframe.setAttribute('allowfullscreen', '');
iframe.setAttribute('allowtransparency', '');
iframe.setAttribute('allow', 'autoplay'); // Set the referrer policy if required
iframe.setAttribute('allow', 'autoplay,fullscreen,picture-in-picture'); // Set the referrer policy if required
if (!is$1.empty(config.referrerPolicy)) {
iframe.setAttribute('referrerPolicy', config.referrerPolicy);
} // Get poster, if already set
if (!is$1.empty(referrerPolicy)) {
iframe.setAttribute('referrerPolicy', referrerPolicy);
} // Inject the package
var poster = player.poster; // Inject the package
var poster = player.poster;
if (premium) {
iframe.setAttribute('data-poster', poster);
player.media = replaceElement(iframe, player.media);
} else {
var wrapper = createElement('div', {
poster: poster,
class: player.config.classNames.embedContainer
class: player.config.classNames.embedContainer,
'data-poster': poster
});
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) {
if (is$1.empty(response)) {
@ -5712,6 +5867,9 @@ typeof navigator === "object" && (function (global, factory) {
player.embed.setPlaybackRate(input).then(function () {
speed = input;
triggerEvent.call(player, player.media, 'ratechange');
}).catch(function () {
// Cannot set Playback Rate, Video is probably not on Pro account
player.options.speed = [1];
});
}
}); // Volume
@ -5998,7 +6156,7 @@ typeof navigator === "object" && (function (global, factory) {
var container = createElement('div', {
id: id,
poster: poster
'data-poster': poster
});
player.media = replaceElement(container, player.media); // Id to poster wrapper
@ -6317,15 +6475,13 @@ typeof navigator === "object" && (function (global, factory) {
class: this.config.classNames.video
}); // Wrap the video in a container
wrap(this.media, this.elements.wrapper); // Faux poster container
wrap(this.media, this.elements.wrapper); // Poster image container
if (this.isEmbed) {
this.elements.poster = createElement('div', {
class: this.config.classNames.poster
});
this.elements.wrapper.appendChild(this.elements.poster);
}
}
if (this.isHTML5) {
html5.setup.call(this);
@ -6451,6 +6607,8 @@ typeof navigator === "object" && (function (global, factory) {
* mobile devices, this initialization is done as the result of a user action.
*/
value: function setupIMA() {
var _this4 = this;
// Create the container for our advertisements
this.elements.container = createElement('div', {
class: this.player.config.classNames.ads
@ -6463,7 +6621,16 @@ typeof navigator === "object" && (function (global, factory) {
google.ima.settings.setDisableCustomPlaybackForIOS10Plus(this.player.config.playsinline); // We assume the adContainer is the video container of the plyr element that will house the ads
this.elements.displayContainer = new google.ima.AdDisplayContainer(this.elements.container, this.player.media); // Request video ads to be pre-loaded
this.elements.displayContainer = new google.ima.AdDisplayContainer(this.elements.container, this.player.media); // Create ads loader
this.loader = new google.ima.AdsLoader(this.elements.displayContainer); // Listen and respond to ads loaded and error events
this.loader.addEventListener(google.ima.AdsManagerLoadedEvent.Type.ADS_MANAGER_LOADED, function (event) {
return _this4.onAdsManagerLoaded(event);
}, false);
this.loader.addEventListener(google.ima.AdErrorEvent.Type.AD_ERROR, function (error) {
return _this4.onAdError(error);
}, false); // Request video ads to be pre-loaded
this.requestAds();
}
@ -6474,21 +6641,10 @@ typeof navigator === "object" && (function (global, factory) {
}, {
key: "requestAds",
value: function requestAds() {
var _this4 = this;
var container = this.player.elements.container;
try {
// Create ads loader
this.loader = new google.ima.AdsLoader(this.elements.displayContainer); // Listen and respond to ads loaded and error events
this.loader.addEventListener(google.ima.AdsManagerLoadedEvent.Type.ADS_MANAGER_LOADED, function (event) {
return _this4.onAdsManagerLoaded(event);
}, false);
this.loader.addEventListener(google.ima.AdErrorEvent.Type.AD_ERROR, function (error) {
return _this4.onAdError(error);
}, false); // Request video ads
// Request video ads
var request = new google.ima.AdsRequest();
request.adTagUrl = this.tagUrl; // Specify the linear and nonlinear slot sizes. This helps the SDK
// to select the correct creative if multiple are returned
@ -6667,7 +6823,13 @@ typeof navigator === "object" && (function (global, factory) {
// };
// TODO: So there is still this thing where a video should only be allowed to start
// playing when the IMA SDK is ready or has failed
if (this.player.ended) {
this.loadAds();
} else {
// The SDK won't allow new ads to be called without receiving a contentComplete()
this.loader.contentComplete();
}
break;
case google.ima.AdEvent.Type.CONTENT_PAUSE_REQUESTED:
@ -6803,7 +6965,7 @@ typeof navigator === "object" && (function (global, factory) {
this.playing = false; // Play video
this.player.media.play();
silencePromise(this.player.media.play());
}
/**
* Pause our video
@ -6860,7 +7022,9 @@ typeof navigator === "object" && (function (global, factory) {
_this11.on('loaded', resolve);
_this11.player.debug.log(_this11.manager);
}); // Now request some new advertisements
}); // Now that the manager has been destroyed set it to also be un-initialized
_this11.initialized = false; // Now request some new advertisements
_this11.requestAds();
}).catch(function () {});
@ -7104,15 +7268,10 @@ typeof navigator === "object" && (function (global, factory) {
if (is$1.empty(src)) {
throw new Error('Missing previewThumbnails.src config attribute');
} // If string, convert into single-element list
} // Resolve promise
var urls = is$1.string(src) ? [src] : src; // Loop through each src URL. Download and process the VTT file, storing the resulting data in this.thumbnails
var promises = urls.map(function (u) {
return _this2.getThumbnail(u);
});
Promise.all(promises).then(function () {
var sortAndResolve = function sortAndResolve() {
// Sort smallest to biggest (e.g., [120p, 480p, 1080p])
_this2.thumbnails.sort(function (x, y) {
return x.height - y.height;
@ -7121,7 +7280,25 @@ typeof navigator === "object" && (function (global, factory) {
_this2.player.debug.log('Preview thumbnails', _this2.thumbnails);
resolve();
}; // Via callback()
if (is$1.function(src)) {
src(function (thumbnails) {
_this2.thumbnails = thumbnails;
sortAndResolve();
});
} // VTT urls
else {
// If string, convert into single-element list
var urls = is$1.string(src) ? [src] : src; // Loop through each src URL. Download and process the VTT file, storing the resulting data in this.thumbnails
var promises = urls.map(function (u) {
return _this2.getThumbnail(u);
}); // Resolve
Promise.all(promises).then(sortAndResolve);
}
});
} // Process individual VTT file
@ -7909,6 +8086,7 @@ typeof navigator === "object" && (function (global, factory) {
this.elements = {
container: null,
fullscreen: null,
captions: null,
buttons: {},
display: {},
@ -8083,9 +8261,11 @@ typeof navigator === "object" && (function (global, factory) {
tabindex: 0
});
wrap(this.media, this.elements.container);
} // Add style hook
} // Migrate custom properties from media to container (so they work 😉)
ui.migrateStyles.call(this); // Add style hook
ui.addStyleHook.call(this); // Setup media
media.setup.call(this); // Listen for events if debugging
@ -8094,10 +8274,12 @@ typeof navigator === "object" && (function (global, factory) {
on.call(this, this.elements.container, this.config.events.join(' '), function (event) {
_this.debug.log("event: ".concat(event.type));
});
} // Setup interface
// If embed but not fully supported, build interface now to avoid flash of controls
} // Setup fullscreen
this.fullscreen = new Fullscreen(this); // Setup interface
// If embed but not fully supported, build interface now to avoid flash of controls
if (this.isHTML5 || this.isEmbed && !this.supported.ui) {
ui.build.call(this);
} // Container listeners
@ -8105,9 +8287,7 @@ typeof navigator === "object" && (function (global, factory) {
this.listeners.container(); // Global listeners
this.listeners.global(); // Setup fullscreen
this.fullscreen = new Fullscreen(this); // Setup ads if provided
this.listeners.global(); // Setup ads if provided
if (this.config.ads.enabled) {
this.ads = new Ads(this);
@ -8116,7 +8296,7 @@ typeof navigator === "object" && (function (global, factory) {
if (this.isHTML5 && this.config.autoplay) {
setTimeout(function () {
return _this.play();
return silencePromise(_this.play());
}, 10);
} // Seek time will be recorded (in listeners.js) so we can prevent hiding controls for a few seconds after seek
@ -8153,7 +8333,7 @@ typeof navigator === "object" && (function (global, factory) {
this.ads.managerPromise.then(function () {
return _this2.ads.play();
}).catch(function () {
return _this2.media.play();
return silencePromise(_this2.media.play());
});
} // Return the promise (for HTML5)
@ -8313,7 +8493,7 @@ typeof navigator === "object" && (function (global, factory) {
var hiding = toggleClass(this.elements.container, this.config.classNames.hideControls, force); // Close menu
if (hiding && this.config.controls.includes('settings') && !is$1.empty(this.config.settings)) {
if (hiding && is$1.array(this.config.controls) && this.config.controls.includes('settings') && !is$1.empty(this.config.settings)) {
controls.toggleMenu.call(this, false);
} // Trigger event on change
@ -8806,7 +8986,7 @@ typeof navigator === "object" && (function (global, factory) {
var updateStorage = true;
if (!options.includes(quality)) {
var value = closest(options, quality);
var value = closest$1(options, quality);
this.debug.warn("Unsupported quality option: ".concat(quality, ", using ").concat(value, " instead"));
quality = value; // Don't update storage if quality is not supported
@ -8951,7 +9131,7 @@ typeof navigator === "object" && (function (global, factory) {
return null;
}
return this.media.getAttribute('poster');
return this.media.getAttribute('poster') || this.media.getAttribute('data-poster');
}
/**
* 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

@ -69,20 +69,52 @@ function _objectSpread2(target) {
return target;
}
function _objectWithoutPropertiesLoose(source, excluded) {
if (source == null) return {};
var target = {};
var sourceKeys = Object.keys(source);
var key, i;
for (i = 0; i < sourceKeys.length; i++) {
key = sourceKeys[i];
if (excluded.indexOf(key) >= 0) continue;
target[key] = source[key];
}
return target;
}
function _objectWithoutProperties(source, excluded) {
if (source == null) return {};
var target = _objectWithoutPropertiesLoose(source, excluded);
var key, i;
if (Object.getOwnPropertySymbols) {
var sourceSymbolKeys = Object.getOwnPropertySymbols(source);
for (i = 0; i < sourceSymbolKeys.length; i++) {
key = sourceSymbolKeys[i];
if (excluded.indexOf(key) >= 0) continue;
if (!Object.prototype.propertyIsEnumerable.call(source, key)) continue;
target[key] = source[key];
}
}
return target;
}
function _slicedToArray(arr, i) {
return _arrayWithHoles(arr) || _iterableToArrayLimit(arr, i) || _nonIterableRest();
return _arrayWithHoles(arr) || _iterableToArrayLimit(arr, i) || _unsupportedIterableToArray(arr, i) || _nonIterableRest();
}
function _toConsumableArray(arr) {
return _arrayWithoutHoles(arr) || _iterableToArray(arr) || _nonIterableSpread();
return _arrayWithoutHoles(arr) || _iterableToArray(arr) || _unsupportedIterableToArray(arr) || _nonIterableSpread();
}
function _arrayWithoutHoles(arr) {
if (Array.isArray(arr)) {
for (var i = 0, arr2 = new Array(arr.length); i < arr.length; i++) arr2[i] = arr[i];
return arr2;
}
if (Array.isArray(arr)) return _arrayLikeToArray(arr);
}
function _arrayWithHoles(arr) {
@ -90,14 +122,11 @@ function _arrayWithHoles(arr) {
}
function _iterableToArray(iter) {
if (Symbol.iterator in Object(iter) || Object.prototype.toString.call(iter) === "[object Arguments]") return Array.from(iter);
if (typeof Symbol !== "undefined" && Symbol.iterator in Object(iter)) return Array.from(iter);
}
function _iterableToArrayLimit(arr, i) {
if (!(Symbol.iterator in Object(arr) || Object.prototype.toString.call(arr) === "[object Arguments]")) {
return;
}
if (typeof Symbol === "undefined" || !(Symbol.iterator in Object(arr))) return;
var _arr = [];
var _n = true;
var _d = false;
@ -123,12 +152,29 @@ function _iterableToArrayLimit(arr, i) {
return _arr;
}
function _unsupportedIterableToArray(o, minLen) {
if (!o) return;
if (typeof o === "string") return _arrayLikeToArray(o, minLen);
var n = Object.prototype.toString.call(o).slice(8, -1);
if (n === "Object" && o.constructor) n = o.constructor.name;
if (n === "Map" || n === "Set") return Array.from(o);
if (n === "Arguments" || /^(?:Ui|I)nt(?:8|16|32)(?:Clamped)?Array$/.test(n)) return _arrayLikeToArray(o, minLen);
}
function _arrayLikeToArray(arr, len) {
if (len == null || len > arr.length) len = arr.length;
for (var i = 0, arr2 = new Array(len); i < len; i++) arr2[i] = arr[i];
return arr2;
}
function _nonIterableSpread() {
throw new TypeError("Invalid attempt to spread non-iterable instance");
throw new TypeError("Invalid attempt to spread non-iterable instance.\nIn order to be iterable, non-array objects must have a [Symbol.iterator]() method.");
}
function _nonIterableRest() {
throw new TypeError("Invalid attempt to destructure non-iterable instance");
throw new TypeError("Invalid attempt to destructure non-iterable instance.\nIn order to be iterable, non-array objects must have a [Symbol.iterator]() method.");
}
function _classCallCheck$1(e, t) {
@ -421,7 +467,7 @@ var isTrack = function isTrack(input) {
};
var isPromise = function isPromise(input) {
return instanceOf$1(input, Promise);
return instanceOf$1(input, Promise) && isFunction$1(input.then);
};
var isEmpty$1 = function isEmpty(input) {
@ -763,12 +809,33 @@ function hasClass(element, className) {
} // Element matches selector
function matches$1(element, selector) {
var _Element = Element,
prototype = _Element.prototype;
function match() {
return Array.from(document.querySelectorAll(selector)).includes(this);
}
var method = match;
var method = prototype.matches || prototype.webkitMatchesSelector || prototype.mozMatchesSelector || prototype.msMatchesSelector || match;
return method.call(element, selector);
} // Closest ancestor element matching selector (also tests element itself)
function closest(element, selector) {
var _Element2 = Element,
prototype = _Element2.prototype; // https://developer.mozilla.org/en-US/docs/Web/API/Element/closest#Polyfill
function closestElement() {
var el = this;
do {
if (matches$1.matches(el, selector)) return el;
el = el.parentElement || el.parentNode;
} while (el !== null && el.nodeType === 1);
return null;
}
var method = prototype.closest || closestElement;
return method.call(element, selector);
} // Find all elements
@ -1011,7 +1078,7 @@ function triggerEvent(element) {
var event = new CustomEvent(type, {
bubbles: bubbles,
detail: _objectSpread2({}, detail, {
detail: _objectSpread2(_objectSpread2({}, detail), {}, {
plyr: this
})
}); // Dispatch the event
@ -1040,6 +1107,19 @@ function ready() {
}).then(function () {});
}
/**
* Silence a Promise-like object.
* This is useful for avoiding non-harmful, but potentially confusing "uncaught
* play promise" rejection error messages.
* @param {Object} value An object that may or may not be `Promise`-like.
*/
function silencePromise(value) {
if (is$1.promise(value)) {
value.then(null, function () {});
}
}
function validateRatio(input) {
if (!is$1.array(input) && (!is$1.string(input) || !input.includes(':'))) {
return false;
@ -1108,8 +1188,8 @@ function setAspectRatio(input) {
var padding = 100 / w * h;
wrapper.style.paddingBottom = "".concat(padding, "%"); // For Vimeo we have an extra <div> to hide the standard controls and UI
if (this.isVimeo && this.supported.ui) {
var height = 240;
if (this.isVimeo && !this.config.vimeo.premium && this.supported.ui) {
var height = 100 / this.media.offsetWidth * parseInt(window.getComputedStyle(this.media).paddingBottom, 10);
var offset = (height - padding) / (height / 50);
this.media.style.transform = "translateY(-".concat(offset, "%)");
} else if (this.isHTML5) {
@ -1216,7 +1296,7 @@ var html5 = {
player.currentTime = currentTime; // Resume playing
if (!paused) {
player.play();
silencePromise(player.play());
}
}); // Load new source
@ -1265,7 +1345,7 @@ function dedupe(array) {
});
} // Get the closest value in an array
function closest(array, value) {
function closest$1(array, value) {
if (!is$1.array(array) || !array.length) {
return null;
}
@ -1303,19 +1383,19 @@ function getPercentage(current, max) {
return (current / max * 100).toFixed(2);
} // Replace all occurances of a string in a string
function replaceAll() {
var replaceAll = function replaceAll() {
var input = arguments.length > 0 && arguments[0] !== undefined ? arguments[0] : '';
var find = arguments.length > 1 && arguments[1] !== undefined ? arguments[1] : '';
var replace = arguments.length > 2 && arguments[2] !== undefined ? arguments[2] : '';
return input.replace(new RegExp(find.toString().replace(/([.*+?^=!:${}()|[\]/\\])/g, '\\$1'), 'g'), replace.toString());
} // Convert to title case
}; // Convert to title case
function toTitleCase() {
var toTitleCase = function toTitleCase() {
var input = arguments.length > 0 && arguments[0] !== undefined ? arguments[0] : '';
return input.toString().replace(/\w\S*/g, function (text) {
return text.charAt(0).toUpperCase() + text.substr(1).toLowerCase();
});
} // Convert string to pascalCase
}; // Convert string to pascalCase
function toPascalCase() {
var input = arguments.length > 0 && arguments[0] !== undefined ? arguments[0] : '';
@ -1676,7 +1756,7 @@ var controls = {
var icon = document.createElementNS(namespace, 'svg');
setAttributes(icon, extend(attributes, {
role: 'presentation',
'aria-hidden': 'true',
focusable: 'false'
})); // Create the <use> to reference sprite
@ -1700,7 +1780,7 @@ var controls = {
var attr = arguments.length > 1 && arguments[1] !== undefined ? arguments[1] : {};
var text = i18n.get(key, this.config);
var attributes = _objectSpread2({}, attr, {
var attributes = _objectSpread2(_objectSpread2({}, attr), {}, {
class: [attr.class, this.config.classNames.hidden].filter(Boolean).join(' ')
});
@ -2459,7 +2539,7 @@ var controls = {
var type = 'captions';
var list = this.elements.settings.panels.captions.querySelector('[role="menu"]');
var list = this.elements.settings.panels.captions.querySelector('[role="menucaptions"]');
var tracks = captions.getTracks.call(this);
var toggle = Boolean(tracks.length); // Toggle the pane and tab
@ -2700,7 +2780,7 @@ var controls = {
showMenuPanel = controls.showMenuPanel;
this.elements.controls = null; // Larger overlaid play button
if (this.config.controls.includes('play-large')) {
if (is$1.array(this.config.controls) && this.config.controls.includes('play-large')) {
this.elements.container.appendChild(createButton.call(this, 'play-large'));
} // Create the container
@ -2712,7 +2792,7 @@ var controls = {
class: 'plyr__controls__item'
}; // Loop through controls in order
dedupe(this.config.controls).forEach(function (control) {
dedupe(is$1.array(this.config.controls) ? this.config.controls : []).forEach(function (control) {
// Restart button
if (control === 'restart') {
container.appendChild(createButton.call(_this10, 'restart', defaultAttributes));
@ -2901,6 +2981,10 @@ var controls = {
pane.appendChild(createElement('div', {
role: 'menu'
})); // Menu Captions
pane.appendChild(createElement('div', {
role: 'menucaptions'
}));
inner.appendChild(pane);
_this10.elements.settings.buttons[type] = menuItem;
@ -3031,8 +3115,6 @@ var controls = {
if (update) {
if (is$1.string(this.config.controls)) {
container = replace(container);
} else if (is$1.element(container)) {
container.innerHTML = replace(container.innerHTML);
}
} // Controls container
@ -3247,9 +3329,15 @@ var captions = {
meta.set(track, {
default: track.mode === 'showing'
}); // Turn off native caption rendering to avoid double captions
// Note: mode='hidden' forces a track to download. To ensure every track
// isn't downloaded at once, only 'showing' tracks should be reassigned
// eslint-disable-next-line no-param-reassign
track.mode = 'hidden'; // Add event listener for cue changes
if (track.mode === 'showing') {
// eslint-disable-next-line no-param-reassign
track.mode = 'hidden';
} // Add event listener for cue changes
on.call(_this, track, 'cuechange', function () {
return captions.updateCues.call(_this);
@ -3266,13 +3354,15 @@ var captions = {
toggleClass(this.elements.container, this.config.classNames.captions.enabled, !is$1.empty(tracks)); // Update available languages in list
if ((this.config.controls || []).includes('settings') && this.config.settings.includes('captions')) {
if (is$1.array(this.config.controls) && this.config.controls.includes('settings') && this.config.settings.includes('captions')) {
controls.setCaptionsMenu.call(this);
}
},
// Toggle captions display
// Used internally for the toggleCaptions method, with the passive option forced to false
toggle: function toggle(input) {
var _this2 = this;
var passive = arguments.length > 1 && arguments[1] !== undefined ? arguments[1] : true;
// If there's no full support
@ -3319,7 +3409,15 @@ var captions = {
controls.updateSetting.call(this, 'captions'); // Trigger event (not used internally)
triggerEvent.call(this, this.media, active ? 'captionsenabled' : 'captionsdisabled');
} // Wait for the call stack to clear before setting mode='hidden'
// on the active track - forcing the browser to download it
setTimeout(function () {
if (active && _this2.captions.toggled) {
_this2.captions.currentTrackNode.mode = 'hidden';
}
});
},
// Set captions by track index
// Used internally for the currentTrack setter with the passive option forced to false
@ -3400,7 +3498,7 @@ var captions = {
// If update is false it will also ignore tracks without metadata
// This is used to "freeze" the language options when captions.update is false
getTracks: function getTracks() {
var _this2 = this;
var _this3 = this;
var update = arguments.length > 0 && arguments[0] !== undefined ? arguments[0] : false;
// Handle media or textTracks missing or null
@ -3408,20 +3506,20 @@ var captions = {
// Filter out removed tracks and tracks that aren't captions/subtitles (for example metadata)
return tracks.filter(function (track) {
return !_this2.isHTML5 || update || _this2.captions.meta.has(track);
return !_this3.isHTML5 || update || _this3.captions.meta.has(track);
}).filter(function (track) {
return ['captions', 'subtitles'].includes(track.kind);
});
},
// Match tracks based on languages and get the first
findTrack: function findTrack(languages) {
var _this3 = this;
var _this4 = this;
var force = arguments.length > 1 && arguments[1] !== undefined ? arguments[1] : false;
var tracks = captions.getTracks.call(this);
var sortIsDefault = function sortIsDefault(track) {
return Number((_this3.captions.meta.get(track) || {}).default);
return Number((_this4.captions.meta.get(track) || {}).default);
};
var sorted = Array.from(tracks).sort(function (a, b) {
@ -3602,6 +3700,9 @@ var defaults$1 = {
fallback: true,
// Fallback using full viewport/window
iosNative: false // Use the native fullscreen in iOS (disables custom controls)
// Selector for the fullscreen container so contextual / non-player content can remain visible in fullscreen mode
// Non-ancestors of the player element will be ignored
// container: null, // defaults to the player element
},
// Local storage
@ -3839,16 +3940,16 @@ var defaults$1 = {
title: false,
speed: true,
transparent: false,
// These settings require a pro or premium account to work
sidedock: false,
controls: false,
// Whether the owner of the video has a Pro or Business account
// (which allows us to properly hide controls without CSS hacks, etc)
premium: false,
// Custom settings from Plyr
referrerPolicy: null // https://developer.mozilla.org/en-US/docs/Web/API/HTMLIFrameElement/referrerPolicy
},
// YouTube plugin
youtube: {
noCookie: false,
noCookie: true,
// Whether to use an alternative version of YouTube without cookies
rel: 0,
// No related vids
@ -3958,7 +4059,10 @@ var Fullscreen = /*#__PURE__*/function () {
y: 0
}; // Force the use of 'full window/browser' rather than fullscreen
this.forceFallback = player.config.fullscreen.fallback === 'force'; // Register event listeners
this.forceFallback = player.config.fullscreen.fallback === 'force'; // Get the fullscreen element
// Checks container is an ancestor, defaults to null
this.player.elements.fullscreen = player.config.fullscreen.container && closest(this.player.elements.container, player.config.fullscreen.container); // Register event listeners
// Handle event (incase user presses escape etc)
on.call(this.player, document, this.prefix === 'ms' ? 'MSFullscreenChange' : "".concat(this.prefix, "fullscreenchange"), function () {
@ -4131,7 +4235,7 @@ var Fullscreen = /*#__PURE__*/function () {
if (browser.isIos && this.player.config.fullscreen.iosNative) {
this.target.webkitExitFullscreen();
this.player.play();
silencePromise(this.player.play());
} else if (!Fullscreen.native || this.forceFallback) {
this.toggleFallback(false);
} else if (!this.prefix) {
@ -4178,13 +4282,13 @@ var Fullscreen = /*#__PURE__*/function () {
}
var element = !this.prefix ? document.fullscreenElement : document["".concat(this.prefix).concat(this.property, "Element")];
return element === this.target;
return element && element.shadowRoot ? element === this.target.getRootNode().host : element === this.target;
} // Get target element
}, {
key: "target",
get: function get() {
return browser.isIos && this.player.config.fullscreen.iosNative ? this.player.media : this.player.elements.container;
return browser.isIos && this.player.config.fullscreen.iosNative ? this.player.media : this.player.elements.fullscreen || this.player.elements.container;
}
}], [{
key: "native",
@ -4246,7 +4350,6 @@ function loadImage(src) {
});
}
// ==========================================================================
var ui = {
addStyleHook: function addStyleHook() {
toggleClass(this.elements.container, this.config.selectors.container.replace('.', ''), true);
@ -4381,12 +4484,7 @@ var ui = {
} // Set property synchronously to respect the call order
this.media.setAttribute('poster', poster); // HTML5 uses native poster attribute
if (this.isHTML5) {
return Promise.resolve(poster);
} // Wait until ui is ready
this.media.setAttribute('data-poster', poster); // Wait until ui is ready
return ready.call(this) // Load image
.then(function () {
@ -4462,6 +4560,26 @@ var ui = {
this.toggleControls(Boolean(force || this.loading || this.paused || controlsElement.pressed || controlsElement.hover || recentTouchSeek));
}
},
// Migrate any custom properties from the media to the parent
migrateStyles: function migrateStyles() {
var _this5 = this;
// Loop through values (as they are the keys when the object is spread 🤔)
Object.values(_objectSpread2({}, this.media.style)) // We're only fussed about Plyr specific properties
.filter(function (key) {
return !is$1.empty(key) && 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');
}
}
};
@ -4556,7 +4674,7 @@ var Listeners = /*#__PURE__*/function () {
case 75:
// Space and K key
if (!repeat) {
player.togglePlay();
silencePromise(player.togglePlay());
}
break;
@ -4670,6 +4788,7 @@ var Listeners = /*#__PURE__*/function () {
removeCurrent(); // Delay the adding of classname until the focus has changed
// This event fires before the focusin event
if (event.type !== 'focusout') {
this.focusTimer = setTimeout(function () {
var focused = document.activeElement; // Ignore if current focus element isn't inside the player
@ -4679,6 +4798,7 @@ var Listeners = /*#__PURE__*/function () {
toggleClass(document.activeElement, player.config.classNames.tabFocus, true);
}, 10);
}
} // Global window & document listeners
}, {
@ -4696,7 +4816,7 @@ var Listeners = /*#__PURE__*/function () {
once.call(player, document.body, 'touchstart', this.firstTouch); // Tab focus detection
toggleListener.call(player, document.body, 'keydown focus blur', this.setTabFocus, toggle, false, true);
toggleListener.call(player, document.body, 'keydown focus blur focusout', this.setTabFocus, toggle, false, true);
} // Container listeners
}, {
@ -4739,7 +4859,7 @@ var Listeners = /*#__PURE__*/function () {
}); // Set a gutter for Vimeo
var setGutter = function setGutter(ratio, padding, toggle) {
if (!player.isVimeo) {
if (!player.isVimeo || player.config.vimeo.premium) {
return;
}
@ -4796,7 +4916,7 @@ var Listeners = /*#__PURE__*/function () {
ratio = _setPlayerSize.ratio; // Set Vimeo gutter
setGutter(ratio, padding, isEnter); // If not using native fullscreen, we need to check for resizes of viewport
setGutter(ratio, padding, isEnter); // If not using native browser fullscreen API, we need to check for resizes of viewport
if (!usingNative) {
if (isEnter) {
@ -4874,9 +4994,13 @@ var Listeners = /*#__PURE__*/function () {
if (player.ended) {
_this.proxy(event, player.restart, 'restart');
_this.proxy(event, player.play, 'play');
_this.proxy(event, function () {
silencePromise(player.play());
}, 'play');
} else {
_this.proxy(event, player.togglePlay, 'play');
_this.proxy(event, function () {
silencePromise(player.togglePlay());
}, 'play');
}
});
} // Disable right click
@ -4974,7 +5098,9 @@ var Listeners = /*#__PURE__*/function () {
if (elements.buttons.play) {
Array.from(elements.buttons.play).forEach(function (button) {
_this3.bind(button, 'click', player.togglePlay, 'play');
_this3.bind(button, 'click', function () {
silencePromise(player.togglePlay());
}, 'play');
});
} // Pause
@ -5071,7 +5197,7 @@ var Listeners = /*#__PURE__*/function () {
if (play && done) {
seek.removeAttribute(attribute);
player.play();
silencePromise(player.play());
} else if (!done && player.playing) {
seek.setAttribute(attribute, '');
player.pause();
@ -5169,7 +5295,18 @@ var Listeners = /*#__PURE__*/function () {
this.bind(elements.controls, 'mouseenter mouseleave', function (event) {
elements.controls.hover = !player.touch && event.type === 'mouseenter';
}); // Update controls.pressed state (used for ui.toggleControls to avoid hiding when interacting)
}); // Also update controls.hover state for any non-player children of fullscreen element (as above)
if (elements.fullscreen) {
Array.from(elements.fullscreen.children).filter(function (c) {
return !c.contains(elements.container);
}).forEach(function (child) {
_this3.bind(child, 'mouseenter mouseleave', function (event) {
elements.controls.hover = !player.touch && event.type === 'mouseenter';
});
});
} // Update controls.pressed state (used for ui.toggleControls to avoid hiding when interacting)
this.bind(elements.controls, 'mousedown mouseup touchstart touchend touchcancel', function (event) {
elements.controls.pressed = ['mousedown', 'touchstart'].includes(event.type);
@ -5585,15 +5722,28 @@ var vimeo = {
var _this = this;
var player = this;
var config = player.config.vimeo; // Get Vimeo params for the iframe
var config = player.config.vimeo;
var 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,
autoplay: player.autoplay,
muted: player.muted,
gesture: 'media',
playsinline: !this.config.fullscreen.iosNative
}, config)); // Get the source URL or ID
}, frameParams)); // Get the source URL or ID
var source = player.media.getAttribute('src'); // Get from <div> if needed
@ -5607,22 +5757,27 @@ var vimeo = {
var src = format(player.config.urls.vimeo.iframe, id, params);
iframe.setAttribute('src', src);
iframe.setAttribute('allowfullscreen', '');
iframe.setAttribute('allowtransparency', '');
iframe.setAttribute('allow', 'autoplay'); // Set the referrer policy if required
iframe.setAttribute('allow', 'autoplay,fullscreen,picture-in-picture'); // Set the referrer policy if required
if (!is$1.empty(config.referrerPolicy)) {
iframe.setAttribute('referrerPolicy', config.referrerPolicy);
} // Get poster, if already set
if (!is$1.empty(referrerPolicy)) {
iframe.setAttribute('referrerPolicy', referrerPolicy);
} // Inject the package
var poster = player.poster; // Inject the package
var poster = player.poster;
if (premium) {
iframe.setAttribute('data-poster', poster);
player.media = replaceElement(iframe, player.media);
} else {
var wrapper = createElement('div', {
poster: poster,
class: player.config.classNames.embedContainer
class: player.config.classNames.embedContainer,
'data-poster': poster
});
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) {
if (is$1.empty(response)) {
@ -5706,6 +5861,9 @@ var vimeo = {
player.embed.setPlaybackRate(input).then(function () {
speed = input;
triggerEvent.call(player, player.media, 'ratechange');
}).catch(function () {
// Cannot set Playback Rate, Video is probably not on Pro account
player.options.speed = [1];
});
}
}); // Volume
@ -5992,7 +6150,7 @@ var youtube = {
var container = createElement('div', {
id: id,
poster: poster
'data-poster': poster
});
player.media = replaceElement(container, player.media); // Id to poster wrapper
@ -6311,15 +6469,13 @@ var media = {
class: this.config.classNames.video
}); // Wrap the video in a container
wrap(this.media, this.elements.wrapper); // Faux poster container
wrap(this.media, this.elements.wrapper); // Poster image container
if (this.isEmbed) {
this.elements.poster = createElement('div', {
class: this.config.classNames.poster
});
this.elements.wrapper.appendChild(this.elements.poster);
}
}
if (this.isHTML5) {
html5.setup.call(this);
@ -6445,6 +6601,8 @@ var Ads = /*#__PURE__*/function () {
* mobile devices, this initialization is done as the result of a user action.
*/
value: function setupIMA() {
var _this4 = this;
// Create the container for our advertisements
this.elements.container = createElement('div', {
class: this.player.config.classNames.ads
@ -6457,7 +6615,16 @@ var Ads = /*#__PURE__*/function () {
google.ima.settings.setDisableCustomPlaybackForIOS10Plus(this.player.config.playsinline); // We assume the adContainer is the video container of the plyr element that will house the ads
this.elements.displayContainer = new google.ima.AdDisplayContainer(this.elements.container, this.player.media); // Request video ads to be pre-loaded
this.elements.displayContainer = new google.ima.AdDisplayContainer(this.elements.container, this.player.media); // Create ads loader
this.loader = new google.ima.AdsLoader(this.elements.displayContainer); // Listen and respond to ads loaded and error events
this.loader.addEventListener(google.ima.AdsManagerLoadedEvent.Type.ADS_MANAGER_LOADED, function (event) {
return _this4.onAdsManagerLoaded(event);
}, false);
this.loader.addEventListener(google.ima.AdErrorEvent.Type.AD_ERROR, function (error) {
return _this4.onAdError(error);
}, false); // Request video ads to be pre-loaded
this.requestAds();
}
@ -6468,21 +6635,10 @@ var Ads = /*#__PURE__*/function () {
}, {
key: "requestAds",
value: function requestAds() {
var _this4 = this;
var container = this.player.elements.container;
try {
// Create ads loader
this.loader = new google.ima.AdsLoader(this.elements.displayContainer); // Listen and respond to ads loaded and error events
this.loader.addEventListener(google.ima.AdsManagerLoadedEvent.Type.ADS_MANAGER_LOADED, function (event) {
return _this4.onAdsManagerLoaded(event);
}, false);
this.loader.addEventListener(google.ima.AdErrorEvent.Type.AD_ERROR, function (error) {
return _this4.onAdError(error);
}, false); // Request video ads
// Request video ads
var request = new google.ima.AdsRequest();
request.adTagUrl = this.tagUrl; // Specify the linear and nonlinear slot sizes. This helps the SDK
// to select the correct creative if multiple are returned
@ -6661,7 +6817,13 @@ var Ads = /*#__PURE__*/function () {
// };
// TODO: So there is still this thing where a video should only be allowed to start
// playing when the IMA SDK is ready or has failed
if (this.player.ended) {
this.loadAds();
} else {
// The SDK won't allow new ads to be called without receiving a contentComplete()
this.loader.contentComplete();
}
break;
case google.ima.AdEvent.Type.CONTENT_PAUSE_REQUESTED:
@ -6797,7 +6959,7 @@ var Ads = /*#__PURE__*/function () {
this.playing = false; // Play video
this.player.media.play();
silencePromise(this.player.media.play());
}
/**
* Pause our video
@ -6854,7 +7016,9 @@ var Ads = /*#__PURE__*/function () {
_this11.on('loaded', resolve);
_this11.player.debug.log(_this11.manager);
}); // Now request some new advertisements
}); // Now that the manager has been destroyed set it to also be un-initialized
_this11.initialized = false; // Now request some new advertisements
_this11.requestAds();
}).catch(function () {});
@ -7098,15 +7262,10 @@ var PreviewThumbnails = /*#__PURE__*/function () {
if (is$1.empty(src)) {
throw new Error('Missing previewThumbnails.src config attribute');
} // If string, convert into single-element list
} // Resolve promise
var urls = is$1.string(src) ? [src] : src; // Loop through each src URL. Download and process the VTT file, storing the resulting data in this.thumbnails
var promises = urls.map(function (u) {
return _this2.getThumbnail(u);
});
Promise.all(promises).then(function () {
var sortAndResolve = function sortAndResolve() {
// Sort smallest to biggest (e.g., [120p, 480p, 1080p])
_this2.thumbnails.sort(function (x, y) {
return x.height - y.height;
@ -7115,7 +7274,25 @@ var PreviewThumbnails = /*#__PURE__*/function () {
_this2.player.debug.log('Preview thumbnails', _this2.thumbnails);
resolve();
}; // Via callback()
if (is$1.function(src)) {
src(function (thumbnails) {
_this2.thumbnails = thumbnails;
sortAndResolve();
});
} // VTT urls
else {
// If string, convert into single-element list
var urls = is$1.string(src) ? [src] : src; // Loop through each src URL. Download and process the VTT file, storing the resulting data in this.thumbnails
var promises = urls.map(function (u) {
return _this2.getThumbnail(u);
}); // Resolve
Promise.all(promises).then(sortAndResolve);
}
});
} // Process individual VTT file
@ -7903,6 +8080,7 @@ var Plyr = /*#__PURE__*/function () {
this.elements = {
container: null,
fullscreen: null,
captions: null,
buttons: {},
display: {},
@ -8077,9 +8255,11 @@ var Plyr = /*#__PURE__*/function () {
tabindex: 0
});
wrap(this.media, this.elements.container);
} // Add style hook
} // Migrate custom properties from media to container (so they work 😉)
ui.migrateStyles.call(this); // Add style hook
ui.addStyleHook.call(this); // Setup media
media.setup.call(this); // Listen for events if debugging
@ -8088,10 +8268,12 @@ var Plyr = /*#__PURE__*/function () {
on.call(this, this.elements.container, this.config.events.join(' '), function (event) {
_this.debug.log("event: ".concat(event.type));
});
} // Setup interface
// If embed but not fully supported, build interface now to avoid flash of controls
} // Setup fullscreen
this.fullscreen = new Fullscreen(this); // Setup interface
// If embed but not fully supported, build interface now to avoid flash of controls
if (this.isHTML5 || this.isEmbed && !this.supported.ui) {
ui.build.call(this);
} // Container listeners
@ -8099,9 +8281,7 @@ var Plyr = /*#__PURE__*/function () {
this.listeners.container(); // Global listeners
this.listeners.global(); // Setup fullscreen
this.fullscreen = new Fullscreen(this); // Setup ads if provided
this.listeners.global(); // Setup ads if provided
if (this.config.ads.enabled) {
this.ads = new Ads(this);
@ -8110,7 +8290,7 @@ var Plyr = /*#__PURE__*/function () {
if (this.isHTML5 && this.config.autoplay) {
setTimeout(function () {
return _this.play();
return silencePromise(_this.play());
}, 10);
} // Seek time will be recorded (in listeners.js) so we can prevent hiding controls for a few seconds after seek
@ -8147,7 +8327,7 @@ var Plyr = /*#__PURE__*/function () {
this.ads.managerPromise.then(function () {
return _this2.ads.play();
}).catch(function () {
return _this2.media.play();
return silencePromise(_this2.media.play());
});
} // Return the promise (for HTML5)
@ -8307,7 +8487,7 @@ var Plyr = /*#__PURE__*/function () {
var hiding = toggleClass(this.elements.container, this.config.classNames.hideControls, force); // Close menu
if (hiding && this.config.controls.includes('settings') && !is$1.empty(this.config.settings)) {
if (hiding && is$1.array(this.config.controls) && this.config.controls.includes('settings') && !is$1.empty(this.config.settings)) {
controls.toggleMenu.call(this, false);
} // Trigger event on change
@ -8800,7 +8980,7 @@ var Plyr = /*#__PURE__*/function () {
var updateStorage = true;
if (!options.includes(quality)) {
var value = closest(options, quality);
var value = closest$1(options, quality);
this.debug.warn("Unsupported quality option: ".concat(quality, ", using ").concat(value, " instead"));
quality = value; // Don't update storage if quality is not supported
@ -8945,7 +9125,7 @@ var Plyr = /*#__PURE__*/function () {
return null;
}
return this.media.getAttribute('poster');
return this.media.getAttribute('poster') || this.media.getAttribute('data-poster');
}
/**
* Get the current aspect ratio in use

View File

@ -269,7 +269,7 @@ typeof navigator === "object" && (function (global, factory) {
(module.exports = function (key, value) {
return sharedStore[key] || (sharedStore[key] = value !== undefined ? value : {});
})('versions', []).push({
version: '3.6.4',
version: '3.6.5',
mode: 'global',
copyright: '© 2020 Denis Pushkarev (zloirock.ru)'
});
@ -3061,7 +3061,7 @@ typeof navigator === "object" && (function (global, factory) {
var INVALID_PORT = 'Invalid port';
var ALPHA = /[A-Za-z]/;
var ALPHANUMERIC = /[\d+\-.A-Za-z]/;
var ALPHANUMERIC = /[\d+-.A-Za-z]/;
var DIGIT = /\d/;
var HEX_START = /^(0x|0X)/;
var OCT = /^[0-7]+$/;
@ -4123,20 +4123,52 @@ typeof navigator === "object" && (function (global, factory) {
return target;
}
function _objectWithoutPropertiesLoose(source, excluded) {
if (source == null) return {};
var target = {};
var sourceKeys = Object.keys(source);
var key, i;
for (i = 0; i < sourceKeys.length; i++) {
key = sourceKeys[i];
if (excluded.indexOf(key) >= 0) continue;
target[key] = source[key];
}
return target;
}
function _objectWithoutProperties(source, excluded) {
if (source == null) return {};
var target = _objectWithoutPropertiesLoose(source, excluded);
var key, i;
if (Object.getOwnPropertySymbols) {
var sourceSymbolKeys = Object.getOwnPropertySymbols(source);
for (i = 0; i < sourceSymbolKeys.length; i++) {
key = sourceSymbolKeys[i];
if (excluded.indexOf(key) >= 0) continue;
if (!Object.prototype.propertyIsEnumerable.call(source, key)) continue;
target[key] = source[key];
}
}
return target;
}
function _slicedToArray(arr, i) {
return _arrayWithHoles(arr) || _iterableToArrayLimit(arr, i) || _nonIterableRest();
return _arrayWithHoles(arr) || _iterableToArrayLimit(arr, i) || _unsupportedIterableToArray(arr, i) || _nonIterableRest();
}
function _toConsumableArray(arr) {
return _arrayWithoutHoles(arr) || _iterableToArray(arr) || _nonIterableSpread();
return _arrayWithoutHoles(arr) || _iterableToArray(arr) || _unsupportedIterableToArray(arr) || _nonIterableSpread();
}
function _arrayWithoutHoles(arr) {
if (Array.isArray(arr)) {
for (var i = 0, arr2 = new Array(arr.length); i < arr.length; i++) arr2[i] = arr[i];
return arr2;
}
if (Array.isArray(arr)) return _arrayLikeToArray(arr);
}
function _arrayWithHoles(arr) {
@ -4144,14 +4176,11 @@ typeof navigator === "object" && (function (global, factory) {
}
function _iterableToArray(iter) {
if (Symbol.iterator in Object(iter) || Object.prototype.toString.call(iter) === "[object Arguments]") return Array.from(iter);
if (typeof Symbol !== "undefined" && Symbol.iterator in Object(iter)) return Array.from(iter);
}
function _iterableToArrayLimit(arr, i) {
if (!(Symbol.iterator in Object(arr) || Object.prototype.toString.call(arr) === "[object Arguments]")) {
return;
}
if (typeof Symbol === "undefined" || !(Symbol.iterator in Object(arr))) return;
var _arr = [];
var _n = true;
var _d = false;
@ -4177,12 +4206,29 @@ typeof navigator === "object" && (function (global, factory) {
return _arr;
}
function _unsupportedIterableToArray(o, minLen) {
if (!o) return;
if (typeof o === "string") return _arrayLikeToArray(o, minLen);
var n = Object.prototype.toString.call(o).slice(8, -1);
if (n === "Object" && o.constructor) n = o.constructor.name;
if (n === "Map" || n === "Set") return Array.from(o);
if (n === "Arguments" || /^(?:Ui|I)nt(?:8|16|32)(?:Clamped)?Array$/.test(n)) return _arrayLikeToArray(o, minLen);
}
function _arrayLikeToArray(arr, len) {
if (len == null || len > arr.length) len = arr.length;
for (var i = 0, arr2 = new Array(len); i < len; i++) arr2[i] = arr[i];
return arr2;
}
function _nonIterableSpread() {
throw new TypeError("Invalid attempt to spread non-iterable instance");
throw new TypeError("Invalid attempt to spread non-iterable instance.\nIn order to be iterable, non-array objects must have a [Symbol.iterator]() method.");
}
function _nonIterableRest() {
throw new TypeError("Invalid attempt to destructure non-iterable instance");
throw new TypeError("Invalid attempt to destructure non-iterable instance.\nIn order to be iterable, non-array objects must have a [Symbol.iterator]() method.");
}
(function (global) {
@ -4486,7 +4532,11 @@ typeof navigator === "object" && (function (global, factory) {
anchorElement.href = anchorElement.href; // force href to refresh
}
if (anchorElement.protocol === ':' || !/:/.test(anchorElement.href)) {
var inputElement = doc.createElement('input');
inputElement.type = 'url';
inputElement.value = url;
if (anchorElement.protocol === ':' || !/:/.test(anchorElement.href) || !inputElement.checkValidity() && !base) {
throw new TypeError('Invalid URL');
}
@ -5998,7 +6048,13 @@ typeof navigator === "object" && (function (global, factory) {
defer = functionBindContext(port.postMessage, port, 1);
// Browsers with postMessage, skip WebWorkers
// 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;
global_1.addEventListener('message', listener, false);
// IE8-
@ -6607,7 +6663,7 @@ typeof navigator === "object" && (function (global, factory) {
};
var isPromise = function isPromise(input) {
return instanceOf$1(input, Promise);
return instanceOf$1(input, Promise) && isFunction$1(input.then);
};
var isEmpty$1 = function isEmpty(input) {
@ -6999,12 +7055,33 @@ typeof navigator === "object" && (function (global, factory) {
} // Element matches selector
function matches$1(element, selector) {
var _Element = Element,
prototype = _Element.prototype;
function match() {
return Array.from(document.querySelectorAll(selector)).includes(this);
}
var method = match;
var method = prototype.matches || prototype.webkitMatchesSelector || prototype.mozMatchesSelector || prototype.msMatchesSelector || match;
return method.call(element, selector);
} // Closest ancestor element matching selector (also tests element itself)
function closest(element, selector) {
var _Element2 = Element,
prototype = _Element2.prototype; // https://developer.mozilla.org/en-US/docs/Web/API/Element/closest#Polyfill
function closestElement() {
var el = this;
do {
if (matches$1.matches(el, selector)) return el;
el = el.parentElement || el.parentNode;
} while (el !== null && el.nodeType === 1);
return null;
}
var method = prototype.closest || closestElement;
return method.call(element, selector);
} // Find all elements
@ -7247,7 +7324,7 @@ typeof navigator === "object" && (function (global, factory) {
var event = new CustomEvent(type, {
bubbles: bubbles,
detail: _objectSpread2({}, detail, {
detail: _objectSpread2(_objectSpread2({}, detail), {}, {
plyr: this
})
}); // Dispatch the event
@ -7276,6 +7353,19 @@ typeof navigator === "object" && (function (global, factory) {
}).then(function () {});
}
/**
* Silence a Promise-like object.
* This is useful for avoiding non-harmful, but potentially confusing "uncaught
* play promise" rejection error messages.
* @param {Object} value An object that may or may not be `Promise`-like.
*/
function silencePromise(value) {
if (is$1.promise(value)) {
value.then(null, function () {});
}
}
function validateRatio(input) {
if (!is$1.array(input) && (!is$1.string(input) || !input.includes(':'))) {
return false;
@ -7344,8 +7434,8 @@ typeof navigator === "object" && (function (global, factory) {
var padding = 100 / w * h;
wrapper.style.paddingBottom = "".concat(padding, "%"); // For Vimeo we have an extra <div> to hide the standard controls and UI
if (this.isVimeo && this.supported.ui) {
var height = 240;
if (this.isVimeo && !this.config.vimeo.premium && this.supported.ui) {
var height = 100 / this.media.offsetWidth * parseInt(window.getComputedStyle(this.media).paddingBottom, 10);
var offset = (height - padding) / (height / 50);
this.media.style.transform = "translateY(-".concat(offset, "%)");
} else if (this.isHTML5) {
@ -7451,7 +7541,7 @@ typeof navigator === "object" && (function (global, factory) {
player.currentTime = currentTime; // Resume playing
if (!paused) {
player.play();
silencePromise(player.play());
}
}); // Load new source
@ -7498,7 +7588,7 @@ typeof navigator === "object" && (function (global, factory) {
});
} // Get the closest value in an array
function closest(array, value) {
function closest$1(array, value) {
if (!is$1.array(array) || !array.length) {
return null;
}
@ -7615,19 +7705,19 @@ typeof navigator === "object" && (function (global, factory) {
return (current / max * 100).toFixed(2);
} // Replace all occurances of a string in a string
function replaceAll() {
var replaceAll = function replaceAll() {
var input = arguments.length > 0 && arguments[0] !== undefined ? arguments[0] : '';
var find = arguments.length > 1 && arguments[1] !== undefined ? arguments[1] : '';
var replace = arguments.length > 2 && arguments[2] !== undefined ? arguments[2] : '';
return input.replace(new RegExp(find.toString().replace(/([.*+?^=!:${}()|[\]/\\])/g, '\\$1'), 'g'), replace.toString());
} // Convert to title case
}; // Convert to title case
function toTitleCase() {
var toTitleCase = function toTitleCase() {
var input = arguments.length > 0 && arguments[0] !== undefined ? arguments[0] : '';
return input.toString().replace(/\w\S*/g, function (text) {
return text.charAt(0).toUpperCase() + text.substr(1).toLowerCase();
});
} // Convert string to pascalCase
}; // Convert string to pascalCase
function toPascalCase() {
var input = arguments.length > 0 && arguments[0] !== undefined ? arguments[0] : '';
@ -7997,7 +8087,7 @@ typeof navigator === "object" && (function (global, factory) {
var icon = document.createElementNS(namespace, 'svg');
setAttributes(icon, extend(attributes, {
role: 'presentation',
'aria-hidden': 'true',
focusable: 'false'
})); // Create the <use> to reference sprite
@ -8021,7 +8111,7 @@ typeof navigator === "object" && (function (global, factory) {
var attr = arguments.length > 1 && arguments[1] !== undefined ? arguments[1] : {};
var text = i18n.get(key, this.config);
var attributes = _objectSpread2({}, attr, {
var attributes = _objectSpread2(_objectSpread2({}, attr), {}, {
class: [attr.class, this.config.classNames.hidden].filter(Boolean).join(' ')
});
@ -8780,7 +8870,7 @@ typeof navigator === "object" && (function (global, factory) {
var type = 'captions';
var list = this.elements.settings.panels.captions.querySelector('[role="menu"]');
var list = this.elements.settings.panels.captions.querySelector('[role="menucaptions"]');
var tracks = captions.getTracks.call(this);
var toggle = Boolean(tracks.length); // Toggle the pane and tab
@ -9021,7 +9111,7 @@ typeof navigator === "object" && (function (global, factory) {
showMenuPanel = controls.showMenuPanel;
this.elements.controls = null; // Larger overlaid play button
if (this.config.controls.includes('play-large')) {
if (is$1.array(this.config.controls) && this.config.controls.includes('play-large')) {
this.elements.container.appendChild(createButton.call(this, 'play-large'));
} // Create the container
@ -9033,7 +9123,7 @@ typeof navigator === "object" && (function (global, factory) {
class: 'plyr__controls__item'
}; // Loop through controls in order
dedupe(this.config.controls).forEach(function (control) {
dedupe(is$1.array(this.config.controls) ? this.config.controls : []).forEach(function (control) {
// Restart button
if (control === 'restart') {
container.appendChild(createButton.call(_this10, 'restart', defaultAttributes));
@ -9222,6 +9312,10 @@ typeof navigator === "object" && (function (global, factory) {
pane.appendChild(createElement('div', {
role: 'menu'
})); // Menu Captions
pane.appendChild(createElement('div', {
role: 'menucaptions'
}));
inner.appendChild(pane);
_this10.elements.settings.buttons[type] = menuItem;
@ -9352,8 +9446,6 @@ typeof navigator === "object" && (function (global, factory) {
if (update) {
if (is$1.string(this.config.controls)) {
container = replace(container);
} else if (is$1.element(container)) {
container.innerHTML = replace(container.innerHTML);
}
} // Controls container
@ -9568,9 +9660,15 @@ typeof navigator === "object" && (function (global, factory) {
meta.set(track, {
default: track.mode === 'showing'
}); // Turn off native caption rendering to avoid double captions
// Note: mode='hidden' forces a track to download. To ensure every track
// isn't downloaded at once, only 'showing' tracks should be reassigned
// eslint-disable-next-line no-param-reassign
track.mode = 'hidden'; // Add event listener for cue changes
if (track.mode === 'showing') {
// eslint-disable-next-line no-param-reassign
track.mode = 'hidden';
} // Add event listener for cue changes
on.call(_this, track, 'cuechange', function () {
return captions.updateCues.call(_this);
@ -9587,13 +9685,15 @@ typeof navigator === "object" && (function (global, factory) {
toggleClass(this.elements.container, this.config.classNames.captions.enabled, !is$1.empty(tracks)); // Update available languages in list
if ((this.config.controls || []).includes('settings') && this.config.settings.includes('captions')) {
if (is$1.array(this.config.controls) && this.config.controls.includes('settings') && this.config.settings.includes('captions')) {
controls.setCaptionsMenu.call(this);
}
},
// Toggle captions display
// Used internally for the toggleCaptions method, with the passive option forced to false
toggle: function toggle(input) {
var _this2 = this;
var passive = arguments.length > 1 && arguments[1] !== undefined ? arguments[1] : true;
// If there's no full support
@ -9640,7 +9740,15 @@ typeof navigator === "object" && (function (global, factory) {
controls.updateSetting.call(this, 'captions'); // Trigger event (not used internally)
triggerEvent.call(this, this.media, active ? 'captionsenabled' : 'captionsdisabled');
} // Wait for the call stack to clear before setting mode='hidden'
// on the active track - forcing the browser to download it
setTimeout(function () {
if (active && _this2.captions.toggled) {
_this2.captions.currentTrackNode.mode = 'hidden';
}
});
},
// Set captions by track index
// Used internally for the currentTrack setter with the passive option forced to false
@ -9721,7 +9829,7 @@ typeof navigator === "object" && (function (global, factory) {
// If update is false it will also ignore tracks without metadata
// This is used to "freeze" the language options when captions.update is false
getTracks: function getTracks() {
var _this2 = this;
var _this3 = this;
var update = arguments.length > 0 && arguments[0] !== undefined ? arguments[0] : false;
// Handle media or textTracks missing or null
@ -9729,20 +9837,20 @@ typeof navigator === "object" && (function (global, factory) {
// Filter out removed tracks and tracks that aren't captions/subtitles (for example metadata)
return tracks.filter(function (track) {
return !_this2.isHTML5 || update || _this2.captions.meta.has(track);
return !_this3.isHTML5 || update || _this3.captions.meta.has(track);
}).filter(function (track) {
return ['captions', 'subtitles'].includes(track.kind);
});
},
// Match tracks based on languages and get the first
findTrack: function findTrack(languages) {
var _this3 = this;
var _this4 = this;
var force = arguments.length > 1 && arguments[1] !== undefined ? arguments[1] : false;
var tracks = captions.getTracks.call(this);
var sortIsDefault = function sortIsDefault(track) {
return Number((_this3.captions.meta.get(track) || {}).default);
return Number((_this4.captions.meta.get(track) || {}).default);
};
var sorted = Array.from(tracks).sort(function (a, b) {
@ -9923,6 +10031,9 @@ typeof navigator === "object" && (function (global, factory) {
fallback: true,
// Fallback using full viewport/window
iosNative: false // Use the native fullscreen in iOS (disables custom controls)
// Selector for the fullscreen container so contextual / non-player content can remain visible in fullscreen mode
// Non-ancestors of the player element will be ignored
// container: null, // defaults to the player element
},
// Local storage
@ -10160,16 +10271,16 @@ typeof navigator === "object" && (function (global, factory) {
title: false,
speed: true,
transparent: false,
// These settings require a pro or premium account to work
sidedock: false,
controls: false,
// Whether the owner of the video has a Pro or Business account
// (which allows us to properly hide controls without CSS hacks, etc)
premium: false,
// Custom settings from Plyr
referrerPolicy: null // https://developer.mozilla.org/en-US/docs/Web/API/HTMLIFrameElement/referrerPolicy
},
// YouTube plugin
youtube: {
noCookie: false,
noCookie: true,
// Whether to use an alternative version of YouTube without cookies
rel: 0,
// No related vids
@ -10279,7 +10390,10 @@ typeof navigator === "object" && (function (global, factory) {
y: 0
}; // Force the use of 'full window/browser' rather than fullscreen
this.forceFallback = player.config.fullscreen.fallback === 'force'; // Register event listeners
this.forceFallback = player.config.fullscreen.fallback === 'force'; // Get the fullscreen element
// Checks container is an ancestor, defaults to null
this.player.elements.fullscreen = player.config.fullscreen.container && closest(this.player.elements.container, player.config.fullscreen.container); // Register event listeners
// Handle event (incase user presses escape etc)
on.call(this.player, document, this.prefix === 'ms' ? 'MSFullscreenChange' : "".concat(this.prefix, "fullscreenchange"), function () {
@ -10452,7 +10566,7 @@ typeof navigator === "object" && (function (global, factory) {
if (browser.isIos && this.player.config.fullscreen.iosNative) {
this.target.webkitExitFullscreen();
this.player.play();
silencePromise(this.player.play());
} else if (!Fullscreen.native || this.forceFallback) {
this.toggleFallback(false);
} else if (!this.prefix) {
@ -10499,13 +10613,13 @@ typeof navigator === "object" && (function (global, factory) {
}
var element = !this.prefix ? document.fullscreenElement : document["".concat(this.prefix).concat(this.property, "Element")];
return element === this.target;
return element && element.shadowRoot ? element === this.target.getRootNode().host : element === this.target;
} // Get target element
}, {
key: "target",
get: function get() {
return browser.isIos && this.player.config.fullscreen.iosNative ? this.player.media : this.player.elements.container;
return browser.isIos && this.player.config.fullscreen.iosNative ? this.player.media : this.player.elements.fullscreen || this.player.elements.container;
}
}], [{
key: "native",
@ -10714,12 +10828,7 @@ typeof navigator === "object" && (function (global, factory) {
} // Set property synchronously to respect the call order
this.media.setAttribute('poster', poster); // HTML5 uses native poster attribute
if (this.isHTML5) {
return Promise.resolve(poster);
} // Wait until ui is ready
this.media.setAttribute('data-poster', poster); // Wait until ui is ready
return ready.call(this) // Load image
.then(function () {
@ -10795,6 +10904,26 @@ typeof navigator === "object" && (function (global, factory) {
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 !is$1.empty(key) && 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');
}
}
};
@ -10889,7 +11018,7 @@ typeof navigator === "object" && (function (global, factory) {
case 75:
// Space and K key
if (!repeat) {
player.togglePlay();
silencePromise(player.togglePlay());
}
break;
@ -11003,6 +11132,7 @@ typeof navigator === "object" && (function (global, factory) {
removeCurrent(); // Delay the adding of classname until the focus has changed
// This event fires before the focusin event
if (event.type !== 'focusout') {
this.focusTimer = setTimeout(function () {
var focused = document.activeElement; // Ignore if current focus element isn't inside the player
@ -11012,6 +11142,7 @@ typeof navigator === "object" && (function (global, factory) {
toggleClass(document.activeElement, player.config.classNames.tabFocus, true);
}, 10);
}
} // Global window & document listeners
}, {
@ -11029,7 +11160,7 @@ typeof navigator === "object" && (function (global, factory) {
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
}, {
@ -11072,7 +11203,7 @@ typeof navigator === "object" && (function (global, factory) {
}); // Set a gutter for Vimeo
var setGutter = function setGutter(ratio, padding, toggle) {
if (!player.isVimeo) {
if (!player.isVimeo || player.config.vimeo.premium) {
return;
}
@ -11129,7 +11260,7 @@ typeof navigator === "object" && (function (global, factory) {
ratio = _setPlayerSize.ratio; // Set Vimeo gutter
setGutter(ratio, padding, isEnter); // If not using native fullscreen, we need to check for resizes of viewport
setGutter(ratio, padding, isEnter); // If not using native browser fullscreen API, we need to check for resizes of viewport
if (!usingNative) {
if (isEnter) {
@ -11207,9 +11338,13 @@ typeof navigator === "object" && (function (global, factory) {
if (player.ended) {
_this.proxy(event, player.restart, 'restart');
_this.proxy(event, player.play, 'play');
_this.proxy(event, function () {
silencePromise(player.play());
}, 'play');
} else {
_this.proxy(event, player.togglePlay, 'play');
_this.proxy(event, function () {
silencePromise(player.togglePlay());
}, 'play');
}
});
} // Disable right click
@ -11307,7 +11442,9 @@ typeof navigator === "object" && (function (global, factory) {
if (elements.buttons.play) {
Array.from(elements.buttons.play).forEach(function (button) {
_this3.bind(button, 'click', player.togglePlay, 'play');
_this3.bind(button, 'click', function () {
silencePromise(player.togglePlay());
}, 'play');
});
} // Pause
@ -11404,7 +11541,7 @@ typeof navigator === "object" && (function (global, factory) {
if (play && done) {
seek.removeAttribute(attribute);
player.play();
silencePromise(player.play());
} else if (!done && player.playing) {
seek.setAttribute(attribute, '');
player.pause();
@ -11502,7 +11639,18 @@ typeof navigator === "object" && (function (global, factory) {
this.bind(elements.controls, 'mouseenter mouseleave', function (event) {
elements.controls.hover = !player.touch && event.type === 'mouseenter';
}); // Update controls.pressed state (used for ui.toggleControls to avoid hiding when interacting)
}); // Also update controls.hover state for any non-player children of fullscreen element (as above)
if (elements.fullscreen) {
Array.from(elements.fullscreen.children).filter(function (c) {
return !c.contains(elements.container);
}).forEach(function (child) {
_this3.bind(child, 'mouseenter mouseleave', function (event) {
elements.controls.hover = !player.touch && event.type === 'mouseenter';
});
});
} // Update controls.pressed state (used for ui.toggleControls to avoid hiding when interacting)
this.bind(elements.controls, 'mousedown mouseup touchstart touchend touchcancel', function (event) {
elements.controls.pressed = ['mousedown', 'touchstart'].includes(event.type);
@ -11971,15 +12119,28 @@ typeof navigator === "object" && (function (global, factory) {
var _this = 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,
autoplay: player.autoplay,
muted: player.muted,
gesture: 'media',
playsinline: !this.config.fullscreen.iosNative
}, config)); // Get the source URL or ID
}, frameParams)); // Get the source URL or ID
var source = player.media.getAttribute('src'); // Get from <div> if needed
@ -11993,22 +12154,27 @@ typeof navigator === "object" && (function (global, factory) {
var src = format(player.config.urls.vimeo.iframe, id, params);
iframe.setAttribute('src', src);
iframe.setAttribute('allowfullscreen', '');
iframe.setAttribute('allowtransparency', '');
iframe.setAttribute('allow', 'autoplay'); // Set the referrer policy if required
iframe.setAttribute('allow', 'autoplay,fullscreen,picture-in-picture'); // Set the referrer policy if required
if (!is$1.empty(config.referrerPolicy)) {
iframe.setAttribute('referrerPolicy', config.referrerPolicy);
} // Get poster, if already set
if (!is$1.empty(referrerPolicy)) {
iframe.setAttribute('referrerPolicy', referrerPolicy);
} // Inject the package
var poster = player.poster; // Inject the package
var poster = player.poster;
if (premium) {
iframe.setAttribute('data-poster', poster);
player.media = replaceElement(iframe, player.media);
} else {
var wrapper = createElement('div', {
poster: poster,
class: player.config.classNames.embedContainer
class: player.config.classNames.embedContainer,
'data-poster': poster
});
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) {
if (is$1.empty(response)) {
@ -12092,6 +12258,9 @@ typeof navigator === "object" && (function (global, factory) {
player.embed.setPlaybackRate(input).then(function () {
speed = input;
triggerEvent.call(player, player.media, 'ratechange');
}).catch(function () {
// Cannot set Playback Rate, Video is probably not on Pro account
player.options.speed = [1];
});
}
}); // Volume
@ -12376,7 +12545,7 @@ typeof navigator === "object" && (function (global, factory) {
var container = createElement('div', {
id: id,
poster: poster
'data-poster': poster
});
player.media = replaceElement(container, player.media); // Id to poster wrapper
@ -12694,15 +12863,13 @@ typeof navigator === "object" && (function (global, factory) {
class: this.config.classNames.video
}); // 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', {
class: this.config.classNames.poster
});
this.elements.wrapper.appendChild(this.elements.poster);
}
}
if (this.isHTML5) {
html5.setup.call(this);
@ -12828,6 +12995,8 @@ typeof navigator === "object" && (function (global, factory) {
* mobile devices, this initialization is done as the result of a user action.
*/
value: function setupIMA() {
var _this4 = this;
// Create the container for our advertisements
this.elements.container = createElement('div', {
class: this.player.config.classNames.ads
@ -12840,7 +13009,16 @@ typeof navigator === "object" && (function (global, factory) {
google.ima.settings.setDisableCustomPlaybackForIOS10Plus(this.player.config.playsinline); // We assume the adContainer is the video container of the plyr element that will house the ads
this.elements.displayContainer = new google.ima.AdDisplayContainer(this.elements.container, this.player.media); // Request video ads to be pre-loaded
this.elements.displayContainer = new google.ima.AdDisplayContainer(this.elements.container, this.player.media); // Create ads loader
this.loader = new google.ima.AdsLoader(this.elements.displayContainer); // Listen and respond to ads loaded and error events
this.loader.addEventListener(google.ima.AdsManagerLoadedEvent.Type.ADS_MANAGER_LOADED, function (event) {
return _this4.onAdsManagerLoaded(event);
}, false);
this.loader.addEventListener(google.ima.AdErrorEvent.Type.AD_ERROR, function (error) {
return _this4.onAdError(error);
}, false); // Request video ads to be pre-loaded
this.requestAds();
}
@ -12851,21 +13029,10 @@ typeof navigator === "object" && (function (global, factory) {
}, {
key: "requestAds",
value: function requestAds() {
var _this4 = this;
var container = this.player.elements.container;
try {
// Create ads loader
this.loader = new google.ima.AdsLoader(this.elements.displayContainer); // Listen and respond to ads loaded and error events
this.loader.addEventListener(google.ima.AdsManagerLoadedEvent.Type.ADS_MANAGER_LOADED, function (event) {
return _this4.onAdsManagerLoaded(event);
}, false);
this.loader.addEventListener(google.ima.AdErrorEvent.Type.AD_ERROR, function (error) {
return _this4.onAdError(error);
}, false); // Request video ads
// Request video ads
var request = new google.ima.AdsRequest();
request.adTagUrl = this.tagUrl; // Specify the linear and nonlinear slot sizes. This helps the SDK
// to select the correct creative if multiple are returned
@ -13044,7 +13211,13 @@ typeof navigator === "object" && (function (global, factory) {
// };
// TODO: So there is still this thing where a video should only be allowed to start
// playing when the IMA SDK is ready or has failed
if (this.player.ended) {
this.loadAds();
} else {
// The SDK won't allow new ads to be called without receiving a contentComplete()
this.loader.contentComplete();
}
break;
case google.ima.AdEvent.Type.CONTENT_PAUSE_REQUESTED:
@ -13180,7 +13353,7 @@ typeof navigator === "object" && (function (global, factory) {
this.playing = false; // Play video
this.player.media.play();
silencePromise(this.player.media.play());
}
/**
* Pause our video
@ -13237,7 +13410,9 @@ typeof navigator === "object" && (function (global, factory) {
_this11.on('loaded', resolve);
_this11.player.debug.log(_this11.manager);
}); // Now request some new advertisements
}); // Now that the manager has been destroyed set it to also be un-initialized
_this11.initialized = false; // Now request some new advertisements
_this11.requestAds();
}).catch(function () {});
@ -13532,15 +13707,10 @@ typeof navigator === "object" && (function (global, factory) {
if (is$1.empty(src)) {
throw new Error('Missing previewThumbnails.src config attribute');
} // If string, convert into single-element list
} // Resolve promise
var urls = is$1.string(src) ? [src] : src; // Loop through each src URL. Download and process the VTT file, storing the resulting data in this.thumbnails
var promises = urls.map(function (u) {
return _this2.getThumbnail(u);
});
Promise.all(promises).then(function () {
var sortAndResolve = function sortAndResolve() {
// Sort smallest to biggest (e.g., [120p, 480p, 1080p])
_this2.thumbnails.sort(function (x, y) {
return x.height - y.height;
@ -13549,7 +13719,25 @@ typeof navigator === "object" && (function (global, factory) {
_this2.player.debug.log('Preview thumbnails', _this2.thumbnails);
resolve();
}; // Via callback()
if (is$1.function(src)) {
src(function (thumbnails) {
_this2.thumbnails = thumbnails;
sortAndResolve();
});
} // VTT urls
else {
// If string, convert into single-element list
var urls = is$1.string(src) ? [src] : src; // Loop through each src URL. Download and process the VTT file, storing the resulting data in this.thumbnails
var promises = urls.map(function (u) {
return _this2.getThumbnail(u);
}); // Resolve
Promise.all(promises).then(sortAndResolve);
}
});
} // Process individual VTT file
@ -14337,6 +14525,7 @@ typeof navigator === "object" && (function (global, factory) {
this.elements = {
container: null,
fullscreen: null,
captions: null,
buttons: {},
display: {},
@ -14511,9 +14700,11 @@ typeof navigator === "object" && (function (global, factory) {
tabindex: 0
});
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
media.setup.call(this); // Listen for events if debugging
@ -14522,10 +14713,12 @@ typeof navigator === "object" && (function (global, factory) {
on.call(this, this.elements.container, this.config.events.join(' '), function (event) {
_this.debug.log("event: ".concat(event.type));
});
} // Setup interface
// If embed but not fully supported, build interface now to avoid flash of controls
} // Setup fullscreen
this.fullscreen = new Fullscreen(this); // Setup interface
// If embed but not fully supported, build interface now to avoid flash of controls
if (this.isHTML5 || this.isEmbed && !this.supported.ui) {
ui.build.call(this);
} // Container listeners
@ -14533,9 +14726,7 @@ typeof navigator === "object" && (function (global, factory) {
this.listeners.container(); // Global listeners
this.listeners.global(); // Setup fullscreen
this.fullscreen = new Fullscreen(this); // Setup ads if provided
this.listeners.global(); // Setup ads if provided
if (this.config.ads.enabled) {
this.ads = new Ads(this);
@ -14544,7 +14735,7 @@ typeof navigator === "object" && (function (global, factory) {
if (this.isHTML5 && this.config.autoplay) {
setTimeout(function () {
return _this.play();
return silencePromise(_this.play());
}, 10);
} // Seek time will be recorded (in listeners.js) so we can prevent hiding controls for a few seconds after seek
@ -14581,7 +14772,7 @@ typeof navigator === "object" && (function (global, factory) {
this.ads.managerPromise.then(function () {
return _this2.ads.play();
}).catch(function () {
return _this2.media.play();
return silencePromise(_this2.media.play());
});
} // Return the promise (for HTML5)
@ -14741,7 +14932,7 @@ typeof navigator === "object" && (function (global, factory) {
var hiding = toggleClass(this.elements.container, this.config.classNames.hideControls, force); // Close menu
if (hiding && this.config.controls.includes('settings') && !is$1.empty(this.config.settings)) {
if (hiding && is$1.array(this.config.controls) && this.config.controls.includes('settings') && !is$1.empty(this.config.settings)) {
controls.toggleMenu.call(this, false);
} // Trigger event on change
@ -15234,7 +15425,7 @@ typeof navigator === "object" && (function (global, factory) {
var updateStorage = true;
if (!options.includes(quality)) {
var value = closest(options, quality);
var value = closest$1(options, quality);
this.debug.warn("Unsupported quality option: ".concat(quality, ", using ").concat(value, " instead"));
quality = value; // Don't update storage if quality is not supported
@ -15379,7 +15570,7 @@ typeof navigator === "object" && (function (global, factory) {
return null;
}
return this.media.getAttribute('poster');
return this.media.getAttribute('poster') || this.media.getAttribute('data-poster');
}
/**
* 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) {
return sharedStore[key] || (sharedStore[key] = value !== undefined ? value : {});
})('versions', []).push({
version: '3.6.4',
version: '3.6.5',
mode: 'global',
copyright: '© 2020 Denis Pushkarev (zloirock.ru)'
});
@ -3055,7 +3055,7 @@ var INVALID_HOST = 'Invalid host';
var INVALID_PORT = 'Invalid port';
var ALPHA = /[A-Za-z]/;
var ALPHANUMERIC = /[\d+\-.A-Za-z]/;
var ALPHANUMERIC = /[\d+-.A-Za-z]/;
var DIGIT = /\d/;
var HEX_START = /^(0x|0X)/;
var OCT = /^[0-7]+$/;
@ -4117,20 +4117,52 @@ function _objectSpread2(target) {
return target;
}
function _objectWithoutPropertiesLoose(source, excluded) {
if (source == null) return {};
var target = {};
var sourceKeys = Object.keys(source);
var key, i;
for (i = 0; i < sourceKeys.length; i++) {
key = sourceKeys[i];
if (excluded.indexOf(key) >= 0) continue;
target[key] = source[key];
}
return target;
}
function _objectWithoutProperties(source, excluded) {
if (source == null) return {};
var target = _objectWithoutPropertiesLoose(source, excluded);
var key, i;
if (Object.getOwnPropertySymbols) {
var sourceSymbolKeys = Object.getOwnPropertySymbols(source);
for (i = 0; i < sourceSymbolKeys.length; i++) {
key = sourceSymbolKeys[i];
if (excluded.indexOf(key) >= 0) continue;
if (!Object.prototype.propertyIsEnumerable.call(source, key)) continue;
target[key] = source[key];
}
}
return target;
}
function _slicedToArray(arr, i) {
return _arrayWithHoles(arr) || _iterableToArrayLimit(arr, i) || _nonIterableRest();
return _arrayWithHoles(arr) || _iterableToArrayLimit(arr, i) || _unsupportedIterableToArray(arr, i) || _nonIterableRest();
}
function _toConsumableArray(arr) {
return _arrayWithoutHoles(arr) || _iterableToArray(arr) || _nonIterableSpread();
return _arrayWithoutHoles(arr) || _iterableToArray(arr) || _unsupportedIterableToArray(arr) || _nonIterableSpread();
}
function _arrayWithoutHoles(arr) {
if (Array.isArray(arr)) {
for (var i = 0, arr2 = new Array(arr.length); i < arr.length; i++) arr2[i] = arr[i];
return arr2;
}
if (Array.isArray(arr)) return _arrayLikeToArray(arr);
}
function _arrayWithHoles(arr) {
@ -4138,14 +4170,11 @@ function _arrayWithHoles(arr) {
}
function _iterableToArray(iter) {
if (Symbol.iterator in Object(iter) || Object.prototype.toString.call(iter) === "[object Arguments]") return Array.from(iter);
if (typeof Symbol !== "undefined" && Symbol.iterator in Object(iter)) return Array.from(iter);
}
function _iterableToArrayLimit(arr, i) {
if (!(Symbol.iterator in Object(arr) || Object.prototype.toString.call(arr) === "[object Arguments]")) {
return;
}
if (typeof Symbol === "undefined" || !(Symbol.iterator in Object(arr))) return;
var _arr = [];
var _n = true;
var _d = false;
@ -4171,12 +4200,29 @@ function _iterableToArrayLimit(arr, i) {
return _arr;
}
function _unsupportedIterableToArray(o, minLen) {
if (!o) return;
if (typeof o === "string") return _arrayLikeToArray(o, minLen);
var n = Object.prototype.toString.call(o).slice(8, -1);
if (n === "Object" && o.constructor) n = o.constructor.name;
if (n === "Map" || n === "Set") return Array.from(o);
if (n === "Arguments" || /^(?:Ui|I)nt(?:8|16|32)(?:Clamped)?Array$/.test(n)) return _arrayLikeToArray(o, minLen);
}
function _arrayLikeToArray(arr, len) {
if (len == null || len > arr.length) len = arr.length;
for (var i = 0, arr2 = new Array(len); i < len; i++) arr2[i] = arr[i];
return arr2;
}
function _nonIterableSpread() {
throw new TypeError("Invalid attempt to spread non-iterable instance");
throw new TypeError("Invalid attempt to spread non-iterable instance.\nIn order to be iterable, non-array objects must have a [Symbol.iterator]() method.");
}
function _nonIterableRest() {
throw new TypeError("Invalid attempt to destructure non-iterable instance");
throw new TypeError("Invalid attempt to destructure non-iterable instance.\nIn order to be iterable, non-array objects must have a [Symbol.iterator]() method.");
}
(function (global) {
@ -4480,7 +4526,11 @@ function _nonIterableRest() {
anchorElement.href = anchorElement.href; // force href to refresh
}
if (anchorElement.protocol === ':' || !/:/.test(anchorElement.href)) {
var inputElement = doc.createElement('input');
inputElement.type = 'url';
inputElement.value = url;
if (anchorElement.protocol === ':' || !/:/.test(anchorElement.href) || !inputElement.checkValidity() && !base) {
throw new TypeError('Invalid URL');
}
@ -5992,7 +6042,13 @@ if (!set$1 || !clear) {
defer = functionBindContext(port.postMessage, port, 1);
// Browsers with postMessage, skip WebWorkers
// 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;
global_1.addEventListener('message', listener, false);
// IE8-
@ -6601,7 +6657,7 @@ var isTrack = function isTrack(input) {
};
var isPromise = function isPromise(input) {
return instanceOf$1(input, Promise);
return instanceOf$1(input, Promise) && isFunction$1(input.then);
};
var isEmpty$1 = function isEmpty(input) {
@ -6993,12 +7049,33 @@ function hasClass(element, className) {
} // Element matches selector
function matches$1(element, selector) {
var _Element = Element,
prototype = _Element.prototype;
function match() {
return Array.from(document.querySelectorAll(selector)).includes(this);
}
var method = match;
var method = prototype.matches || prototype.webkitMatchesSelector || prototype.mozMatchesSelector || prototype.msMatchesSelector || match;
return method.call(element, selector);
} // Closest ancestor element matching selector (also tests element itself)
function closest(element, selector) {
var _Element2 = Element,
prototype = _Element2.prototype; // https://developer.mozilla.org/en-US/docs/Web/API/Element/closest#Polyfill
function closestElement() {
var el = this;
do {
if (matches$1.matches(el, selector)) return el;
el = el.parentElement || el.parentNode;
} while (el !== null && el.nodeType === 1);
return null;
}
var method = prototype.closest || closestElement;
return method.call(element, selector);
} // Find all elements
@ -7241,7 +7318,7 @@ function triggerEvent(element) {
var event = new CustomEvent(type, {
bubbles: bubbles,
detail: _objectSpread2({}, detail, {
detail: _objectSpread2(_objectSpread2({}, detail), {}, {
plyr: this
})
}); // Dispatch the event
@ -7270,6 +7347,19 @@ function ready() {
}).then(function () {});
}
/**
* Silence a Promise-like object.
* This is useful for avoiding non-harmful, but potentially confusing "uncaught
* play promise" rejection error messages.
* @param {Object} value An object that may or may not be `Promise`-like.
*/
function silencePromise(value) {
if (is$1.promise(value)) {
value.then(null, function () {});
}
}
function validateRatio(input) {
if (!is$1.array(input) && (!is$1.string(input) || !input.includes(':'))) {
return false;
@ -7338,8 +7428,8 @@ function setAspectRatio(input) {
var padding = 100 / w * h;
wrapper.style.paddingBottom = "".concat(padding, "%"); // For Vimeo we have an extra <div> to hide the standard controls and UI
if (this.isVimeo && this.supported.ui) {
var height = 240;
if (this.isVimeo && !this.config.vimeo.premium && this.supported.ui) {
var height = 100 / this.media.offsetWidth * parseInt(window.getComputedStyle(this.media).paddingBottom, 10);
var offset = (height - padding) / (height / 50);
this.media.style.transform = "translateY(-".concat(offset, "%)");
} else if (this.isHTML5) {
@ -7445,7 +7535,7 @@ var html5 = {
player.currentTime = currentTime; // Resume playing
if (!paused) {
player.play();
silencePromise(player.play());
}
}); // Load new source
@ -7492,7 +7582,7 @@ function dedupe(array) {
});
} // Get the closest value in an array
function closest(array, value) {
function closest$1(array, value) {
if (!is$1.array(array) || !array.length) {
return null;
}
@ -7609,19 +7699,19 @@ function getPercentage(current, max) {
return (current / max * 100).toFixed(2);
} // Replace all occurances of a string in a string
function replaceAll() {
var replaceAll = function replaceAll() {
var input = arguments.length > 0 && arguments[0] !== undefined ? arguments[0] : '';
var find = arguments.length > 1 && arguments[1] !== undefined ? arguments[1] : '';
var replace = arguments.length > 2 && arguments[2] !== undefined ? arguments[2] : '';
return input.replace(new RegExp(find.toString().replace(/([.*+?^=!:${}()|[\]/\\])/g, '\\$1'), 'g'), replace.toString());
} // Convert to title case
}; // Convert to title case
function toTitleCase() {
var toTitleCase = function toTitleCase() {
var input = arguments.length > 0 && arguments[0] !== undefined ? arguments[0] : '';
return input.toString().replace(/\w\S*/g, function (text) {
return text.charAt(0).toUpperCase() + text.substr(1).toLowerCase();
});
} // Convert string to pascalCase
}; // Convert string to pascalCase
function toPascalCase() {
var input = arguments.length > 0 && arguments[0] !== undefined ? arguments[0] : '';
@ -7991,7 +8081,7 @@ var controls = {
var icon = document.createElementNS(namespace, 'svg');
setAttributes(icon, extend(attributes, {
role: 'presentation',
'aria-hidden': 'true',
focusable: 'false'
})); // Create the <use> to reference sprite
@ -8015,7 +8105,7 @@ var controls = {
var attr = arguments.length > 1 && arguments[1] !== undefined ? arguments[1] : {};
var text = i18n.get(key, this.config);
var attributes = _objectSpread2({}, attr, {
var attributes = _objectSpread2(_objectSpread2({}, attr), {}, {
class: [attr.class, this.config.classNames.hidden].filter(Boolean).join(' ')
});
@ -8774,7 +8864,7 @@ var controls = {
var type = 'captions';
var list = this.elements.settings.panels.captions.querySelector('[role="menu"]');
var list = this.elements.settings.panels.captions.querySelector('[role="menucaptions"]');
var tracks = captions.getTracks.call(this);
var toggle = Boolean(tracks.length); // Toggle the pane and tab
@ -9015,7 +9105,7 @@ var controls = {
showMenuPanel = controls.showMenuPanel;
this.elements.controls = null; // Larger overlaid play button
if (this.config.controls.includes('play-large')) {
if (is$1.array(this.config.controls) && this.config.controls.includes('play-large')) {
this.elements.container.appendChild(createButton.call(this, 'play-large'));
} // Create the container
@ -9027,7 +9117,7 @@ var controls = {
class: 'plyr__controls__item'
}; // Loop through controls in order
dedupe(this.config.controls).forEach(function (control) {
dedupe(is$1.array(this.config.controls) ? this.config.controls : []).forEach(function (control) {
// Restart button
if (control === 'restart') {
container.appendChild(createButton.call(_this10, 'restart', defaultAttributes));
@ -9216,6 +9306,10 @@ var controls = {
pane.appendChild(createElement('div', {
role: 'menu'
})); // Menu Captions
pane.appendChild(createElement('div', {
role: 'menucaptions'
}));
inner.appendChild(pane);
_this10.elements.settings.buttons[type] = menuItem;
@ -9346,8 +9440,6 @@ var controls = {
if (update) {
if (is$1.string(this.config.controls)) {
container = replace(container);
} else if (is$1.element(container)) {
container.innerHTML = replace(container.innerHTML);
}
} // Controls container
@ -9562,9 +9654,15 @@ var captions = {
meta.set(track, {
default: track.mode === 'showing'
}); // Turn off native caption rendering to avoid double captions
// Note: mode='hidden' forces a track to download. To ensure every track
// isn't downloaded at once, only 'showing' tracks should be reassigned
// eslint-disable-next-line no-param-reassign
track.mode = 'hidden'; // Add event listener for cue changes
if (track.mode === 'showing') {
// eslint-disable-next-line no-param-reassign
track.mode = 'hidden';
} // Add event listener for cue changes
on.call(_this, track, 'cuechange', function () {
return captions.updateCues.call(_this);
@ -9581,13 +9679,15 @@ var captions = {
toggleClass(this.elements.container, this.config.classNames.captions.enabled, !is$1.empty(tracks)); // Update available languages in list
if ((this.config.controls || []).includes('settings') && this.config.settings.includes('captions')) {
if (is$1.array(this.config.controls) && this.config.controls.includes('settings') && this.config.settings.includes('captions')) {
controls.setCaptionsMenu.call(this);
}
},
// Toggle captions display
// Used internally for the toggleCaptions method, with the passive option forced to false
toggle: function toggle(input) {
var _this2 = this;
var passive = arguments.length > 1 && arguments[1] !== undefined ? arguments[1] : true;
// If there's no full support
@ -9634,7 +9734,15 @@ var captions = {
controls.updateSetting.call(this, 'captions'); // Trigger event (not used internally)
triggerEvent.call(this, this.media, active ? 'captionsenabled' : 'captionsdisabled');
} // Wait for the call stack to clear before setting mode='hidden'
// on the active track - forcing the browser to download it
setTimeout(function () {
if (active && _this2.captions.toggled) {
_this2.captions.currentTrackNode.mode = 'hidden';
}
});
},
// Set captions by track index
// Used internally for the currentTrack setter with the passive option forced to false
@ -9715,7 +9823,7 @@ var captions = {
// If update is false it will also ignore tracks without metadata
// This is used to "freeze" the language options when captions.update is false
getTracks: function getTracks() {
var _this2 = this;
var _this3 = this;
var update = arguments.length > 0 && arguments[0] !== undefined ? arguments[0] : false;
// Handle media or textTracks missing or null
@ -9723,20 +9831,20 @@ var captions = {
// Filter out removed tracks and tracks that aren't captions/subtitles (for example metadata)
return tracks.filter(function (track) {
return !_this2.isHTML5 || update || _this2.captions.meta.has(track);
return !_this3.isHTML5 || update || _this3.captions.meta.has(track);
}).filter(function (track) {
return ['captions', 'subtitles'].includes(track.kind);
});
},
// Match tracks based on languages and get the first
findTrack: function findTrack(languages) {
var _this3 = this;
var _this4 = this;
var force = arguments.length > 1 && arguments[1] !== undefined ? arguments[1] : false;
var tracks = captions.getTracks.call(this);
var sortIsDefault = function sortIsDefault(track) {
return Number((_this3.captions.meta.get(track) || {}).default);
return Number((_this4.captions.meta.get(track) || {}).default);
};
var sorted = Array.from(tracks).sort(function (a, b) {
@ -9917,6 +10025,9 @@ var defaults$1 = {
fallback: true,
// Fallback using full viewport/window
iosNative: false // Use the native fullscreen in iOS (disables custom controls)
// Selector for the fullscreen container so contextual / non-player content can remain visible in fullscreen mode
// Non-ancestors of the player element will be ignored
// container: null, // defaults to the player element
},
// Local storage
@ -10154,16 +10265,16 @@ var defaults$1 = {
title: false,
speed: true,
transparent: false,
// These settings require a pro or premium account to work
sidedock: false,
controls: false,
// Whether the owner of the video has a Pro or Business account
// (which allows us to properly hide controls without CSS hacks, etc)
premium: false,
// Custom settings from Plyr
referrerPolicy: null // https://developer.mozilla.org/en-US/docs/Web/API/HTMLIFrameElement/referrerPolicy
},
// YouTube plugin
youtube: {
noCookie: false,
noCookie: true,
// Whether to use an alternative version of YouTube without cookies
rel: 0,
// No related vids
@ -10273,7 +10384,10 @@ var Fullscreen = /*#__PURE__*/function () {
y: 0
}; // Force the use of 'full window/browser' rather than fullscreen
this.forceFallback = player.config.fullscreen.fallback === 'force'; // Register event listeners
this.forceFallback = player.config.fullscreen.fallback === 'force'; // Get the fullscreen element
// Checks container is an ancestor, defaults to null
this.player.elements.fullscreen = player.config.fullscreen.container && closest(this.player.elements.container, player.config.fullscreen.container); // Register event listeners
// Handle event (incase user presses escape etc)
on.call(this.player, document, this.prefix === 'ms' ? 'MSFullscreenChange' : "".concat(this.prefix, "fullscreenchange"), function () {
@ -10446,7 +10560,7 @@ var Fullscreen = /*#__PURE__*/function () {
if (browser.isIos && this.player.config.fullscreen.iosNative) {
this.target.webkitExitFullscreen();
this.player.play();
silencePromise(this.player.play());
} else if (!Fullscreen.native || this.forceFallback) {
this.toggleFallback(false);
} else if (!this.prefix) {
@ -10493,13 +10607,13 @@ var Fullscreen = /*#__PURE__*/function () {
}
var element = !this.prefix ? document.fullscreenElement : document["".concat(this.prefix).concat(this.property, "Element")];
return element === this.target;
return element && element.shadowRoot ? element === this.target.getRootNode().host : element === this.target;
} // Get target element
}, {
key: "target",
get: function get() {
return browser.isIos && this.player.config.fullscreen.iosNative ? this.player.media : this.player.elements.container;
return browser.isIos && this.player.config.fullscreen.iosNative ? this.player.media : this.player.elements.fullscreen || this.player.elements.container;
}
}], [{
key: "native",
@ -10708,12 +10822,7 @@ var ui = {
} // Set property synchronously to respect the call order
this.media.setAttribute('poster', poster); // HTML5 uses native poster attribute
if (this.isHTML5) {
return Promise.resolve(poster);
} // Wait until ui is ready
this.media.setAttribute('data-poster', poster); // Wait until ui is ready
return ready.call(this) // Load image
.then(function () {
@ -10789,6 +10898,26 @@ var ui = {
this.toggleControls(Boolean(force || this.loading || this.paused || controlsElement.pressed || controlsElement.hover || recentTouchSeek));
}
},
// Migrate any custom properties from the media to the parent
migrateStyles: function migrateStyles() {
var _this5 = this;
// Loop through values (as they are the keys when the object is spread 🤔)
Object.values(_objectSpread2({}, this.media.style)) // We're only fussed about Plyr specific properties
.filter(function (key) {
return !is$1.empty(key) && 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');
}
}
};
@ -10883,7 +11012,7 @@ var Listeners = /*#__PURE__*/function () {
case 75:
// Space and K key
if (!repeat) {
player.togglePlay();
silencePromise(player.togglePlay());
}
break;
@ -10997,6 +11126,7 @@ var Listeners = /*#__PURE__*/function () {
removeCurrent(); // Delay the adding of classname until the focus has changed
// This event fires before the focusin event
if (event.type !== 'focusout') {
this.focusTimer = setTimeout(function () {
var focused = document.activeElement; // Ignore if current focus element isn't inside the player
@ -11006,6 +11136,7 @@ var Listeners = /*#__PURE__*/function () {
toggleClass(document.activeElement, player.config.classNames.tabFocus, true);
}, 10);
}
} // Global window & document listeners
}, {
@ -11023,7 +11154,7 @@ var Listeners = /*#__PURE__*/function () {
once.call(player, document.body, 'touchstart', this.firstTouch); // Tab focus detection
toggleListener.call(player, document.body, 'keydown focus blur', this.setTabFocus, toggle, false, true);
toggleListener.call(player, document.body, 'keydown focus blur focusout', this.setTabFocus, toggle, false, true);
} // Container listeners
}, {
@ -11066,7 +11197,7 @@ var Listeners = /*#__PURE__*/function () {
}); // Set a gutter for Vimeo
var setGutter = function setGutter(ratio, padding, toggle) {
if (!player.isVimeo) {
if (!player.isVimeo || player.config.vimeo.premium) {
return;
}
@ -11123,7 +11254,7 @@ var Listeners = /*#__PURE__*/function () {
ratio = _setPlayerSize.ratio; // Set Vimeo gutter
setGutter(ratio, padding, isEnter); // If not using native fullscreen, we need to check for resizes of viewport
setGutter(ratio, padding, isEnter); // If not using native browser fullscreen API, we need to check for resizes of viewport
if (!usingNative) {
if (isEnter) {
@ -11201,9 +11332,13 @@ var Listeners = /*#__PURE__*/function () {
if (player.ended) {
_this.proxy(event, player.restart, 'restart');
_this.proxy(event, player.play, 'play');
_this.proxy(event, function () {
silencePromise(player.play());
}, 'play');
} else {
_this.proxy(event, player.togglePlay, 'play');
_this.proxy(event, function () {
silencePromise(player.togglePlay());
}, 'play');
}
});
} // Disable right click
@ -11301,7 +11436,9 @@ var Listeners = /*#__PURE__*/function () {
if (elements.buttons.play) {
Array.from(elements.buttons.play).forEach(function (button) {
_this3.bind(button, 'click', player.togglePlay, 'play');
_this3.bind(button, 'click', function () {
silencePromise(player.togglePlay());
}, 'play');
});
} // Pause
@ -11398,7 +11535,7 @@ var Listeners = /*#__PURE__*/function () {
if (play && done) {
seek.removeAttribute(attribute);
player.play();
silencePromise(player.play());
} else if (!done && player.playing) {
seek.setAttribute(attribute, '');
player.pause();
@ -11496,7 +11633,18 @@ var Listeners = /*#__PURE__*/function () {
this.bind(elements.controls, 'mouseenter mouseleave', function (event) {
elements.controls.hover = !player.touch && event.type === 'mouseenter';
}); // Update controls.pressed state (used for ui.toggleControls to avoid hiding when interacting)
}); // Also update controls.hover state for any non-player children of fullscreen element (as above)
if (elements.fullscreen) {
Array.from(elements.fullscreen.children).filter(function (c) {
return !c.contains(elements.container);
}).forEach(function (child) {
_this3.bind(child, 'mouseenter mouseleave', function (event) {
elements.controls.hover = !player.touch && event.type === 'mouseenter';
});
});
} // Update controls.pressed state (used for ui.toggleControls to avoid hiding when interacting)
this.bind(elements.controls, 'mousedown mouseup touchstart touchend touchcancel', function (event) {
elements.controls.pressed = ['mousedown', 'touchstart'].includes(event.type);
@ -11965,15 +12113,28 @@ var vimeo = {
var _this = this;
var player = this;
var config = player.config.vimeo; // Get Vimeo params for the iframe
var config = player.config.vimeo;
var 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,
autoplay: player.autoplay,
muted: player.muted,
gesture: 'media',
playsinline: !this.config.fullscreen.iosNative
}, config)); // Get the source URL or ID
}, frameParams)); // Get the source URL or ID
var source = player.media.getAttribute('src'); // Get from <div> if needed
@ -11987,22 +12148,27 @@ var vimeo = {
var src = format(player.config.urls.vimeo.iframe, id, params);
iframe.setAttribute('src', src);
iframe.setAttribute('allowfullscreen', '');
iframe.setAttribute('allowtransparency', '');
iframe.setAttribute('allow', 'autoplay'); // Set the referrer policy if required
iframe.setAttribute('allow', 'autoplay,fullscreen,picture-in-picture'); // Set the referrer policy if required
if (!is$1.empty(config.referrerPolicy)) {
iframe.setAttribute('referrerPolicy', config.referrerPolicy);
} // Get poster, if already set
if (!is$1.empty(referrerPolicy)) {
iframe.setAttribute('referrerPolicy', referrerPolicy);
} // Inject the package
var poster = player.poster; // Inject the package
var poster = player.poster;
if (premium) {
iframe.setAttribute('data-poster', poster);
player.media = replaceElement(iframe, player.media);
} else {
var wrapper = createElement('div', {
poster: poster,
class: player.config.classNames.embedContainer
class: player.config.classNames.embedContainer,
'data-poster': poster
});
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) {
if (is$1.empty(response)) {
@ -12086,6 +12252,9 @@ var vimeo = {
player.embed.setPlaybackRate(input).then(function () {
speed = input;
triggerEvent.call(player, player.media, 'ratechange');
}).catch(function () {
// Cannot set Playback Rate, Video is probably not on Pro account
player.options.speed = [1];
});
}
}); // Volume
@ -12370,7 +12539,7 @@ var youtube = {
var container = createElement('div', {
id: id,
poster: poster
'data-poster': poster
});
player.media = replaceElement(container, player.media); // Id to poster wrapper
@ -12688,15 +12857,13 @@ var media = {
class: this.config.classNames.video
}); // 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', {
class: this.config.classNames.poster
});
this.elements.wrapper.appendChild(this.elements.poster);
}
}
if (this.isHTML5) {
html5.setup.call(this);
@ -12822,6 +12989,8 @@ var Ads = /*#__PURE__*/function () {
* mobile devices, this initialization is done as the result of a user action.
*/
value: function setupIMA() {
var _this4 = this;
// Create the container for our advertisements
this.elements.container = createElement('div', {
class: this.player.config.classNames.ads
@ -12834,7 +13003,16 @@ var Ads = /*#__PURE__*/function () {
google.ima.settings.setDisableCustomPlaybackForIOS10Plus(this.player.config.playsinline); // We assume the adContainer is the video container of the plyr element that will house the ads
this.elements.displayContainer = new google.ima.AdDisplayContainer(this.elements.container, this.player.media); // Request video ads to be pre-loaded
this.elements.displayContainer = new google.ima.AdDisplayContainer(this.elements.container, this.player.media); // Create ads loader
this.loader = new google.ima.AdsLoader(this.elements.displayContainer); // Listen and respond to ads loaded and error events
this.loader.addEventListener(google.ima.AdsManagerLoadedEvent.Type.ADS_MANAGER_LOADED, function (event) {
return _this4.onAdsManagerLoaded(event);
}, false);
this.loader.addEventListener(google.ima.AdErrorEvent.Type.AD_ERROR, function (error) {
return _this4.onAdError(error);
}, false); // Request video ads to be pre-loaded
this.requestAds();
}
@ -12845,21 +13023,10 @@ var Ads = /*#__PURE__*/function () {
}, {
key: "requestAds",
value: function requestAds() {
var _this4 = this;
var container = this.player.elements.container;
try {
// Create ads loader
this.loader = new google.ima.AdsLoader(this.elements.displayContainer); // Listen and respond to ads loaded and error events
this.loader.addEventListener(google.ima.AdsManagerLoadedEvent.Type.ADS_MANAGER_LOADED, function (event) {
return _this4.onAdsManagerLoaded(event);
}, false);
this.loader.addEventListener(google.ima.AdErrorEvent.Type.AD_ERROR, function (error) {
return _this4.onAdError(error);
}, false); // Request video ads
// Request video ads
var request = new google.ima.AdsRequest();
request.adTagUrl = this.tagUrl; // Specify the linear and nonlinear slot sizes. This helps the SDK
// to select the correct creative if multiple are returned
@ -13038,7 +13205,13 @@ var Ads = /*#__PURE__*/function () {
// };
// TODO: So there is still this thing where a video should only be allowed to start
// playing when the IMA SDK is ready or has failed
if (this.player.ended) {
this.loadAds();
} else {
// The SDK won't allow new ads to be called without receiving a contentComplete()
this.loader.contentComplete();
}
break;
case google.ima.AdEvent.Type.CONTENT_PAUSE_REQUESTED:
@ -13174,7 +13347,7 @@ var Ads = /*#__PURE__*/function () {
this.playing = false; // Play video
this.player.media.play();
silencePromise(this.player.media.play());
}
/**
* Pause our video
@ -13231,7 +13404,9 @@ var Ads = /*#__PURE__*/function () {
_this11.on('loaded', resolve);
_this11.player.debug.log(_this11.manager);
}); // Now request some new advertisements
}); // Now that the manager has been destroyed set it to also be un-initialized
_this11.initialized = false; // Now request some new advertisements
_this11.requestAds();
}).catch(function () {});
@ -13526,15 +13701,10 @@ var PreviewThumbnails = /*#__PURE__*/function () {
if (is$1.empty(src)) {
throw new Error('Missing previewThumbnails.src config attribute');
} // If string, convert into single-element list
} // Resolve promise
var urls = is$1.string(src) ? [src] : src; // Loop through each src URL. Download and process the VTT file, storing the resulting data in this.thumbnails
var promises = urls.map(function (u) {
return _this2.getThumbnail(u);
});
Promise.all(promises).then(function () {
var sortAndResolve = function sortAndResolve() {
// Sort smallest to biggest (e.g., [120p, 480p, 1080p])
_this2.thumbnails.sort(function (x, y) {
return x.height - y.height;
@ -13543,7 +13713,25 @@ var PreviewThumbnails = /*#__PURE__*/function () {
_this2.player.debug.log('Preview thumbnails', _this2.thumbnails);
resolve();
}; // Via callback()
if (is$1.function(src)) {
src(function (thumbnails) {
_this2.thumbnails = thumbnails;
sortAndResolve();
});
} // VTT urls
else {
// If string, convert into single-element list
var urls = is$1.string(src) ? [src] : src; // Loop through each src URL. Download and process the VTT file, storing the resulting data in this.thumbnails
var promises = urls.map(function (u) {
return _this2.getThumbnail(u);
}); // Resolve
Promise.all(promises).then(sortAndResolve);
}
});
} // Process individual VTT file
@ -14331,6 +14519,7 @@ var Plyr = /*#__PURE__*/function () {
this.elements = {
container: null,
fullscreen: null,
captions: null,
buttons: {},
display: {},
@ -14505,9 +14694,11 @@ var Plyr = /*#__PURE__*/function () {
tabindex: 0
});
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
media.setup.call(this); // Listen for events if debugging
@ -14516,10 +14707,12 @@ var Plyr = /*#__PURE__*/function () {
on.call(this, this.elements.container, this.config.events.join(' '), function (event) {
_this.debug.log("event: ".concat(event.type));
});
} // Setup interface
// If embed but not fully supported, build interface now to avoid flash of controls
} // Setup fullscreen
this.fullscreen = new Fullscreen(this); // Setup interface
// If embed but not fully supported, build interface now to avoid flash of controls
if (this.isHTML5 || this.isEmbed && !this.supported.ui) {
ui.build.call(this);
} // Container listeners
@ -14527,9 +14720,7 @@ var Plyr = /*#__PURE__*/function () {
this.listeners.container(); // Global listeners
this.listeners.global(); // Setup fullscreen
this.fullscreen = new Fullscreen(this); // Setup ads if provided
this.listeners.global(); // Setup ads if provided
if (this.config.ads.enabled) {
this.ads = new Ads(this);
@ -14538,7 +14729,7 @@ var Plyr = /*#__PURE__*/function () {
if (this.isHTML5 && this.config.autoplay) {
setTimeout(function () {
return _this.play();
return silencePromise(_this.play());
}, 10);
} // Seek time will be recorded (in listeners.js) so we can prevent hiding controls for a few seconds after seek
@ -14575,7 +14766,7 @@ var Plyr = /*#__PURE__*/function () {
this.ads.managerPromise.then(function () {
return _this2.ads.play();
}).catch(function () {
return _this2.media.play();
return silencePromise(_this2.media.play());
});
} // Return the promise (for HTML5)
@ -14735,7 +14926,7 @@ var Plyr = /*#__PURE__*/function () {
var hiding = toggleClass(this.elements.container, this.config.classNames.hideControls, force); // Close menu
if (hiding && this.config.controls.includes('settings') && !is$1.empty(this.config.settings)) {
if (hiding && is$1.array(this.config.controls) && this.config.controls.includes('settings') && !is$1.empty(this.config.settings)) {
controls.toggleMenu.call(this, false);
} // Trigger event on change
@ -15228,7 +15419,7 @@ var Plyr = /*#__PURE__*/function () {
var updateStorage = true;
if (!options.includes(quality)) {
var value = closest(options, quality);
var value = closest$1(options, quality);
this.debug.warn("Unsupported quality option: ".concat(quality, ", using ").concat(value, " instead"));
quality = value; // Don't update storage if quality is not supported
@ -15373,7 +15564,7 @@ var Plyr = /*#__PURE__*/function () {
return null;
}
return this.media.getAttribute('poster');
return this.media.getAttribute('poster') || this.media.getAttribute('data-poster');
}
/**
* Get the current aspect ratio in use

View File

@ -263,7 +263,7 @@
{% block extend_js %}
<!-- Plyr -->
<script src="{{ SITEURL }}/{{ THEME_STATIC_DIR }}/modules/plyr/plyr.min.js"
integrity="sha512-h2OOBB+c2Z3y4ROK8VhcWgO0KtUl5yDHpUFlpDN7YN96fv8XUbapjrf6EEvKoxW+9nMN/QcJ9wrk9N8+OxYhOA=="
integrity="sha512-l6ZzdXpfMHRfifqaR79wbYCEWjLDMI9DnROvb+oLkKq6d7MGroGpMbI7HFpicvmAH/2aQO+vJhewq8rhysrImw=="
crossorigin="anonymous"></script>
<script src="{{ SITEURL }}/{{ THEME_STATIC_DIR }}/js/play.js"></script>
<!-- /Plyr -->