WIP
This commit is contained in:
parent
edd67b0da3
commit
3e0a911418
2
demo/dist/demo.css
vendored
2
demo/dist/demo.css
vendored
File diff suppressed because one or more lines are too long
128
demo/dist/demo.js
vendored
128
demo/dist/demo.js
vendored
@ -1,4 +1,4 @@
|
||||
(function () {
|
||||
typeof navigator === "object" && (function () {
|
||||
'use strict';
|
||||
|
||||
var commonjsGlobal = typeof window !== 'undefined' ? window : typeof global !== 'undefined' ? global : typeof self !== 'undefined' ? self : {};
|
||||
@ -97,7 +97,7 @@ function isObject(what) {
|
||||
// Yanked from https://git.io/vS8DV re-used under CC0
|
||||
// with some tiny modifications
|
||||
function isError(value) {
|
||||
switch ({}.toString.call(value)) {
|
||||
switch (Object.prototype.toString.call(value)) {
|
||||
case '[object Error]':
|
||||
return true;
|
||||
case '[object Exception]':
|
||||
@ -110,7 +110,15 @@ function isError(value) {
|
||||
}
|
||||
|
||||
function isErrorEvent(value) {
|
||||
return supportsErrorEvent() && {}.toString.call(value) === '[object ErrorEvent]';
|
||||
return Object.prototype.toString.call(value) === '[object ErrorEvent]';
|
||||
}
|
||||
|
||||
function isDOMError(value) {
|
||||
return Object.prototype.toString.call(value) === '[object DOMError]';
|
||||
}
|
||||
|
||||
function isDOMException(value) {
|
||||
return Object.prototype.toString.call(value) === '[object DOMException]';
|
||||
}
|
||||
|
||||
function isUndefined(what) {
|
||||
@ -153,6 +161,24 @@ function supportsErrorEvent() {
|
||||
}
|
||||
}
|
||||
|
||||
function supportsDOMError() {
|
||||
try {
|
||||
new DOMError(''); // eslint-disable-line no-new
|
||||
return true;
|
||||
} catch (e) {
|
||||
return false;
|
||||
}
|
||||
}
|
||||
|
||||
function supportsDOMException() {
|
||||
try {
|
||||
new DOMException(''); // eslint-disable-line no-new
|
||||
return true;
|
||||
} catch (e) {
|
||||
return false;
|
||||
}
|
||||
}
|
||||
|
||||
function supportsFetch() {
|
||||
if (!('fetch' in _window)) return false;
|
||||
|
||||
@ -668,6 +694,8 @@ var utils = {
|
||||
isObject: isObject,
|
||||
isError: isError,
|
||||
isErrorEvent: isErrorEvent,
|
||||
isDOMError: isDOMError,
|
||||
isDOMException: isDOMException,
|
||||
isUndefined: isUndefined,
|
||||
isFunction: isFunction,
|
||||
isPlainObject: isPlainObject,
|
||||
@ -675,6 +703,8 @@ var utils = {
|
||||
isArray: isArray,
|
||||
isEmptyObject: isEmptyObject,
|
||||
supportsErrorEvent: supportsErrorEvent,
|
||||
supportsDOMError: supportsDOMError,
|
||||
supportsDOMException: supportsDOMException,
|
||||
supportsFetch: supportsFetch,
|
||||
supportsReferrerPolicy: supportsReferrerPolicy,
|
||||
supportsPromiseRejectionEvent: supportsPromiseRejectionEvent,
|
||||
@ -729,10 +759,24 @@ var ERROR_TYPES_RE = /^(?:[Uu]ncaught (?:exception: )?)?(?:((?:Eval|Internal|Ran
|
||||
|
||||
function getLocationHref() {
|
||||
if (typeof document === 'undefined' || document.location == null) return '';
|
||||
|
||||
return document.location.href;
|
||||
}
|
||||
|
||||
function getLocationOrigin() {
|
||||
if (typeof document === 'undefined' || document.location == null) return '';
|
||||
|
||||
// Oh dear IE10...
|
||||
if (!document.location.origin) {
|
||||
document.location.origin =
|
||||
document.location.protocol +
|
||||
'//' +
|
||||
document.location.hostname +
|
||||
(document.location.port ? ':' + document.location.port : '');
|
||||
}
|
||||
|
||||
return document.location.origin;
|
||||
}
|
||||
|
||||
/**
|
||||
* TraceKit.report: cross-browser processing of unhandled exceptions
|
||||
*
|
||||
@ -1140,6 +1184,44 @@ TraceKit.computeStackTrace = (function computeStackTraceWrapper() {
|
||||
element.func = UNKNOWN_FUNCTION;
|
||||
}
|
||||
|
||||
if (element.url && element.url.substr(0, 5) === 'blob:') {
|
||||
// Special case for handling JavaScript loaded into a blob.
|
||||
// We use a synchronous AJAX request here as a blob is already in
|
||||
// memory - it's not making a network request. This will generate a warning
|
||||
// in the browser console, but there has already been an error so that's not
|
||||
// that much of an issue.
|
||||
var xhr = new XMLHttpRequest();
|
||||
xhr.open('GET', element.url, false);
|
||||
xhr.send(null);
|
||||
|
||||
// If we failed to download the source, skip this patch
|
||||
if (xhr.status === 200) {
|
||||
var source = xhr.responseText || '';
|
||||
|
||||
// We trim the source down to the last 300 characters as sourceMappingURL is always at the end of the file.
|
||||
// Why 300? To be in line with: https://github.com/getsentry/sentry/blob/4af29e8f2350e20c28a6933354e4f42437b4ba42/src/sentry/lang/javascript/processor.py#L164-L175
|
||||
source = source.slice(-300);
|
||||
|
||||
// Now we dig out the source map URL
|
||||
var sourceMaps = source.match(/\/\/# sourceMappingURL=(.*)$/);
|
||||
|
||||
// If we don't find a source map comment or we find more than one, continue on to the next element.
|
||||
if (sourceMaps) {
|
||||
var sourceMapAddress = sourceMaps[1];
|
||||
|
||||
// Now we check to see if it's a relative URL.
|
||||
// If it is, convert it to an absolute one.
|
||||
if (sourceMapAddress.charAt(0) === '~') {
|
||||
sourceMapAddress = getLocationOrigin() + sourceMapAddress.slice(1);
|
||||
}
|
||||
|
||||
// Now we strip the '.map' off of the end of the URL and update the
|
||||
// element so that Sentry can match the map to the blob.
|
||||
element.url = sourceMapAddress.slice(0, -4);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
stack.push(element);
|
||||
}
|
||||
|
||||
@ -1651,10 +1733,12 @@ var console$1 = {
|
||||
|
||||
|
||||
|
||||
var isErrorEvent$1 = utils.isErrorEvent;
|
||||
var isDOMError$1 = utils.isDOMError;
|
||||
var isDOMException$1 = utils.isDOMException;
|
||||
var isError$1 = utils.isError;
|
||||
var isObject$1 = utils.isObject;
|
||||
var isPlainObject$1 = utils.isPlainObject;
|
||||
var isErrorEvent$1 = utils.isErrorEvent;
|
||||
var isUndefined$1 = utils.isUndefined;
|
||||
var isFunction$1 = utils.isFunction;
|
||||
var isString$1 = utils.isString;
|
||||
@ -1782,7 +1866,7 @@ Raven.prototype = {
|
||||
// webpack (using a build step causes webpack #1617). Grunt verifies that
|
||||
// this value matches package.json during build.
|
||||
// See: https://github.com/getsentry/raven-js/issues/465
|
||||
VERSION: '3.24.2',
|
||||
VERSION: '3.25.2',
|
||||
|
||||
debug: false,
|
||||
|
||||
@ -2114,6 +2198,23 @@ Raven.prototype = {
|
||||
if (isErrorEvent$1(ex) && ex.error) {
|
||||
// If it is an ErrorEvent with `error` property, extract it to get actual Error
|
||||
ex = ex.error;
|
||||
} else if (isDOMError$1(ex) || isDOMException$1(ex)) {
|
||||
// If it is a DOMError or DOMException (which are legacy APIs, but still supported in some browsers)
|
||||
// then we just extract the name and message, as they don't provide anything else
|
||||
// https://developer.mozilla.org/en-US/docs/Web/API/DOMError
|
||||
// https://developer.mozilla.org/en-US/docs/Web/API/DOMException
|
||||
var name = ex.name || (isDOMError$1(ex) ? 'DOMError' : 'DOMException');
|
||||
var message = ex.message ? name + ': ' + ex.message : name;
|
||||
|
||||
return this.captureMessage(
|
||||
message,
|
||||
objectMerge$1(options, {
|
||||
// neither DOMError or DOMException provide stack trace and we most likely wont get it this way as well
|
||||
// but it's barely any overhead so we may at least try
|
||||
stacktrace: true,
|
||||
trimHeadFrames: options.trimHeadFrames + 1
|
||||
})
|
||||
);
|
||||
} else if (isError$1(ex)) {
|
||||
// we have a real Error object
|
||||
ex = ex;
|
||||
@ -2125,6 +2226,7 @@ Raven.prototype = {
|
||||
ex = new Error(options.message);
|
||||
} else {
|
||||
// If none of previous checks were valid, then it means that
|
||||
// it's not a DOMError/DOMException
|
||||
// it's not a plain Object
|
||||
// it's not a valid ErrorEvent (one with an error property)
|
||||
// it's not an Error
|
||||
@ -3073,8 +3175,8 @@ Raven.prototype = {
|
||||
var hasPushAndReplaceState =
|
||||
!isChromePackagedApp &&
|
||||
_window$2.history &&
|
||||
history.pushState &&
|
||||
history.replaceState;
|
||||
_window$2.history.pushState &&
|
||||
_window$2.history.replaceState;
|
||||
if (autoBreadcrumbs.location && hasPushAndReplaceState) {
|
||||
// TODO: remove onpopstate handler on uninstall()
|
||||
var oldOnPopState = _window$2.onpopstate;
|
||||
@ -3103,8 +3205,8 @@ Raven.prototype = {
|
||||
};
|
||||
};
|
||||
|
||||
fill$1(history, 'pushState', historyReplacementFunction, wrappedBuiltIns);
|
||||
fill$1(history, 'replaceState', historyReplacementFunction, wrappedBuiltIns);
|
||||
fill$1(_window$2.history, 'pushState', historyReplacementFunction, wrappedBuiltIns);
|
||||
fill$1(_window$2.history, 'replaceState', historyReplacementFunction, wrappedBuiltIns);
|
||||
}
|
||||
|
||||
if (autoBreadcrumbs.console && 'console' in _window$2 && console.log) {
|
||||
@ -3320,7 +3422,7 @@ Raven.prototype = {
|
||||
}
|
||||
]
|
||||
},
|
||||
culprit: fileurl
|
||||
transaction: fileurl
|
||||
},
|
||||
options
|
||||
);
|
||||
@ -3394,7 +3496,7 @@ Raven.prototype = {
|
||||
|
||||
if (this._hasNavigator && _navigator.userAgent) {
|
||||
httpData.headers = {
|
||||
'User-Agent': navigator.userAgent
|
||||
'User-Agent': _navigator.userAgent
|
||||
};
|
||||
}
|
||||
|
||||
@ -3435,7 +3537,7 @@ Raven.prototype = {
|
||||
if (
|
||||
!last ||
|
||||
current.message !== last.message || // defined for captureMessage
|
||||
current.culprit !== last.culprit // defined for captureException/onerror
|
||||
current.transaction !== last.transaction // defined for captureException/onerror
|
||||
)
|
||||
return false;
|
||||
|
||||
|
2
demo/dist/demo.js.map
vendored
2
demo/dist/demo.js.map
vendored
File diff suppressed because one or more lines are too long
2
demo/dist/demo.min.js
vendored
2
demo/dist/demo.min.js
vendored
File diff suppressed because one or more lines are too long
2
demo/dist/demo.min.js.map
vendored
2
demo/dist/demo.min.js.map
vendored
File diff suppressed because one or more lines are too long
2
dist/plyr.css
vendored
2
dist/plyr.css
vendored
File diff suppressed because one or more lines are too long
581
dist/plyr.js
vendored
581
dist/plyr.js
vendored
@ -1,4 +1,4 @@
|
||||
(function (global, factory) {
|
||||
typeof navigator === "object" && (function (global, factory) {
|
||||
typeof exports === 'object' && typeof module !== 'undefined' ? module.exports = factory() :
|
||||
typeof define === 'function' && define.amd ? define('Plyr', factory) :
|
||||
(global.Plyr = factory());
|
||||
@ -602,6 +602,24 @@ var utils = {
|
||||
},
|
||||
|
||||
|
||||
// Load image avoiding xhr/fetch CORS issues
|
||||
// Server status can't be obtained this way unfortunately, so this uses "naturalWidth" to determine if the image has loaded.
|
||||
// By default it checks if it is at least 1px, but you can add a second argument to change this.
|
||||
loadImage: function loadImage(src) {
|
||||
var minWidth = arguments.length > 1 && arguments[1] !== undefined ? arguments[1] : 1;
|
||||
|
||||
return new Promise(function (resolve, reject) {
|
||||
var image = new Image();
|
||||
var handler = function handler() {
|
||||
delete image.onload;
|
||||
delete image.onerror;
|
||||
(image.naturalWidth >= minWidth ? resolve : reject)(image);
|
||||
};
|
||||
Object.assign(image, { onload: handler, onerror: handler, src: src });
|
||||
});
|
||||
},
|
||||
|
||||
|
||||
// Load an external script
|
||||
loadScript: function loadScript(url) {
|
||||
return new Promise(function (resolve, reject) {
|
||||
@ -730,7 +748,7 @@ var utils = {
|
||||
|
||||
// Add text node
|
||||
if (utils.is.string(text)) {
|
||||
element.textContent = text;
|
||||
element.innerText = text;
|
||||
}
|
||||
|
||||
// Return built element
|
||||
@ -884,14 +902,16 @@ var utils = {
|
||||
},
|
||||
|
||||
|
||||
// Toggle class on an element
|
||||
toggleClass: function toggleClass(element, className, toggle) {
|
||||
// Mirror Element.classList.toggle, with IE compatibility for "force" argument
|
||||
toggleClass: function toggleClass(element, className, force) {
|
||||
if (utils.is.element(element)) {
|
||||
var contains = element.classList.contains(className);
|
||||
var method = 'toggle';
|
||||
if (typeof force !== 'undefined') {
|
||||
method = force ? 'add' : 'remove';
|
||||
}
|
||||
|
||||
element.classList[toggle ? 'add' : 'remove'](className);
|
||||
|
||||
return toggle && !contains || !toggle && contains;
|
||||
element.classList[method](className);
|
||||
return element.classList.contains(className);
|
||||
}
|
||||
|
||||
return null;
|
||||
@ -1274,6 +1294,12 @@ var utils = {
|
||||
},
|
||||
|
||||
|
||||
// Clone nested objects
|
||||
cloneDeep: function cloneDeep(object) {
|
||||
return JSON.parse(JSON.stringify(object));
|
||||
},
|
||||
|
||||
|
||||
// Get the closest value in an array
|
||||
closest: function closest(array, value) {
|
||||
if (!utils.is.array(array) || !array.length) {
|
||||
@ -2093,7 +2119,7 @@ var controls = {
|
||||
break;
|
||||
}
|
||||
|
||||
progress.textContent = '% ' + suffix.toLowerCase();
|
||||
progress.innerText = '% ' + suffix.toLowerCase();
|
||||
}
|
||||
|
||||
this.elements.display[type] = progress;
|
||||
@ -2167,7 +2193,7 @@ var controls = {
|
||||
var forceHours = utils.getHours(this.duration) > 0;
|
||||
|
||||
// eslint-disable-next-line no-param-reassign
|
||||
target.textContent = utils.formatTime(time, forceHours, inverted);
|
||||
target.innerText = utils.formatTime(time, forceHours, inverted);
|
||||
},
|
||||
|
||||
|
||||
@ -2236,6 +2262,7 @@ var controls = {
|
||||
// Video playing
|
||||
case 'timeupdate':
|
||||
case 'seeking':
|
||||
case 'seeked':
|
||||
value = utils.getPercentage(this.currentTime, this.duration);
|
||||
|
||||
// Set seek range value only if it's a 'natural' time event
|
||||
@ -2293,7 +2320,7 @@ var controls = {
|
||||
|
||||
// Calculate percentage
|
||||
var percent = 0;
|
||||
var clientRect = this.elements.inputs.seek.getBoundingClientRect();
|
||||
var clientRect = this.elements.progress.getBoundingClientRect();
|
||||
var visible = this.config.classNames.tooltip + '--visible';
|
||||
|
||||
var toggle = function toggle(_toggle) {
|
||||
@ -2354,9 +2381,10 @@ var controls = {
|
||||
},
|
||||
|
||||
|
||||
// Show the duration on metadataloaded
|
||||
// Show the duration on metadataloaded or durationchange events
|
||||
durationUpdate: function durationUpdate() {
|
||||
if (!this.supported.ui) {
|
||||
// Bail if no ui or durationchange event triggered after playing/seek when invertTime is false
|
||||
if (!this.supported.ui || !this.config.invertTime && this.currentTime) {
|
||||
return;
|
||||
}
|
||||
|
||||
@ -3471,7 +3499,7 @@ var captions = {
|
||||
|
||||
// Set the span content
|
||||
if (utils.is.string(caption)) {
|
||||
content.textContent = caption.trim();
|
||||
content.innerText = caption.trim();
|
||||
} else {
|
||||
content.appendChild(caption);
|
||||
}
|
||||
@ -3709,8 +3737,7 @@ var defaults$1 = {
|
||||
},
|
||||
youtube: {
|
||||
sdk: 'https://www.youtube.com/iframe_api',
|
||||
api: 'https://www.googleapis.com/youtube/v3/videos?id={0}&key={1}&fields=items(snippet(title))&part=snippet',
|
||||
poster: 'https://img.youtube.com/vi/{0}/maxresdefault.jpg,https://img.youtube.com/vi/{0}/hqdefault.jpg'
|
||||
api: 'https://www.googleapis.com/youtube/v3/videos?id={0}&key={1}&fields=items(snippet(title))&part=snippet'
|
||||
},
|
||||
googleIMA: {
|
||||
sdk: 'https://imasdk.googleapis.com/js/sdkloader/ima3.js'
|
||||
@ -3806,13 +3833,13 @@ var defaults$1 = {
|
||||
embed: 'plyr__video-embed',
|
||||
embedContainer: 'plyr__video-embed__container',
|
||||
poster: 'plyr__poster',
|
||||
posterEnabled: 'plyr__poster-enabled',
|
||||
ads: 'plyr__ads',
|
||||
control: 'plyr__control',
|
||||
playing: 'plyr--playing',
|
||||
paused: 'plyr--paused',
|
||||
stopped: 'plyr--stopped',
|
||||
loading: 'plyr--loading',
|
||||
error: 'plyr--has-error',
|
||||
hover: 'plyr--hover',
|
||||
tooltip: 'plyr__tooltip',
|
||||
cues: 'plyr__cues',
|
||||
@ -4207,8 +4234,10 @@ var ui = {
|
||||
// Set the title
|
||||
ui.setTitle.call(this);
|
||||
|
||||
// Set the poster image
|
||||
ui.setPoster.call(this);
|
||||
// Assure the poster image is set, if the property was added before the element was created
|
||||
if (this.poster && this.elements.poster && !this.elements.poster.style.backgroundImage) {
|
||||
ui.setPoster.call(this, this.poster);
|
||||
}
|
||||
},
|
||||
|
||||
|
||||
@ -4250,17 +4279,43 @@ var ui = {
|
||||
},
|
||||
|
||||
|
||||
// Set the poster image
|
||||
setPoster: function setPoster() {
|
||||
if (!utils.is.element(this.elements.poster) || utils.is.empty(this.poster)) {
|
||||
return;
|
||||
// Toggle poster
|
||||
togglePoster: function togglePoster(enable) {
|
||||
utils.toggleClass(this.elements.container, this.config.classNames.posterEnabled, enable);
|
||||
},
|
||||
|
||||
|
||||
// Set the poster image (async)
|
||||
setPoster: function setPoster(poster) {
|
||||
var _this2 = this;
|
||||
|
||||
// Set property regardless of validity
|
||||
this.media.setAttribute('poster', poster);
|
||||
|
||||
// Bail if element is missing
|
||||
if (!utils.is.element(this.elements.poster)) {
|
||||
return Promise.reject();
|
||||
}
|
||||
|
||||
// Set the inline style
|
||||
var posters = this.poster.split(',');
|
||||
this.elements.poster.style.backgroundImage = posters.map(function (p) {
|
||||
return 'url(\'' + p + '\')';
|
||||
}).join(',');
|
||||
// Load the image, and set poster if successful
|
||||
var loadPromise = utils.loadImage(poster).then(function () {
|
||||
_this2.elements.poster.style.backgroundImage = 'url(\'' + poster + '\')';
|
||||
Object.assign(_this2.elements.poster.style, {
|
||||
backgroundImage: 'url(\'' + poster + '\')',
|
||||
// Reset backgroundSize as well (since it can be set to "cover" for padded thumbnails for youtube)
|
||||
backgroundSize: ''
|
||||
});
|
||||
ui.togglePoster.call(_this2, true);
|
||||
return poster;
|
||||
});
|
||||
|
||||
// Hide the element if the poster can't be loaded (otherwise it will just be a black element covering the video)
|
||||
loadPromise.catch(function () {
|
||||
return ui.togglePoster.call(_this2, false);
|
||||
});
|
||||
|
||||
// Return the promise so the caller can use it as well
|
||||
return loadPromise;
|
||||
},
|
||||
|
||||
|
||||
@ -4280,13 +4335,13 @@ var ui = {
|
||||
}
|
||||
|
||||
// Toggle controls
|
||||
this.toggleControls(!this.playing);
|
||||
ui.toggleControls.call(this);
|
||||
},
|
||||
|
||||
|
||||
// Check if media is loading
|
||||
checkLoading: function checkLoading(event) {
|
||||
var _this2 = this;
|
||||
var _this3 = this;
|
||||
|
||||
this.loading = ['stalled', 'waiting'].includes(event.type);
|
||||
|
||||
@ -4295,38 +4350,24 @@ var ui = {
|
||||
|
||||
// Timer to prevent flicker when seeking
|
||||
this.timers.loading = setTimeout(function () {
|
||||
// Toggle container class hook
|
||||
utils.toggleClass(_this2.elements.container, _this2.config.classNames.loading, _this2.loading);
|
||||
// Update progress bar loading class state
|
||||
utils.toggleClass(_this3.elements.container, _this3.config.classNames.loading, _this3.loading);
|
||||
|
||||
// Show controls if loading, hide if done
|
||||
_this2.toggleControls(_this2.loading);
|
||||
// Update controls visibility
|
||||
ui.toggleControls.call(_this3);
|
||||
}, this.loading ? 250 : 0);
|
||||
},
|
||||
|
||||
|
||||
// Check if media failed to load
|
||||
checkFailed: function checkFailed() {
|
||||
var _this3 = this;
|
||||
// Toggle controls based on state and `force` argument
|
||||
toggleControls: function toggleControls(force) {
|
||||
var controls$$1 = this.elements.controls;
|
||||
|
||||
// https://developer.mozilla.org/en-US/docs/Web/API/HTMLMediaElement/networkState
|
||||
this.failed = this.media.networkState === 3;
|
||||
|
||||
if (this.failed) {
|
||||
utils.toggleClass(this.elements.container, this.config.classNames.loading, false);
|
||||
utils.toggleClass(this.elements.container, this.config.classNames.error, true);
|
||||
if (controls$$1 && this.config.hideControls) {
|
||||
// Show controls if force, loading, paused, or button interaction, otherwise hide
|
||||
this.toggleControls(Boolean(force || this.loading || this.paused || controls$$1.pressed || controls$$1.hover));
|
||||
}
|
||||
|
||||
// Clear timer
|
||||
clearTimeout(this.timers.failed);
|
||||
|
||||
// Timer to prevent flicker when seeking
|
||||
this.timers.loading = setTimeout(function () {
|
||||
// Toggle container class hook
|
||||
utils.toggleClass(_this3.elements.container, _this3.config.classNames.loading, _this3.loading);
|
||||
|
||||
// Show controls if loading, hide if done
|
||||
_this3.toggleControls(_this3.loading);
|
||||
}, this.loading ? 250 : 0);
|
||||
}
|
||||
};
|
||||
|
||||
@ -4564,13 +4605,35 @@ var Listeners = function () {
|
||||
}, 0);
|
||||
});
|
||||
|
||||
// Toggle controls visibility based on mouse movement
|
||||
if (this.player.config.hideControls) {
|
||||
// Toggle controls on mouse events and entering fullscreen
|
||||
utils.on(this.player.elements.container, 'mouseenter mouseleave mousemove touchstart touchend touchmove enterfullscreen exitfullscreen', function (event) {
|
||||
_this2.player.toggleControls(event);
|
||||
});
|
||||
utils.on(this.player.elements.container, 'mousemove mouseleave touchstart touchmove enterfullscreen exitfullscreen', function (event) {
|
||||
var controls$$1 = _this2.player.elements.controls;
|
||||
|
||||
// Remove button states for fullscreen
|
||||
|
||||
if (event.type === 'enterfullscreen') {
|
||||
controls$$1.pressed = false;
|
||||
controls$$1.hover = false;
|
||||
}
|
||||
|
||||
// Show, then hide after a timeout unless another control event occurs
|
||||
var show = ['touchstart', 'touchmove', 'mousemove'].includes(event.type);
|
||||
|
||||
var delay = 0;
|
||||
|
||||
if (show) {
|
||||
ui.toggleControls.call(_this2.player, true);
|
||||
// Use longer timeout for touch devices
|
||||
delay = _this2.player.touch ? 3000 : 2000;
|
||||
}
|
||||
|
||||
// Clear timer
|
||||
clearTimeout(_this2.player.timers.controls);
|
||||
// Timer to prevent flicker when seeking
|
||||
_this2.player.timers.controls = setTimeout(function () {
|
||||
return ui.toggleControls.call(_this2.player, false);
|
||||
}, delay);
|
||||
});
|
||||
}
|
||||
|
||||
// Listen for media events
|
||||
@ -4581,7 +4644,7 @@ var Listeners = function () {
|
||||
var _this3 = this;
|
||||
|
||||
// Time change on media
|
||||
utils.on(this.player.media, 'timeupdate seeking', function (event) {
|
||||
utils.on(this.player.media, 'timeupdate seeking seeked', function (event) {
|
||||
return controls.timeUpdate.call(_this3.player, event);
|
||||
});
|
||||
|
||||
@ -4607,7 +4670,7 @@ var Listeners = function () {
|
||||
});
|
||||
|
||||
// Check for buffer progress
|
||||
utils.on(this.player.media, 'progress playing', function (event) {
|
||||
utils.on(this.player.media, 'progress playing seeking seeked', function (event) {
|
||||
return controls.updateProgress.call(_this3.player, event);
|
||||
});
|
||||
|
||||
@ -4626,9 +4689,6 @@ var Listeners = function () {
|
||||
return ui.checkLoading.call(_this3.player, event);
|
||||
});
|
||||
|
||||
// Check if media failed to load
|
||||
// utils.on(this.player.media, 'play', event => ui.checkFailed.call(this.player, event));
|
||||
|
||||
// If autoplay, then load advertisement if required
|
||||
// TODO: Show some sort of loading state while the ad manager loads else there's a delay before ad shows
|
||||
utils.on(this.player.media, 'playing', function () {
|
||||
@ -4850,9 +4910,47 @@ var Listeners = function () {
|
||||
}
|
||||
});
|
||||
|
||||
// Set range input alternative "value", which matches the tooltip time (#954)
|
||||
on(this.player.elements.inputs.seek, 'mousedown mousemove', function (event) {
|
||||
var clientRect = _this4.player.elements.progress.getBoundingClientRect();
|
||||
var percent = 100 / clientRect.width * (event.pageX - clientRect.left);
|
||||
event.currentTarget.setAttribute('seek-value', percent);
|
||||
});
|
||||
|
||||
// Pause while seeking
|
||||
on(this.player.elements.inputs.seek, 'mousedown mouseup keydown keyup touchstart touchend', function (event) {
|
||||
var seek = event.currentTarget;
|
||||
|
||||
// Was playing before?
|
||||
var play = seek.hasAttribute('play-on-seeked');
|
||||
|
||||
// Done seeking
|
||||
var done = ['mouseup', 'touchend', 'keyup'].includes(event.type);
|
||||
|
||||
// If we're done seeking and it was playing, resume playback
|
||||
if (play && done) {
|
||||
seek.removeAttribute('play-on-seeked');
|
||||
_this4.player.play();
|
||||
} else if (!done && _this4.player.playing) {
|
||||
seek.setAttribute('play-on-seeked', '');
|
||||
_this4.player.pause();
|
||||
}
|
||||
});
|
||||
|
||||
// Seek
|
||||
on(this.player.elements.inputs.seek, inputEvent, function (event) {
|
||||
_this4.player.currentTime = event.target.value / event.target.max * _this4.player.duration;
|
||||
var seek = event.currentTarget;
|
||||
|
||||
// If it exists, use seek-value instead of "value" for consistency with tooltip time (#954)
|
||||
var seekTo = seek.getAttribute('seek-value');
|
||||
|
||||
if (utils.is.empty(seekTo)) {
|
||||
seekTo = seek.value;
|
||||
}
|
||||
|
||||
seek.removeAttribute('seek-value');
|
||||
|
||||
_this4.player.currentTime = seekTo / seek.max * _this4.player.duration;
|
||||
}, 'seek');
|
||||
|
||||
// Current time invert
|
||||
@ -4887,23 +4985,48 @@ var Listeners = function () {
|
||||
return controls.updateSeekTooltip.call(_this4.player, event);
|
||||
});
|
||||
|
||||
// Toggle controls visibility based on mouse movement
|
||||
if (this.player.config.hideControls) {
|
||||
// Watch for cursor over controls so they don't hide when trying to interact
|
||||
// Update controls.hover state (used for ui.toggleControls to avoid hiding when interacting)
|
||||
on(this.player.elements.controls, 'mouseenter mouseleave', function (event) {
|
||||
_this4.player.elements.controls.hover = !_this4.player.touch && event.type === 'mouseenter';
|
||||
});
|
||||
|
||||
// Watch for cursor over controls so they don't hide when trying to interact
|
||||
// Update controls.pressed state (used for ui.toggleControls to avoid hiding when interacting)
|
||||
on(this.player.elements.controls, 'mousedown mouseup touchstart touchend touchcancel', function (event) {
|
||||
_this4.player.elements.controls.pressed = ['mousedown', 'touchstart'].includes(event.type);
|
||||
});
|
||||
|
||||
// Focus in/out on controls
|
||||
on(this.player.elements.controls, 'focusin focusout', function (event) {
|
||||
_this4.player.toggleControls(event);
|
||||
});
|
||||
var _player = _this4.player,
|
||||
config = _player.config,
|
||||
elements = _player.elements,
|
||||
timers = _player.timers;
|
||||
|
||||
// Skip transition to prevent focus from scrolling the parent element
|
||||
|
||||
utils.toggleClass(elements.controls, config.classNames.noTransition, event.type === 'focusin');
|
||||
|
||||
// Toggle
|
||||
ui.toggleControls.call(_this4.player, event.type === 'focusin');
|
||||
|
||||
// If focusin, hide again after delay
|
||||
if (event.type === 'focusin') {
|
||||
// Restore transition
|
||||
setTimeout(function () {
|
||||
utils.toggleClass(elements.controls, config.classNames.noTransition, false);
|
||||
}, 0);
|
||||
|
||||
// Delay a little more for keyboard users
|
||||
var delay = _this4.touch ? 3000 : 4000;
|
||||
|
||||
// Clear timer
|
||||
clearTimeout(timers.controls);
|
||||
// Hide
|
||||
timers.controls = setTimeout(function () {
|
||||
return ui.toggleControls.call(_this4.player, false);
|
||||
}, delay);
|
||||
}
|
||||
});
|
||||
|
||||
// Mouse wheel for volume
|
||||
on(this.player.elements.inputs.volume, 'wheel', function (event) {
|
||||
@ -4955,6 +5078,14 @@ var Listeners = function () {
|
||||
|
||||
// ==========================================================================
|
||||
|
||||
// Set playback state and trigger change (only on actual change)
|
||||
function assurePlaybackState(play) {
|
||||
if (this.media.paused === play) {
|
||||
this.media.paused = !play;
|
||||
utils.dispatchEvent.call(this, this.media, play ? 'play' : 'pause');
|
||||
}
|
||||
}
|
||||
|
||||
var vimeo = {
|
||||
setup: function setup() {
|
||||
var _this = this;
|
||||
@ -5050,11 +5181,8 @@ var vimeo = {
|
||||
// Get original image
|
||||
url.pathname = url.pathname.split('_')[0] + '.jpg';
|
||||
|
||||
// Set attribute
|
||||
player.media.setAttribute('poster', url.href);
|
||||
|
||||
// Update
|
||||
ui.setPoster.call(player);
|
||||
// Set and show poster
|
||||
ui.setPoster.call(player, url.href);
|
||||
});
|
||||
|
||||
// Setup instance
|
||||
@ -5074,15 +5202,13 @@ var vimeo = {
|
||||
|
||||
// Create a faux HTML5 API using the Vimeo API
|
||||
player.media.play = function () {
|
||||
player.embed.play().then(function () {
|
||||
player.media.paused = false;
|
||||
});
|
||||
assurePlaybackState.call(player, true);
|
||||
return player.embed.play();
|
||||
};
|
||||
|
||||
player.media.pause = function () {
|
||||
player.embed.pause().then(function () {
|
||||
player.media.paused = true;
|
||||
});
|
||||
assurePlaybackState.call(player, false);
|
||||
return player.embed.pause();
|
||||
};
|
||||
|
||||
player.media.stop = function () {
|
||||
@ -5098,26 +5224,35 @@ var vimeo = {
|
||||
return currentTime;
|
||||
},
|
||||
set: function set(time) {
|
||||
// Get current paused state
|
||||
// Vimeo will automatically play on seek
|
||||
var paused = player.media.paused;
|
||||
// Vimeo will automatically play on seek if the video hasn't been played before
|
||||
|
||||
// Set seeking flag
|
||||
// Get current paused state and volume etc
|
||||
var embed = player.embed,
|
||||
media = player.media,
|
||||
paused = player.paused,
|
||||
volume = player.volume;
|
||||
|
||||
player.media.seeking = true;
|
||||
// Set seeking state and trigger event
|
||||
|
||||
// Trigger seeking
|
||||
utils.dispatchEvent.call(player, player.media, 'seeking');
|
||||
media.seeking = true;
|
||||
utils.dispatchEvent.call(player, media, 'seeking');
|
||||
|
||||
// Seek after events
|
||||
player.embed.setCurrentTime(time).catch(function () {
|
||||
// If paused, mute until seek is complete
|
||||
Promise.resolve(paused && embed.setVolume(0))
|
||||
// Seek
|
||||
.then(function () {
|
||||
return embed.setCurrentTime(time);
|
||||
})
|
||||
// Restore paused
|
||||
.then(function () {
|
||||
return paused && embed.pause();
|
||||
})
|
||||
// Restore volume
|
||||
.then(function () {
|
||||
return paused && embed.setVolume(volume);
|
||||
}).catch(function () {
|
||||
// Do nothing
|
||||
});
|
||||
|
||||
// Restore pause state
|
||||
if (paused) {
|
||||
player.pause();
|
||||
}
|
||||
}
|
||||
});
|
||||
|
||||
@ -5265,17 +5400,12 @@ var vimeo = {
|
||||
});
|
||||
|
||||
player.embed.on('play', function () {
|
||||
// Only fire play if paused before
|
||||
if (player.media.paused) {
|
||||
utils.dispatchEvent.call(player, player.media, 'play');
|
||||
}
|
||||
player.media.paused = false;
|
||||
assurePlaybackState.call(player, true);
|
||||
utils.dispatchEvent.call(player, player.media, 'playing');
|
||||
});
|
||||
|
||||
player.embed.on('pause', function () {
|
||||
player.media.paused = true;
|
||||
utils.dispatchEvent.call(player, player.media, 'pause');
|
||||
assurePlaybackState.call(player, false);
|
||||
});
|
||||
|
||||
player.embed.on('timeupdate', function (data) {
|
||||
@ -5306,7 +5436,6 @@ var vimeo = {
|
||||
player.embed.on('seeked', function () {
|
||||
player.media.seeking = false;
|
||||
utils.dispatchEvent.call(player, player.media, 'seeked');
|
||||
utils.dispatchEvent.call(player, player.media, 'play');
|
||||
});
|
||||
|
||||
player.embed.on('ended', function () {
|
||||
@ -5388,6 +5517,14 @@ function mapQualityUnits(levels) {
|
||||
}));
|
||||
}
|
||||
|
||||
// Set playback state and trigger change (only on actual change)
|
||||
function assurePlaybackState$1(play) {
|
||||
if (this.media.paused === play) {
|
||||
this.media.paused = !play;
|
||||
utils.dispatchEvent.call(this, this.media, play ? 'play' : 'pause');
|
||||
}
|
||||
}
|
||||
|
||||
var youtube = {
|
||||
setup: function setup() {
|
||||
var _this = this;
|
||||
@ -5491,7 +5628,26 @@ var youtube = {
|
||||
player.media = utils.replaceElement(container, player.media);
|
||||
|
||||
// Set poster image
|
||||
player.media.setAttribute('poster', utils.format(player.config.urls.youtube.poster, videoId));
|
||||
var posterSrc = function posterSrc(format) {
|
||||
return 'https://img.youtube.com/vi/' + videoId + '/' + format + 'default.jpg';
|
||||
};
|
||||
|
||||
// Check thumbnail images in order of quality, but reject fallback thumbnails (120px wide)
|
||||
utils.loadImage(posterSrc('maxres'), 121) // Higest quality and unpadded
|
||||
.catch(function () {
|
||||
return utils.loadImage(posterSrc('sd'), 121);
|
||||
}) // 480p padded 4:3
|
||||
.catch(function () {
|
||||
return utils.loadImage(posterSrc('hq'));
|
||||
}) // 360p padded 4:3. Always exists
|
||||
.then(function (image) {
|
||||
return ui.setPoster.call(player, image.src);
|
||||
}).then(function (posterSrc) {
|
||||
// If the image is padded, use background-size "cover" instead (like youtube does too with their posters)
|
||||
if (!posterSrc.includes('maxres')) {
|
||||
player.elements.poster.style.backgroundSize = 'cover';
|
||||
}
|
||||
});
|
||||
|
||||
// Setup instance
|
||||
// https://developers.google.com/youtube/iframe_api_reference
|
||||
@ -5578,10 +5734,12 @@ var youtube = {
|
||||
|
||||
// Create a faux HTML5 API using the YouTube API
|
||||
player.media.play = function () {
|
||||
assurePlaybackState$1.call(player, true);
|
||||
instance.playVideo();
|
||||
};
|
||||
|
||||
player.media.pause = function () {
|
||||
assurePlaybackState$1.call(player, false);
|
||||
instance.pauseVideo();
|
||||
};
|
||||
|
||||
@ -5599,23 +5757,17 @@ var youtube = {
|
||||
return Number(instance.getCurrentTime());
|
||||
},
|
||||
set: function set(time) {
|
||||
// Vimeo will automatically play on seek
|
||||
var paused = player.media.paused;
|
||||
|
||||
// Set seeking flag
|
||||
// If paused, mute audio preventively (YouTube starts playing on seek if the video hasn't been played yet).
|
||||
if (player.paused) {
|
||||
player.embed.mute();
|
||||
}
|
||||
|
||||
// Set seeking state and trigger event
|
||||
player.media.seeking = true;
|
||||
|
||||
// Trigger seeking
|
||||
utils.dispatchEvent.call(player, player.media, 'seeking');
|
||||
|
||||
// Seek after events sent
|
||||
instance.seekTo(time);
|
||||
|
||||
// Restore pause state
|
||||
if (paused) {
|
||||
player.pause();
|
||||
}
|
||||
}
|
||||
});
|
||||
|
||||
@ -5738,6 +5890,14 @@ var youtube = {
|
||||
// Reset timer
|
||||
clearInterval(player.timers.playing);
|
||||
|
||||
var seeked = player.media.seeking && [1, 2].includes(event.data);
|
||||
|
||||
if (seeked) {
|
||||
// Unset seeking and fire seeked event
|
||||
player.media.seeking = false;
|
||||
utils.dispatchEvent.call(player, player.media, 'seeked');
|
||||
}
|
||||
|
||||
// Handle events
|
||||
// -1 Unstarted
|
||||
// 0 Ended
|
||||
@ -5757,7 +5917,7 @@ var youtube = {
|
||||
break;
|
||||
|
||||
case 0:
|
||||
player.media.paused = true;
|
||||
assurePlaybackState$1.call(player, false);
|
||||
|
||||
// YouTube doesn't support loop for a single video, so mimick it.
|
||||
if (player.media.loop) {
|
||||
@ -5771,17 +5931,11 @@ var youtube = {
|
||||
break;
|
||||
|
||||
case 1:
|
||||
// If we were seeking, fire seeked event
|
||||
if (player.media.seeking) {
|
||||
utils.dispatchEvent.call(player, player.media, 'seeked');
|
||||
}
|
||||
player.media.seeking = false;
|
||||
|
||||
// Only fire play if paused before
|
||||
// Restore paused state (YouTube starts playing on seek if the video hasn't been played yet)
|
||||
if (player.media.paused) {
|
||||
utils.dispatchEvent.call(player, player.media, 'play');
|
||||
}
|
||||
player.media.paused = false;
|
||||
player.media.pause();
|
||||
} else {
|
||||
assurePlaybackState$1.call(player, true);
|
||||
|
||||
utils.dispatchEvent.call(player, player.media, 'playing');
|
||||
|
||||
@ -5800,13 +5954,16 @@ var youtube = {
|
||||
|
||||
// Get quality
|
||||
controls.setQualityMenu.call(player, mapQualityUnits(instance.getAvailableQualityLevels()));
|
||||
}
|
||||
|
||||
break;
|
||||
|
||||
case 2:
|
||||
player.media.paused = true;
|
||||
|
||||
utils.dispatchEvent.call(player, player.media, 'pause');
|
||||
// Restore audio (YouTube starts playing on seek if the video hasn't been played yet)
|
||||
if (!player.muted) {
|
||||
player.embed.unMute();
|
||||
}
|
||||
assurePlaybackState$1.call(player, false);
|
||||
|
||||
break;
|
||||
|
||||
@ -6740,7 +6897,7 @@ var Plyr = function () {
|
||||
}
|
||||
|
||||
// Set config
|
||||
this.config = utils.extend({}, defaults$1, options || {}, function () {
|
||||
this.config = utils.extend({}, defaults$1, Plyr.defaults, options || {}, function () {
|
||||
try {
|
||||
return JSON.parse(_this.media.getAttribute('data-plyr-config'));
|
||||
} catch (e) {
|
||||
@ -7180,114 +7337,35 @@ var Plyr = function () {
|
||||
|
||||
/**
|
||||
* Toggle the player controls
|
||||
* @param {boolean} toggle - Whether to show the controls
|
||||
* @param {boolean} [toggle] - Whether to show the controls
|
||||
*/
|
||||
|
||||
}, {
|
||||
key: 'toggleControls',
|
||||
value: function toggleControls(toggle) {
|
||||
var _this2 = this;
|
||||
// Don't toggle if missing UI support or if it's audio
|
||||
if (this.supported.ui && !this.isAudio) {
|
||||
// Get state before change
|
||||
var isHidden = utils.hasClass(this.elements.container, this.config.classNames.hideControls);
|
||||
|
||||
// We need controls of course...
|
||||
if (!utils.is.element(this.elements.controls)) {
|
||||
return;
|
||||
// Negate the argument if not undefined since adding the class to hides the controls
|
||||
var force = typeof toggle === 'undefined' ? undefined : !toggle;
|
||||
|
||||
// Apply and get updated state
|
||||
var hiding = utils.toggleClass(this.elements.container, this.config.classNames.hideControls, force);
|
||||
|
||||
// Close menu
|
||||
if (hiding && this.config.controls.includes('settings') && !utils.is.empty(this.config.settings)) {
|
||||
controls.toggleMenu.call(this, false);
|
||||
}
|
||||
|
||||
// Don't hide if no UI support or it's audio
|
||||
if (!this.supported.ui || this.isAudio) {
|
||||
return;
|
||||
// Trigger event on change
|
||||
if (hiding !== isHidden) {
|
||||
var eventName = hiding ? 'controlshidden' : 'controlsshown';
|
||||
utils.dispatchEvent.call(this, this.media, eventName);
|
||||
}
|
||||
|
||||
var delay = 0;
|
||||
var show = toggle;
|
||||
var isEnterFullscreen = false;
|
||||
|
||||
// Get toggle state if not set
|
||||
if (!utils.is.boolean(toggle)) {
|
||||
if (utils.is.event(toggle)) {
|
||||
// Is the enter fullscreen event
|
||||
isEnterFullscreen = toggle.type === 'enterfullscreen';
|
||||
|
||||
// Events that show the controls
|
||||
var showEvents = ['touchstart', 'touchmove', 'mouseenter', 'mousemove', 'focusin'];
|
||||
|
||||
// Events that delay hiding
|
||||
var delayEvents = ['touchmove', 'touchend', 'mousemove'];
|
||||
|
||||
// Whether to show controls
|
||||
show = showEvents.includes(toggle.type);
|
||||
|
||||
// Delay hiding on move events
|
||||
if (delayEvents.includes(toggle.type)) {
|
||||
delay = 2000;
|
||||
}
|
||||
|
||||
// Delay a little more for keyboard users
|
||||
if (!this.touch && toggle.type === 'focusin') {
|
||||
delay = 3000;
|
||||
utils.toggleClass(this.elements.controls, this.config.classNames.noTransition, true);
|
||||
}
|
||||
} else {
|
||||
show = utils.hasClass(this.elements.container, this.config.classNames.hideControls);
|
||||
}
|
||||
}
|
||||
|
||||
// Clear timer on every call
|
||||
clearTimeout(this.timers.controls);
|
||||
|
||||
// If the mouse is not over the controls, set a timeout to hide them
|
||||
if (show || this.paused || this.loading) {
|
||||
// Check if controls toggled
|
||||
var toggled = utils.toggleClass(this.elements.container, this.config.classNames.hideControls, false);
|
||||
|
||||
// Trigger event
|
||||
if (toggled) {
|
||||
utils.dispatchEvent.call(this, this.media, 'controlsshown');
|
||||
}
|
||||
|
||||
// Always show controls when paused or if touch
|
||||
if (this.paused || this.loading) {
|
||||
return;
|
||||
}
|
||||
|
||||
// Delay for hiding on touch
|
||||
if (this.touch) {
|
||||
delay = 3000;
|
||||
}
|
||||
}
|
||||
|
||||
// If toggle is false or if we're playing (regardless of toggle),
|
||||
// then set the timer to hide the controls
|
||||
if (!show || this.playing) {
|
||||
this.timers.controls = setTimeout(function () {
|
||||
// We need controls of course...
|
||||
if (!utils.is.element(_this2.elements.controls)) {
|
||||
return;
|
||||
}
|
||||
|
||||
// If the mouse is over the controls (and not entering fullscreen), bail
|
||||
if ((_this2.elements.controls.pressed || _this2.elements.controls.hover) && !isEnterFullscreen) {
|
||||
return;
|
||||
}
|
||||
|
||||
// Restore transition behaviour
|
||||
if (!utils.hasClass(_this2.elements.container, _this2.config.classNames.hideControls)) {
|
||||
utils.toggleClass(_this2.elements.controls, _this2.config.classNames.noTransition, false);
|
||||
}
|
||||
|
||||
// Set hideControls class
|
||||
var toggled = utils.toggleClass(_this2.elements.container, _this2.config.classNames.hideControls, _this2.config.hideControls);
|
||||
|
||||
// Trigger event and close menu
|
||||
if (toggled) {
|
||||
utils.dispatchEvent.call(_this2, _this2.media, 'controlshidden');
|
||||
|
||||
if (_this2.config.controls.includes('settings') && !utils.is.empty(_this2.config.settings)) {
|
||||
controls.toggleMenu.call(_this2, false);
|
||||
}
|
||||
}
|
||||
}, delay);
|
||||
return !hiding;
|
||||
}
|
||||
return false;
|
||||
}
|
||||
|
||||
/**
|
||||
@ -7325,7 +7403,7 @@ var Plyr = function () {
|
||||
}, {
|
||||
key: 'destroy',
|
||||
value: function destroy(callback) {
|
||||
var _this3 = this;
|
||||
var _this2 = this;
|
||||
|
||||
var soft = arguments.length > 1 && arguments[1] !== undefined ? arguments[1] : false;
|
||||
|
||||
@ -7338,22 +7416,22 @@ var Plyr = function () {
|
||||
document.body.style.overflow = '';
|
||||
|
||||
// GC for embed
|
||||
_this3.embed = null;
|
||||
_this2.embed = null;
|
||||
|
||||
// If it's a soft destroy, make minimal changes
|
||||
if (soft) {
|
||||
if (Object.keys(_this3.elements).length) {
|
||||
if (Object.keys(_this2.elements).length) {
|
||||
// Remove elements
|
||||
utils.removeElement(_this3.elements.buttons.play);
|
||||
utils.removeElement(_this3.elements.captions);
|
||||
utils.removeElement(_this3.elements.controls);
|
||||
utils.removeElement(_this3.elements.wrapper);
|
||||
utils.removeElement(_this2.elements.buttons.play);
|
||||
utils.removeElement(_this2.elements.captions);
|
||||
utils.removeElement(_this2.elements.controls);
|
||||
utils.removeElement(_this2.elements.wrapper);
|
||||
|
||||
// Clear for GC
|
||||
_this3.elements.buttons.play = null;
|
||||
_this3.elements.captions = null;
|
||||
_this3.elements.controls = null;
|
||||
_this3.elements.wrapper = null;
|
||||
_this2.elements.buttons.play = null;
|
||||
_this2.elements.captions = null;
|
||||
_this2.elements.controls = null;
|
||||
_this2.elements.wrapper = null;
|
||||
}
|
||||
|
||||
// Callback
|
||||
@ -7362,26 +7440,26 @@ var Plyr = function () {
|
||||
}
|
||||
} else {
|
||||
// Unbind listeners
|
||||
_this3.listeners.clear();
|
||||
_this2.listeners.clear();
|
||||
|
||||
// Replace the container with the original element provided
|
||||
utils.replaceElement(_this3.elements.original, _this3.elements.container);
|
||||
utils.replaceElement(_this2.elements.original, _this2.elements.container);
|
||||
|
||||
// Event
|
||||
utils.dispatchEvent.call(_this3, _this3.elements.original, 'destroyed', true);
|
||||
utils.dispatchEvent.call(_this2, _this2.elements.original, 'destroyed', true);
|
||||
|
||||
// Callback
|
||||
if (utils.is.function(callback)) {
|
||||
callback.call(_this3.elements.original);
|
||||
callback.call(_this2.elements.original);
|
||||
}
|
||||
|
||||
// Reset state
|
||||
_this3.ready = false;
|
||||
_this2.ready = false;
|
||||
|
||||
// Clear for garbage collection
|
||||
setTimeout(function () {
|
||||
_this3.elements = null;
|
||||
_this3.media = null;
|
||||
_this2.elements = null;
|
||||
_this2.media = null;
|
||||
}, 200);
|
||||
}
|
||||
};
|
||||
@ -7900,10 +7978,7 @@ var Plyr = function () {
|
||||
return;
|
||||
}
|
||||
|
||||
if (utils.is.string(input)) {
|
||||
this.media.setAttribute('poster', input);
|
||||
ui.setPoster.call(this);
|
||||
}
|
||||
ui.setPoster.call(this, input);
|
||||
}
|
||||
|
||||
/**
|
||||
@ -8084,6 +8159,8 @@ var Plyr = function () {
|
||||
return Plyr;
|
||||
}();
|
||||
|
||||
Plyr.defaults = utils.cloneDeep(defaults$1);
|
||||
|
||||
return Plyr;
|
||||
|
||||
})));
|
||||
|
2
dist/plyr.js.map
vendored
2
dist/plyr.js.map
vendored
File diff suppressed because one or more lines are too long
2
dist/plyr.min.js
vendored
2
dist/plyr.min.js
vendored
File diff suppressed because one or more lines are too long
2
dist/plyr.min.js.map
vendored
2
dist/plyr.min.js.map
vendored
File diff suppressed because one or more lines are too long
961
dist/plyr.polyfilled.js
vendored
961
dist/plyr.polyfilled.js
vendored
File diff suppressed because it is too large
Load Diff
2
dist/plyr.polyfilled.js.map
vendored
2
dist/plyr.polyfilled.js.map
vendored
File diff suppressed because one or more lines are too long
2
dist/plyr.polyfilled.min.js
vendored
2
dist/plyr.polyfilled.min.js
vendored
File diff suppressed because one or more lines are too long
2
dist/plyr.polyfilled.min.js.map
vendored
2
dist/plyr.polyfilled.min.js.map
vendored
File diff suppressed because one or more lines are too long
@ -12,6 +12,8 @@ const concat = require('gulp-concat');
|
||||
const filter = require('gulp-filter');
|
||||
const sass = require('gulp-sass');
|
||||
const cleancss = require('gulp-clean-css');
|
||||
const postcss = require('gulp-postcss');
|
||||
const customprops = require('postcss-custom-properties');
|
||||
const run = require('run-sequence');
|
||||
const header = require('gulp-header');
|
||||
const prefix = require('gulp-autoprefixer');
|
||||
@ -171,6 +173,7 @@ const build = {
|
||||
.on('error', gutil.log)
|
||||
.pipe(concat(key))
|
||||
.pipe(prefix(browsers, { cascade: false }))
|
||||
.pipe(postcss([customprops()]))
|
||||
.pipe(cleancss())
|
||||
.pipe(size(sizeOptions))
|
||||
.pipe(gulp.dest(paths[bundle].output)),
|
||||
|
@ -10,7 +10,7 @@
|
||||
.plyr__captions {
|
||||
animation: plyr-fade-in 0.3s ease;
|
||||
bottom: 0;
|
||||
color: $plyr-captions-color;
|
||||
color: var(--plyr-captions-text-color);
|
||||
display: none;
|
||||
font-size: $plyr-font-size-captions-small;
|
||||
left: 0;
|
||||
@ -22,7 +22,7 @@
|
||||
width: 100%;
|
||||
|
||||
span {
|
||||
background: $plyr-captions-bg;
|
||||
background: var(--plyr-captions-background);
|
||||
border-radius: 2px;
|
||||
box-decoration-break: clone;
|
||||
line-height: 185%;
|
||||
|
@ -5,21 +5,21 @@
|
||||
.plyr__control {
|
||||
background: transparent;
|
||||
border: 0;
|
||||
border-radius: $plyr-control-radius;
|
||||
border-radius: var(--plyr-control-radius);
|
||||
color: inherit;
|
||||
cursor: pointer;
|
||||
flex-shrink: 0;
|
||||
overflow: visible; // IE11
|
||||
padding: $plyr-control-padding;
|
||||
padding: var(--plyr-control-padding);
|
||||
position: relative;
|
||||
transition: all 0.3s ease;
|
||||
|
||||
svg {
|
||||
display: block;
|
||||
fill: currentColor;
|
||||
height: $plyr-control-icon-size;
|
||||
height: var(--plyr-control-icon-size);
|
||||
pointer-events: none;
|
||||
width: $plyr-control-icon-size;
|
||||
width: var(--plyr-control-icon-size);
|
||||
}
|
||||
|
||||
// Default focus
|
||||
@ -46,18 +46,18 @@
|
||||
&.plyr__tab-focus,
|
||||
&:hover,
|
||||
&[aria-expanded='true'] {
|
||||
background: $plyr-audio-control-bg-hover;
|
||||
color: $plyr-audio-control-color-hover;
|
||||
background: var(--plyr-audio-control-bg-hover);
|
||||
color: var(--plyr-audio-control-color-hover);
|
||||
}
|
||||
}
|
||||
|
||||
// Large play button (video only)
|
||||
.plyr__control--overlaid {
|
||||
background: rgba($plyr-video-control-bg-hover, 0.8);
|
||||
background: var(--plyr-video-control-bg-hover);
|
||||
border: 0;
|
||||
border-radius: 100%;
|
||||
box-shadow: 0 1px 1px rgba(#000, 0.15);
|
||||
color: $plyr-video-control-color;
|
||||
color: var(--plyr-video-control-color);
|
||||
display: none;
|
||||
left: 50%;
|
||||
padding: ceil($plyr-control-spacing * 1.5);
|
||||
@ -67,15 +67,15 @@
|
||||
z-index: 2;
|
||||
|
||||
svg {
|
||||
height: $plyr-control-icon-size-large;
|
||||
height: var(--plyr-control-icon-size-large);
|
||||
left: 2px; // Offset to make the play button look right
|
||||
position: relative;
|
||||
width: $plyr-control-icon-size-large;
|
||||
width: var(--plyr-control-icon-size-large);
|
||||
}
|
||||
|
||||
&:hover,
|
||||
&:focus {
|
||||
background: $plyr-video-control-bg-hover;
|
||||
background: var(--plyr-video-control-bg-hover);
|
||||
}
|
||||
}
|
||||
|
||||
|
131
src/sass/lib/css-vars.scss
Normal file
131
src/sass/lib/css-vars.scss
Normal file
@ -0,0 +1,131 @@
|
||||
// Downloaded from https://github.com/malyw/css-vars
|
||||
|
||||
//// VARIABLES ////
|
||||
|
||||
// global map to be filled via variables
|
||||
$css-vars: ();
|
||||
|
||||
// the variable may be set to "true" anywhere in the code,
|
||||
// so native CSS custom properties will be used instead of the Sass global map
|
||||
$css-vars-use-native: false !default;
|
||||
|
||||
// enables the output of debug messages
|
||||
$css-vars-debug-log: false !default;
|
||||
|
||||
//// FUNCTIONS ////
|
||||
|
||||
///
|
||||
// Assigns a variable to the global map
|
||||
///
|
||||
@function _cssVarAssign($varName: null, $varValue: null) {
|
||||
// CHECK PARAMS
|
||||
@if ($varName==null) {
|
||||
@error 'Variable name is expected, instead got: null';
|
||||
}
|
||||
@if ($varValue==null) {
|
||||
@error 'Variable value is expected, instead got: null';
|
||||
}
|
||||
|
||||
// assign to the global map
|
||||
@if ($css-vars-debug-log and map-get($css-vars, $varName)) {
|
||||
@debug "'#{$varName}' variable is reassigned";
|
||||
}
|
||||
|
||||
@return map-merge($css-vars, ($varName: $varValue));
|
||||
}
|
||||
|
||||
///
|
||||
// Emulates var() CSS native function behavior
|
||||
//
|
||||
// $args[0] {String} "--" + variable name
|
||||
// [$args[1]] Optional default value if variable is not assigned yet
|
||||
//
|
||||
// E.G.:
|
||||
// color: var(--main-color);
|
||||
// background: var(--main-bg, green);
|
||||
///
|
||||
@function var($args...) {
|
||||
// CHECK PARAMS
|
||||
@if (length($args) ==0) {
|
||||
@error 'Variable name is expected to be passed to the var() function';
|
||||
}
|
||||
@if (str-length(nth($args, 1)) < 2 or str-slice(nth($args, 1), 0, 2) != '--') {
|
||||
@error "Variable name is expected to start from '--'";
|
||||
}
|
||||
|
||||
// PROCESS
|
||||
$varName: nth($args, 1);
|
||||
$varValue: map-get($css-vars, $varName);
|
||||
|
||||
@if ($css-vars-debug-log or not $css-vars-use-native) {
|
||||
// Sass or debug
|
||||
@if ($varValue==null) {
|
||||
// variable is not provided so far
|
||||
@if (length($args) ==2) {
|
||||
// the default value is passed
|
||||
@if ($css-vars-debug-log) {
|
||||
@debug "Provided default value is used for the variable: '#{$varName}'";
|
||||
}
|
||||
$varValue: nth($args, 2);
|
||||
} @else if ($css-vars-debug-log) {
|
||||
@debug "Variable '#{$varName}' is not assigned";
|
||||
@if (not $css-vars-use-native) {
|
||||
@debug "The 'var(#{$varName}...)' usage will be skipped in the output CSS";
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@if ($css-vars-use-native) {
|
||||
// CSS variables
|
||||
// Native CSS: don't process function in case of native
|
||||
@return unquote('var(' + $args + ')');
|
||||
} @else {
|
||||
// Sass: return value from the map
|
||||
@return $varValue;
|
||||
}
|
||||
}
|
||||
|
||||
//// MIXIN ////
|
||||
|
||||
///
|
||||
// CSS mixin to provide variables
|
||||
// E.G.:
|
||||
// @include css-vars((
|
||||
// --color: rebeccapurple,
|
||||
// --height: 68px,
|
||||
// --margin-top: calc(2vh + 20px)
|
||||
// ));
|
||||
///
|
||||
@mixin css-vars($varMap: null) {
|
||||
// CHECK PARAMS
|
||||
@if ($varMap==null) {
|
||||
@error 'Map of variables is expected, instead got: null';
|
||||
}
|
||||
@if (type_of($varMap) !=map) {
|
||||
@error 'Map of variables is expected, instead got another type passed: #{type_of($varMap)}';
|
||||
}
|
||||
|
||||
// PROCESS
|
||||
@if ($css-vars-debug-log or not $css-vars-use-native) {
|
||||
// Sass or debug
|
||||
// merge variables and values to the global map (provides no output)
|
||||
@each $varName, $varValue in $varMap {
|
||||
$css-vars: _cssVarAssign($varName, $varValue) !global; // store in global variable
|
||||
}
|
||||
}
|
||||
|
||||
@if ($css-vars-use-native) {
|
||||
// CSS variables
|
||||
// Native CSS: assign CSS custom properties to the global scope
|
||||
@at-root :root {
|
||||
@each $varName, $varValue in $varMap {
|
||||
@if (type_of($varValue) ==string) {
|
||||
#{$varName}: $varValue; // to prevent quotes interpolation
|
||||
} @else {
|
||||
#{$varName}: #{$varValue};
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
@ -5,6 +5,9 @@
|
||||
// ==========================================================================
|
||||
@charset 'UTF-8';
|
||||
|
||||
@import 'lib/css-vars';
|
||||
$css-vars-use-native: true;
|
||||
|
||||
@import 'settings/breakpoints';
|
||||
@import 'settings/colors';
|
||||
@import 'settings/cosmetics';
|
||||
|
@ -2,9 +2,17 @@
|
||||
// Captions
|
||||
// ==========================================================================
|
||||
|
||||
$plyr-captions-bg: rgba(#000, 0.8) !default;
|
||||
$plyr-captions-color: #fff !default;
|
||||
$plyr-captions-background: rgba(#000, 0.8) !default;
|
||||
$plyr-captions-text-color: #fff !default;
|
||||
|
||||
$plyr-font-size-captions-base: $plyr-font-size-base !default;
|
||||
$plyr-font-size-captions-small: $plyr-font-size-small !default;
|
||||
$plyr-font-size-captions-medium: $plyr-font-size-large !default;
|
||||
$plyr-font-size-captions-large: $plyr-font-size-xlarge !default;
|
||||
|
||||
@include css-vars(
|
||||
(
|
||||
--plyr-captions-background: $plyr-captions-background,
|
||||
--plyr-captions-text-color: $plyr-captions-text-color
|
||||
)
|
||||
);
|
||||
|
@ -7,3 +7,13 @@ $plyr-color-gunmetal: #2f343d !default;
|
||||
$plyr-color-fiord: #4f5b5f !default;
|
||||
$plyr-color-lynch: #6b7d85 !default;
|
||||
$plyr-color-heather: #b7c5cd !default;
|
||||
|
||||
@include css-vars(
|
||||
(
|
||||
--plyr-color-main: $plyr-color-main,
|
||||
--plyr-color-gunmetal: $plyr-color-gunmetal,
|
||||
--plyr-color-fiord: $plyr-color-fiord,
|
||||
--plyr-color-lynch: $plyr-color-lynch,
|
||||
--plyr-color-heather: $plyr-color-heather
|
||||
)
|
||||
);
|
||||
|
@ -11,9 +11,27 @@ $plyr-control-radius: 3px !default;
|
||||
$plyr-video-controls-bg: #000 !default;
|
||||
$plyr-video-control-color: #fff !default;
|
||||
$plyr-video-control-color-hover: #fff !default;
|
||||
$plyr-video-control-bg-hover: $plyr-color-main !default;
|
||||
$plyr-video-control-bg-hover: var(--plyr-color-main) !default;
|
||||
|
||||
$plyr-audio-controls-bg: #fff !default;
|
||||
$plyr-audio-control-color: $plyr-color-fiord !default;
|
||||
$plyr-audio-control-color: var(--plyr-color-fiord) !default;
|
||||
$plyr-audio-control-color-hover: #fff !default;
|
||||
$plyr-audio-control-bg-hover: $plyr-color-main !default;
|
||||
$plyr-audio-control-bg-hover: var(--plyr-color-main) !default;
|
||||
|
||||
@include css-vars(
|
||||
(
|
||||
--plyr-control-icon-size: $plyr-control-icon-size,
|
||||
--plyr-control-icon-size-large: $plyr-control-icon-size-large,
|
||||
--plyr-control-spacing: $plyr-control-spacing,
|
||||
--plyr-control-padding: $plyr-control-padding,
|
||||
--plyr-control-radius: $plyr-control-radius,
|
||||
--plyr-video-controls-bg: $plyr-video-controls-bg,
|
||||
--plyr-video-control-color: $plyr-video-control-color,
|
||||
--plyr-video-control-color-hover: $plyr-video-control-color-hover,
|
||||
--plyr-video-control-bg-hover: $plyr-video-control-bg-hover,
|
||||
--plyr-audio-controls-bg: $plyr-audio-controls-bg,
|
||||
--plyr-audio-control-color: $plyr-audio-control-color,
|
||||
--plyr-audio-control-color-hover: $plyr-audio-control-color-hover,
|
||||
--plyr-audio-control-bg-hover: $plyr-audio-control-bg-hover
|
||||
)
|
||||
);
|
||||
|
@ -3,3 +3,5 @@
|
||||
// ==========================================================================
|
||||
|
||||
$plyr-tab-focus-default-color: $plyr-color-main !default;
|
||||
|
||||
@include css-vars((--plyr-tab-focus-default-color: $plyr-tab-focus-default-color));
|
||||
|
@ -16,7 +16,7 @@ $plyr-range-track-height: 6px !default;
|
||||
$plyr-range-max-height: ($plyr-range-thumb-active-shadow-width * 2) + $plyr-range-thumb-height !default;
|
||||
|
||||
// Fill
|
||||
$plyr-range-fill-bg: $plyr-color-main !default;
|
||||
$plyr-range-fill-bg: var(--plyr-color-main);
|
||||
|
||||
// Type specific
|
||||
$plyr-video-range-track-bg: $plyr-video-progress-buffered-bg !default;
|
||||
|
Loading…
x
Reference in New Issue
Block a user