v3.6.0
This commit is contained in:
parent
e48b1d11ce
commit
66c5780616
18
CHANGELOG.md
18
CHANGELOG.md
@ -1,6 +1,22 @@
|
||||
## v3.6.0
|
||||
|
||||
- You can now easily change colors using CSS Custom Properties.
|
||||
- You can now easily change colors using CSS Custom Properties. See the [README](README.md#customizing-the-css).
|
||||
- Bug fix for Vimeo fullscreen.
|
||||
- Various typos (thanks @likev)
|
||||
- Preload TextTracks as per default video element (thanks @theprojectsomething)
|
||||
- Features/fullscreen container (thanks @theprojectsomething)
|
||||
- Ignore internal play promises (thanks @ydylla)
|
||||
- Ads plugin fixes to allow multiple VAST requests (thanks @Steejo)
|
||||
- Fix shadowroot (thanks @jnoordsij)
|
||||
- Add financial contributors for Open Collective (thanks @monkeywithacupcake)
|
||||
- Update the gitpod setup description to be more precise. (thanks @nisarhassan12)
|
||||
- Completely hide SVG icons to screen readers (thanks @LeBenLeBen)
|
||||
- Preview thumbnails via src:callback() (thanks @doublex)
|
||||
- Add missing Typescripts types and options (thanks @hug963)
|
||||
- Use number instead of string in TS quality definitions (thanks @mogzol)
|
||||
- Fix Vimeo playback rate (thanks @hug963)
|
||||
- Fix issue when controls config is string or element (thanks @CzBiX)
|
||||
- Simplify contributions by fully automating the dev setup with gitpod (thanks @nisarhassan12)
|
||||
|
||||
### v3.5.10
|
||||
|
||||
|
2
demo/dist/demo.css
vendored
2
demo/dist/demo.css
vendored
File diff suppressed because one or more lines are too long
262
demo/dist/demo.js
vendored
262
demo/dist/demo.js
vendored
@ -4380,6 +4380,42 @@ typeof navigator === "object" && (function () {
|
||||
return target;
|
||||
}
|
||||
|
||||
function _objectWithoutPropertiesLoose(source, excluded) {
|
||||
if (source == null) return {};
|
||||
var target = {};
|
||||
var sourceKeys = Object.keys(source);
|
||||
var key, i;
|
||||
|
||||
for (i = 0; i < sourceKeys.length; i++) {
|
||||
key = sourceKeys[i];
|
||||
if (excluded.indexOf(key) >= 0) continue;
|
||||
target[key] = source[key];
|
||||
}
|
||||
|
||||
return target;
|
||||
}
|
||||
|
||||
function _objectWithoutProperties(source, excluded) {
|
||||
if (source == null) return {};
|
||||
|
||||
var target = _objectWithoutPropertiesLoose(source, excluded);
|
||||
|
||||
var key, i;
|
||||
|
||||
if (Object.getOwnPropertySymbols) {
|
||||
var sourceSymbolKeys = Object.getOwnPropertySymbols(source);
|
||||
|
||||
for (i = 0; i < sourceSymbolKeys.length; i++) {
|
||||
key = sourceSymbolKeys[i];
|
||||
if (excluded.indexOf(key) >= 0) continue;
|
||||
if (!Object.prototype.propertyIsEnumerable.call(source, key)) continue;
|
||||
target[key] = source[key];
|
||||
}
|
||||
}
|
||||
|
||||
return target;
|
||||
}
|
||||
|
||||
function _slicedToArray(arr, i) {
|
||||
return _arrayWithHoles(arr) || _iterableToArrayLimit(arr, i) || _unsupportedIterableToArray(arr, i) || _nonIterableRest();
|
||||
}
|
||||
@ -14612,7 +14648,7 @@ typeof navigator === "object" && (function () {
|
||||
(module.exports = function (key, value) {
|
||||
return sharedStore$1[key] || (sharedStore$1[key] = value !== undefined ? value : {});
|
||||
})('versions', []).push({
|
||||
version: '3.6.4',
|
||||
version: '3.6.5',
|
||||
mode: 'global',
|
||||
copyright: '© 2020 Denis Pushkarev (zloirock.ru)'
|
||||
});
|
||||
@ -17622,7 +17658,7 @@ typeof navigator === "object" && (function () {
|
||||
var INVALID_PORT$1 = 'Invalid port';
|
||||
|
||||
var ALPHA$1 = /[A-Za-z]/;
|
||||
var ALPHANUMERIC$1 = /[\d+\-.A-Za-z]/;
|
||||
var ALPHANUMERIC$1 = /[\d+-.A-Za-z]/;
|
||||
var DIGIT$1 = /\d/;
|
||||
var HEX_START$1 = /^(0x|0X)/;
|
||||
var OCT$1 = /^[0-7]+$/;
|
||||
@ -19629,7 +19665,13 @@ typeof navigator === "object" && (function () {
|
||||
defer$1 = functionBindContext$1(port$1.postMessage, port$1, 1);
|
||||
// Browsers with postMessage, skip WebWorkers
|
||||
// IE8 has postMessage, but it's sync & typeof its postMessage is 'object'
|
||||
} else if (global_1$1.addEventListener && typeof postMessage == 'function' && !global_1$1.importScripts && !fails$1(post$1)) {
|
||||
} else if (
|
||||
global_1$1.addEventListener &&
|
||||
typeof postMessage == 'function' &&
|
||||
!global_1$1.importScripts &&
|
||||
!fails$1(post$1) &&
|
||||
location$1.protocol !== 'file:'
|
||||
) {
|
||||
defer$1 = post$1;
|
||||
global_1$1.addEventListener('message', listener$1, false);
|
||||
// IE8-
|
||||
@ -20639,6 +20681,25 @@ typeof navigator === "object" && (function () {
|
||||
|
||||
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$2.matches(el, selector)) return el;
|
||||
el = el.parentElement || el.parentNode;
|
||||
} while (el !== null && el.nodeType === 1);
|
||||
|
||||
return null;
|
||||
}
|
||||
|
||||
var method = prototype.closest || closestElement;
|
||||
return method.call(element, selector);
|
||||
} // Find all elements
|
||||
|
||||
function getElements(selector) {
|
||||
@ -20990,8 +21051,8 @@ typeof navigator === "object" && (function () {
|
||||
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) {
|
||||
@ -21144,7 +21205,7 @@ typeof navigator === "object" && (function () {
|
||||
});
|
||||
} // Get the closest value in an array
|
||||
|
||||
function closest(array, value) {
|
||||
function closest$1(array, value) {
|
||||
if (!is$2.array(array) || !array.length) {
|
||||
return null;
|
||||
}
|
||||
@ -23252,9 +23313,15 @@ typeof navigator === "object" && (function () {
|
||||
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);
|
||||
@ -23278,6 +23345,8 @@ typeof navigator === "object" && (function () {
|
||||
// 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
|
||||
@ -23324,7 +23393,15 @@ typeof navigator === "object" && (function () {
|
||||
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
|
||||
@ -23405,7 +23482,7 @@ typeof navigator === "object" && (function () {
|
||||
// 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
|
||||
@ -23413,20 +23490,20 @@ typeof navigator === "object" && (function () {
|
||||
// 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) {
|
||||
@ -23607,6 +23684,9 @@ typeof navigator === "object" && (function () {
|
||||
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
|
||||
@ -23844,16 +23924,16 @@ typeof navigator === "object" && (function () {
|
||||
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
|
||||
@ -23963,7 +24043,10 @@ typeof navigator === "object" && (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 () {
|
||||
@ -24189,7 +24272,7 @@ typeof navigator === "object" && (function () {
|
||||
}, {
|
||||
key: "target",
|
||||
get: function get() {
|
||||
return browser.isIos && this.player.config.fullscreen.iosNative ? this.player.media : this.player.elements.container;
|
||||
return browser.isIos && this.player.config.fullscreen.iosNative ? this.player.media : this.player.elements.fullscreen || this.player.elements.container;
|
||||
}
|
||||
}], [{
|
||||
key: "native",
|
||||
@ -24398,12 +24481,7 @@ typeof navigator === "object" && (function () {
|
||||
} // 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 () {
|
||||
@ -24479,6 +24557,26 @@ typeof navigator === "object" && (function () {
|
||||
|
||||
this.toggleControls(Boolean(force || this.loading || this.paused || controlsElement.pressed || controlsElement.hover || recentTouchSeek));
|
||||
}
|
||||
},
|
||||
// Migrate any custom properties from the media to the parent
|
||||
migrateStyles: function migrateStyles() {
|
||||
var _this5 = this;
|
||||
|
||||
// Loop through values (as they are the keys when the object is spread 🤔)
|
||||
Object.values(_objectSpread2({}, this.media.style)) // We're only fussed about Plyr specific properties
|
||||
.filter(function (key) {
|
||||
return key.startsWith('--plyr');
|
||||
}).forEach(function (key) {
|
||||
// Set on the container
|
||||
_this5.elements.container.style.setProperty(key, _this5.media.style.getPropertyValue(key)); // Clean up from media element
|
||||
|
||||
|
||||
_this5.media.style.removeProperty(key);
|
||||
}); // Remove attribute if empty
|
||||
|
||||
if (is$2.empty(this.media.style)) {
|
||||
this.media.removeAttribute('style');
|
||||
}
|
||||
}
|
||||
};
|
||||
|
||||
@ -24687,15 +24785,17 @@ typeof navigator === "object" && (function () {
|
||||
removeCurrent(); // Delay the adding of classname until the focus has changed
|
||||
// This event fires before the focusin event
|
||||
|
||||
this.focusTimer = setTimeout(function () {
|
||||
var focused = document.activeElement; // Ignore if current focus element isn't inside the player
|
||||
if (event.type !== 'focusout') {
|
||||
this.focusTimer = setTimeout(function () {
|
||||
var focused = document.activeElement; // Ignore if current focus element isn't inside the player
|
||||
|
||||
if (!elements.container.contains(focused)) {
|
||||
return;
|
||||
}
|
||||
if (!elements.container.contains(focused)) {
|
||||
return;
|
||||
}
|
||||
|
||||
toggleClass(document.activeElement, player.config.classNames.tabFocus, true);
|
||||
}, 10);
|
||||
toggleClass(document.activeElement, player.config.classNames.tabFocus, true);
|
||||
}, 10);
|
||||
}
|
||||
} // Global window & document listeners
|
||||
|
||||
}, {
|
||||
@ -24713,7 +24813,7 @@ typeof navigator === "object" && (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
|
||||
|
||||
}, {
|
||||
@ -24756,7 +24856,7 @@ typeof navigator === "object" && (function () {
|
||||
}); // Set a gutter for Vimeo
|
||||
|
||||
var setGutter = function setGutter(ratio, padding, toggle) {
|
||||
if (!player.isVimeo) {
|
||||
if (!player.isVimeo || player.config.vimeo.premium) {
|
||||
return;
|
||||
}
|
||||
|
||||
@ -24813,7 +24913,7 @@ typeof navigator === "object" && (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) {
|
||||
@ -25192,7 +25292,18 @@ typeof navigator === "object" && (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);
|
||||
@ -25661,15 +25772,28 @@ typeof navigator === "object" && (function () {
|
||||
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$1({}, {
|
||||
var premium = config.premium,
|
||||
referrerPolicy = config.referrerPolicy,
|
||||
frameParams = _objectWithoutProperties(config, ["premium", "referrerPolicy"]); // If the owner has a pro or premium account then we can hide controls etc
|
||||
|
||||
|
||||
if (premium) {
|
||||
Object.assign(frameParams, {
|
||||
controls: false,
|
||||
sidedock: false
|
||||
});
|
||||
} // Get Vimeo params for the iframe
|
||||
|
||||
|
||||
var params = buildUrlParams(_objectSpread2({
|
||||
loop: player.config.loop.active,
|
||||
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
|
||||
|
||||
@ -25683,22 +25807,27 @@ typeof navigator === "object" && (function () {
|
||||
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$2.empty(config.referrerPolicy)) {
|
||||
iframe.setAttribute('referrerPolicy', config.referrerPolicy);
|
||||
} // Get poster, if already set
|
||||
if (!is$2.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$1('div', {
|
||||
class: player.config.classNames.embedContainer,
|
||||
'data-poster': poster
|
||||
});
|
||||
wrapper.appendChild(iframe);
|
||||
player.media = replaceElement(wrapper, player.media);
|
||||
} // Get poster image
|
||||
|
||||
var wrapper = createElement$1('div', {
|
||||
poster: poster,
|
||||
class: player.config.classNames.embedContainer
|
||||
});
|
||||
wrapper.appendChild(iframe);
|
||||
player.media = replaceElement(wrapper, player.media); // Get poster image
|
||||
|
||||
fetch(format(player.config.urls.vimeo.api, id), 'json').then(function (response) {
|
||||
if (is$2.empty(response)) {
|
||||
@ -26069,7 +26198,7 @@ typeof navigator === "object" && (function () {
|
||||
|
||||
var container = createElement$1('div', {
|
||||
id: id,
|
||||
poster: poster
|
||||
'data-poster': poster
|
||||
});
|
||||
player.media = replaceElement(container, player.media); // Id to poster wrapper
|
||||
|
||||
@ -26387,14 +26516,12 @@ typeof navigator === "object" && (function () {
|
||||
class: this.config.classNames.video
|
||||
}); // Wrap the video in a container
|
||||
|
||||
wrap$4(this.media, this.elements.wrapper); // Faux poster container
|
||||
wrap$4(this.media, this.elements.wrapper); // Poster image container
|
||||
|
||||
if (this.isEmbed) {
|
||||
this.elements.poster = createElement$1('div', {
|
||||
class: this.config.classNames.poster
|
||||
});
|
||||
this.elements.wrapper.appendChild(this.elements.poster);
|
||||
}
|
||||
this.elements.poster = createElement$1('div', {
|
||||
class: this.config.classNames.poster
|
||||
});
|
||||
this.elements.wrapper.appendChild(this.elements.poster);
|
||||
}
|
||||
|
||||
if (this.isHTML5) {
|
||||
@ -28051,6 +28178,7 @@ typeof navigator === "object" && (function () {
|
||||
|
||||
this.elements = {
|
||||
container: null,
|
||||
fullscreen: null,
|
||||
captions: null,
|
||||
buttons: {},
|
||||
display: {},
|
||||
@ -28225,9 +28353,11 @@ typeof navigator === "object" && (function () {
|
||||
tabindex: 0
|
||||
});
|
||||
wrap$4(this.media, this.elements.container);
|
||||
} // Add style hook
|
||||
} // Migrate custom properties from media to container (so they work 😉)
|
||||
|
||||
|
||||
ui.migrateStyles.call(this); // Add style hook
|
||||
|
||||
ui.addStyleHook.call(this); // Setup media
|
||||
|
||||
media.setup.call(this); // Listen for events if debugging
|
||||
@ -28236,10 +28366,12 @@ typeof navigator === "object" && (function () {
|
||||
on.call(this, this.elements.container, this.config.events.join(' '), function (event) {
|
||||
_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
|
||||
@ -28247,9 +28379,7 @@ typeof navigator === "object" && (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);
|
||||
@ -28948,7 +29078,7 @@ typeof navigator === "object" && (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
|
||||
|
||||
@ -29093,7 +29223,7 @@ typeof navigator === "object" && (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
|
||||
|
6
demo/dist/demo.min.js
vendored
6
demo/dist/demo.min.js
vendored
File diff suppressed because one or more lines are too long
2
demo/dist/demo.min.js.map
vendored
2
demo/dist/demo.min.js.map
vendored
File diff suppressed because one or more lines are too long
2
dist/plyr.css
vendored
2
dist/plyr.css
vendored
File diff suppressed because one or more lines are too long
251
dist/plyr.js
vendored
251
dist/plyr.js
vendored
@ -75,6 +75,42 @@ 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) || _unsupportedIterableToArray(arr, i) || _nonIterableRest();
|
||||
}
|
||||
@ -788,6 +824,25 @@ typeof navigator === "object" && (function (global, factory) {
|
||||
|
||||
var method = prototype.matches || prototype.webkitMatchesSelector || prototype.mozMatchesSelector || prototype.msMatchesSelector || match;
|
||||
return method.call(element, selector);
|
||||
} // Closest ancestor element matching selector (also tests element itself)
|
||||
|
||||
function closest(element, selector) {
|
||||
var _Element2 = Element,
|
||||
prototype = _Element2.prototype; // https://developer.mozilla.org/en-US/docs/Web/API/Element/closest#Polyfill
|
||||
|
||||
function closestElement() {
|
||||
var el = this;
|
||||
|
||||
do {
|
||||
if (matches$1.matches(el, selector)) return el;
|
||||
el = el.parentElement || el.parentNode;
|
||||
} while (el !== null && el.nodeType === 1);
|
||||
|
||||
return null;
|
||||
}
|
||||
|
||||
var method = prototype.closest || closestElement;
|
||||
return method.call(element, selector);
|
||||
} // Find all elements
|
||||
|
||||
function getElements(selector) {
|
||||
@ -1139,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) {
|
||||
@ -1296,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;
|
||||
}
|
||||
@ -3278,9 +3333,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);
|
||||
@ -3304,6 +3365,8 @@ typeof navigator === "object" && (function (global, factory) {
|
||||
// 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
|
||||
@ -3350,7 +3413,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
|
||||
@ -3431,7 +3502,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
|
||||
@ -3439,20 +3510,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) {
|
||||
@ -3633,6 +3704,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
|
||||
@ -3870,16 +3944,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
|
||||
@ -3989,7 +4063,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 () {
|
||||
@ -4215,7 +4292,7 @@ typeof navigator === "object" && (function (global, factory) {
|
||||
}, {
|
||||
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",
|
||||
@ -4277,7 +4354,6 @@ typeof navigator === "object" && (function (global, factory) {
|
||||
});
|
||||
}
|
||||
|
||||
// ==========================================================================
|
||||
var ui = {
|
||||
addStyleHook: function addStyleHook() {
|
||||
toggleClass(this.elements.container, this.config.selectors.container.replace('.', ''), true);
|
||||
@ -4412,12 +4488,7 @@ typeof navigator === "object" && (function (global, factory) {
|
||||
} // Set property synchronously to respect the call order
|
||||
|
||||
|
||||
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 () {
|
||||
@ -4493,6 +4564,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 key.startsWith('--plyr');
|
||||
}).forEach(function (key) {
|
||||
// Set on the container
|
||||
_this5.elements.container.style.setProperty(key, _this5.media.style.getPropertyValue(key)); // Clean up from media element
|
||||
|
||||
|
||||
_this5.media.style.removeProperty(key);
|
||||
}); // Remove attribute if empty
|
||||
|
||||
if (is$1.empty(this.media.style)) {
|
||||
this.media.removeAttribute('style');
|
||||
}
|
||||
}
|
||||
};
|
||||
|
||||
@ -4701,15 +4792,17 @@ typeof navigator === "object" && (function (global, factory) {
|
||||
removeCurrent(); // Delay the adding of classname until the focus has changed
|
||||
// This event fires before the focusin event
|
||||
|
||||
this.focusTimer = setTimeout(function () {
|
||||
var focused = document.activeElement; // Ignore if current focus element isn't inside the player
|
||||
if (event.type !== 'focusout') {
|
||||
this.focusTimer = setTimeout(function () {
|
||||
var focused = document.activeElement; // Ignore if current focus element isn't inside the player
|
||||
|
||||
if (!elements.container.contains(focused)) {
|
||||
return;
|
||||
}
|
||||
if (!elements.container.contains(focused)) {
|
||||
return;
|
||||
}
|
||||
|
||||
toggleClass(document.activeElement, player.config.classNames.tabFocus, true);
|
||||
}, 10);
|
||||
toggleClass(document.activeElement, player.config.classNames.tabFocus, true);
|
||||
}, 10);
|
||||
}
|
||||
} // Global window & document listeners
|
||||
|
||||
}, {
|
||||
@ -4727,7 +4820,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
|
||||
|
||||
}, {
|
||||
@ -4770,7 +4863,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;
|
||||
}
|
||||
|
||||
@ -4827,7 +4920,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) {
|
||||
@ -5206,7 +5299,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);
|
||||
@ -5622,15 +5726,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
|
||||
|
||||
@ -5644,22 +5761,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', {
|
||||
class: player.config.classNames.embedContainer,
|
||||
'data-poster': poster
|
||||
});
|
||||
wrapper.appendChild(iframe);
|
||||
player.media = replaceElement(wrapper, player.media);
|
||||
} // Get poster image
|
||||
|
||||
var wrapper = createElement('div', {
|
||||
poster: poster,
|
||||
class: player.config.classNames.embedContainer
|
||||
});
|
||||
wrapper.appendChild(iframe);
|
||||
player.media = replaceElement(wrapper, player.media); // Get poster image
|
||||
|
||||
fetch(format(player.config.urls.vimeo.api, id), 'json').then(function (response) {
|
||||
if (is$1.empty(response)) {
|
||||
@ -6032,7 +6154,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
|
||||
|
||||
@ -6351,14 +6473,12 @@ 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);
|
||||
}
|
||||
this.elements.poster = createElement('div', {
|
||||
class: this.config.classNames.poster
|
||||
});
|
||||
this.elements.wrapper.appendChild(this.elements.poster);
|
||||
}
|
||||
|
||||
if (this.isHTML5) {
|
||||
@ -7964,6 +8084,7 @@ typeof navigator === "object" && (function (global, factory) {
|
||||
|
||||
this.elements = {
|
||||
container: null,
|
||||
fullscreen: null,
|
||||
captions: null,
|
||||
buttons: {},
|
||||
display: {},
|
||||
@ -8138,9 +8259,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
|
||||
@ -8149,10 +8272,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
|
||||
@ -8160,9 +8285,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);
|
||||
@ -8861,7 +8984,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
|
||||
|
||||
@ -9006,7 +9129,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
|
||||
|
4
dist/plyr.min.js
vendored
4
dist/plyr.min.js
vendored
File diff suppressed because one or more lines are too long
2
dist/plyr.min.js.map
vendored
2
dist/plyr.min.js.map
vendored
File diff suppressed because one or more lines are too long
4
dist/plyr.min.mjs
vendored
4
dist/plyr.min.mjs
vendored
File diff suppressed because one or more lines are too long
2
dist/plyr.min.mjs.map
vendored
2
dist/plyr.min.mjs.map
vendored
File diff suppressed because one or more lines are too long
251
dist/plyr.mjs
vendored
251
dist/plyr.mjs
vendored
@ -69,6 +69,42 @@ function _objectSpread2(target) {
|
||||
return target;
|
||||
}
|
||||
|
||||
function _objectWithoutPropertiesLoose(source, excluded) {
|
||||
if (source == null) return {};
|
||||
var target = {};
|
||||
var sourceKeys = Object.keys(source);
|
||||
var key, i;
|
||||
|
||||
for (i = 0; i < sourceKeys.length; i++) {
|
||||
key = sourceKeys[i];
|
||||
if (excluded.indexOf(key) >= 0) continue;
|
||||
target[key] = source[key];
|
||||
}
|
||||
|
||||
return target;
|
||||
}
|
||||
|
||||
function _objectWithoutProperties(source, excluded) {
|
||||
if (source == null) return {};
|
||||
|
||||
var target = _objectWithoutPropertiesLoose(source, excluded);
|
||||
|
||||
var key, i;
|
||||
|
||||
if (Object.getOwnPropertySymbols) {
|
||||
var sourceSymbolKeys = Object.getOwnPropertySymbols(source);
|
||||
|
||||
for (i = 0; i < sourceSymbolKeys.length; i++) {
|
||||
key = sourceSymbolKeys[i];
|
||||
if (excluded.indexOf(key) >= 0) continue;
|
||||
if (!Object.prototype.propertyIsEnumerable.call(source, key)) continue;
|
||||
target[key] = source[key];
|
||||
}
|
||||
}
|
||||
|
||||
return target;
|
||||
}
|
||||
|
||||
function _slicedToArray(arr, i) {
|
||||
return _arrayWithHoles(arr) || _iterableToArrayLimit(arr, i) || _unsupportedIterableToArray(arr, i) || _nonIterableRest();
|
||||
}
|
||||
@ -782,6 +818,25 @@ function matches$1(element, selector) {
|
||||
|
||||
var method = prototype.matches || prototype.webkitMatchesSelector || prototype.mozMatchesSelector || prototype.msMatchesSelector || match;
|
||||
return method.call(element, selector);
|
||||
} // Closest ancestor element matching selector (also tests element itself)
|
||||
|
||||
function closest(element, selector) {
|
||||
var _Element2 = Element,
|
||||
prototype = _Element2.prototype; // https://developer.mozilla.org/en-US/docs/Web/API/Element/closest#Polyfill
|
||||
|
||||
function closestElement() {
|
||||
var el = this;
|
||||
|
||||
do {
|
||||
if (matches$1.matches(el, selector)) return el;
|
||||
el = el.parentElement || el.parentNode;
|
||||
} while (el !== null && el.nodeType === 1);
|
||||
|
||||
return null;
|
||||
}
|
||||
|
||||
var method = prototype.closest || closestElement;
|
||||
return method.call(element, selector);
|
||||
} // Find all elements
|
||||
|
||||
function getElements(selector) {
|
||||
@ -1133,8 +1188,8 @@ function setAspectRatio(input) {
|
||||
var padding = 100 / w * h;
|
||||
wrapper.style.paddingBottom = "".concat(padding, "%"); // For Vimeo we have an extra <div> to hide the standard controls and UI
|
||||
|
||||
if (this.isVimeo && this.supported.ui) {
|
||||
var height = 240;
|
||||
if (this.isVimeo && !this.config.vimeo.premium && this.supported.ui) {
|
||||
var height = 100 / this.media.offsetWidth * parseInt(window.getComputedStyle(this.media).paddingBottom, 10);
|
||||
var offset = (height - padding) / (height / 50);
|
||||
this.media.style.transform = "translateY(-".concat(offset, "%)");
|
||||
} else if (this.isHTML5) {
|
||||
@ -1290,7 +1345,7 @@ function dedupe(array) {
|
||||
});
|
||||
} // Get the closest value in an array
|
||||
|
||||
function closest(array, value) {
|
||||
function closest$1(array, value) {
|
||||
if (!is$1.array(array) || !array.length) {
|
||||
return null;
|
||||
}
|
||||
@ -3272,9 +3327,15 @@ var captions = {
|
||||
meta.set(track, {
|
||||
default: track.mode === 'showing'
|
||||
}); // Turn off native caption rendering to avoid double captions
|
||||
// Note: mode='hidden' forces a track to download. To ensure every track
|
||||
// isn't downloaded at once, only 'showing' tracks should be reassigned
|
||||
// eslint-disable-next-line no-param-reassign
|
||||
|
||||
track.mode = 'hidden'; // Add event listener for cue changes
|
||||
if (track.mode === 'showing') {
|
||||
// eslint-disable-next-line no-param-reassign
|
||||
track.mode = 'hidden';
|
||||
} // Add event listener for cue changes
|
||||
|
||||
|
||||
on.call(_this, track, 'cuechange', function () {
|
||||
return captions.updateCues.call(_this);
|
||||
@ -3298,6 +3359,8 @@ var captions = {
|
||||
// Toggle captions display
|
||||
// Used internally for the toggleCaptions method, with the passive option forced to false
|
||||
toggle: function toggle(input) {
|
||||
var _this2 = this;
|
||||
|
||||
var passive = arguments.length > 1 && arguments[1] !== undefined ? arguments[1] : true;
|
||||
|
||||
// If there's no full support
|
||||
@ -3344,7 +3407,15 @@ var captions = {
|
||||
controls.updateSetting.call(this, 'captions'); // Trigger event (not used internally)
|
||||
|
||||
triggerEvent.call(this, this.media, active ? 'captionsenabled' : 'captionsdisabled');
|
||||
}
|
||||
} // Wait for the call stack to clear before setting mode='hidden'
|
||||
// on the active track - forcing the browser to download it
|
||||
|
||||
|
||||
setTimeout(function () {
|
||||
if (active && _this2.captions.toggled) {
|
||||
_this2.captions.currentTrackNode.mode = 'hidden';
|
||||
}
|
||||
});
|
||||
},
|
||||
// Set captions by track index
|
||||
// Used internally for the currentTrack setter with the passive option forced to false
|
||||
@ -3425,7 +3496,7 @@ var captions = {
|
||||
// If update is false it will also ignore tracks without metadata
|
||||
// This is used to "freeze" the language options when captions.update is false
|
||||
getTracks: function getTracks() {
|
||||
var _this2 = this;
|
||||
var _this3 = this;
|
||||
|
||||
var update = arguments.length > 0 && arguments[0] !== undefined ? arguments[0] : false;
|
||||
// Handle media or textTracks missing or null
|
||||
@ -3433,20 +3504,20 @@ var captions = {
|
||||
// Filter out removed tracks and tracks that aren't captions/subtitles (for example metadata)
|
||||
|
||||
return tracks.filter(function (track) {
|
||||
return !_this2.isHTML5 || update || _this2.captions.meta.has(track);
|
||||
return !_this3.isHTML5 || update || _this3.captions.meta.has(track);
|
||||
}).filter(function (track) {
|
||||
return ['captions', 'subtitles'].includes(track.kind);
|
||||
});
|
||||
},
|
||||
// Match tracks based on languages and get the first
|
||||
findTrack: function findTrack(languages) {
|
||||
var _this3 = this;
|
||||
var _this4 = this;
|
||||
|
||||
var force = arguments.length > 1 && arguments[1] !== undefined ? arguments[1] : false;
|
||||
var tracks = captions.getTracks.call(this);
|
||||
|
||||
var sortIsDefault = function sortIsDefault(track) {
|
||||
return Number((_this3.captions.meta.get(track) || {}).default);
|
||||
return Number((_this4.captions.meta.get(track) || {}).default);
|
||||
};
|
||||
|
||||
var sorted = Array.from(tracks).sort(function (a, b) {
|
||||
@ -3627,6 +3698,9 @@ var defaults$1 = {
|
||||
fallback: true,
|
||||
// Fallback using full viewport/window
|
||||
iosNative: false // Use the native fullscreen in iOS (disables custom controls)
|
||||
// Selector for the fullscreen container so contextual / non-player content can remain visible in fullscreen mode
|
||||
// Non-ancestors of the player element will be ignored
|
||||
// container: null, // defaults to the player element
|
||||
|
||||
},
|
||||
// Local storage
|
||||
@ -3864,16 +3938,16 @@ var defaults$1 = {
|
||||
title: false,
|
||||
speed: true,
|
||||
transparent: false,
|
||||
// These settings require a pro or premium account to work
|
||||
sidedock: false,
|
||||
controls: false,
|
||||
// Whether the owner of the video has a Pro or Business account
|
||||
// (which allows us to properly hide controls without CSS hacks, etc)
|
||||
premium: false,
|
||||
// Custom settings from Plyr
|
||||
referrerPolicy: null // https://developer.mozilla.org/en-US/docs/Web/API/HTMLIFrameElement/referrerPolicy
|
||||
|
||||
},
|
||||
// YouTube plugin
|
||||
youtube: {
|
||||
noCookie: false,
|
||||
noCookie: true,
|
||||
// Whether to use an alternative version of YouTube without cookies
|
||||
rel: 0,
|
||||
// No related vids
|
||||
@ -3983,7 +4057,10 @@ var Fullscreen = /*#__PURE__*/function () {
|
||||
y: 0
|
||||
}; // Force the use of 'full window/browser' rather than fullscreen
|
||||
|
||||
this.forceFallback = player.config.fullscreen.fallback === 'force'; // Register event listeners
|
||||
this.forceFallback = player.config.fullscreen.fallback === 'force'; // Get the fullscreen element
|
||||
// Checks container is an ancestor, defaults to null
|
||||
|
||||
this.player.elements.fullscreen = player.config.fullscreen.container && closest(this.player.elements.container, player.config.fullscreen.container); // Register event listeners
|
||||
// Handle event (incase user presses escape etc)
|
||||
|
||||
on.call(this.player, document, this.prefix === 'ms' ? 'MSFullscreenChange' : "".concat(this.prefix, "fullscreenchange"), function () {
|
||||
@ -4209,7 +4286,7 @@ var Fullscreen = /*#__PURE__*/function () {
|
||||
}, {
|
||||
key: "target",
|
||||
get: function get() {
|
||||
return browser.isIos && this.player.config.fullscreen.iosNative ? this.player.media : this.player.elements.container;
|
||||
return browser.isIos && this.player.config.fullscreen.iosNative ? this.player.media : this.player.elements.fullscreen || this.player.elements.container;
|
||||
}
|
||||
}], [{
|
||||
key: "native",
|
||||
@ -4271,7 +4348,6 @@ function loadImage(src) {
|
||||
});
|
||||
}
|
||||
|
||||
// ==========================================================================
|
||||
var ui = {
|
||||
addStyleHook: function addStyleHook() {
|
||||
toggleClass(this.elements.container, this.config.selectors.container.replace('.', ''), true);
|
||||
@ -4406,12 +4482,7 @@ var ui = {
|
||||
} // Set property synchronously to respect the call order
|
||||
|
||||
|
||||
this.media.setAttribute('poster', poster); // HTML5 uses native poster attribute
|
||||
|
||||
if (this.isHTML5) {
|
||||
return Promise.resolve(poster);
|
||||
} // Wait until ui is ready
|
||||
|
||||
this.media.setAttribute('data-poster', poster); // Wait until ui is ready
|
||||
|
||||
return ready.call(this) // Load image
|
||||
.then(function () {
|
||||
@ -4487,6 +4558,26 @@ var ui = {
|
||||
|
||||
this.toggleControls(Boolean(force || this.loading || this.paused || controlsElement.pressed || controlsElement.hover || recentTouchSeek));
|
||||
}
|
||||
},
|
||||
// Migrate any custom properties from the media to the parent
|
||||
migrateStyles: function migrateStyles() {
|
||||
var _this5 = this;
|
||||
|
||||
// Loop through values (as they are the keys when the object is spread 🤔)
|
||||
Object.values(_objectSpread2({}, this.media.style)) // We're only fussed about Plyr specific properties
|
||||
.filter(function (key) {
|
||||
return key.startsWith('--plyr');
|
||||
}).forEach(function (key) {
|
||||
// Set on the container
|
||||
_this5.elements.container.style.setProperty(key, _this5.media.style.getPropertyValue(key)); // Clean up from media element
|
||||
|
||||
|
||||
_this5.media.style.removeProperty(key);
|
||||
}); // Remove attribute if empty
|
||||
|
||||
if (is$1.empty(this.media.style)) {
|
||||
this.media.removeAttribute('style');
|
||||
}
|
||||
}
|
||||
};
|
||||
|
||||
@ -4695,15 +4786,17 @@ var Listeners = /*#__PURE__*/function () {
|
||||
removeCurrent(); // Delay the adding of classname until the focus has changed
|
||||
// This event fires before the focusin event
|
||||
|
||||
this.focusTimer = setTimeout(function () {
|
||||
var focused = document.activeElement; // Ignore if current focus element isn't inside the player
|
||||
if (event.type !== 'focusout') {
|
||||
this.focusTimer = setTimeout(function () {
|
||||
var focused = document.activeElement; // Ignore if current focus element isn't inside the player
|
||||
|
||||
if (!elements.container.contains(focused)) {
|
||||
return;
|
||||
}
|
||||
if (!elements.container.contains(focused)) {
|
||||
return;
|
||||
}
|
||||
|
||||
toggleClass(document.activeElement, player.config.classNames.tabFocus, true);
|
||||
}, 10);
|
||||
toggleClass(document.activeElement, player.config.classNames.tabFocus, true);
|
||||
}, 10);
|
||||
}
|
||||
} // Global window & document listeners
|
||||
|
||||
}, {
|
||||
@ -4721,7 +4814,7 @@ var Listeners = /*#__PURE__*/function () {
|
||||
|
||||
once.call(player, document.body, 'touchstart', this.firstTouch); // Tab focus detection
|
||||
|
||||
toggleListener.call(player, document.body, 'keydown focus blur', this.setTabFocus, toggle, false, true);
|
||||
toggleListener.call(player, document.body, 'keydown focus blur focusout', this.setTabFocus, toggle, false, true);
|
||||
} // Container listeners
|
||||
|
||||
}, {
|
||||
@ -4764,7 +4857,7 @@ var Listeners = /*#__PURE__*/function () {
|
||||
}); // Set a gutter for Vimeo
|
||||
|
||||
var setGutter = function setGutter(ratio, padding, toggle) {
|
||||
if (!player.isVimeo) {
|
||||
if (!player.isVimeo || player.config.vimeo.premium) {
|
||||
return;
|
||||
}
|
||||
|
||||
@ -4821,7 +4914,7 @@ var Listeners = /*#__PURE__*/function () {
|
||||
ratio = _setPlayerSize.ratio; // Set Vimeo gutter
|
||||
|
||||
|
||||
setGutter(ratio, padding, isEnter); // If not using native fullscreen, we need to check for resizes of viewport
|
||||
setGutter(ratio, padding, isEnter); // If not using native browser fullscreen API, we need to check for resizes of viewport
|
||||
|
||||
if (!usingNative) {
|
||||
if (isEnter) {
|
||||
@ -5200,7 +5293,18 @@ var Listeners = /*#__PURE__*/function () {
|
||||
|
||||
this.bind(elements.controls, 'mouseenter mouseleave', function (event) {
|
||||
elements.controls.hover = !player.touch && event.type === 'mouseenter';
|
||||
}); // Update controls.pressed state (used for ui.toggleControls to avoid hiding when interacting)
|
||||
}); // Also update controls.hover state for any non-player children of fullscreen element (as above)
|
||||
|
||||
if (elements.fullscreen) {
|
||||
Array.from(elements.fullscreen.children).filter(function (c) {
|
||||
return !c.contains(elements.container);
|
||||
}).forEach(function (child) {
|
||||
_this3.bind(child, 'mouseenter mouseleave', function (event) {
|
||||
elements.controls.hover = !player.touch && event.type === 'mouseenter';
|
||||
});
|
||||
});
|
||||
} // Update controls.pressed state (used for ui.toggleControls to avoid hiding when interacting)
|
||||
|
||||
|
||||
this.bind(elements.controls, 'mousedown mouseup touchstart touchend touchcancel', function (event) {
|
||||
elements.controls.pressed = ['mousedown', 'touchstart'].includes(event.type);
|
||||
@ -5616,15 +5720,28 @@ var vimeo = {
|
||||
var _this = this;
|
||||
|
||||
var player = this;
|
||||
var config = player.config.vimeo; // Get Vimeo params for the iframe
|
||||
var config = player.config.vimeo;
|
||||
|
||||
var 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
|
||||
|
||||
@ -5638,22 +5755,27 @@ var vimeo = {
|
||||
var src = format(player.config.urls.vimeo.iframe, id, params);
|
||||
iframe.setAttribute('src', src);
|
||||
iframe.setAttribute('allowfullscreen', '');
|
||||
iframe.setAttribute('allowtransparency', '');
|
||||
iframe.setAttribute('allow', 'autoplay'); // Set the referrer policy if required
|
||||
iframe.setAttribute('allow', 'autoplay,fullscreen,picture-in-picture'); // Set the referrer policy if required
|
||||
|
||||
if (!is$1.empty(config.referrerPolicy)) {
|
||||
iframe.setAttribute('referrerPolicy', config.referrerPolicy);
|
||||
} // Get poster, if already set
|
||||
if (!is$1.empty(referrerPolicy)) {
|
||||
iframe.setAttribute('referrerPolicy', referrerPolicy);
|
||||
} // Inject the package
|
||||
|
||||
|
||||
var poster = player.poster; // Inject the package
|
||||
var poster = player.poster;
|
||||
|
||||
if (premium) {
|
||||
iframe.setAttribute('data-poster', poster);
|
||||
player.media = replaceElement(iframe, player.media);
|
||||
} else {
|
||||
var wrapper = createElement('div', {
|
||||
class: player.config.classNames.embedContainer,
|
||||
'data-poster': poster
|
||||
});
|
||||
wrapper.appendChild(iframe);
|
||||
player.media = replaceElement(wrapper, player.media);
|
||||
} // Get poster image
|
||||
|
||||
var wrapper = createElement('div', {
|
||||
poster: poster,
|
||||
class: player.config.classNames.embedContainer
|
||||
});
|
||||
wrapper.appendChild(iframe);
|
||||
player.media = replaceElement(wrapper, player.media); // Get poster image
|
||||
|
||||
fetch(format(player.config.urls.vimeo.api, id), 'json').then(function (response) {
|
||||
if (is$1.empty(response)) {
|
||||
@ -6026,7 +6148,7 @@ var youtube = {
|
||||
|
||||
var container = createElement('div', {
|
||||
id: id,
|
||||
poster: poster
|
||||
'data-poster': poster
|
||||
});
|
||||
player.media = replaceElement(container, player.media); // Id to poster wrapper
|
||||
|
||||
@ -6345,14 +6467,12 @@ var media = {
|
||||
class: this.config.classNames.video
|
||||
}); // Wrap the video in a container
|
||||
|
||||
wrap(this.media, this.elements.wrapper); // Faux poster container
|
||||
wrap(this.media, this.elements.wrapper); // Poster image container
|
||||
|
||||
if (this.isEmbed) {
|
||||
this.elements.poster = createElement('div', {
|
||||
class: this.config.classNames.poster
|
||||
});
|
||||
this.elements.wrapper.appendChild(this.elements.poster);
|
||||
}
|
||||
this.elements.poster = createElement('div', {
|
||||
class: this.config.classNames.poster
|
||||
});
|
||||
this.elements.wrapper.appendChild(this.elements.poster);
|
||||
}
|
||||
|
||||
if (this.isHTML5) {
|
||||
@ -7958,6 +8078,7 @@ var Plyr = /*#__PURE__*/function () {
|
||||
|
||||
this.elements = {
|
||||
container: null,
|
||||
fullscreen: null,
|
||||
captions: null,
|
||||
buttons: {},
|
||||
display: {},
|
||||
@ -8132,9 +8253,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
|
||||
@ -8143,10 +8266,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
|
||||
@ -8154,9 +8279,7 @@ var Plyr = /*#__PURE__*/function () {
|
||||
|
||||
this.listeners.container(); // Global listeners
|
||||
|
||||
this.listeners.global(); // Setup fullscreen
|
||||
|
||||
this.fullscreen = new Fullscreen(this); // Setup ads if provided
|
||||
this.listeners.global(); // Setup ads if provided
|
||||
|
||||
if (this.config.ads.enabled) {
|
||||
this.ads = new Ads(this);
|
||||
@ -8855,7 +8978,7 @@ var Plyr = /*#__PURE__*/function () {
|
||||
var updateStorage = true;
|
||||
|
||||
if (!options.includes(quality)) {
|
||||
var value = closest(options, quality);
|
||||
var value = closest$1(options, quality);
|
||||
this.debug.warn("Unsupported quality option: ".concat(quality, ", using ").concat(value, " instead"));
|
||||
quality = value; // Don't update storage if quality is not supported
|
||||
|
||||
@ -9000,7 +9123,7 @@ var Plyr = /*#__PURE__*/function () {
|
||||
return null;
|
||||
}
|
||||
|
||||
return this.media.getAttribute('poster');
|
||||
return this.media.getAttribute('poster') || this.media.getAttribute('data-poster');
|
||||
}
|
||||
/**
|
||||
* Get the current aspect ratio in use
|
||||
|
262
dist/plyr.polyfilled.js
vendored
262
dist/plyr.polyfilled.js
vendored
@ -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,6 +4123,42 @@ 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) || _unsupportedIterableToArray(arr, i) || _nonIterableRest();
|
||||
}
|
||||
@ -6008,7 +6044,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-
|
||||
@ -7018,6 +7060,25 @@ typeof navigator === "object" && (function (global, factory) {
|
||||
|
||||
var method = prototype.matches || prototype.webkitMatchesSelector || prototype.mozMatchesSelector || prototype.msMatchesSelector || match;
|
||||
return method.call(element, selector);
|
||||
} // Closest ancestor element matching selector (also tests element itself)
|
||||
|
||||
function closest(element, selector) {
|
||||
var _Element2 = Element,
|
||||
prototype = _Element2.prototype; // https://developer.mozilla.org/en-US/docs/Web/API/Element/closest#Polyfill
|
||||
|
||||
function closestElement() {
|
||||
var el = this;
|
||||
|
||||
do {
|
||||
if (matches$1.matches(el, selector)) return el;
|
||||
el = el.parentElement || el.parentNode;
|
||||
} while (el !== null && el.nodeType === 1);
|
||||
|
||||
return null;
|
||||
}
|
||||
|
||||
var method = prototype.closest || closestElement;
|
||||
return method.call(element, selector);
|
||||
} // Find all elements
|
||||
|
||||
function getElements(selector) {
|
||||
@ -7369,8 +7430,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) {
|
||||
@ -7523,7 +7584,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;
|
||||
}
|
||||
@ -9593,9 +9654,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);
|
||||
@ -9619,6 +9686,8 @@ typeof navigator === "object" && (function (global, factory) {
|
||||
// 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
|
||||
@ -9665,7 +9734,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
|
||||
@ -9746,7 +9823,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
|
||||
@ -9754,20 +9831,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) {
|
||||
@ -9948,6 +10025,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
|
||||
@ -10185,16 +10265,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
|
||||
@ -10304,7 +10384,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 () {
|
||||
@ -10530,7 +10613,7 @@ typeof navigator === "object" && (function (global, factory) {
|
||||
}, {
|
||||
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",
|
||||
@ -10739,12 +10822,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 () {
|
||||
@ -10820,6 +10898,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 key.startsWith('--plyr');
|
||||
}).forEach(function (key) {
|
||||
// Set on the container
|
||||
_this5.elements.container.style.setProperty(key, _this5.media.style.getPropertyValue(key)); // Clean up from media element
|
||||
|
||||
|
||||
_this5.media.style.removeProperty(key);
|
||||
}); // Remove attribute if empty
|
||||
|
||||
if (is$1.empty(this.media.style)) {
|
||||
this.media.removeAttribute('style');
|
||||
}
|
||||
}
|
||||
};
|
||||
|
||||
@ -11028,15 +11126,17 @@ typeof navigator === "object" && (function (global, factory) {
|
||||
removeCurrent(); // Delay the adding of classname until the focus has changed
|
||||
// This event fires before the focusin event
|
||||
|
||||
this.focusTimer = setTimeout(function () {
|
||||
var focused = document.activeElement; // Ignore if current focus element isn't inside the player
|
||||
if (event.type !== 'focusout') {
|
||||
this.focusTimer = setTimeout(function () {
|
||||
var focused = document.activeElement; // Ignore if current focus element isn't inside the player
|
||||
|
||||
if (!elements.container.contains(focused)) {
|
||||
return;
|
||||
}
|
||||
if (!elements.container.contains(focused)) {
|
||||
return;
|
||||
}
|
||||
|
||||
toggleClass(document.activeElement, player.config.classNames.tabFocus, true);
|
||||
}, 10);
|
||||
toggleClass(document.activeElement, player.config.classNames.tabFocus, true);
|
||||
}, 10);
|
||||
}
|
||||
} // Global window & document listeners
|
||||
|
||||
}, {
|
||||
@ -11054,7 +11154,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
|
||||
|
||||
}, {
|
||||
@ -11097,7 +11197,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;
|
||||
}
|
||||
|
||||
@ -11154,7 +11254,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) {
|
||||
@ -11533,7 +11633,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);
|
||||
@ -12002,15 +12113,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
|
||||
|
||||
@ -12024,22 +12148,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', {
|
||||
class: player.config.classNames.embedContainer,
|
||||
'data-poster': poster
|
||||
});
|
||||
wrapper.appendChild(iframe);
|
||||
player.media = replaceElement(wrapper, player.media);
|
||||
} // Get poster image
|
||||
|
||||
var wrapper = createElement('div', {
|
||||
poster: poster,
|
||||
class: player.config.classNames.embedContainer
|
||||
});
|
||||
wrapper.appendChild(iframe);
|
||||
player.media = replaceElement(wrapper, player.media); // Get poster image
|
||||
|
||||
fetch(format(player.config.urls.vimeo.api, id), 'json').then(function (response) {
|
||||
if (is$1.empty(response)) {
|
||||
@ -12410,7 +12539,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
|
||||
|
||||
@ -12728,14 +12857,12 @@ 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);
|
||||
}
|
||||
this.elements.poster = createElement('div', {
|
||||
class: this.config.classNames.poster
|
||||
});
|
||||
this.elements.wrapper.appendChild(this.elements.poster);
|
||||
}
|
||||
|
||||
if (this.isHTML5) {
|
||||
@ -14392,6 +14519,7 @@ typeof navigator === "object" && (function (global, factory) {
|
||||
|
||||
this.elements = {
|
||||
container: null,
|
||||
fullscreen: null,
|
||||
captions: null,
|
||||
buttons: {},
|
||||
display: {},
|
||||
@ -14566,9 +14694,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
|
||||
@ -14577,10 +14707,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
|
||||
@ -14588,9 +14720,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);
|
||||
@ -15289,7 +15419,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
|
||||
|
||||
@ -15434,7 +15564,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
|
||||
|
4
dist/plyr.polyfilled.min.js
vendored
4
dist/plyr.polyfilled.min.js
vendored
File diff suppressed because one or more lines are too long
2
dist/plyr.polyfilled.min.js.map
vendored
2
dist/plyr.polyfilled.min.js.map
vendored
File diff suppressed because one or more lines are too long
4
dist/plyr.polyfilled.min.mjs
vendored
4
dist/plyr.polyfilled.min.mjs
vendored
File diff suppressed because one or more lines are too long
2
dist/plyr.polyfilled.min.mjs.map
vendored
2
dist/plyr.polyfilled.min.mjs.map
vendored
File diff suppressed because one or more lines are too long
262
dist/plyr.polyfilled.mjs
vendored
262
dist/plyr.polyfilled.mjs
vendored
@ -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,6 +4117,42 @@ function _objectSpread2(target) {
|
||||
return target;
|
||||
}
|
||||
|
||||
function _objectWithoutPropertiesLoose(source, excluded) {
|
||||
if (source == null) return {};
|
||||
var target = {};
|
||||
var sourceKeys = Object.keys(source);
|
||||
var key, i;
|
||||
|
||||
for (i = 0; i < sourceKeys.length; i++) {
|
||||
key = sourceKeys[i];
|
||||
if (excluded.indexOf(key) >= 0) continue;
|
||||
target[key] = source[key];
|
||||
}
|
||||
|
||||
return target;
|
||||
}
|
||||
|
||||
function _objectWithoutProperties(source, excluded) {
|
||||
if (source == null) return {};
|
||||
|
||||
var target = _objectWithoutPropertiesLoose(source, excluded);
|
||||
|
||||
var key, i;
|
||||
|
||||
if (Object.getOwnPropertySymbols) {
|
||||
var sourceSymbolKeys = Object.getOwnPropertySymbols(source);
|
||||
|
||||
for (i = 0; i < sourceSymbolKeys.length; i++) {
|
||||
key = sourceSymbolKeys[i];
|
||||
if (excluded.indexOf(key) >= 0) continue;
|
||||
if (!Object.prototype.propertyIsEnumerable.call(source, key)) continue;
|
||||
target[key] = source[key];
|
||||
}
|
||||
}
|
||||
|
||||
return target;
|
||||
}
|
||||
|
||||
function _slicedToArray(arr, i) {
|
||||
return _arrayWithHoles(arr) || _iterableToArrayLimit(arr, i) || _unsupportedIterableToArray(arr, i) || _nonIterableRest();
|
||||
}
|
||||
@ -6002,7 +6038,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-
|
||||
@ -7012,6 +7054,25 @@ function matches$1(element, selector) {
|
||||
|
||||
var method = prototype.matches || prototype.webkitMatchesSelector || prototype.mozMatchesSelector || prototype.msMatchesSelector || match;
|
||||
return method.call(element, selector);
|
||||
} // Closest ancestor element matching selector (also tests element itself)
|
||||
|
||||
function closest(element, selector) {
|
||||
var _Element2 = Element,
|
||||
prototype = _Element2.prototype; // https://developer.mozilla.org/en-US/docs/Web/API/Element/closest#Polyfill
|
||||
|
||||
function closestElement() {
|
||||
var el = this;
|
||||
|
||||
do {
|
||||
if (matches$1.matches(el, selector)) return el;
|
||||
el = el.parentElement || el.parentNode;
|
||||
} while (el !== null && el.nodeType === 1);
|
||||
|
||||
return null;
|
||||
}
|
||||
|
||||
var method = prototype.closest || closestElement;
|
||||
return method.call(element, selector);
|
||||
} // Find all elements
|
||||
|
||||
function getElements(selector) {
|
||||
@ -7363,8 +7424,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) {
|
||||
@ -7517,7 +7578,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;
|
||||
}
|
||||
@ -9587,9 +9648,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);
|
||||
@ -9613,6 +9680,8 @@ var captions = {
|
||||
// Toggle captions display
|
||||
// Used internally for the toggleCaptions method, with the passive option forced to false
|
||||
toggle: function toggle(input) {
|
||||
var _this2 = this;
|
||||
|
||||
var passive = arguments.length > 1 && arguments[1] !== undefined ? arguments[1] : true;
|
||||
|
||||
// If there's no full support
|
||||
@ -9659,7 +9728,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
|
||||
@ -9740,7 +9817,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
|
||||
@ -9748,20 +9825,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) {
|
||||
@ -9942,6 +10019,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
|
||||
@ -10179,16 +10259,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
|
||||
@ -10298,7 +10378,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 () {
|
||||
@ -10524,7 +10607,7 @@ var Fullscreen = /*#__PURE__*/function () {
|
||||
}, {
|
||||
key: "target",
|
||||
get: function get() {
|
||||
return browser.isIos && this.player.config.fullscreen.iosNative ? this.player.media : this.player.elements.container;
|
||||
return browser.isIos && this.player.config.fullscreen.iosNative ? this.player.media : this.player.elements.fullscreen || this.player.elements.container;
|
||||
}
|
||||
}], [{
|
||||
key: "native",
|
||||
@ -10733,12 +10816,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 () {
|
||||
@ -10814,6 +10892,26 @@ var ui = {
|
||||
|
||||
this.toggleControls(Boolean(force || this.loading || this.paused || controlsElement.pressed || controlsElement.hover || recentTouchSeek));
|
||||
}
|
||||
},
|
||||
// Migrate any custom properties from the media to the parent
|
||||
migrateStyles: function migrateStyles() {
|
||||
var _this5 = this;
|
||||
|
||||
// Loop through values (as they are the keys when the object is spread 🤔)
|
||||
Object.values(_objectSpread2({}, this.media.style)) // We're only fussed about Plyr specific properties
|
||||
.filter(function (key) {
|
||||
return key.startsWith('--plyr');
|
||||
}).forEach(function (key) {
|
||||
// Set on the container
|
||||
_this5.elements.container.style.setProperty(key, _this5.media.style.getPropertyValue(key)); // Clean up from media element
|
||||
|
||||
|
||||
_this5.media.style.removeProperty(key);
|
||||
}); // Remove attribute if empty
|
||||
|
||||
if (is$1.empty(this.media.style)) {
|
||||
this.media.removeAttribute('style');
|
||||
}
|
||||
}
|
||||
};
|
||||
|
||||
@ -11022,15 +11120,17 @@ var Listeners = /*#__PURE__*/function () {
|
||||
removeCurrent(); // Delay the adding of classname until the focus has changed
|
||||
// This event fires before the focusin event
|
||||
|
||||
this.focusTimer = setTimeout(function () {
|
||||
var focused = document.activeElement; // Ignore if current focus element isn't inside the player
|
||||
if (event.type !== 'focusout') {
|
||||
this.focusTimer = setTimeout(function () {
|
||||
var focused = document.activeElement; // Ignore if current focus element isn't inside the player
|
||||
|
||||
if (!elements.container.contains(focused)) {
|
||||
return;
|
||||
}
|
||||
if (!elements.container.contains(focused)) {
|
||||
return;
|
||||
}
|
||||
|
||||
toggleClass(document.activeElement, player.config.classNames.tabFocus, true);
|
||||
}, 10);
|
||||
toggleClass(document.activeElement, player.config.classNames.tabFocus, true);
|
||||
}, 10);
|
||||
}
|
||||
} // Global window & document listeners
|
||||
|
||||
}, {
|
||||
@ -11048,7 +11148,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
|
||||
|
||||
}, {
|
||||
@ -11091,7 +11191,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;
|
||||
}
|
||||
|
||||
@ -11148,7 +11248,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) {
|
||||
@ -11527,7 +11627,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);
|
||||
@ -11996,15 +12107,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
|
||||
|
||||
@ -12018,22 +12142,27 @@ var vimeo = {
|
||||
var src = format(player.config.urls.vimeo.iframe, id, params);
|
||||
iframe.setAttribute('src', src);
|
||||
iframe.setAttribute('allowfullscreen', '');
|
||||
iframe.setAttribute('allowtransparency', '');
|
||||
iframe.setAttribute('allow', 'autoplay'); // Set the referrer policy if required
|
||||
iframe.setAttribute('allow', 'autoplay,fullscreen,picture-in-picture'); // Set the referrer policy if required
|
||||
|
||||
if (!is$1.empty(config.referrerPolicy)) {
|
||||
iframe.setAttribute('referrerPolicy', config.referrerPolicy);
|
||||
} // Get poster, if already set
|
||||
if (!is$1.empty(referrerPolicy)) {
|
||||
iframe.setAttribute('referrerPolicy', referrerPolicy);
|
||||
} // Inject the package
|
||||
|
||||
|
||||
var poster = player.poster; // Inject the package
|
||||
var poster = player.poster;
|
||||
|
||||
if (premium) {
|
||||
iframe.setAttribute('data-poster', poster);
|
||||
player.media = replaceElement(iframe, player.media);
|
||||
} else {
|
||||
var wrapper = createElement('div', {
|
||||
class: player.config.classNames.embedContainer,
|
||||
'data-poster': poster
|
||||
});
|
||||
wrapper.appendChild(iframe);
|
||||
player.media = replaceElement(wrapper, player.media);
|
||||
} // Get poster image
|
||||
|
||||
var wrapper = createElement('div', {
|
||||
poster: poster,
|
||||
class: player.config.classNames.embedContainer
|
||||
});
|
||||
wrapper.appendChild(iframe);
|
||||
player.media = replaceElement(wrapper, player.media); // Get poster image
|
||||
|
||||
fetch(format(player.config.urls.vimeo.api, id), 'json').then(function (response) {
|
||||
if (is$1.empty(response)) {
|
||||
@ -12404,7 +12533,7 @@ var youtube = {
|
||||
|
||||
var container = createElement('div', {
|
||||
id: id,
|
||||
poster: poster
|
||||
'data-poster': poster
|
||||
});
|
||||
player.media = replaceElement(container, player.media); // Id to poster wrapper
|
||||
|
||||
@ -12722,14 +12851,12 @@ 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);
|
||||
}
|
||||
this.elements.poster = createElement('div', {
|
||||
class: this.config.classNames.poster
|
||||
});
|
||||
this.elements.wrapper.appendChild(this.elements.poster);
|
||||
}
|
||||
|
||||
if (this.isHTML5) {
|
||||
@ -14386,6 +14513,7 @@ var Plyr = /*#__PURE__*/function () {
|
||||
|
||||
this.elements = {
|
||||
container: null,
|
||||
fullscreen: null,
|
||||
captions: null,
|
||||
buttons: {},
|
||||
display: {},
|
||||
@ -14560,9 +14688,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
|
||||
@ -14571,10 +14701,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
|
||||
@ -14582,9 +14714,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);
|
||||
@ -15283,7 +15413,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
|
||||
|
||||
@ -15428,7 +15558,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
|
||||
|
@ -1,6 +1,6 @@
|
||||
{
|
||||
"name": "plyr",
|
||||
"version": "3.5.10",
|
||||
"version": "3.6.0",
|
||||
"description": "A simple, accessible and customizable HTML5, YouTube and Vimeo media player",
|
||||
"homepage": "https://plyr.io",
|
||||
"author": "Sam Potts <sam@potts.es>",
|
||||
|
Loading…
x
Reference in New Issue
Block a user