diff options
Diffstat (limited to 'dist/plyr.js')
-rw-r--r-- | dist/plyr.js | 980 |
1 files changed, 523 insertions, 457 deletions
diff --git a/dist/plyr.js b/dist/plyr.js index 0bcd4d39..fa39b186 100644 --- a/dist/plyr.js +++ b/dist/plyr.js @@ -75,20 +75,52 @@ typeof navigator === "object" && (function (global, factory) { return target; } + function _objectWithoutPropertiesLoose(source, excluded) { + if (source == null) return {}; + var target = {}; + var sourceKeys = Object.keys(source); + var key, i; + + for (i = 0; i < sourceKeys.length; i++) { + key = sourceKeys[i]; + if (excluded.indexOf(key) >= 0) continue; + target[key] = source[key]; + } + + return target; + } + + function _objectWithoutProperties(source, excluded) { + if (source == null) return {}; + + var target = _objectWithoutPropertiesLoose(source, excluded); + + var key, i; + + if (Object.getOwnPropertySymbols) { + var sourceSymbolKeys = Object.getOwnPropertySymbols(source); + + for (i = 0; i < sourceSymbolKeys.length; i++) { + key = sourceSymbolKeys[i]; + if (excluded.indexOf(key) >= 0) continue; + if (!Object.prototype.propertyIsEnumerable.call(source, key)) continue; + target[key] = source[key]; + } + } + + return target; + } + function _slicedToArray(arr, i) { - return _arrayWithHoles(arr) || _iterableToArrayLimit(arr, i) || _nonIterableRest(); + return _arrayWithHoles(arr) || _iterableToArrayLimit(arr, i) || _unsupportedIterableToArray(arr, i) || _nonIterableRest(); } function _toConsumableArray(arr) { - return _arrayWithoutHoles(arr) || _iterableToArray(arr) || _nonIterableSpread(); + return _arrayWithoutHoles(arr) || _iterableToArray(arr) || _unsupportedIterableToArray(arr) || _nonIterableSpread(); } function _arrayWithoutHoles(arr) { - if (Array.isArray(arr)) { - for (var i = 0, arr2 = new Array(arr.length); i < arr.length; i++) arr2[i] = arr[i]; - - return arr2; - } + if (Array.isArray(arr)) return _arrayLikeToArray(arr); } function _arrayWithHoles(arr) { @@ -96,14 +128,11 @@ typeof navigator === "object" && (function (global, factory) { } function _iterableToArray(iter) { - if (Symbol.iterator in Object(iter) || Object.prototype.toString.call(iter) === "[object Arguments]") return Array.from(iter); + if (typeof Symbol !== "undefined" && Symbol.iterator in Object(iter)) return Array.from(iter); } function _iterableToArrayLimit(arr, i) { - if (!(Symbol.iterator in Object(arr) || Object.prototype.toString.call(arr) === "[object Arguments]")) { - return; - } - + if (typeof Symbol === "undefined" || !(Symbol.iterator in Object(arr))) return; var _arr = []; var _n = true; var _d = false; @@ -129,102 +158,142 @@ typeof navigator === "object" && (function (global, factory) { return _arr; } - function _nonIterableSpread() { - throw new TypeError("Invalid attempt to spread non-iterable instance"); - } - - function _nonIterableRest() { - throw new TypeError("Invalid attempt to destructure non-iterable instance"); + function _unsupportedIterableToArray(o, minLen) { + if (!o) return; + if (typeof o === "string") return _arrayLikeToArray(o, minLen); + var n = Object.prototype.toString.call(o).slice(8, -1); + if (n === "Object" && o.constructor) n = o.constructor.name; + if (n === "Map" || n === "Set") return Array.from(n); + if (n === "Arguments" || /^(?:Ui|I)nt(?:8|16|32)(?:Clamped)?Array$/.test(n)) return _arrayLikeToArray(o, minLen); } - var defaults = { - addCSS: true, - // Add CSS to the element to improve usability (required here or in your CSS!) - thumbWidth: 15, - // The width of the thumb handle - watch: true // Watch for new elements that match a string target - - }; + function _arrayLikeToArray(arr, len) { + if (len == null || len > arr.length) len = arr.length; - // Element matches a selector - function matches(element, selector) { - - function match() { - return Array.from(document.querySelectorAll(selector)).includes(this); - } + for (var i = 0, arr2 = new Array(len); i < len; i++) arr2[i] = arr[i]; - var matches = match; - return matches.call(element, selector); + return arr2; } - // Trigger event - function trigger(element, type) { - if (!element || !type) { - return; - } // Create and dispatch the event - - - var event = new Event(type); // Dispatch the event - - element.dispatchEvent(event); + function _nonIterableSpread() { + throw new TypeError("Invalid attempt to spread non-iterable instance.\nIn order to be iterable, non-array objects must have a [Symbol.iterator]() method."); } - // ========================================================================== - // Type checking utils - // ========================================================================== - var getConstructor = function getConstructor(input) { - return input !== null && typeof input !== 'undefined' ? input.constructor : null; - }; + function _nonIterableRest() { + throw new TypeError("Invalid attempt to destructure non-iterable instance.\nIn order to be iterable, non-array objects must have a [Symbol.iterator]() method."); + } - var instanceOf = function instanceOf(input, constructor) { - return Boolean(input && constructor && input instanceof constructor); - }; + function _classCallCheck$1(e, t) { + if (!(e instanceof t)) throw new TypeError("Cannot call a class as a function"); + } - var isNullOrUndefined = function isNullOrUndefined(input) { - return input === null || typeof input === 'undefined'; - }; + function _defineProperties$1(e, t) { + for (var n = 0; n < t.length; n++) { + var r = t[n]; + r.enumerable = r.enumerable || !1, r.configurable = !0, "value" in r && (r.writable = !0), Object.defineProperty(e, r.key, r); + } + } - var isObject = function isObject(input) { - return getConstructor(input) === Object; - }; + function _createClass$1(e, t, n) { + return t && _defineProperties$1(e.prototype, t), n && _defineProperties$1(e, n), e; + } - var isNumber = function isNumber(input) { - return getConstructor(input) === Number && !Number.isNaN(input); - }; + function _defineProperty$1(e, t, n) { + return t in e ? Object.defineProperty(e, t, { + value: n, + enumerable: !0, + configurable: !0, + writable: !0 + }) : e[t] = n, e; + } - var isString = function isString(input) { - return getConstructor(input) === String; - }; + function ownKeys$1(e, t) { + var n = Object.keys(e); - var isBoolean = function isBoolean(input) { - return getConstructor(input) === Boolean; - }; + if (Object.getOwnPropertySymbols) { + var r = Object.getOwnPropertySymbols(e); + t && (r = r.filter(function (t) { + return Object.getOwnPropertyDescriptor(e, t).enumerable; + })), n.push.apply(n, r); + } - var isFunction = function isFunction(input) { - return getConstructor(input) === Function; - }; + return n; + } - var isArray = function isArray(input) { - return Array.isArray(input); - }; + function _objectSpread2$1(e) { + for (var t = 1; t < arguments.length; t++) { + var n = null != arguments[t] ? arguments[t] : {}; + t % 2 ? ownKeys$1(Object(n), !0).forEach(function (t) { + _defineProperty$1(e, t, n[t]); + }) : Object.getOwnPropertyDescriptors ? Object.defineProperties(e, Object.getOwnPropertyDescriptors(n)) : ownKeys$1(Object(n)).forEach(function (t) { + Object.defineProperty(e, t, Object.getOwnPropertyDescriptor(n, t)); + }); + } - var isNodeList = function isNodeList(input) { - return instanceOf(input, NodeList); - }; + return e; + } - var isElement = function isElement(input) { - return instanceOf(input, Element); + var defaults = { + addCSS: !0, + thumbWidth: 15, + watch: !0 }; - var isEvent = function isEvent(input) { - return instanceOf(input, Event); - }; + function matches(e, t) { + return function () { + return Array.from(document.querySelectorAll(t)).includes(this); + }.call(e, t); + } - var isEmpty = function isEmpty(input) { - return isNullOrUndefined(input) || (isString(input) || isArray(input) || isNodeList(input)) && !input.length || isObject(input) && !Object.keys(input).length; - }; + function trigger(e, t) { + if (e && t) { + var n = new Event(t, { + bubbles: !0 + }); + e.dispatchEvent(n); + } + } - var is = { + var getConstructor = function getConstructor(e) { + return null != e ? e.constructor : null; + }, + instanceOf = function instanceOf(e, t) { + return !!(e && t && e instanceof t); + }, + isNullOrUndefined = function isNullOrUndefined(e) { + return null == e; + }, + isObject = function isObject(e) { + return getConstructor(e) === Object; + }, + isNumber = function isNumber(e) { + return getConstructor(e) === Number && !Number.isNaN(e); + }, + isString = function isString(e) { + return getConstructor(e) === String; + }, + isBoolean = function isBoolean(e) { + return getConstructor(e) === Boolean; + }, + isFunction = function isFunction(e) { + return getConstructor(e) === Function; + }, + isArray = function isArray(e) { + return Array.isArray(e); + }, + isNodeList = function isNodeList(e) { + return instanceOf(e, NodeList); + }, + isElement = function isElement(e) { + return instanceOf(e, Element); + }, + isEvent = function isEvent(e) { + return instanceOf(e, Event); + }, + isEmpty = function isEmpty(e) { + return isNullOrUndefined(e) || (isString(e) || isArray(e) || isNodeList(e)) && !e.length || isObject(e) && !Object.keys(e).length; + }, + is = { nullOrUndefined: isNullOrUndefined, object: isObject, number: isNumber, @@ -238,219 +307,98 @@ typeof navigator === "object" && (function (global, factory) { empty: isEmpty }; - // Get the number of decimal places - function getDecimalPlaces(value) { - var match = "".concat(value).match(/(?:\.(\d+))?(?:[eE]([+-]?\d+))?$/); - - if (!match) { - return 0; - } - - return Math.max(0, // Number of digits right of decimal point. - (match[1] ? match[1].length : 0) - ( // Adjust for scientific notation. - match[2] ? +match[2] : 0)); - } // Round to the nearest step + function getDecimalPlaces(e) { + var t = "".concat(e).match(/(?:\.(\d+))?(?:[eE]([+-]?\d+))?$/); + return t ? Math.max(0, (t[1] ? t[1].length : 0) - (t[2] ? +t[2] : 0)) : 0; + } - function round(number, step) { - if (step < 1) { - var places = getDecimalPlaces(step); - return parseFloat(number.toFixed(places)); + function round(e, t) { + if (1 > t) { + var n = getDecimalPlaces(t); + return parseFloat(e.toFixed(n)); } - return Math.round(number / step) * step; + return Math.round(e / t) * t; } - var RangeTouch = - /*#__PURE__*/ - function () { - /** - * Setup a new instance - * @param {String|Element} target - * @param {Object} options - */ - function RangeTouch(target, options) { - _classCallCheck(this, RangeTouch); - - if (is.element(target)) { - // An Element is passed, use it directly - this.element = target; - } else if (is.string(target)) { - // A CSS Selector is passed, fetch it from the DOM - this.element = document.querySelector(target); - } - - if (!is.element(this.element) || !is.empty(this.element.rangeTouch)) { - return; - } - - this.config = Object.assign({}, defaults, options); - this.init(); + var RangeTouch = function () { + function e(t, n) { + _classCallCheck$1(this, e), is.element(t) ? this.element = t : is.string(t) && (this.element = document.querySelector(t)), is.element(this.element) && is.empty(this.element.rangeTouch) && (this.config = _objectSpread2$1({}, defaults, {}, n), this.init()); } - _createClass(RangeTouch, [{ + return _createClass$1(e, [{ key: "init", - value: function init() { - // Bail if not a touch enabled device - if (!RangeTouch.enabled) { - return; - } // Add useful CSS - - - if (this.config.addCSS) { - // TODO: Restore original values on destroy - this.element.style.userSelect = 'none'; - this.element.style.webKitUserSelect = 'none'; - this.element.style.touchAction = 'manipulation'; - } - - this.listeners(true); - this.element.rangeTouch = this; + value: function value() { + e.enabled && (this.config.addCSS && (this.element.style.userSelect = "none", this.element.style.webKitUserSelect = "none", this.element.style.touchAction = "manipulation"), this.listeners(!0), this.element.rangeTouch = this); } }, { key: "destroy", - value: function destroy() { - // Bail if not a touch enabled device - if (!RangeTouch.enabled) { - return; - } - - this.listeners(false); - this.element.rangeTouch = null; + value: function value() { + e.enabled && (this.config.addCSS && (this.element.style.userSelect = "", this.element.style.webKitUserSelect = "", this.element.style.touchAction = ""), this.listeners(!1), this.element.rangeTouch = null); } }, { key: "listeners", - value: function listeners(toggle) { - var _this = this; - - var method = toggle ? 'addEventListener' : 'removeEventListener'; // Listen for events - - ['touchstart', 'touchmove', 'touchend'].forEach(function (type) { - _this.element[method](type, function (event) { - return _this.set(event); - }, false); + value: function value(e) { + var t = this, + n = e ? "addEventListener" : "removeEventListener"; + ["touchstart", "touchmove", "touchend"].forEach(function (e) { + t.element[n](e, function (e) { + return t.set(e); + }, !1); }); } - /** - * Get the value based on touch position - * @param {Event} event - */ - }, { key: "get", - value: function get(event) { - if (!RangeTouch.enabled || !is.event(event)) { - return null; - } - - var input = event.target; - var touch = event.changedTouches[0]; - var min = parseFloat(input.getAttribute('min')) || 0; - var max = parseFloat(input.getAttribute('max')) || 100; - var step = parseFloat(input.getAttribute('step')) || 1; - var delta = max - min; // Calculate percentage - - var percent; - var clientRect = input.getBoundingClientRect(); - var thumbWidth = 100 / clientRect.width * (this.config.thumbWidth / 2) / 100; // Determine left percentage - - percent = 100 / clientRect.width * (touch.clientX - clientRect.left); // Don't allow outside bounds - - if (percent < 0) { - percent = 0; - } else if (percent > 100) { - percent = 100; - } // Factor in the thumb offset - - - if (percent < 50) { - percent -= (100 - percent * 2) * thumbWidth; - } else if (percent > 50) { - percent += (percent - 50) * 2 * thumbWidth; - } // Find the closest step to the mouse position - - - return min + round(delta * (percent / 100), step); + value: function value(t) { + if (!e.enabled || !is.event(t)) return null; + var n, + r = t.target, + i = t.changedTouches[0], + o = parseFloat(r.getAttribute("min")) || 0, + s = parseFloat(r.getAttribute("max")) || 100, + u = parseFloat(r.getAttribute("step")) || 1, + c = r.getBoundingClientRect(), + a = 100 / c.width * (this.config.thumbWidth / 2) / 100; + return 0 > (n = 100 / c.width * (i.clientX - c.left)) ? n = 0 : 100 < n && (n = 100), 50 > n ? n -= (100 - 2 * n) * a : 50 < n && (n += 2 * (n - 50) * a), o + round(n / 100 * (s - o), u); } - /** - * Update range value based on position - * @param {Event} event - */ - }, { key: "set", - value: function set(event) { - if (!RangeTouch.enabled || !is.event(event) || event.target.disabled) { - return; - } // Prevent text highlight on iOS - - - event.preventDefault(); // Set value - - event.target.value = this.get(event); // Trigger event - - trigger(event.target, event.type === 'touchend' ? 'change' : 'input'); + value: function value(t) { + e.enabled && is.event(t) && !t.target.disabled && (t.preventDefault(), t.target.value = this.get(t), trigger(t.target, "touchend" === t.type ? "change" : "input")); } }], [{ key: "setup", - - /** - * Setup multiple instances - * @param {String|Element|NodeList|Array} target - * @param {Object} options - */ - value: function setup(target) { - var options = arguments.length > 1 && arguments[1] !== undefined ? arguments[1] : {}; - var targets = null; - - if (is.empty(target) || is.string(target)) { - targets = Array.from(document.querySelectorAll(is.string(target) ? target : 'input[type="range"]')); - } else if (is.element(target)) { - targets = [target]; - } else if (is.nodeList(target)) { - targets = Array.from(target); - } else if (is.array(target)) { - targets = target.filter(is.element); - } - - if (is.empty(targets)) { - return null; - } - - var config = Object.assign({}, defaults, options); - - if (is.string(target) && config.watch) { - // Create an observer instance - var observer = new MutationObserver(function (mutations) { - Array.from(mutations).forEach(function (mutation) { - Array.from(mutation.addedNodes).forEach(function (node) { - if (!is.element(node) || !matches(node, target)) { - return; - } // eslint-disable-next-line no-unused-vars - - - var range = new RangeTouch(node, config); + value: function value(t) { + var n = 1 < arguments.length && void 0 !== arguments[1] ? arguments[1] : {}, + r = null; + if (is.empty(t) || is.string(t) ? r = Array.from(document.querySelectorAll(is.string(t) ? t : 'input[type="range"]')) : is.element(t) ? r = [t] : is.nodeList(t) ? r = Array.from(t) : is.array(t) && (r = t.filter(is.element)), is.empty(r)) return null; + + var i = _objectSpread2$1({}, defaults, {}, n); + + if (is.string(t) && i.watch) { + var o = new MutationObserver(function (n) { + Array.from(n).forEach(function (n) { + Array.from(n.addedNodes).forEach(function (n) { + is.element(n) && matches(n, t) && new e(n, i); }); }); - }); // Pass in the target node, as well as the observer options - - observer.observe(document.body, { - childList: true, - subtree: true + }); + o.observe(document.body, { + childList: !0, + subtree: !0 }); } - return targets.map(function (t) { - return new RangeTouch(t, options); + return r.map(function (t) { + return new e(t, n); }); } }, { key: "enabled", get: function get() { - return 'ontouchstart' in document.documentElement; + return "ontouchstart" in document.documentElement; } - }]); - - return RangeTouch; + }]), e; }(); // ========================================================================== @@ -525,7 +473,7 @@ typeof navigator === "object" && (function (global, factory) { }; var isPromise = function isPromise(input) { - return instanceOf$1(input, Promise); + return instanceOf$1(input, Promise) && isFunction$1(input.then); }; var isEmpty$1 = function isEmpty(input) { @@ -867,12 +815,33 @@ typeof navigator === "object" && (function (global, factory) { } // Element matches selector function matches$1(element, selector) { + var _Element = Element, + prototype = _Element.prototype; function match() { return Array.from(document.querySelectorAll(selector)).includes(this); } - var method = match; + var method = prototype.matches || prototype.webkitMatchesSelector || prototype.mozMatchesSelector || prototype.msMatchesSelector || match; + return method.call(element, selector); + } // Closest ancestor element matching selector (also tests element itself) + + function closest(element, selector) { + var _Element2 = Element, + prototype = _Element2.prototype; // https://developer.mozilla.org/en-US/docs/Web/API/Element/closest#Polyfill + + function closestElement() { + var el = this; + + do { + if (matches$1.matches(el, selector)) return el; + el = el.parentElement || el.parentNode; + } while (el !== null && el.nodeType === 1); + + return null; + } + + var method = prototype.closest || closestElement; return method.call(element, selector); } // Find all elements @@ -1144,6 +1113,19 @@ typeof navigator === "object" && (function (global, factory) { }).then(function () {}); } + /** + * Silence a Promise-like object. + * This is useful for avoiding non-harmful, but potentially confusing "uncaught + * play promise" rejection error messages. + * @param {Object} value An object that may or may not be `Promise`-like. + */ + + function silencePromise(value) { + if (is$1.promise(value)) { + value.then(null, function () {}); + } + } + function validateRatio(input) { if (!is$1.array(input) && (!is$1.string(input) || !input.includes(':'))) { return false; @@ -1212,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) { @@ -1320,7 +1302,7 @@ typeof navigator === "object" && (function (global, factory) { player.currentTime = currentTime; // Resume playing if (!paused) { - player.play(); + silencePromise(player.play()); } }); // Load new source @@ -1369,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; } @@ -1407,19 +1389,19 @@ typeof navigator === "object" && (function (global, factory) { return (current / max * 100).toFixed(2); } // Replace all occurances of a string in a string - function replaceAll() { + var replaceAll = function replaceAll() { var input = arguments.length > 0 && arguments[0] !== undefined ? arguments[0] : ''; var find = arguments.length > 1 && arguments[1] !== undefined ? arguments[1] : ''; var replace = arguments.length > 2 && arguments[2] !== undefined ? arguments[2] : ''; return input.replace(new RegExp(find.toString().replace(/([.*+?^=!:${}()|[\]/\\])/g, '\\$1'), 'g'), replace.toString()); - } // Convert to title case + }; // Convert to title case - function toTitleCase() { + var toTitleCase = function toTitleCase() { var input = arguments.length > 0 && arguments[0] !== undefined ? arguments[0] : ''; return input.toString().replace(/\w\S*/g, function (text) { return text.charAt(0).toUpperCase() + text.substr(1).toLowerCase(); }); - } // Convert string to pascalCase + }; // Convert string to pascalCase function toPascalCase() { var input = arguments.length > 0 && arguments[0] !== undefined ? arguments[0] : ''; @@ -1498,9 +1480,7 @@ typeof navigator === "object" && (function (global, factory) { } }; - var Storage = - /*#__PURE__*/ - function () { + var Storage = /*#__PURE__*/function () { function Storage(player) { _classCallCheck(this, Storage); @@ -1782,7 +1762,7 @@ typeof navigator === "object" && (function (global, factory) { var icon = document.createElementNS(namespace, 'svg'); setAttributes(icon, extend(attributes, { - role: 'presentation', + 'aria-hidden': 'true', focusable: 'false' })); // Create the <use> to reference sprite @@ -2519,39 +2499,39 @@ typeof navigator === "object" && (function (global, factory) { // Set the looping options /* setLoopMenu() { - // Menu required - if (!is.element(this.elements.settings.panels.loop)) { - return; - } - const options = ['start', 'end', 'all', 'reset']; - const list = this.elements.settings.panels.loop.querySelector('[role="menu"]'); - // Show the pane and tab - toggleHidden(this.elements.settings.buttons.loop, false); - toggleHidden(this.elements.settings.panels.loop, false); - // Toggle the pane and tab - const toggle = !is.empty(this.loop.options); - controls.toggleMenuButton.call(this, 'loop', toggle); - // Empty the menu - emptyElement(list); - options.forEach(option => { - const item = createElement('li'); - const button = createElement( - 'button', - extend(getAttributesFromSelector(this.config.selectors.buttons.loop), { - type: 'button', - class: this.config.classNames.control, - 'data-plyr-loop-action': option, - }), - i18n.get(option, this.config) - ); - if (['start', 'end'].includes(option)) { - const badge = controls.createBadge.call(this, '00:00'); - button.appendChild(badge); - } - item.appendChild(button); - list.appendChild(item); - }); - }, */ + // Menu required + if (!is.element(this.elements.settings.panels.loop)) { + return; + } + const options = ['start', 'end', 'all', 'reset']; + const list = this.elements.settings.panels.loop.querySelector('[role="menu"]'); + // Show the pane and tab + toggleHidden(this.elements.settings.buttons.loop, false); + toggleHidden(this.elements.settings.panels.loop, false); + // Toggle the pane and tab + const toggle = !is.empty(this.loop.options); + controls.toggleMenuButton.call(this, 'loop', toggle); + // Empty the menu + emptyElement(list); + options.forEach(option => { + const item = createElement('li'); + const button = createElement( + 'button', + extend(getAttributesFromSelector(this.config.selectors.buttons.loop), { + type: 'button', + class: this.config.classNames.control, + 'data-plyr-loop-action': option, + }), + i18n.get(option, this.config) + ); + if (['start', 'end'].includes(option)) { + const badge = controls.createBadge.call(this, '00:00'); + button.appendChild(badge); + } + item.appendChild(button); + list.appendChild(item); + }); + }, */ // Get current selected caption language // TODO: rework this to user the getter in the API? // Set a list of available captions languages @@ -3353,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); @@ -3372,13 +3358,15 @@ typeof navigator === "object" && (function (global, factory) { toggleClass(this.elements.container, this.config.classNames.captions.enabled, !is$1.empty(tracks)); // Update available languages in list - if ((this.config.controls || []).includes('settings') && this.config.settings.includes('captions')) { + if (is$1.array(this.config.controls) && this.config.controls.includes('settings') && this.config.settings.includes('captions')) { controls.setCaptionsMenu.call(this); } }, // Toggle captions display // Used internally for the toggleCaptions method, with the passive option forced to false toggle: function toggle(input) { + var _this2 = this; + var passive = arguments.length > 1 && arguments[1] !== undefined ? arguments[1] : true; // If there's no full support @@ -3425,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 @@ -3506,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 @@ -3514,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) { @@ -3708,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 @@ -3945,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 @@ -4011,9 +4010,7 @@ typeof navigator === "object" && (function (global, factory) { // ========================================================================== var noop = function noop() {}; - var Console = - /*#__PURE__*/ - function () { + var Console = /*#__PURE__*/function () { function Console() { var enabled = arguments.length > 0 && arguments[0] !== undefined ? arguments[0] : false; @@ -4049,9 +4046,7 @@ typeof navigator === "object" && (function (global, factory) { return Console; }(); - var Fullscreen = - /*#__PURE__*/ - function () { + var Fullscreen = /*#__PURE__*/function () { function Fullscreen(player) { var _this = this; @@ -4068,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 () { @@ -4241,7 +4239,7 @@ typeof navigator === "object" && (function (global, factory) { if (browser.isIos && this.player.config.fullscreen.iosNative) { this.target.webkitExitFullscreen(); - this.player.play(); + silencePromise(this.player.play()); } else if (!Fullscreen.native || this.forceFallback) { this.toggleFallback(false); } else if (!this.prefix) { @@ -4288,13 +4286,13 @@ typeof navigator === "object" && (function (global, factory) { } var element = !this.prefix ? document.fullscreenElement : document["".concat(this.prefix).concat(this.property, "Element")]; - return element === this.target; + return element && element.shadowRoot ? element === this.target.getRootNode().host : element === this.target; } // Get target element }, { key: "target", get: function get() { - return browser.isIos && this.player.config.fullscreen.iosNative ? this.player.media : this.player.elements.container; + return browser.isIos && this.player.config.fullscreen.iosNative ? this.player.media : this.player.elements.fullscreen || this.player.elements.container; } }], [{ key: "native", @@ -4356,7 +4354,6 @@ typeof navigator === "object" && (function (global, factory) { }); } - // ========================================================================== var ui = { addStyleHook: function addStyleHook() { toggleClass(this.elements.container, this.config.selectors.container.replace('.', ''), true); @@ -4491,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 () { @@ -4572,12 +4564,30 @@ 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'); + } } }; - var Listeners = - /*#__PURE__*/ - function () { + var Listeners = /*#__PURE__*/function () { function Listeners(player) { _classCallCheck(this, Listeners); @@ -4668,7 +4678,7 @@ typeof navigator === "object" && (function (global, factory) { case 75: // Space and K key if (!repeat) { - player.togglePlay(); + silencePromise(player.togglePlay()); } break; @@ -4782,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 }, { @@ -4808,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 }, { @@ -4851,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; } @@ -4908,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) { @@ -4986,9 +4998,13 @@ typeof navigator === "object" && (function (global, factory) { if (player.ended) { _this.proxy(event, player.restart, 'restart'); - _this.proxy(event, player.play, 'play'); + _this.proxy(event, function () { + silencePromise(player.play()); + }, 'play'); } else { - _this.proxy(event, player.togglePlay, 'play'); + _this.proxy(event, function () { + silencePromise(player.togglePlay()); + }, 'play'); } }); } // Disable right click @@ -5086,7 +5102,9 @@ typeof navigator === "object" && (function (global, factory) { if (elements.buttons.play) { Array.from(elements.buttons.play).forEach(function (button) { - _this3.bind(button, 'click', player.togglePlay, 'play'); + _this3.bind(button, 'click', function () { + silencePromise(player.togglePlay()); + }, 'play'); }); } // Pause @@ -5183,7 +5201,7 @@ typeof navigator === "object" && (function (global, factory) { if (play && done) { seek.removeAttribute(attribute); - player.play(); + silencePromise(player.play()); } else if (!done && player.playing) { seek.setAttribute(attribute, ''); player.pause(); @@ -5281,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); @@ -5697,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 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 + - var params = buildUrlParams(extend({}, { + 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 @@ -5719,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)) { @@ -5818,6 +5865,9 @@ typeof navigator === "object" && (function (global, factory) { player.embed.setPlaybackRate(input).then(function () { speed = input; triggerEvent.call(player, player.media, 'ratechange'); + }).catch(function () { + // Cannot set Playback Rate, Video is probably not on Pro account + player.options.speed = [1]; }); } }); // Volume @@ -6104,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 @@ -6423,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) { @@ -6457,9 +6505,7 @@ typeof navigator === "object" && (function (global, factory) { instance.elements.container.remove(); }; - var Ads = - /*#__PURE__*/ - function () { + var Ads = /*#__PURE__*/function () { /** * Ads constructor. * @param {Object} player @@ -6559,6 +6605,8 @@ typeof navigator === "object" && (function (global, factory) { * mobile devices, this initialization is done as the result of a user action. */ value: function setupIMA() { + var _this4 = this; + // Create the container for our advertisements this.elements.container = createElement('div', { class: this.player.config.classNames.ads @@ -6571,7 +6619,16 @@ typeof navigator === "object" && (function (global, factory) { google.ima.settings.setDisableCustomPlaybackForIOS10Plus(this.player.config.playsinline); // We assume the adContainer is the video container of the plyr element that will house the ads - this.elements.displayContainer = new google.ima.AdDisplayContainer(this.elements.container, this.player.media); // Request video ads to be pre-loaded + this.elements.displayContainer = new google.ima.AdDisplayContainer(this.elements.container, this.player.media); // Create ads loader + + this.loader = new google.ima.AdsLoader(this.elements.displayContainer); // Listen and respond to ads loaded and error events + + this.loader.addEventListener(google.ima.AdsManagerLoadedEvent.Type.ADS_MANAGER_LOADED, function (event) { + return _this4.onAdsManagerLoaded(event); + }, false); + this.loader.addEventListener(google.ima.AdErrorEvent.Type.AD_ERROR, function (error) { + return _this4.onAdError(error); + }, false); // Request video ads to be pre-loaded this.requestAds(); } @@ -6582,21 +6639,10 @@ typeof navigator === "object" && (function (global, factory) { }, { key: "requestAds", value: function requestAds() { - var _this4 = this; - var container = this.player.elements.container; try { - // Create ads loader - this.loader = new google.ima.AdsLoader(this.elements.displayContainer); // Listen and respond to ads loaded and error events - - this.loader.addEventListener(google.ima.AdsManagerLoadedEvent.Type.ADS_MANAGER_LOADED, function (event) { - return _this4.onAdsManagerLoaded(event); - }, false); - this.loader.addEventListener(google.ima.AdErrorEvent.Type.AD_ERROR, function (error) { - return _this4.onAdError(error); - }, false); // Request video ads - + // Request video ads var request = new google.ima.AdsRequest(); request.adTagUrl = this.tagUrl; // Specify the linear and nonlinear slot sizes. This helps the SDK // to select the correct creative if multiple are returned @@ -6775,7 +6821,13 @@ typeof navigator === "object" && (function (global, factory) { // }; // TODO: So there is still this thing where a video should only be allowed to start // playing when the IMA SDK is ready or has failed - this.loadAds(); + if (this.player.ended) { + this.loadAds(); + } else { + // The SDK won't allow new ads to be called without receiving a contentComplete() + this.loader.contentComplete(); + } + break; case google.ima.AdEvent.Type.CONTENT_PAUSE_REQUESTED: @@ -6911,7 +6963,7 @@ typeof navigator === "object" && (function (global, factory) { this.playing = false; // Play video - this.player.media.play(); + silencePromise(this.player.media.play()); } /** * Pause our video @@ -6968,7 +7020,9 @@ typeof navigator === "object" && (function (global, factory) { _this11.on('loaded', resolve); _this11.player.debug.log(_this11.manager); - }); // Now request some new advertisements + }); // Now that the manager has been destroyed set it to also be un-initialized + + _this11.initialized = false; // Now request some new advertisements _this11.requestAds(); }).catch(function () {}); @@ -7151,9 +7205,7 @@ typeof navigator === "object" && (function (global, factory) { return result; }; - var PreviewThumbnails = - /*#__PURE__*/ - function () { + var PreviewThumbnails = /*#__PURE__*/function () { /** * PreviewThumbnails constructor. * @param {Plyr} player @@ -7214,15 +7266,10 @@ typeof navigator === "object" && (function (global, factory) { if (is$1.empty(src)) { throw new Error('Missing previewThumbnails.src config attribute'); - } // If string, convert into single-element list + } // Resolve promise - var urls = is$1.string(src) ? [src] : src; // Loop through each src URL. Download and process the VTT file, storing the resulting data in this.thumbnails - - var promises = urls.map(function (u) { - return _this2.getThumbnail(u); - }); - Promise.all(promises).then(function () { + var sortAndResolve = function sortAndResolve() { // Sort smallest to biggest (e.g., [120p, 480p, 1080p]) _this2.thumbnails.sort(function (x, y) { return x.height - y.height; @@ -7231,7 +7278,25 @@ typeof navigator === "object" && (function (global, factory) { _this2.player.debug.log('Preview thumbnails', _this2.thumbnails); resolve(); - }); + }; // Via callback() + + + if (is$1.function(src)) { + src(function (thumbnails) { + _this2.thumbnails = thumbnails; + sortAndResolve(); + }); + } // VTT urls + else { + // If string, convert into single-element list + var urls = is$1.string(src) ? [src] : src; // Loop through each src URL. Download and process the VTT file, storing the resulting data in this.thumbnails + + var promises = urls.map(function (u) { + return _this2.getThumbnail(u); + }); // Resolve + + Promise.all(promises).then(sortAndResolve); + } }); } // Process individual VTT file @@ -7982,9 +8047,7 @@ typeof navigator === "object" && (function (global, factory) { // const globals = new WeakMap(); // Plyr instance - var Plyr = - /*#__PURE__*/ - function () { + var Plyr = /*#__PURE__*/function () { function Plyr(target, options) { var _this = this; @@ -8021,6 +8084,7 @@ typeof navigator === "object" && (function (global, factory) { this.elements = { container: null, + fullscreen: null, captions: null, buttons: {}, display: {}, @@ -8195,8 +8259,10 @@ 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 @@ -8206,9 +8272,11 @@ 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); @@ -8217,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); @@ -8228,7 +8294,7 @@ typeof navigator === "object" && (function (global, factory) { if (this.isHTML5 && this.config.autoplay) { setTimeout(function () { - return _this.play(); + return silencePromise(_this.play()); }, 10); } // Seek time will be recorded (in listeners.js) so we can prevent hiding controls for a few seconds after seek @@ -8265,7 +8331,7 @@ typeof navigator === "object" && (function (global, factory) { this.ads.managerPromise.then(function () { return _this2.ads.play(); }).catch(function () { - return _this2.media.play(); + return silencePromise(_this2.media.play()); }); } // Return the promise (for HTML5) @@ -8918,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 @@ -8957,41 +9023,41 @@ typeof navigator === "object" && (function (global, factory) { this.media.loop = toggle; // Set default to be a true toggle /* const type = ['start', 'end', 'all', 'none', 'toggle'].includes(input) ? input : 'toggle'; - switch (type) { - case 'start': - if (this.config.loop.end && this.config.loop.end <= this.currentTime) { - this.config.loop.end = null; - } - this.config.loop.start = this.currentTime; - // this.config.loop.indicator.start = this.elements.display.played.value; - break; - case 'end': - if (this.config.loop.start >= this.currentTime) { - return this; - } - this.config.loop.end = this.currentTime; - // this.config.loop.indicator.end = this.elements.display.played.value; - break; - case 'all': - this.config.loop.start = 0; - this.config.loop.end = this.duration - 2; - this.config.loop.indicator.start = 0; - this.config.loop.indicator.end = 100; - break; - case 'toggle': - if (this.config.loop.active) { - this.config.loop.start = 0; - this.config.loop.end = null; - } else { + switch (type) { + case 'start': + if (this.config.loop.end && this.config.loop.end <= this.currentTime) { + this.config.loop.end = null; + } + this.config.loop.start = this.currentTime; + // this.config.loop.indicator.start = this.elements.display.played.value; + break; + case 'end': + if (this.config.loop.start >= this.currentTime) { + return this; + } + this.config.loop.end = this.currentTime; + // this.config.loop.indicator.end = this.elements.display.played.value; + break; + case 'all': this.config.loop.start = 0; this.config.loop.end = this.duration - 2; - } - break; - default: - this.config.loop.start = 0; - this.config.loop.end = null; - break; - } */ + this.config.loop.indicator.start = 0; + this.config.loop.indicator.end = 100; + break; + case 'toggle': + if (this.config.loop.active) { + this.config.loop.start = 0; + this.config.loop.end = null; + } else { + this.config.loop.start = 0; + this.config.loop.end = this.duration - 2; + } + break; + default: + this.config.loop.start = 0; + this.config.loop.end = null; + break; + } */ } /** * Get current loop state @@ -9063,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 |