aboutsummaryrefslogtreecommitdiffstats
path: root/dist/plyr.mjs
diff options
context:
space:
mode:
Diffstat (limited to 'dist/plyr.mjs')
-rw-r--r--dist/plyr.mjs1617
1 files changed, 836 insertions, 781 deletions
diff --git a/dist/plyr.mjs b/dist/plyr.mjs
index e30c272b..59572923 100644
--- a/dist/plyr.mjs
+++ b/dist/plyr.mjs
@@ -35,20 +35,50 @@ function _defineProperty(obj, key, value) {
return obj;
}
+function ownKeys(object, enumerableOnly) {
+ var keys = Object.keys(object);
+
+ if (Object.getOwnPropertySymbols) {
+ var symbols = Object.getOwnPropertySymbols(object);
+ if (enumerableOnly) symbols = symbols.filter(function (sym) {
+ return Object.getOwnPropertyDescriptor(object, sym).enumerable;
+ });
+ keys.push.apply(keys, symbols);
+ }
+
+ return keys;
+}
+
+function _objectSpread2(target) {
+ for (var i = 1; i < arguments.length; i++) {
+ var source = arguments[i] != null ? arguments[i] : {};
+
+ if (i % 2) {
+ ownKeys(Object(source), true).forEach(function (key) {
+ _defineProperty(target, key, source[key]);
+ });
+ } else if (Object.getOwnPropertyDescriptors) {
+ Object.defineProperties(target, Object.getOwnPropertyDescriptors(source));
+ } else {
+ ownKeys(Object(source)).forEach(function (key) {
+ Object.defineProperty(target, key, Object.getOwnPropertyDescriptor(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) {
@@ -56,10 +86,11 @@ function _arrayWithHoles(arr) {
}
function _iterableToArray(iter) {
- if (Symbol.iterator in Object(iter) || Object.prototype.toString.call(iter) === "[object Arguments]") return Array.from(iter);
+ if (typeof Symbol !== "undefined" && Symbol.iterator in Object(iter)) return Array.from(iter);
}
function _iterableToArrayLimit(arr, i) {
+ if (typeof Symbol === "undefined" || !(Symbol.iterator in Object(arr))) return;
var _arr = [];
var _n = true;
var _d = false;
@@ -85,102 +116,142 @@ function _iterableToArrayLimit(arr, i) {
return _arr;
}
-function _nonIterableSpread() {
- throw new TypeError("Invalid attempt to spread 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);
}
-function _nonIterableRest() {
- throw new TypeError("Invalid attempt to destructure non-iterable instance");
-}
+function _arrayLikeToArray(arr, len) {
+ if (len == null || len > arr.length) len = arr.length;
-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
+ for (var i = 0, arr2 = new Array(len); i < len; i++) arr2[i] = arr[i];
-};
-
-// Element matches a selector
-function matches(element, selector) {
-
- function match() {
- return Array.from(document.querySelectorAll(selector)).includes(this);
- }
-
- 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,
@@ -194,219 +265,98 @@ var is = {
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;
}();
// ==========================================================================
@@ -481,7 +431,7 @@ var isTrack = function isTrack(input) {
};
var isPromise = function isPromise(input) {
- return instanceOf$1(input, Promise);
+ return instanceOf$1(input, Promise) && isFunction$1(input.then);
};
var isEmpty$1 = function isEmpty(input) {
@@ -535,151 +485,48 @@ var is$1 = {
};
// ==========================================================================
-// https://github.com/WICG/EventListenerOptions/blob/gh-pages/explainer.md
-// https://www.youtube.com/watch?v=NPM6172J22g
-
-var supportsPassiveListeners = function () {
- // Test via a getter in the options object to see if the passive property is accessed
- var supported = false;
-
- try {
- var options = Object.defineProperty({}, 'passive', {
- get: function get() {
- supported = true;
- return null;
- }
- });
- window.addEventListener('test', null, options);
- window.removeEventListener('test', null, options);
- } catch (e) {// Do nothing
- }
-
- return supported;
-}(); // Toggle event listener
-
-
-function toggleListener(element, event, callback) {
- var _this = this;
-
- var toggle = arguments.length > 3 && arguments[3] !== undefined ? arguments[3] : false;
- var passive = arguments.length > 4 && arguments[4] !== undefined ? arguments[4] : true;
- var capture = arguments.length > 5 && arguments[5] !== undefined ? arguments[5] : false;
-
- // Bail if no element, event, or callback
- if (!element || !('addEventListener' in element) || is$1.empty(event) || !is$1.function(callback)) {
- return;
- } // Allow multiple events
-
-
- var events = event.split(' '); // Build options
- // Default to just the capture boolean for browsers with no passive listener support
-
- var options = capture; // If passive events listeners are supported
-
- if (supportsPassiveListeners) {
- options = {
- // Whether the listener can be passive (i.e. default never prevented)
- passive: passive,
- // Whether the listener is a capturing listener or not
- capture: capture
- };
- } // If a single node is passed, bind the event listener
-
-
- events.forEach(function (type) {
- if (_this && _this.eventListeners && toggle) {
- // Cache event listener
- _this.eventListeners.push({
- element: element,
- type: type,
- callback: callback,
- options: options
- });
- }
-
- element[toggle ? 'addEventListener' : 'removeEventListener'](type, callback, options);
+var transitionEndEvent = function () {
+ var element = document.createElement('span');
+ var events = {
+ WebkitTransition: 'webkitTransitionEnd',
+ MozTransition: 'transitionend',
+ OTransition: 'oTransitionEnd otransitionend',
+ transition: 'transitionend'
+ };
+ var type = Object.keys(events).find(function (event) {
+ return element.style[event] !== undefined;
});
-} // Bind event handler
-
-function on(element) {
- var events = arguments.length > 1 && arguments[1] !== undefined ? arguments[1] : '';
- var callback = arguments.length > 2 ? arguments[2] : undefined;
- var passive = arguments.length > 3 && arguments[3] !== undefined ? arguments[3] : true;
- var capture = arguments.length > 4 && arguments[4] !== undefined ? arguments[4] : false;
- toggleListener.call(this, element, events, callback, true, passive, capture);
-} // Unbind event handler
-
-function off(element) {
- var events = arguments.length > 1 && arguments[1] !== undefined ? arguments[1] : '';
- var callback = arguments.length > 2 ? arguments[2] : undefined;
- var passive = arguments.length > 3 && arguments[3] !== undefined ? arguments[3] : true;
- var capture = arguments.length > 4 && arguments[4] !== undefined ? arguments[4] : false;
- toggleListener.call(this, element, events, callback, false, passive, capture);
-} // Bind once-only event handler
-
-function once(element) {
- var _this2 = this;
+ return is$1.string(type) ? events[type] : false;
+}(); // Force repaint of element
- var events = arguments.length > 1 && arguments[1] !== undefined ? arguments[1] : '';
- var callback = arguments.length > 2 ? arguments[2] : undefined;
- var passive = arguments.length > 3 && arguments[3] !== undefined ? arguments[3] : true;
- var capture = arguments.length > 4 && arguments[4] !== undefined ? arguments[4] : false;
+function repaint(element, delay) {
+ setTimeout(function () {
+ try {
+ // eslint-disable-next-line no-param-reassign
+ element.hidden = true; // eslint-disable-next-line no-unused-expressions
- var onceCallback = function onceCallback() {
- off(element, events, onceCallback, passive, capture);
+ element.offsetHeight; // eslint-disable-next-line no-param-reassign
- for (var _len = arguments.length, args = new Array(_len), _key = 0; _key < _len; _key++) {
- args[_key] = arguments[_key];
+ element.hidden = false;
+ } catch (e) {// Do nothing
}
-
- callback.apply(_this2, args);
- };
-
- toggleListener.call(this, element, events, onceCallback, true, passive, capture);
-} // Trigger event
-
-function triggerEvent(element) {
- var type = arguments.length > 1 && arguments[1] !== undefined ? arguments[1] : '';
- var bubbles = arguments.length > 2 && arguments[2] !== undefined ? arguments[2] : false;
- var detail = arguments.length > 3 && arguments[3] !== undefined ? arguments[3] : {};
-
- // Bail if no element
- if (!is$1.element(element) || is$1.empty(type)) {
- return;
- } // Create and dispatch the event
-
-
- var event = new CustomEvent(type, {
- bubbles: bubbles,
- detail: Object.assign({}, detail, {
- plyr: this
- })
- }); // Dispatch the event
-
- element.dispatchEvent(event);
-} // Unbind all cached event listeners
-
-function unbindListeners() {
- if (this && this.eventListeners) {
- this.eventListeners.forEach(function (item) {
- var element = item.element,
- type = item.type,
- callback = item.callback,
- options = item.options;
- element.removeEventListener(type, callback, options);
- });
- this.eventListeners = [];
- }
-} // Run method when / if player is ready
-
-function ready() {
- var _this3 = this;
-
- return new Promise(function (resolve) {
- return _this3.ready ? setTimeout(resolve, 0) : on.call(_this3, _this3.elements.container, 'ready', resolve);
- }).then(function () {});
+ }, delay);
}
+// ==========================================================================
+// Browser sniffing
+// Unfortunately, due to mixed support, UA sniffing is required
+// ==========================================================================
+var browser = {
+ isIE:
+ /* @cc_on!@ */
+ !!document.documentMode,
+ isEdge: window.navigator.userAgent.includes('Edge'),
+ isWebkit: 'WebkitAppearance' in document.documentElement.style && !/Edge/.test(navigator.userAgent),
+ isIPhone: /(iPhone|iPod)/gi.test(navigator.platform),
+ isIos: /(iPad|iPhone|iPod)/gi.test(navigator.platform)
+};
+
function cloneDeep(object) {
return JSON.parse(JSON.stringify(object));
} // Get a nested value in an object
@@ -880,9 +727,6 @@ function getAttributesFromSelector(sel, existingAttributes) {
// Attribute selector
attributes[key] = value;
break;
-
- default:
- break;
}
});
return extend(existing, attributes);
@@ -897,13 +741,10 @@ function toggleHidden(element, hidden) {
if (!is$1.boolean(hide)) {
hide = !element.hidden;
- }
+ } // eslint-disable-next-line no-param-reassign
- if (hide) {
- element.setAttribute('hidden', '');
- } else {
- element.removeAttribute('hidden');
- }
+
+ element.hidden = hide;
} // Mirror Element.classList.toggle, with IE compatibility for "force" argument
function toggleClass(element, className, force) {
@@ -932,12 +773,14 @@ function hasClass(element, className) {
} // Element matches selector
function matches$1(element, selector) {
+ var _Element = Element,
+ prototype = _Element.prototype;
function match() {
return Array.from(document.querySelectorAll(selector)).includes(this);
}
- var method = match;
+ var method = prototype.matches || prototype.webkitMatchesSelector || prototype.mozMatchesSelector || prototype.msMatchesSelector || match;
return method.call(element, selector);
} // Find all elements
@@ -947,41 +790,6 @@ function getElements(selector) {
function getElement(selector) {
return this.elements.container.querySelector(selector);
-} // Trap focus inside container
-
-function trapFocus() {
- var element = arguments.length > 0 && arguments[0] !== undefined ? arguments[0] : null;
- var toggle = arguments.length > 1 && arguments[1] !== undefined ? arguments[1] : false;
-
- if (!is$1.element(element)) {
- return;
- }
-
- var focusable = getElements.call(this, 'button:not(:disabled), input:not(:disabled), [tabindex]');
- var first = focusable[0];
- var last = focusable[focusable.length - 1];
-
- var trap = function trap(event) {
- // Bail if not tab key or not fullscreen
- if (event.key !== 'Tab' || event.keyCode !== 9) {
- return;
- } // Get the current focused element
-
-
- var focused = document.activeElement;
-
- if (focused === last && !event.shiftKey) {
- // Move focus to first element that can be tabbed if Shift isn't used
- first.focus();
- event.preventDefault();
- } else if (focused === first && event.shiftKey) {
- // Move focus to last element that can be tabbed if Shift is used
- last.focus();
- event.preventDefault();
- }
- };
-
- toggleListener.call(this, this.elements.container, 'keydown', trap, toggle, false);
} // Set focus and tab focus class
function setFocus() {
@@ -1002,47 +810,6 @@ function setFocus() {
}
}
-// ==========================================================================
-var transitionEndEvent = function () {
- var element = document.createElement('span');
- var events = {
- WebkitTransition: 'webkitTransitionEnd',
- MozTransition: 'transitionend',
- OTransition: 'oTransitionEnd otransitionend',
- transition: 'transitionend'
- };
- var type = Object.keys(events).find(function (event) {
- return element.style[event] !== undefined;
- });
- return is$1.string(type) ? events[type] : false;
-}(); // Force repaint of element
-
-function repaint(element) {
- setTimeout(function () {
- try {
- toggleHidden(element, true);
- element.offsetHeight; // eslint-disable-line
-
- toggleHidden(element, false);
- } catch (e) {// Do nothing
- }
- }, 0);
-}
-
-// ==========================================================================
-// Browser sniffing
-// Unfortunately, due to mixed support, UA sniffing is required
-// ==========================================================================
-var browser = {
- isIE:
- /* @cc_on!@ */
- !!document.documentMode,
- isEdge: window.navigator.userAgent.includes('Edge'),
- isWebkit: 'WebkitAppearance' in document.documentElement.style && !/Edge/.test(navigator.userAgent),
- isIPhone: /(iPhone|iPod)/gi.test(navigator.platform),
- isIos: /(iPad|iPhone|iPod)/gi.test(navigator.platform)
-};
-
var defaultCodecs = {
'audio/ogg': 'vorbis',
'audio/wav': '1',
@@ -1140,6 +907,164 @@ var support = {
reducedMotion: 'matchMedia' in window && window.matchMedia('(prefers-reduced-motion)').matches
};
+// https://github.com/WICG/EventListenerOptions/blob/gh-pages/explainer.md
+// https://www.youtube.com/watch?v=NPM6172J22g
+
+var supportsPassiveListeners = function () {
+ // Test via a getter in the options object to see if the passive property is accessed
+ var supported = false;
+
+ try {
+ var options = Object.defineProperty({}, 'passive', {
+ get: function get() {
+ supported = true;
+ return null;
+ }
+ });
+ window.addEventListener('test', null, options);
+ window.removeEventListener('test', null, options);
+ } catch (e) {// Do nothing
+ }
+
+ return supported;
+}(); // Toggle event listener
+
+
+function toggleListener(element, event, callback) {
+ var _this = this;
+
+ var toggle = arguments.length > 3 && arguments[3] !== undefined ? arguments[3] : false;
+ var passive = arguments.length > 4 && arguments[4] !== undefined ? arguments[4] : true;
+ var capture = arguments.length > 5 && arguments[5] !== undefined ? arguments[5] : false;
+
+ // Bail if no element, event, or callback
+ if (!element || !('addEventListener' in element) || is$1.empty(event) || !is$1.function(callback)) {
+ return;
+ } // Allow multiple events
+
+
+ var events = event.split(' '); // Build options
+ // Default to just the capture boolean for browsers with no passive listener support
+
+ var options = capture; // If passive events listeners are supported
+
+ if (supportsPassiveListeners) {
+ options = {
+ // Whether the listener can be passive (i.e. default never prevented)
+ passive: passive,
+ // Whether the listener is a capturing listener or not
+ capture: capture
+ };
+ } // If a single node is passed, bind the event listener
+
+
+ events.forEach(function (type) {
+ if (_this && _this.eventListeners && toggle) {
+ // Cache event listener
+ _this.eventListeners.push({
+ element: element,
+ type: type,
+ callback: callback,
+ options: options
+ });
+ }
+
+ element[toggle ? 'addEventListener' : 'removeEventListener'](type, callback, options);
+ });
+} // Bind event handler
+
+function on(element) {
+ var events = arguments.length > 1 && arguments[1] !== undefined ? arguments[1] : '';
+ var callback = arguments.length > 2 ? arguments[2] : undefined;
+ var passive = arguments.length > 3 && arguments[3] !== undefined ? arguments[3] : true;
+ var capture = arguments.length > 4 && arguments[4] !== undefined ? arguments[4] : false;
+ toggleListener.call(this, element, events, callback, true, passive, capture);
+} // Unbind event handler
+
+function off(element) {
+ var events = arguments.length > 1 && arguments[1] !== undefined ? arguments[1] : '';
+ var callback = arguments.length > 2 ? arguments[2] : undefined;
+ var passive = arguments.length > 3 && arguments[3] !== undefined ? arguments[3] : true;
+ var capture = arguments.length > 4 && arguments[4] !== undefined ? arguments[4] : false;
+ toggleListener.call(this, element, events, callback, false, passive, capture);
+} // Bind once-only event handler
+
+function once(element) {
+ var _this2 = this;
+
+ var events = arguments.length > 1 && arguments[1] !== undefined ? arguments[1] : '';
+ var callback = arguments.length > 2 ? arguments[2] : undefined;
+ var passive = arguments.length > 3 && arguments[3] !== undefined ? arguments[3] : true;
+ var capture = arguments.length > 4 && arguments[4] !== undefined ? arguments[4] : false;
+
+ var onceCallback = function onceCallback() {
+ off(element, events, onceCallback, passive, capture);
+
+ for (var _len = arguments.length, args = new Array(_len), _key = 0; _key < _len; _key++) {
+ args[_key] = arguments[_key];
+ }
+
+ callback.apply(_this2, args);
+ };
+
+ toggleListener.call(this, element, events, onceCallback, true, passive, capture);
+} // Trigger event
+
+function triggerEvent(element) {
+ var type = arguments.length > 1 && arguments[1] !== undefined ? arguments[1] : '';
+ var bubbles = arguments.length > 2 && arguments[2] !== undefined ? arguments[2] : false;
+ var detail = arguments.length > 3 && arguments[3] !== undefined ? arguments[3] : {};
+
+ // Bail if no element
+ if (!is$1.element(element) || is$1.empty(type)) {
+ return;
+ } // Create and dispatch the event
+
+
+ var event = new CustomEvent(type, {
+ bubbles: bubbles,
+ detail: _objectSpread2({}, detail, {
+ plyr: this
+ })
+ }); // Dispatch the event
+
+ element.dispatchEvent(event);
+} // Unbind all cached event listeners
+
+function unbindListeners() {
+ if (this && this.eventListeners) {
+ this.eventListeners.forEach(function (item) {
+ var element = item.element,
+ type = item.type,
+ callback = item.callback,
+ options = item.options;
+ element.removeEventListener(type, callback, options);
+ });
+ this.eventListeners = [];
+ }
+} // Run method when / if player is ready
+
+function ready() {
+ var _this3 = this;
+
+ return new Promise(function (resolve) {
+ return _this3.ready ? setTimeout(resolve, 0) : on.call(_this3, _this3.elements.container, 'ready', resolve);
+ }).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;
@@ -1166,12 +1091,8 @@ function reduceAspectRatio(ratio) {
}
function getAspectRatio(input) {
var parse = function parse(ratio) {
- if (!validateRatio(ratio)) {
- return null;
- }
-
- return ratio.split(':').map(Number);
- }; // Provided ratio
+ return validateRatio(ratio) ? ratio.split(':').map(Number) : null;
+ }; // Try provided ratio
var ratio = parse(input); // Get from config
@@ -1201,6 +1122,7 @@ function setAspectRatio(input) {
return {};
}
+ var wrapper = this.elements.wrapper;
var ratio = getAspectRatio.call(this, input);
var _ref = is$1.array(ratio) ? ratio : [0, 0],
@@ -1209,14 +1131,14 @@ function setAspectRatio(input) {
h = _ref2[1];
var padding = 100 / w * h;
- this.elements.wrapper.style.paddingBottom = "".concat(padding, "%"); // For Vimeo we have an extra <div> to hide the standard controls and UI
+ wrapper.style.paddingBottom = "".concat(padding, "%"); // For Vimeo we have an extra <div> to hide the standard controls and UI
if (this.isVimeo && this.supported.ui) {
var height = 240;
var offset = (height - padding) / (height / 50);
this.media.style.transform = "translateY(-".concat(offset, "%)");
} else if (this.isHTML5) {
- this.elements.wrapper.classList.toggle(this.config.classNames.videoFixedRatio, ratio !== null);
+ wrapper.classList.toggle(this.config.classNames.videoFixedRatio, ratio !== null);
}
return {
@@ -1248,19 +1170,29 @@ var html5 = {
},
// Get quality levels
getQualityOptions: function getQualityOptions() {
- // Get sizes from <source> elements
+ // Whether we're forcing all options (e.g. for streaming)
+ if (this.config.quality.forced) {
+ return this.config.quality.options;
+ } // Get sizes from <source> elements
+
+
return html5.getSources.call(this).map(function (source) {
return Number(source.getAttribute('size'));
}).filter(Boolean);
},
- extend: function extend() {
+ setup: function setup() {
if (!this.isHTML5) {
return;
}
- var player = this; // Set aspect ratio if set
+ var player = this; // Set speed options from config
+
+ player.options.speed = player.config.speed.options; // Set aspect ratio if fixed
+
+ if (!is$1.empty(this.config.ratio)) {
+ setAspectRatio.call(player);
+ } // Quality
- setAspectRatio.call(player); // Quality
Object.defineProperty(player.media, 'quality', {
get: function get() {
@@ -1273,37 +1205,48 @@ var html5 = {
return source && Number(source.getAttribute('size'));
},
set: function set(input) {
- // Get sources
- var sources = html5.getSources.call(player); // Get first match for requested size
+ if (player.quality === input) {
+ return;
+ } // If we're using an an external handler...
- var source = sources.find(function (s) {
- return Number(s.getAttribute('size')) === input;
- }); // No matching source found
- if (!source) {
- return;
- } // Get current state
+ if (player.config.quality.forced && is$1.function(player.config.quality.onChange)) {
+ player.config.quality.onChange(input);
+ } else {
+ // Get sources
+ var sources = html5.getSources.call(player); // Get first match for requested size
+ var source = sources.find(function (s) {
+ return Number(s.getAttribute('size')) === input;
+ }); // No matching source found
- var _player$media = player.media,
- currentTime = _player$media.currentTime,
- paused = _player$media.paused,
- preload = _player$media.preload,
- readyState = _player$media.readyState; // Set new source
+ if (!source) {
+ return;
+ } // Get current state
- player.media.src = source.getAttribute('src'); // Prevent loading if preload="none" and the current source isn't loaded (#1044)
- if (preload !== 'none' || readyState) {
- // Restore time
- player.once('loadedmetadata', function () {
- player.currentTime = currentTime; // Resume playing
+ var _player$media = player.media,
+ currentTime = _player$media.currentTime,
+ paused = _player$media.paused,
+ preload = _player$media.preload,
+ readyState = _player$media.readyState,
+ playbackRate = _player$media.playbackRate; // Set new source
- if (!paused) {
- player.play();
- }
- }); // Load new source
+ player.media.src = source.getAttribute('src'); // Prevent loading if preload="none" and the current source isn't loaded (#1044)
- player.media.load();
+ if (preload !== 'none' || readyState) {
+ // Restore time
+ player.once('loadedmetadata', function () {
+ player.speed = playbackRate;
+ player.currentTime = currentTime; // Resume playing
+
+ if (!paused) {
+ silencePromise(player.play());
+ }
+ }); // Load new source
+
+ player.media.load();
+ }
} // Trigger change event
@@ -1476,9 +1419,7 @@ var i18n = {
}
};
-var Storage =
-/*#__PURE__*/
-function () {
+var Storage = /*#__PURE__*/function () {
function Storage(player) {
_classCallCheck(this, Storage);
@@ -1674,7 +1615,7 @@ function formatTime() {
// Bail if the value isn't a number
if (!is$1.number(time)) {
- return formatTime(null, displayHours, inverted);
+ return formatTime(undefined, displayHours, inverted);
} // Format time component to add leading zero
@@ -1760,7 +1701,7 @@ var controls = {
var icon = document.createElementNS(namespace, 'svg');
setAttributes(icon, extend(attributes, {
- role: 'presentation',
+ 'aria-hidden': 'true',
focusable: 'false'
})); // Create the <use> to reference sprite
@@ -1783,9 +1724,11 @@ var controls = {
createLabel: function createLabel(key) {
var attr = arguments.length > 1 && arguments[1] !== undefined ? arguments[1] : {};
var text = i18n.get(key, this.config);
- var attributes = Object.assign({}, attr, {
+
+ var attributes = _objectSpread2({}, attr, {
class: [attr.class, this.config.classNames.hidden].filter(Boolean).join(' ')
});
+
return createElement('span', attributes, text);
},
// Create a badge
@@ -1995,7 +1938,7 @@ var controls = {
var _this2 = this;
// Navigate through menus via arrow keys and space
- on(menuItem, 'keydown keyup', function (event) {
+ on.call(this, menuItem, 'keydown keyup', function (event) {
// We only care about space and ⬆️ ⬇️️ ➡️
if (![32, 38, 39, 40].includes(event.which)) {
return;
@@ -2037,7 +1980,7 @@ var controls = {
}, false); // Enter will fire a `click` event but we still need to manage focus
// So we bind to keyup which fires after and set focus here
- on(menuItem, 'keyup', function (event) {
+ on.call(this, menuItem, 'keyup', function (event) {
if (event.which !== 13) {
return;
}
@@ -2114,9 +2057,6 @@ var controls = {
case 'speed':
_this3.speed = parseFloat(value);
break;
-
- default:
- break;
}
controls.showMenuPanel.call(_this3, 'home', is$1.keyboardEvent(event));
@@ -2225,9 +2165,6 @@ var controls = {
case 'progress':
setProgress(this.elements.display.buffer, this.buffered * 100);
break;
-
- default:
- break;
}
}
},
@@ -2585,7 +2522,7 @@ var controls = {
controls.updateSetting.call(this, type, list);
},
// Set a list of available captions languages
- setSpeedMenu: function setSpeedMenu(options) {
+ setSpeedMenu: function setSpeedMenu() {
var _this8 = this;
// Menu required
@@ -2594,17 +2531,10 @@ var controls = {
}
var type = 'speed';
- var list = this.elements.settings.panels.speed.querySelector('[role="menu"]'); // Set the speed options
-
- if (is$1.array(options)) {
- this.options.speed = options;
- } else if (this.isHTML5 || this.isVimeo) {
- this.options.speed = [0.5, 0.75, 1, 1.25, 1.5, 1.75, 2];
- } // Set options if passed and filter based on config
-
+ var list = this.elements.settings.panels.speed.querySelector('[role="menu"]'); // Filter out invalid speeds
- this.options.speed = this.options.speed.filter(function (speed) {
- return _this8.config.speed.options.includes(speed);
+ this.options.speed = this.options.speed.filter(function (o) {
+ return o >= _this8.minimumSpeed && o <= _this8.maximumSpeed;
}); // Toggle the pane and tab
var toggle = !is$1.empty(this.options.speed) && this.options.speed.length > 1;
@@ -2881,9 +2811,11 @@ var controls = {
if (control === 'mute') {
volume.appendChild(createButton.call(_this10, 'mute'));
} // Volume range control
+ // Ignored on iOS as it's handled globally
+ // https://developer.apple.com/library/safari/documentation/AudioVideo/Conceptual/Using_HTML5_Audio_Video/Device-SpecificConsiderations/Device-SpecificConsiderations.html
- if (control === 'volume') {
+ if (control === 'volume' && !browser.isIos) {
// Set the attributes
var attributes = {
max: 1,
@@ -2942,7 +2874,7 @@ var controls = {
bindMenuItemShortcuts.call(_this10, menuItem, type); // Show menu on click
- on(menuItem, 'click', function () {
+ on.call(_this10, menuItem, 'click', function () {
showMenuPanel.call(_this10, type, false);
});
var flex = createElement('span', null, i18n.get(type, _this10.config));
@@ -2973,7 +2905,7 @@ var controls = {
class: _this10.config.classNames.hidden
}, i18n.get('menuBack', _this10.config))); // Go back via keyboard
- on(pane, 'keydown', function (event) {
+ on.call(_this10, pane, 'keydown', function (event) {
// We only care about <-
if (event.which !== 37) {
return;
@@ -2986,7 +2918,7 @@ var controls = {
showMenuPanel.call(_this10, 'home', true);
}, false); // Go back via button click
- on(backButton, 'click', function () {
+ on.call(_this10, backButton, 'click', function () {
showMenuPanel.call(_this10, 'home', false);
}); // Add to pane
@@ -3023,7 +2955,12 @@ var controls = {
element: 'a',
href: _this10.download,
target: '_blank'
- });
+ }); // Set download attribute for HTML5 only
+
+
+ if (_this10.isHTML5) {
+ _attributes.download = '';
+ }
var download = _this10.config.urls.download;
@@ -3335,10 +3272,9 @@ var captions = {
meta.set(track, {
default: track.mode === 'showing'
}); // Turn off native caption rendering to avoid double captions
+ // eslint-disable-next-line no-param-reassign
- Object.assign(track, {
- mode: 'hidden'
- }); // Add event listener for cue changes
+ track.mode = 'hidden'; // Add event listener for cue changes
on.call(_this, track, 'cuechange', function () {
return captions.updateCues.call(_this);
@@ -3355,7 +3291,7 @@ var captions = {
toggleClass(this.elements.container, this.config.classNames.captions.enabled, !is$1.empty(tracks)); // Update available languages in list
- if ((this.config.controls || []).includes('settings') && this.config.settings.includes('captions')) {
+ if (is$1.array(this.config.controls) && this.config.controls.includes('settings') && this.config.settings.includes('captions')) {
controls.setCaptionsMenu.call(this);
}
},
@@ -3643,13 +3579,16 @@ var defaults$1 = {
// Sprite (for icons)
loadSprite: true,
iconPrefix: 'plyr',
- iconUrl: 'https://cdn.plyr.io/3.5.2/plyr.svg',
+ iconUrl: 'https://cdn.plyr.io/3.5.10/plyr.svg',
// Blank video (used to prevent errors on source change)
blankVideo: 'https://cdn.plyr.io/static/blank.mp4',
// Quality default
quality: {
default: 576,
- options: [4320, 2880, 2160, 1440, 1080, 720, 576, 480, 360, 240]
+ // The options to display in the UI, if available for the source media
+ options: [4320, 2880, 2160, 1440, 1080, 720, 576, 480, 360, 240],
+ forced: false,
+ onChange: null
},
// Set loops
loop: {
@@ -3660,7 +3599,8 @@ var defaults$1 = {
// Speed default and options to display
speed: {
selected: 1,
- options: [0.5, 0.75, 1, 1.25, 1.5, 1.75, 2]
+ // The options to display in the UI, if available for the source media (e.g. Vimeo and YouTube only support 0.5x-4x)
+ options: [0.5, 0.75, 1, 1.25, 1.5, 1.75, 2, 4]
},
// Keyboard shortcut settings
keyboard: {
@@ -3698,7 +3638,8 @@ var defaults$1 = {
controls: ['play-large', // 'restart',
// 'rewind',
'play', // 'fast-forward',
- 'progress', 'current-time', 'mute', 'volume', 'captions', 'settings', 'pip', 'airplay', // 'download',
+ 'progress', 'current-time', // 'duration',
+ 'mute', 'volume', 'captions', 'settings', 'pip', 'airplay', // 'download',
'fullscreen'],
settings: ['captions', 'quality', 'speed'],
// Localisation
@@ -3725,6 +3666,7 @@ var defaults$1 = {
frameTitle: 'Player for {title}',
captions: 'Captions',
settings: 'Settings',
+ pip: 'PIP',
menuBack: 'Go back to previous menu',
speed: 'Speed',
normal: 'Normal',
@@ -3756,8 +3698,7 @@ var defaults$1 = {
},
youtube: {
sdk: 'https://www.youtube.com/iframe_api',
- api: 'https://noembed.com/embed?url=https://www.youtube.com/watch?v={0}' // 'https://www.googleapis.com/youtube/v3/videos?id={0}&key={1}&fields=items(snippet(title),fileDetails)&part=snippet',
-
+ api: 'https://noembed.com/embed?url=https://www.youtube.com/watch?v={0}'
},
googleIMA: {
sdk: 'https://imasdk.googleapis.com/js/sdkloader/ima3.js'
@@ -3922,7 +3863,13 @@ var defaults$1 = {
portrait: false,
title: false,
speed: true,
- transparent: false
+ transparent: false,
+ // These settings require a pro or premium account to work
+ sidedock: false,
+ controls: false,
+ // Custom settings from Plyr
+ referrerPolicy: null // https://developer.mozilla.org/en-US/docs/Web/API/HTMLIFrameElement/referrerPolicy
+
},
// YouTube plugin
youtube: {
@@ -3983,9 +3930,7 @@ function getProviderByUrl(url) {
// ==========================================================================
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;
@@ -4021,123 +3966,144 @@ function () {
return Console;
}();
-function onChange() {
- if (!this.enabled) {
- return;
- } // Update toggle button
+var Fullscreen = /*#__PURE__*/function () {
+ function Fullscreen(player) {
+ var _this = this;
+ _classCallCheck(this, Fullscreen);
- var button = this.player.elements.buttons.fullscreen;
+ // Keep reference to parent
+ this.player = player; // Get prefix
- if (is$1.element(button)) {
- button.pressed = this.active;
- } // Trigger an event
+ this.prefix = Fullscreen.prefix;
+ this.property = Fullscreen.property; // Scroll position
+ this.scrollPosition = {
+ x: 0,
+ y: 0
+ }; // Force the use of 'full window/browser' rather than fullscreen
- triggerEvent.call(this.player, this.target, this.active ? 'enterfullscreen' : 'exitfullscreen', true); // Trap focus in container
+ this.forceFallback = player.config.fullscreen.fallback === 'force'; // Register event listeners
+ // Handle event (incase user presses escape etc)
- if (!browser.isIos) {
- trapFocus.call(this.player, this.target, this.active);
- }
-}
+ on.call(this.player, document, this.prefix === 'ms' ? 'MSFullscreenChange' : "".concat(this.prefix, "fullscreenchange"), function () {
+ // TODO: Filter for target??
+ _this.onChange();
+ }); // Fullscreen toggle on double click
-function toggleFallback() {
- var _this = this;
+ on.call(this.player, this.player.elements.container, 'dblclick', function (event) {
+ // Ignore double click in controls
+ if (is$1.element(_this.player.elements.controls) && _this.player.elements.controls.contains(event.target)) {
+ return;
+ }
- var toggle = arguments.length > 0 && arguments[0] !== undefined ? arguments[0] : false;
+ _this.toggle();
+ }); // Tap focus when in fullscreen
- // Store or restore scroll position
- if (toggle) {
- this.scrollPosition = {
- x: window.scrollX || 0,
- y: window.scrollY || 0
- };
- } else {
- window.scrollTo(this.scrollPosition.x, this.scrollPosition.y);
- } // Toggle scroll
+ on.call(this, this.player.elements.container, 'keydown', function (event) {
+ return _this.trapFocus(event);
+ }); // Update the UI
+ this.update();
+ } // Determine if native supported
- document.body.style.overflow = toggle ? 'hidden' : ''; // Toggle class hook
- toggleClass(this.target, this.player.config.classNames.fullscreen.fallback, toggle); // Force full viewport on iPhone X+
+ _createClass(Fullscreen, [{
+ key: "onChange",
+ value: function onChange() {
+ if (!this.enabled) {
+ return;
+ } // Update toggle button
- if (browser.isIos) {
- var viewport = document.head.querySelector('meta[name="viewport"]');
- var property = 'viewport-fit=cover'; // Inject the viewport meta if required
- if (!viewport) {
- viewport = document.createElement('meta');
- viewport.setAttribute('name', 'viewport');
- } // Check if the property already exists
+ var button = this.player.elements.buttons.fullscreen;
+ if (is$1.element(button)) {
+ button.pressed = this.active;
+ } // Trigger an event
- var hasProperty = is$1.string(viewport.content) && viewport.content.includes(property);
- if (toggle) {
- this.cleanupViewport = !hasProperty;
+ triggerEvent.call(this.player, this.target, this.active ? 'enterfullscreen' : 'exitfullscreen', true);
+ }
+ }, {
+ key: "toggleFallback",
+ value: function toggleFallback() {
+ var toggle = arguments.length > 0 && arguments[0] !== undefined ? arguments[0] : false;
- if (!hasProperty) {
- viewport.content += ",".concat(property);
- }
- } else if (this.cleanupViewport) {
- viewport.content = viewport.content.split(',').filter(function (part) {
- return part.trim() !== property;
- }).join(',');
- } // Force a repaint as sometimes Safari doesn't want to fill the screen
+ // Store or restore scroll position
+ if (toggle) {
+ this.scrollPosition = {
+ x: window.scrollX || 0,
+ y: window.scrollY || 0
+ };
+ } else {
+ window.scrollTo(this.scrollPosition.x, this.scrollPosition.y);
+ } // Toggle scroll
- setTimeout(function () {
- return repaint(_this.target);
- }, 100);
- } // Toggle button and fire events
+ document.body.style.overflow = toggle ? 'hidden' : ''; // Toggle class hook
+ toggleClass(this.target, this.player.config.classNames.fullscreen.fallback, toggle); // Force full viewport on iPhone X+
- onChange.call(this);
-}
+ if (browser.isIos) {
+ var viewport = document.head.querySelector('meta[name="viewport"]');
+ var property = 'viewport-fit=cover'; // Inject the viewport meta if required
-var Fullscreen =
-/*#__PURE__*/
-function () {
- function Fullscreen(player) {
- var _this2 = this;
+ if (!viewport) {
+ viewport = document.createElement('meta');
+ viewport.setAttribute('name', 'viewport');
+ } // Check if the property already exists
- _classCallCheck(this, Fullscreen);
- // Keep reference to parent
- this.player = player; // Get prefix
+ var hasProperty = is$1.string(viewport.content) && viewport.content.includes(property);
- this.prefix = Fullscreen.prefix;
- this.property = Fullscreen.property; // Scroll position
+ if (toggle) {
+ this.cleanupViewport = !hasProperty;
- this.scrollPosition = {
- x: 0,
- y: 0
- }; // Force the use of 'full window/browser' rather than fullscreen
+ if (!hasProperty) {
+ viewport.content += ",".concat(property);
+ }
+ } else if (this.cleanupViewport) {
+ viewport.content = viewport.content.split(',').filter(function (part) {
+ return part.trim() !== property;
+ }).join(',');
+ }
+ } // Toggle button and fire events
- this.forceFallback = player.config.fullscreen.fallback === 'force'; // Register event listeners
- // Handle event (incase user presses escape etc)
- on.call(this.player, document, this.prefix === 'ms' ? 'MSFullscreenChange' : "".concat(this.prefix, "fullscreenchange"), function () {
- // TODO: Filter for target??
- onChange.call(_this2);
- }); // Fullscreen toggle on double click
+ this.onChange();
+ } // Trap focus inside container
- on.call(this.player, this.player.elements.container, 'dblclick', function (event) {
- // Ignore double click in controls
- if (is$1.element(_this2.player.elements.controls) && _this2.player.elements.controls.contains(event.target)) {
+ }, {
+ key: "trapFocus",
+ value: function trapFocus(event) {
+ // Bail if iOS, not active, not the tab key
+ if (browser.isIos || !this.active || event.key !== 'Tab' || event.keyCode !== 9) {
return;
- }
+ } // Get the current focused element
- _this2.toggle();
- }); // Update the UI
- this.update();
- } // Determine if native supported
+ var focused = document.activeElement;
+ var focusable = getElements.call(this.player, 'a[href], button:not(:disabled), input:not(:disabled), [tabindex]');
+ var _focusable = _slicedToArray(focusable, 1),
+ first = _focusable[0];
- _createClass(Fullscreen, [{
+ var last = focusable[focusable.length - 1];
+
+ if (focused === last && !event.shiftKey) {
+ // Move focus to first element that can be tabbed if Shift isn't used
+ first.focus();
+ event.preventDefault();
+ } else if (focused === first && event.shiftKey) {
+ // Move focus to last element that can be tabbed if Shift is used
+ last.focus();
+ event.preventDefault();
+ }
+ } // Update UI
+
+ }, {
key: "update",
- // Update UI
value: function update() {
if (this.enabled) {
var mode;
@@ -4170,9 +4136,11 @@ function () {
if (browser.isIos && this.player.config.fullscreen.iosNative) {
this.target.webkitEnterFullscreen();
} else if (!Fullscreen.native || this.forceFallback) {
- toggleFallback.call(this, true);
+ this.toggleFallback(true);
} else if (!this.prefix) {
- this.target.requestFullscreen();
+ this.target.requestFullscreen({
+ navigationUI: 'hide'
+ });
} else if (!is$1.empty(this.prefix)) {
this.target["".concat(this.prefix, "Request").concat(this.property)]();
}
@@ -4188,9 +4156,9 @@ function () {
if (browser.isIos && this.player.config.fullscreen.iosNative) {
this.target.webkitExitFullscreen();
- this.player.play();
+ silencePromise(this.player.play());
} else if (!Fullscreen.native || this.forceFallback) {
- toggleFallback.call(this, false);
+ this.toggleFallback(false);
} else if (!this.prefix) {
(document.cancelFullScreen || document.exitFullscreen).call(document);
} else if (!is$1.empty(this.prefix)) {
@@ -4235,7 +4203,7 @@ function () {
}
var element = !this.prefix ? document.fullscreenElement : document["".concat(this.prefix).concat(this.property, "Element")];
- return element === this.target;
+ return element && element.shadowRoot ? element === this.target.getRootNode().host : element === this.target;
} // Get target element
}, {
@@ -4438,7 +4406,12 @@ var ui = {
} // Set property synchronously to respect the call order
- this.media.setAttribute('poster', poster); // Wait until ui is ready
+ this.media.setAttribute('poster', poster); // HTML5 uses native poster attribute
+
+ if (this.isHTML5) {
+ return Promise.resolve(poster);
+ } // Wait until ui is ready
+
return ready.call(this) // Load image
.then(function () {
@@ -4479,6 +4452,7 @@ var ui = {
Object.assign(target, {
pressed: _this3.playing
});
+ target.setAttribute('aria-label', i18n.get(_this3.playing ? 'pause' : 'play', _this3.config));
}); // Only update controls on non timeupdate events
if (is$1.event(event) && event.type === 'timeupdate') {
@@ -4516,9 +4490,7 @@ var ui = {
}
};
-var Listeners =
-/*#__PURE__*/
-function () {
+var Listeners = /*#__PURE__*/function () {
function Listeners(player) {
_classCallCheck(this, Listeners);
@@ -4609,7 +4581,7 @@ function () {
case 75:
// Space and K key
if (!repeat) {
- player.togglePlay();
+ silencePromise(player.togglePlay());
}
break;
@@ -4659,19 +4631,6 @@ function () {
// L key
player.loop = !player.loop;
break;
-
- /* case 73:
- this.setLoop('start');
- break;
- case 76:
- this.setLoop();
- break;
- case 79:
- this.setLoop('end');
- break; */
-
- default:
- break;
} // Escape is handle natively when in full screen
// So we only need to worry about non native
@@ -4802,15 +4761,7 @@ function () {
timers.controls = setTimeout(function () {
return ui.toggleControls.call(player, false);
}, delay);
- }); // Force edge to repaint on exit fullscreen
- // TODO: Fix weird bug where Edge doesn't re-draw when exiting fullscreen
-
- /* if (browser.isEdge) {
- on.call(player, elements.container, 'exitfullscreen', () => {
- setTimeout(() => repaint(elements.container), 100);
- });
- } */
- // Set a gutter for Vimeo
+ }); // Set a gutter for Vimeo
var setGutter = function setGutter(ratio, padding, toggle) {
if (!player.isVimeo) {
@@ -4852,9 +4803,14 @@ function () {
on.call(player, elements.container, 'enterfullscreen exitfullscreen', function (event) {
var _player$fullscreen = player.fullscreen,
target = _player$fullscreen.target,
- usingNative = _player$fullscreen.usingNative; // Ignore for iOS native
+ usingNative = _player$fullscreen.usingNative; // Ignore events not from target
- if (!player.isEmbed || target !== elements.container) {
+ if (target !== elements.container) {
+ return;
+ } // If it's not an embed and no ratio specified
+
+
+ if (!player.isEmbed && is$1.empty(player.config.ratio)) {
return;
}
@@ -4891,19 +4847,15 @@ function () {
on.call(player, player.media, 'durationchange loadeddata loadedmetadata', function (event) {
return controls.durationUpdate.call(player, event);
- }); // Check for audio tracks on load
- // We can't use `loadedmetadata` as it doesn't seem to have audio tracks at that point
-
- on.call(player, player.media, 'canplay loadeddata', function () {
- toggleHidden(elements.volume, !player.hasAudio);
- toggleHidden(elements.buttons.mute, !player.hasAudio);
}); // Handle the media finishing
on.call(player, player.media, 'ended', function () {
// Show poster on end
if (player.isHTML5 && player.isVideo && player.config.resetOnEnd) {
// Restart
- player.restart();
+ player.restart(); // Call pause otherwise IE11 will start playing the video again
+
+ player.pause();
}
}); // Check for buffer progress
@@ -4947,9 +4899,13 @@ function () {
if (player.ended) {
_this.proxy(event, player.restart, 'restart');
- _this.proxy(event, player.play, 'play');
+ _this.proxy(event, function () {
+ silencePromise(player.play());
+ }, 'play');
} else {
- _this.proxy(event, player.togglePlay, 'play');
+ _this.proxy(event, function () {
+ silencePromise(player.togglePlay());
+ }, 'play');
}
});
} // Disable right click
@@ -5016,7 +4972,7 @@ function () {
} // Only call default handler if not prevented in custom handler
- if (returned && is$1.function(defaultHandler)) {
+ if (returned !== false && is$1.function(defaultHandler)) {
defaultHandler.call(player, event);
}
} // Trigger custom and default handlers
@@ -5047,7 +5003,9 @@ function () {
if (elements.buttons.play) {
Array.from(elements.buttons.play).forEach(function (button) {
- _this3.bind(button, 'click', player.togglePlay, 'play');
+ _this3.bind(button, 'click', function () {
+ silencePromise(player.togglePlay());
+ }, 'play');
});
} // Pause
@@ -5083,9 +5041,11 @@ function () {
this.bind(elements.buttons.settings, 'click', function (event) {
// Prevent the document click listener closing the menu
event.stopPropagation();
+ event.preventDefault();
controls.toggleMenu.call(player, event);
- }); // Settings menu - keyboard toggle
+ }, null, false); // Can't be passive as we're preventing default
+ // Settings menu - keyboard toggle
// We have to bind to keyup otherwise Firefox triggers a click when a keydown event handler shifts focus
// https://bugzilla.mozilla.org/show_bug.cgi?id=1220143
@@ -5142,7 +5102,7 @@ function () {
if (play && done) {
seek.removeAttribute(attribute);
- player.play();
+ silencePromise(player.play());
} else if (!done && player.playing) {
seek.setAttribute(attribute, '');
player.pause();
@@ -5187,7 +5147,7 @@ function () {
}
}); // Hide thumbnail preview - on mouse click, mouse leave, and video play/seek. All four are required, e.g., for buffering
- this.bind(elements.progress, 'mouseleave click', function () {
+ this.bind(elements.progress, 'mouseleave touchend click', function () {
var previewThumbnails = player.previewThumbnails;
if (previewThumbnails && previewThumbnails.loaded) {
@@ -5404,12 +5364,13 @@ var loadjs_umd = createCommonjsModule(function (module, exports) {
async = args.async,
maxTries = (args.numRetries || 0) + 1,
beforeCallbackFn = args.before || devnull,
+ pathname = path.replace(/[\?|#].*$/, ''),
pathStripped = path.replace(/^(css|img)!/, ''),
isLegacyIECss,
e;
numTries = numTries || 0;
- if (/(^css!|\.css$)/.test(path)) {
+ if (/(^css!|\.css$)/.test(pathname)) {
// css
e = doc.createElement('link');
e.rel = 'stylesheet';
@@ -5422,7 +5383,7 @@ var loadjs_umd = createCommonjsModule(function (module, exports) {
e.rel = 'preload';
e.as = 'style';
}
- } else if (/(^img!|\.(png|gif|jpg|svg)$)/.test(path)) {
+ } else if (/(^img!|\.(png|gif|jpg|svg|webp)$)/.test(pathname)) {
// image
e = doc.createElement('img');
e.src = pathStripped;
@@ -5632,26 +5593,27 @@ function assurePlaybackState(play) {
var vimeo = {
setup: function setup() {
- var _this = this;
+ var player = this; // Add embed class for responsive
- // Add embed class for responsive
- toggleClass(this.elements.wrapper, this.config.classNames.embed, true); // Set intial ratio
+ toggleClass(player.elements.wrapper, player.config.classNames.embed, true); // Set speed options from config
- setAspectRatio.call(this); // Load the SDK if not already
+ player.options.speed = player.config.speed.options; // Set intial ratio
+
+ setAspectRatio.call(player); // Load the SDK if not already
if (!is$1.object(window.Vimeo)) {
- loadScript(this.config.urls.vimeo.sdk).then(function () {
- vimeo.ready.call(_this);
+ loadScript(player.config.urls.vimeo.sdk).then(function () {
+ vimeo.ready.call(player);
}).catch(function (error) {
- _this.debug.warn('Vimeo SDK (player.js) failed to load', error);
+ player.debug.warn('Vimeo SDK (player.js) failed to load', error);
});
} else {
- vimeo.ready.call(this);
+ vimeo.ready.call(player);
}
},
// API Ready
ready: function ready() {
- var _this2 = this;
+ var _this = this;
var player = this;
var config = player.config.vimeo; // Get Vimeo params for the iframe
@@ -5677,7 +5639,12 @@ var vimeo = {
iframe.setAttribute('src', src);
iframe.setAttribute('allowfullscreen', '');
iframe.setAttribute('allowtransparency', '');
- iframe.setAttribute('allow', 'autoplay'); // Get poster, if already set
+ iframe.setAttribute('allow', 'autoplay'); // Set the referrer policy if required
+
+ if (!is$1.empty(config.referrerPolicy)) {
+ iframe.setAttribute('referrerPolicy', config.referrerPolicy);
+ } // Get poster, if already set
+
var poster = player.poster; // Inject the package
@@ -5770,11 +5737,9 @@ var vimeo = {
player.embed.setPlaybackRate(input).then(function () {
speed = input;
triggerEvent.call(player, player.media, 'ratechange');
- }).catch(function (error) {
- // Hide menu item (and menu if empty)
- if (error.name === 'Error') {
- controls.setSpeedMenu.call(player, []);
- }
+ }).catch(function () {
+ // Cannot set Playback Rate, Video is probably not on Pro account
+ player.options.speed = [1];
});
}
}); // Volume
@@ -5824,7 +5789,7 @@ var vimeo = {
currentSrc = value;
controls.setDownloadUrl.call(player);
}).catch(function (error) {
- _this2.debug.warn(error);
+ _this.debug.warn(error);
});
Object.defineProperty(player.media, 'currentSrc', {
get: function get() {
@@ -5844,7 +5809,7 @@ var vimeo = {
height = _dimensions[1];
player.embed.ratio = [width, height];
- setAspectRatio.call(_this2);
+ setAspectRatio.call(_this);
}); // Set autopause
player.embed.setAutopause(player.config.autopause).then(function (state) {
@@ -5853,7 +5818,7 @@ var vimeo = {
player.embed.getVideoTitle().then(function (title) {
player.config.title = title;
- ui.setTitle.call(_this2);
+ ui.setTitle.call(_this);
}); // Get current time
player.embed.getCurrentTime().then(function (value) {
@@ -5895,6 +5860,12 @@ var vimeo = {
frame.setAttribute('tabindex', -1);
}
});
+ player.embed.on('bufferstart', function () {
+ triggerEvent.call(player, player.media, 'waiting');
+ });
+ player.embed.on('bufferend', function () {
+ triggerEvent.call(player, player.media, 'playing');
+ });
player.embed.on('play', function () {
assurePlaybackState.call(player, true);
triggerEvent.call(player, player.media, 'playing');
@@ -6222,7 +6193,11 @@ var youtube = {
}
}); // Get available speeds
- player.options.speed = instance.getAvailablePlaybackRates(); // Set the tabindex to avoid focus entering iframe
+ var speeds = instance.getAvailablePlaybackRates(); // Filter based on config
+
+ player.options.speed = speeds.filter(function (s) {
+ return player.config.speed.options.includes(s);
+ }); // Set the tabindex to avoid focus entering iframe
if (player.supported.ui) {
player.media.setAttribute('tabindex', -1);
@@ -6328,7 +6303,9 @@ var youtube = {
assurePlaybackState$1.call(player, false);
break;
- default:
+ case 3:
+ // Trigger waiting event to add loading classes to container as the video buffers.
+ triggerEvent.call(player, player.media, 'waiting');
break;
}
@@ -6370,14 +6347,16 @@ var media = {
wrap(this.media, this.elements.wrapper); // Faux poster container
- this.elements.poster = createElement('div', {
- class: this.config.classNames.poster
- });
- this.elements.wrapper.appendChild(this.elements.poster);
+ if (this.isEmbed) {
+ this.elements.poster = createElement('div', {
+ class: this.config.classNames.poster
+ });
+ this.elements.wrapper.appendChild(this.elements.poster);
+ }
}
if (this.isHTML5) {
- html5.extend.call(this);
+ html5.setup.call(this);
} else if (this.isYouTube) {
youtube.setup.call(this);
} else if (this.isVimeo) {
@@ -6400,9 +6379,7 @@ var destroy = function destroy(instance) {
instance.elements.container.remove();
};
-var Ads =
-/*#__PURE__*/
-function () {
+var Ads = /*#__PURE__*/function () {
/**
* Ads constructor.
* @param {Object} player
@@ -6502,6 +6479,8 @@ function () {
* mobile devices, this initialization is done as the result of a user action.
*/
value: function setupIMA() {
+ var _this4 = this;
+
// Create the container for our advertisements
this.elements.container = createElement('div', {
class: this.player.config.classNames.ads
@@ -6514,7 +6493,16 @@ function () {
google.ima.settings.setDisableCustomPlaybackForIOS10Plus(this.player.config.playsinline); // We assume the adContainer is the video container of the plyr element that will house the ads
- this.elements.displayContainer = new google.ima.AdDisplayContainer(this.elements.container, this.player.media); // Request video ads to be pre-loaded
+ this.elements.displayContainer = new google.ima.AdDisplayContainer(this.elements.container, this.player.media); // Create ads loader
+
+ this.loader = new google.ima.AdsLoader(this.elements.displayContainer); // Listen and respond to ads loaded and error events
+
+ this.loader.addEventListener(google.ima.AdsManagerLoadedEvent.Type.ADS_MANAGER_LOADED, function (event) {
+ return _this4.onAdsManagerLoaded(event);
+ }, false);
+ this.loader.addEventListener(google.ima.AdErrorEvent.Type.AD_ERROR, function (error) {
+ return _this4.onAdError(error);
+ }, false); // Request video ads to be pre-loaded
this.requestAds();
}
@@ -6525,21 +6513,10 @@ function () {
}, {
key: "requestAds",
value: function requestAds() {
- var _this4 = this;
-
var container = this.player.elements.container;
try {
- // Create ads loader
- this.loader = new google.ima.AdsLoader(this.elements.displayContainer); // Listen and respond to ads loaded and error events
-
- this.loader.addEventListener(google.ima.AdsManagerLoadedEvent.Type.ADS_MANAGER_LOADED, function (event) {
- return _this4.onAdsManagerLoaded(event);
- }, false);
- this.loader.addEventListener(google.ima.AdErrorEvent.Type.AD_ERROR, function (error) {
- return _this4.onAdError(error);
- }, false); // Request video ads
-
+ // Request video ads
var request = new google.ima.AdsRequest();
request.adTagUrl = this.tagUrl; // Specify the linear and nonlinear slot sizes. This helps the SDK
// to select the correct creative if multiple are returned
@@ -6718,7 +6695,13 @@ function () {
// };
// TODO: So there is still this thing where a video should only be allowed to start
// playing when the IMA SDK is ready or has failed
- 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:
@@ -6743,9 +6726,6 @@ function () {
}
break;
-
- default:
- break;
}
}
/**
@@ -6857,7 +6837,7 @@ function () {
this.playing = false; // Play video
- this.player.media.play();
+ silencePromise(this.player.media.play());
}
/**
* Pause our video
@@ -6914,7 +6894,9 @@ function () {
_this11.on('loaded', resolve);
_this11.player.debug.log(_this11.manager);
- }); // Now request some new advertisements
+ }); // Now that the manager has been destroyed set it to also be un-initialized
+
+ _this11.initialized = false; // Now request some new advertisements
_this11.requestAds();
}).catch(function () {});
@@ -7017,7 +6999,7 @@ function () {
cb: Date.now(),
AV_WIDTH: 640,
AV_HEIGHT: 480,
- AV_CDIM2: this.publisherId
+ AV_CDIM2: config.publisherId
};
var base = 'https://go.aniview.com/api/adserver6/vast/';
return "".concat(base, "?").concat(buildUrlParams(params));
@@ -7082,9 +7064,22 @@ var parseVtt = function parseVtt(vttDataString) {
*/
-var PreviewThumbnails =
-/*#__PURE__*/
-function () {
+var fitRatio = function fitRatio(ratio, outer) {
+ var targetRatio = outer.width / outer.height;
+ var result = {};
+
+ if (ratio > targetRatio) {
+ result.width = outer.width;
+ result.height = 1 / ratio * outer.width;
+ } else {
+ result.height = outer.height;
+ result.width = ratio * outer.height;
+ }
+
+ return result;
+};
+
+var PreviewThumbnails = /*#__PURE__*/function () {
/**
* PreviewThumbnails constructor.
* @param {Plyr} player
@@ -7111,7 +7106,7 @@ function () {
value: function load() {
var _this = this;
- // Togglethe regular seek tooltip
+ // Toggle the regular seek tooltip
if (this.player.elements.display.seekTooltip) {
this.player.elements.display.seekTooltip.hidden = this.enabled;
}
@@ -7121,7 +7116,11 @@ function () {
}
this.getThumbnails().then(function () {
- // Render DOM elements
+ if (!_this.enabled) {
+ return;
+ } // Render DOM elements
+
+
_this.render(); // Check to see if thumb container size was specified manually in CSS
@@ -7141,15 +7140,10 @@ function () {
if (is$1.empty(src)) {
throw new Error('Missing previewThumbnails.src config attribute');
- } // If string, convert into single-element list
-
+ } // Resolve promise
- var urls = is$1.string(src) ? [src] : src; // Loop through each src URL. Download and process the VTT file, storing the resulting data in this.thumbnails
- var promises = urls.map(function (u) {
- return _this2.getThumbnail(u);
- });
- Promise.all(promises).then(function () {
+ var sortAndResolve = function sortAndResolve() {
// Sort smallest to biggest (e.g., [120p, 480p, 1080p])
_this2.thumbnails.sort(function (x, y) {
return x.height - y.height;
@@ -7158,7 +7152,25 @@ function () {
_this2.player.debug.log('Preview thumbnails', _this2.thumbnails);
resolve();
- });
+ }; // Via callback()
+
+
+ if (is$1.function(src)) {
+ src(function (thumbnails) {
+ _this2.thumbnails = thumbnails;
+ sortAndResolve();
+ });
+ } // VTT urls
+ else {
+ // If string, convert into single-element list
+ var urls = is$1.string(src) ? [src] : src; // Loop through each src URL. Download and process the VTT file, storing the resulting data in this.thumbnails
+
+ var promises = urls.map(function (u) {
+ return _this2.getThumbnail(u);
+ }); // Resolve
+
+ Promise.all(promises).then(sortAndResolve);
+ }
});
} // Process individual VTT file
@@ -7248,8 +7260,8 @@ function () {
}, {
key: "startScrubbing",
value: function startScrubbing(event) {
- // Only act on left mouse button (0), or touch device (event.button is false)
- if (event.button === false || event.button === 0) {
+ // Only act on left mouse button (0), or touch device (event.button does not exist or is false)
+ if (is$1.nullOrUndefined(event.button) || event.button === false || event.button === 0) {
this.mouseDown = true; // Wait until media has a duration
if (this.player.media.duration) {
@@ -7335,6 +7347,17 @@ function () {
this.player.elements.wrapper.appendChild(this.elements.scrubbing.container);
}
}, {
+ key: "destroy",
+ value: function destroy() {
+ if (this.elements.thumb.container) {
+ this.elements.thumb.container.remove();
+ }
+
+ if (this.elements.scrubbing.container) {
+ this.elements.scrubbing.container.remove();
+ }
+ }
+ }, {
key: "showImageAtCurrentTime",
value: function showImageAtCurrentTime() {
var _this6 = this;
@@ -7579,7 +7602,7 @@ function () {
}, {
key: "determineContainerAutoSizing",
value: function determineContainerAutoSizing() {
- if (this.elements.thumb.imageContainer.clientHeight > 20) {
+ if (this.elements.thumb.imageContainer.clientHeight > 20 || this.elements.thumb.imageContainer.clientWidth > 20) {
// This will prevent auto sizing in this.setThumbContainerSizeAndPos()
this.sizeSpecifiedInCSS = true;
}
@@ -7592,6 +7615,13 @@ function () {
var thumbWidth = Math.floor(this.thumbContainerHeight * this.thumbAspectRatio);
this.elements.thumb.imageContainer.style.height = "".concat(this.thumbContainerHeight, "px");
this.elements.thumb.imageContainer.style.width = "".concat(thumbWidth, "px");
+ } else if (this.elements.thumb.imageContainer.clientHeight > 20 && this.elements.thumb.imageContainer.clientWidth < 20) {
+ var _thumbWidth = Math.floor(this.elements.thumb.imageContainer.clientHeight * this.thumbAspectRatio);
+
+ this.elements.thumb.imageContainer.style.width = "".concat(_thumbWidth, "px");
+ } else if (this.elements.thumb.imageContainer.clientHeight < 20 && this.elements.thumb.imageContainer.clientWidth > 20) {
+ var thumbHeight = Math.floor(this.elements.thumb.imageContainer.clientWidth / this.thumbAspectRatio);
+ this.elements.thumb.imageContainer.style.height = "".concat(thumbHeight, "px");
}
this.setThumbContainerPos();
@@ -7622,9 +7652,15 @@ function () {
}, {
key: "setScrubbingContainerSize",
value: function setScrubbingContainerSize() {
- this.elements.scrubbing.container.style.width = "".concat(this.player.media.clientWidth, "px"); // Can't use media.clientHeight - html5 video goes big and does black bars above and below
-
- this.elements.scrubbing.container.style.height = "".concat(this.player.media.clientWidth / this.thumbAspectRatio, "px");
+ var _fitRatio = fitRatio(this.thumbAspectRatio, {
+ width: this.player.media.clientWidth,
+ height: this.player.media.clientHeight
+ }),
+ width = _fitRatio.width,
+ height = _fitRatio.height;
+
+ this.elements.scrubbing.container.style.width = "".concat(width, "px");
+ this.elements.scrubbing.container.style.height = "".concat(height, "px");
} // Sprites need to be offset to the correct location
}, {
@@ -7637,9 +7673,9 @@ function () {
var multiplier = this.thumbContainerHeight / frame.h; // eslint-disable-next-line no-param-reassign
- previewImage.style.height = "".concat(Math.floor(previewImage.naturalHeight * multiplier), "px"); // eslint-disable-next-line no-param-reassign
+ previewImage.style.height = "".concat(previewImage.naturalHeight * multiplier, "px"); // eslint-disable-next-line no-param-reassign
- previewImage.style.width = "".concat(Math.floor(previewImage.naturalWidth * multiplier), "px"); // eslint-disable-next-line no-param-reassign
+ previewImage.style.width = "".concat(previewImage.naturalWidth * multiplier, "px"); // eslint-disable-next-line no-param-reassign
previewImage.style.left = "-".concat(frame.x * multiplier, "px"); // eslint-disable-next-line no-param-reassign
@@ -7677,8 +7713,18 @@ function () {
key: "thumbContainerHeight",
get: function get() {
if (this.mouseDown) {
- // Can't use media.clientHeight - HTML5 video goes big and does black bars above and below
- return Math.floor(this.player.media.clientWidth / this.thumbAspectRatio);
+ var _fitRatio2 = fitRatio(this.thumbAspectRatio, {
+ width: this.player.media.clientWidth,
+ height: this.player.media.clientHeight
+ }),
+ height = _fitRatio2.height;
+
+ return height;
+ } // If css is used this needs to return the css height for sprites to work (see setImageSizeAndOffset)
+
+
+ if (this.sizeSpecifiedInCSS) {
+ return this.elements.thumb.imageContainer.clientHeight;
}
return Math.floor(this.player.media.clientWidth / this.thumbAspectRatio / 4);
@@ -7828,11 +7874,22 @@ var source = {
if (_this2.isHTML5) {
_this2.media.load();
- } // Reload thumbnails
+ } // Update previewThumbnails config & reload plugin
+
+
+ if (!is$1.empty(input.previewThumbnails)) {
+ Object.assign(_this2.config.previewThumbnails, input.previewThumbnails); // Cleanup previewThumbnails plugin if it was loaded
+ if (_this2.previewThumbnails && _this2.previewThumbnails.loaded) {
+ _this2.previewThumbnails.destroy();
- if (_this2.previewThumbnails) {
- _this2.previewThumbnails.load();
+ _this2.previewThumbnails = null;
+ } // Create new instance if it is still enabled
+
+
+ if (_this2.config.previewThumbnails.enabled) {
+ _this2.previewThumbnails = new PreviewThumbnails(_this2);
+ }
} // Update the fullscreen support
@@ -7864,9 +7921,7 @@ function clamp() {
// const globals = new WeakMap();
// Plyr instance
-var Plyr =
-/*#__PURE__*/
-function () {
+var Plyr = /*#__PURE__*/function () {
function Plyr(target, options) {
var _this = this;
@@ -8110,7 +8165,7 @@ function () {
if (this.isHTML5 && this.config.autoplay) {
setTimeout(function () {
- return _this.play();
+ return silencePromise(_this.play());
}, 10);
} // Seek time will be recorded (in listeners.js) so we can prevent hiding controls for a few seconds after seek
@@ -8147,7 +8202,7 @@ function () {
this.ads.managerPromise.then(function () {
return _this2.ads.play();
}).catch(function () {
- return _this2.media.play();
+ return silencePromise(_this2.media.play());
});
} // Return the promise (for HTML5)
@@ -8162,10 +8217,10 @@ function () {
key: "pause",
value: function pause() {
if (!this.playing || !is$1.function(this.media.pause)) {
- return;
+ return null;
}
- this.media.pause();
+ return this.media.pause();
}
/**
* Get playing state
@@ -8183,10 +8238,10 @@ function () {
var toggle = is$1.boolean(input) ? input : !this.playing;
if (toggle) {
- this.play();
- } else {
- this.pause();
+ return this.play();
}
+
+ return this.pause();
}
/**
* Stop playback
@@ -8219,7 +8274,7 @@ function () {
}, {
key: "rewind",
value: function rewind(seekTime) {
- this.currentTime = this.currentTime - (is$1.number(seekTime) ? seekTime : this.config.seekTime);
+ this.currentTime -= is$1.number(seekTime) ? seekTime : this.config.seekTime;
}
/**
* Fast forward
@@ -8229,7 +8284,7 @@ function () {
}, {
key: "forward",
value: function forward(seekTime) {
- this.currentTime = this.currentTime + (is$1.number(seekTime) ? seekTime : this.config.seekTime);
+ this.currentTime += is$1.number(seekTime) ? seekTime : this.config.seekTime;
}
/**
* Seek to a time