v3.3.0
This commit is contained in:
parent
5ca769807e
commit
9ebc2719d3
11
changelog.md
11
changelog.md
@ -1,3 +1,14 @@
|
|||||||
|
## v3.3.0
|
||||||
|
|
||||||
|
* Now using a custom poster image element to hide the YouTube play button and give more control over when the poster image shows
|
||||||
|
* Renamed `showPosterOnEnd` to `resetOnEnd` as it makes more sense and now works for all players and does not reload media
|
||||||
|
* Fix for same domain SVG URLs (raised by Jochem in Slack)
|
||||||
|
* [`URL`](https://developer.mozilla.org/en-US/docs/Web/API/Window/URL) is polyfill now required
|
||||||
|
* Added pause className (fixes #941)
|
||||||
|
* Button height set in CSS (auto) (fixes #928)
|
||||||
|
* Don't autoplay cloned original media (fixes #936)
|
||||||
|
* Return to the home menu pane after selecting an option
|
||||||
|
|
||||||
## v3.2.4
|
## v3.2.4
|
||||||
|
|
||||||
* Fix issue wher player never reports as ready if controls is empty array
|
* Fix issue wher player never reports as ready if controls is empty array
|
||||||
|
2
demo/dist/demo.css
vendored
2
demo/dist/demo.css
vendored
File diff suppressed because one or more lines are too long
225
demo/dist/demo.js
vendored
225
demo/dist/demo.js
vendored
@ -85,15 +85,6 @@ function serializer(replacer, cycleReplacer) {
|
|||||||
});
|
});
|
||||||
var stringify_2 = stringify_1.getSerialize;
|
var stringify_2 = stringify_1.getSerialize;
|
||||||
|
|
||||||
|
|
||||||
var stringify = Object.freeze({
|
|
||||||
default: stringify_1,
|
|
||||||
__moduleExports: stringify_1,
|
|
||||||
getSerialize: stringify_2
|
|
||||||
});
|
|
||||||
|
|
||||||
var stringify$1 = ( stringify && stringify_1 ) || stringify;
|
|
||||||
|
|
||||||
var _window =
|
var _window =
|
||||||
typeof window !== 'undefined'
|
typeof window !== 'undefined'
|
||||||
? window
|
? window
|
||||||
@ -606,7 +597,7 @@ function serializeException(ex, depth, maxSize) {
|
|||||||
|
|
||||||
var serialized = serializeObject(ex, depth);
|
var serialized = serializeObject(ex, depth);
|
||||||
|
|
||||||
if (jsonSize(stringify$1(serialized)) > maxSize) {
|
if (jsonSize(stringify_1(serialized)) > maxSize) {
|
||||||
return serializeException(ex, depth - 1);
|
return serializeException(ex, depth - 1);
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -644,7 +635,7 @@ function sanitize(input, sanitizeKeys) {
|
|||||||
var safeInput;
|
var safeInput;
|
||||||
|
|
||||||
try {
|
try {
|
||||||
safeInput = JSON.parse(stringify$1(input));
|
safeInput = JSON.parse(stringify_1(input));
|
||||||
} catch (o_O) {
|
} catch (o_O) {
|
||||||
return input;
|
return input;
|
||||||
}
|
}
|
||||||
@ -707,78 +698,6 @@ var utils = {
|
|||||||
serializeKeysForMessage: serializeKeysForMessage,
|
serializeKeysForMessage: serializeKeysForMessage,
|
||||||
sanitize: sanitize
|
sanitize: sanitize
|
||||||
};
|
};
|
||||||
var utils_1 = utils.isObject;
|
|
||||||
var utils_2 = utils.isError;
|
|
||||||
var utils_3 = utils.isErrorEvent;
|
|
||||||
var utils_4 = utils.isUndefined;
|
|
||||||
var utils_5 = utils.isFunction;
|
|
||||||
var utils_6 = utils.isPlainObject;
|
|
||||||
var utils_7 = utils.isString;
|
|
||||||
var utils_8 = utils.isArray;
|
|
||||||
var utils_9 = utils.isEmptyObject;
|
|
||||||
var utils_10 = utils.supportsErrorEvent;
|
|
||||||
var utils_11 = utils.supportsFetch;
|
|
||||||
var utils_12 = utils.supportsReferrerPolicy;
|
|
||||||
var utils_13 = utils.supportsPromiseRejectionEvent;
|
|
||||||
var utils_14 = utils.wrappedCallback;
|
|
||||||
var utils_15 = utils.each;
|
|
||||||
var utils_16 = utils.objectMerge;
|
|
||||||
var utils_17 = utils.truncate;
|
|
||||||
var utils_18 = utils.objectFrozen;
|
|
||||||
var utils_19 = utils.hasKey;
|
|
||||||
var utils_20 = utils.joinRegExp;
|
|
||||||
var utils_21 = utils.urlencode;
|
|
||||||
var utils_22 = utils.uuid4;
|
|
||||||
var utils_23 = utils.htmlTreeAsString;
|
|
||||||
var utils_24 = utils.htmlElementAsString;
|
|
||||||
var utils_25 = utils.isSameException;
|
|
||||||
var utils_26 = utils.isSameStacktrace;
|
|
||||||
var utils_27 = utils.parseUrl;
|
|
||||||
var utils_28 = utils.fill;
|
|
||||||
var utils_29 = utils.safeJoin;
|
|
||||||
var utils_30 = utils.serializeException;
|
|
||||||
var utils_31 = utils.serializeKeysForMessage;
|
|
||||||
var utils_32 = utils.sanitize;
|
|
||||||
|
|
||||||
|
|
||||||
var utils$1 = Object.freeze({
|
|
||||||
default: utils,
|
|
||||||
__moduleExports: utils,
|
|
||||||
isObject: utils_1,
|
|
||||||
isError: utils_2,
|
|
||||||
isErrorEvent: utils_3,
|
|
||||||
isUndefined: utils_4,
|
|
||||||
isFunction: utils_5,
|
|
||||||
isPlainObject: utils_6,
|
|
||||||
isString: utils_7,
|
|
||||||
isArray: utils_8,
|
|
||||||
isEmptyObject: utils_9,
|
|
||||||
supportsErrorEvent: utils_10,
|
|
||||||
supportsFetch: utils_11,
|
|
||||||
supportsReferrerPolicy: utils_12,
|
|
||||||
supportsPromiseRejectionEvent: utils_13,
|
|
||||||
wrappedCallback: utils_14,
|
|
||||||
each: utils_15,
|
|
||||||
objectMerge: utils_16,
|
|
||||||
truncate: utils_17,
|
|
||||||
objectFrozen: utils_18,
|
|
||||||
hasKey: utils_19,
|
|
||||||
joinRegExp: utils_20,
|
|
||||||
urlencode: utils_21,
|
|
||||||
uuid4: utils_22,
|
|
||||||
htmlTreeAsString: utils_23,
|
|
||||||
htmlElementAsString: utils_24,
|
|
||||||
isSameException: utils_25,
|
|
||||||
isSameStacktrace: utils_26,
|
|
||||||
parseUrl: utils_27,
|
|
||||||
fill: utils_28,
|
|
||||||
safeJoin: utils_29,
|
|
||||||
serializeException: utils_30,
|
|
||||||
serializeKeysForMessage: utils_31,
|
|
||||||
sanitize: utils_32
|
|
||||||
});
|
|
||||||
|
|
||||||
var utils$2 = ( utils$1 && utils ) || utils$1;
|
|
||||||
|
|
||||||
/*
|
/*
|
||||||
TraceKit - Cross brower stack traces
|
TraceKit - Cross brower stack traces
|
||||||
@ -928,9 +847,9 @@ TraceKit.report = (function reportModuleWrapper() {
|
|||||||
function traceKitWindowOnError(msg, url, lineNo, colNo, ex) {
|
function traceKitWindowOnError(msg, url, lineNo, colNo, ex) {
|
||||||
var stack = null;
|
var stack = null;
|
||||||
// If 'ex' is ErrorEvent, get real Error from inside
|
// If 'ex' is ErrorEvent, get real Error from inside
|
||||||
var exception = utils$2.isErrorEvent(ex) ? ex.error : ex;
|
var exception = utils.isErrorEvent(ex) ? ex.error : ex;
|
||||||
// If 'msg' is ErrorEvent, get real message from inside
|
// If 'msg' is ErrorEvent, get real message from inside
|
||||||
var message = utils$2.isErrorEvent(msg) ? msg.message : msg;
|
var message = utils.isErrorEvent(msg) ? msg.message : msg;
|
||||||
|
|
||||||
if (lastExceptionStack) {
|
if (lastExceptionStack) {
|
||||||
TraceKit.computeStackTrace.augmentStackTraceWithInitialElement(
|
TraceKit.computeStackTrace.augmentStackTraceWithInitialElement(
|
||||||
@ -940,7 +859,7 @@ TraceKit.report = (function reportModuleWrapper() {
|
|||||||
message
|
message
|
||||||
);
|
);
|
||||||
processLastException();
|
processLastException();
|
||||||
} else if (exception && utils$2.isError(exception)) {
|
} else if (exception && utils.isError(exception)) {
|
||||||
// non-string `exception` arg; attempt to extract stack trace
|
// non-string `exception` arg; attempt to extract stack trace
|
||||||
|
|
||||||
// New chrome and blink send along a real error object
|
// New chrome and blink send along a real error object
|
||||||
@ -1407,12 +1326,6 @@ TraceKit.computeStackTrace = (function computeStackTraceWrapper() {
|
|||||||
|
|
||||||
var tracekit = TraceKit;
|
var tracekit = TraceKit;
|
||||||
|
|
||||||
|
|
||||||
var tracekit$1 = Object.freeze({
|
|
||||||
default: tracekit,
|
|
||||||
__moduleExports: tracekit
|
|
||||||
});
|
|
||||||
|
|
||||||
/*
|
/*
|
||||||
* JavaScript MD5
|
* JavaScript MD5
|
||||||
* https://github.com/blueimp/JavaScript-MD5
|
* https://github.com/blueimp/JavaScript-MD5
|
||||||
@ -1680,12 +1593,6 @@ function md5(string, key, raw) {
|
|||||||
|
|
||||||
var md5_1 = md5;
|
var md5_1 = md5;
|
||||||
|
|
||||||
|
|
||||||
var md5$1 = Object.freeze({
|
|
||||||
default: md5_1,
|
|
||||||
__moduleExports: md5_1
|
|
||||||
});
|
|
||||||
|
|
||||||
function RavenConfigError(message) {
|
function RavenConfigError(message) {
|
||||||
this.name = 'RavenConfigError';
|
this.name = 'RavenConfigError';
|
||||||
this.message = message;
|
this.message = message;
|
||||||
@ -1695,12 +1602,6 @@ RavenConfigError.prototype.constructor = RavenConfigError;
|
|||||||
|
|
||||||
var configError = RavenConfigError;
|
var configError = RavenConfigError;
|
||||||
|
|
||||||
|
|
||||||
var configError$1 = Object.freeze({
|
|
||||||
default: configError,
|
|
||||||
__moduleExports: configError
|
|
||||||
});
|
|
||||||
|
|
||||||
var wrapMethod = function(console, level, callback) {
|
var wrapMethod = function(console, level, callback) {
|
||||||
var originalConsoleLevel = console[level];
|
var originalConsoleLevel = console[level];
|
||||||
var originalConsole = console;
|
var originalConsole = console;
|
||||||
@ -1714,14 +1615,14 @@ var wrapMethod = function(console, level, callback) {
|
|||||||
console[level] = function() {
|
console[level] = function() {
|
||||||
var args = [].slice.call(arguments);
|
var args = [].slice.call(arguments);
|
||||||
|
|
||||||
var msg = utils$2.safeJoin(args, ' ');
|
var msg = utils.safeJoin(args, ' ');
|
||||||
var data = {level: sentryLevel, logger: 'console', extra: {arguments: args}};
|
var data = {level: sentryLevel, logger: 'console', extra: {arguments: args}};
|
||||||
|
|
||||||
if (level === 'assert') {
|
if (level === 'assert') {
|
||||||
if (args[0] === false) {
|
if (args[0] === false) {
|
||||||
// Default browsers message
|
// Default browsers message
|
||||||
msg =
|
msg =
|
||||||
'Assertion failed: ' + (utils$2.safeJoin(args.slice(1), ' ') || 'console.assert');
|
'Assertion failed: ' + (utils.safeJoin(args.slice(1), ' ') || 'console.assert');
|
||||||
data.extra.arguments = args.slice(1);
|
data.extra.arguments = args.slice(1);
|
||||||
callback && callback(msg, data);
|
callback && callback(msg, data);
|
||||||
}
|
}
|
||||||
@ -1741,22 +1642,6 @@ var wrapMethod = function(console, level, callback) {
|
|||||||
var console$1 = {
|
var console$1 = {
|
||||||
wrapMethod: wrapMethod
|
wrapMethod: wrapMethod
|
||||||
};
|
};
|
||||||
var console_1 = console$1.wrapMethod;
|
|
||||||
|
|
||||||
|
|
||||||
var console$2 = Object.freeze({
|
|
||||||
default: console$1,
|
|
||||||
__moduleExports: console$1,
|
|
||||||
wrapMethod: console_1
|
|
||||||
});
|
|
||||||
|
|
||||||
var TraceKit$1 = ( tracekit$1 && tracekit ) || tracekit$1;
|
|
||||||
|
|
||||||
var md5$2 = ( md5$1 && md5_1 ) || md5$1;
|
|
||||||
|
|
||||||
var RavenConfigError$1 = ( configError$1 && configError ) || configError$1;
|
|
||||||
|
|
||||||
var require$$0 = ( console$2 && console$1 ) || console$2;
|
|
||||||
|
|
||||||
/*global XDomainRequest:false */
|
/*global XDomainRequest:false */
|
||||||
|
|
||||||
@ -1766,35 +1651,35 @@ var require$$0 = ( console$2 && console$1 ) || console$2;
|
|||||||
|
|
||||||
|
|
||||||
|
|
||||||
var isError$1 = utils$2.isError;
|
var isError$1 = utils.isError;
|
||||||
var isObject$1 = utils$2.isObject;
|
var isObject$1 = utils.isObject;
|
||||||
var isPlainObject$1 = utils$2.isPlainObject;
|
var isPlainObject$1 = utils.isPlainObject;
|
||||||
var isErrorEvent$1 = utils$2.isErrorEvent;
|
var isErrorEvent$1 = utils.isErrorEvent;
|
||||||
var isUndefined$1 = utils$2.isUndefined;
|
var isUndefined$1 = utils.isUndefined;
|
||||||
var isFunction$1 = utils$2.isFunction;
|
var isFunction$1 = utils.isFunction;
|
||||||
var isString$1 = utils$2.isString;
|
var isString$1 = utils.isString;
|
||||||
var isArray$1 = utils$2.isArray;
|
var isArray$1 = utils.isArray;
|
||||||
var isEmptyObject$1 = utils$2.isEmptyObject;
|
var isEmptyObject$1 = utils.isEmptyObject;
|
||||||
var each$1 = utils$2.each;
|
var each$1 = utils.each;
|
||||||
var objectMerge$1 = utils$2.objectMerge;
|
var objectMerge$1 = utils.objectMerge;
|
||||||
var truncate$1 = utils$2.truncate;
|
var truncate$1 = utils.truncate;
|
||||||
var objectFrozen$1 = utils$2.objectFrozen;
|
var objectFrozen$1 = utils.objectFrozen;
|
||||||
var hasKey$1 = utils$2.hasKey;
|
var hasKey$1 = utils.hasKey;
|
||||||
var joinRegExp$1 = utils$2.joinRegExp;
|
var joinRegExp$1 = utils.joinRegExp;
|
||||||
var urlencode$1 = utils$2.urlencode;
|
var urlencode$1 = utils.urlencode;
|
||||||
var uuid4$1 = utils$2.uuid4;
|
var uuid4$1 = utils.uuid4;
|
||||||
var htmlTreeAsString$1 = utils$2.htmlTreeAsString;
|
var htmlTreeAsString$1 = utils.htmlTreeAsString;
|
||||||
var isSameException$1 = utils$2.isSameException;
|
var isSameException$1 = utils.isSameException;
|
||||||
var isSameStacktrace$1 = utils$2.isSameStacktrace;
|
var isSameStacktrace$1 = utils.isSameStacktrace;
|
||||||
var parseUrl$1 = utils$2.parseUrl;
|
var parseUrl$1 = utils.parseUrl;
|
||||||
var fill$1 = utils$2.fill;
|
var fill$1 = utils.fill;
|
||||||
var supportsFetch$1 = utils$2.supportsFetch;
|
var supportsFetch$1 = utils.supportsFetch;
|
||||||
var supportsReferrerPolicy$1 = utils$2.supportsReferrerPolicy;
|
var supportsReferrerPolicy$1 = utils.supportsReferrerPolicy;
|
||||||
var serializeKeysForMessage$1 = utils$2.serializeKeysForMessage;
|
var serializeKeysForMessage$1 = utils.serializeKeysForMessage;
|
||||||
var serializeException$1 = utils$2.serializeException;
|
var serializeException$1 = utils.serializeException;
|
||||||
var sanitize$1 = utils$2.sanitize;
|
var sanitize$1 = utils.sanitize;
|
||||||
|
|
||||||
var wrapConsoleMethod = require$$0.wrapMethod;
|
var wrapConsoleMethod = console$1.wrapMethod;
|
||||||
|
|
||||||
var dsnKeys = 'source protocol user pass host port path'.split(' '),
|
var dsnKeys = 'source protocol user pass host port path'.split(' '),
|
||||||
dsnPattern = /^(?:(\w+):)?\/\/(?:(\w+)(:\w+)?@)?([\w\.-]+)(?::(\d+))?(\/.*)/;
|
dsnPattern = /^(?:(\w+):)?\/\/(?:(\w+)(:\w+)?@)?([\w\.-]+)(?::(\d+))?(\/.*)/;
|
||||||
@ -1901,7 +1786,7 @@ Raven.prototype = {
|
|||||||
|
|
||||||
debug: false,
|
debug: false,
|
||||||
|
|
||||||
TraceKit: TraceKit$1, // alias to TraceKit
|
TraceKit: tracekit, // alias to TraceKit
|
||||||
|
|
||||||
/*
|
/*
|
||||||
* Configure Raven with a DSN and extra options
|
* Configure Raven with a DSN and extra options
|
||||||
@ -1982,7 +1867,7 @@ Raven.prototype = {
|
|||||||
}
|
}
|
||||||
globalOptions.instrument = instrument;
|
globalOptions.instrument = instrument;
|
||||||
|
|
||||||
TraceKit$1.collectWindowErrors = !!globalOptions.collectWindowErrors;
|
tracekit.collectWindowErrors = !!globalOptions.collectWindowErrors;
|
||||||
|
|
||||||
// return for chaining
|
// return for chaining
|
||||||
return self;
|
return self;
|
||||||
@ -1999,7 +1884,7 @@ Raven.prototype = {
|
|||||||
install: function() {
|
install: function() {
|
||||||
var self = this;
|
var self = this;
|
||||||
if (self.isSetup() && !self._isRavenInstalled) {
|
if (self.isSetup() && !self._isRavenInstalled) {
|
||||||
TraceKit$1.report.subscribe(function() {
|
tracekit.report.subscribe(function() {
|
||||||
self._handleOnErrorStackInfo.apply(self, arguments);
|
self._handleOnErrorStackInfo.apply(self, arguments);
|
||||||
});
|
});
|
||||||
|
|
||||||
@ -2163,7 +2048,7 @@ Raven.prototype = {
|
|||||||
* @return {Raven}
|
* @return {Raven}
|
||||||
*/
|
*/
|
||||||
uninstall: function() {
|
uninstall: function() {
|
||||||
TraceKit$1.report.uninstall();
|
tracekit.report.uninstall();
|
||||||
|
|
||||||
this._detachPromiseRejectionHandler();
|
this._detachPromiseRejectionHandler();
|
||||||
this._unpatchFunctionToString();
|
this._unpatchFunctionToString();
|
||||||
@ -2262,7 +2147,7 @@ Raven.prototype = {
|
|||||||
// raises an exception different from the one we asked to
|
// raises an exception different from the one we asked to
|
||||||
// report on.
|
// report on.
|
||||||
try {
|
try {
|
||||||
var stack = TraceKit$1.computeStackTrace(ex);
|
var stack = tracekit.computeStackTrace(ex);
|
||||||
this._handleStackInfo(stack, options);
|
this._handleStackInfo(stack, options);
|
||||||
} catch (ex1) {
|
} catch (ex1) {
|
||||||
if (ex !== ex1) {
|
if (ex !== ex1) {
|
||||||
@ -2278,7 +2163,7 @@ Raven.prototype = {
|
|||||||
var options = objectMerge$1(currentOptions, {
|
var options = objectMerge$1(currentOptions, {
|
||||||
message:
|
message:
|
||||||
'Non-Error exception captured with keys: ' + serializeKeysForMessage$1(exKeys),
|
'Non-Error exception captured with keys: ' + serializeKeysForMessage$1(exKeys),
|
||||||
fingerprint: [md5$2(exKeys)],
|
fingerprint: [md5_1(exKeys)],
|
||||||
extra: currentOptions.extra || {}
|
extra: currentOptions.extra || {}
|
||||||
});
|
});
|
||||||
options.extra.__serialized__ = serializeException$1(ex);
|
options.extra.__serialized__ = serializeException$1(ex);
|
||||||
@ -2327,7 +2212,7 @@ Raven.prototype = {
|
|||||||
|
|
||||||
// null exception name so `Error` isn't prefixed to msg
|
// null exception name so `Error` isn't prefixed to msg
|
||||||
ex.name = null;
|
ex.name = null;
|
||||||
var stack = TraceKit$1.computeStackTrace(ex);
|
var stack = tracekit.computeStackTrace(ex);
|
||||||
|
|
||||||
// stack[0] is `throw new Error(msg)` call itself, we are interested in the frame that was just before that, stack[1]
|
// stack[0] is `throw new Error(msg)` call itself, we are interested in the frame that was just before that, stack[1]
|
||||||
var initialCall = isArray$1(stack.stack) && stack.stack[1];
|
var initialCall = isArray$1(stack.stack) && stack.stack[1];
|
||||||
@ -2482,7 +2367,7 @@ Raven.prototype = {
|
|||||||
*/
|
*/
|
||||||
getContext: function() {
|
getContext: function() {
|
||||||
// lol javascript
|
// lol javascript
|
||||||
return JSON.parse(stringify$1(this._globalContext));
|
return JSON.parse(stringify_1(this._globalContext));
|
||||||
},
|
},
|
||||||
|
|
||||||
/*
|
/*
|
||||||
@ -2618,12 +2503,12 @@ Raven.prototype = {
|
|||||||
|
|
||||||
var lastEventId = options.eventId || this.lastEventId();
|
var lastEventId = options.eventId || this.lastEventId();
|
||||||
if (!lastEventId) {
|
if (!lastEventId) {
|
||||||
throw new RavenConfigError$1('Missing eventId');
|
throw new configError('Missing eventId');
|
||||||
}
|
}
|
||||||
|
|
||||||
var dsn = options.dsn || this._dsn;
|
var dsn = options.dsn || this._dsn;
|
||||||
if (!dsn) {
|
if (!dsn) {
|
||||||
throw new RavenConfigError$1('Missing DSN');
|
throw new configError('Missing DSN');
|
||||||
}
|
}
|
||||||
|
|
||||||
var encode = encodeURIComponent;
|
var encode = encodeURIComponent;
|
||||||
@ -3278,11 +3163,11 @@ Raven.prototype = {
|
|||||||
try {
|
try {
|
||||||
while (i--) dsn[dsnKeys[i]] = m[i] || '';
|
while (i--) dsn[dsnKeys[i]] = m[i] || '';
|
||||||
} catch (e) {
|
} catch (e) {
|
||||||
throw new RavenConfigError$1('Invalid DSN: ' + str);
|
throw new configError('Invalid DSN: ' + str);
|
||||||
}
|
}
|
||||||
|
|
||||||
if (dsn.pass && !this._globalOptions.allowSecretKey) {
|
if (dsn.pass && !this._globalOptions.allowSecretKey) {
|
||||||
throw new RavenConfigError$1(
|
throw new configError(
|
||||||
'Do not specify your secret key in the DSN. See: http://bit.ly/raven-secret-key'
|
'Do not specify your secret key in the DSN. See: http://bit.ly/raven-secret-key'
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
@ -3803,7 +3688,7 @@ Raven.prototype = {
|
|||||||
}
|
}
|
||||||
|
|
||||||
if (supportsFetch$1()) {
|
if (supportsFetch$1()) {
|
||||||
evaluatedFetchParameters.body = stringify$1(opts.data);
|
evaluatedFetchParameters.body = stringify_1(opts.data);
|
||||||
|
|
||||||
var defaultFetchOptions = objectMerge$1({}, this._fetchDefaults);
|
var defaultFetchOptions = objectMerge$1({}, this._fetchDefaults);
|
||||||
var fetchOptions = objectMerge$1(defaultFetchOptions, evaluatedFetchParameters);
|
var fetchOptions = objectMerge$1(defaultFetchOptions, evaluatedFetchParameters);
|
||||||
@ -3878,7 +3763,7 @@ Raven.prototype = {
|
|||||||
});
|
});
|
||||||
}
|
}
|
||||||
|
|
||||||
request.send(stringify$1(opts.data));
|
request.send(stringify_1(opts.data));
|
||||||
},
|
},
|
||||||
|
|
||||||
_evaluateHash: function(hash) {
|
_evaluateHash: function(hash) {
|
||||||
@ -3924,14 +3809,6 @@ Raven.prototype.setReleaseContext = Raven.prototype.setRelease;
|
|||||||
|
|
||||||
var raven = Raven;
|
var raven = Raven;
|
||||||
|
|
||||||
|
|
||||||
var raven$1 = Object.freeze({
|
|
||||||
default: raven,
|
|
||||||
__moduleExports: raven
|
|
||||||
});
|
|
||||||
|
|
||||||
var RavenConstructor = ( raven$1 && raven ) || raven$1;
|
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Enforces a single instance of the Raven client, and the
|
* Enforces a single instance of the Raven client, and the
|
||||||
* main entry point for Raven. If you are a consumer of the
|
* main entry point for Raven. If you are a consumer of the
|
||||||
@ -3947,7 +3824,7 @@ var _window$3 =
|
|||||||
: typeof commonjsGlobal !== 'undefined' ? commonjsGlobal : typeof self !== 'undefined' ? self : {};
|
: typeof commonjsGlobal !== 'undefined' ? commonjsGlobal : typeof self !== 'undefined' ? self : {};
|
||||||
var _Raven = _window$3.Raven;
|
var _Raven = _window$3.Raven;
|
||||||
|
|
||||||
var Raven$1 = new RavenConstructor();
|
var Raven$1 = new raven();
|
||||||
|
|
||||||
/*
|
/*
|
||||||
* Allow multiple versions of Raven to be installed.
|
* Allow multiple versions of Raven to be installed.
|
||||||
@ -3998,7 +3875,7 @@ var singleton = Raven$1;
|
|||||||
*
|
*
|
||||||
* It should "just work".
|
* It should "just work".
|
||||||
*/
|
*/
|
||||||
var Client = RavenConstructor;
|
var Client = raven;
|
||||||
singleton.Client = Client;
|
singleton.Client = Client;
|
||||||
|
|
||||||
// ==========================================================================
|
// ==========================================================================
|
||||||
|
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
@ -171,7 +171,7 @@
|
|||||||
</aside>
|
</aside>
|
||||||
|
|
||||||
<!-- Polyfills -->
|
<!-- Polyfills -->
|
||||||
<script src="https://cdn.polyfill.io/v2/polyfill.min.js?features=es6,Array.prototype.includes,CustomEvent,Object.entries,Object.values"
|
<script src="https://cdn.polyfill.io/v2/polyfill.min.js?features=es6,Array.prototype.includes,CustomEvent,Object.entries,Object.values,URL"
|
||||||
crossorigin="anonymous"></script>
|
crossorigin="anonymous"></script>
|
||||||
|
|
||||||
<!-- Plyr core script -->
|
<!-- Plyr core script -->
|
||||||
|
@ -29,6 +29,7 @@ video {
|
|||||||
position: absolute;
|
position: absolute;
|
||||||
right: 0;
|
right: 0;
|
||||||
top: 0;
|
top: 0;
|
||||||
|
z-index: 3;
|
||||||
}
|
}
|
||||||
|
|
||||||
// Style full supported player
|
// Style full supported player
|
||||||
|
2
dist/plyr.css
vendored
2
dist/plyr.css
vendored
File diff suppressed because one or more lines are too long
4292
dist/plyr.js
vendored
4292
dist/plyr.js
vendored
File diff suppressed because it is too large
Load Diff
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
6708
dist/plyr.polyfilled.js
vendored
6708
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
13
gulpfile.js
13
gulpfile.js
@ -129,7 +129,7 @@ const build = {
|
|||||||
tasks.js.push(name);
|
tasks.js.push(name);
|
||||||
const { output } = paths[bundle];
|
const { output } = paths[bundle];
|
||||||
|
|
||||||
gulp.task(name, () =>
|
return gulp.task(name, () =>
|
||||||
gulp
|
gulp
|
||||||
.src(bundles[bundle].js[key])
|
.src(bundles[bundle].js[key])
|
||||||
.pipe(sourcemaps.init())
|
.pipe(sourcemaps.init())
|
||||||
@ -162,7 +162,7 @@ const build = {
|
|||||||
const name = `sass:${key}`;
|
const name = `sass:${key}`;
|
||||||
tasks.sass.push(name);
|
tasks.sass.push(name);
|
||||||
|
|
||||||
gulp.task(name, () =>
|
return gulp.task(name, () =>
|
||||||
gulp
|
gulp
|
||||||
.src(bundles[bundle].sass[key])
|
.src(bundles[bundle].sass[key])
|
||||||
.pipe(sass())
|
.pipe(sass())
|
||||||
@ -180,7 +180,7 @@ const build = {
|
|||||||
tasks.sprite.push(name);
|
tasks.sprite.push(name);
|
||||||
|
|
||||||
// Process Icons
|
// Process Icons
|
||||||
gulp.task(name, () =>
|
return gulp.task(name, () =>
|
||||||
gulp
|
gulp
|
||||||
.src(paths[bundle].src.sprite)
|
.src(paths[bundle].src.sprite)
|
||||||
.pipe(
|
.pipe(
|
||||||
@ -287,7 +287,8 @@ if (Object.keys(aws).includes('cdn') && Object.keys(aws).includes('demo')) {
|
|||||||
'plyr.polyfilled.js',
|
'plyr.polyfilled.js',
|
||||||
'defaults.js',
|
'defaults.js',
|
||||||
];
|
];
|
||||||
gulp
|
|
||||||
|
return gulp
|
||||||
.src(files.map(file => path.join(root, `src/js/${file}`)))
|
.src(files.map(file => path.join(root, `src/js/${file}`)))
|
||||||
.pipe(replace(semver, `v${version}`))
|
.pipe(replace(semver, `v${version}`))
|
||||||
.pipe(replace(cdnpath, `${aws.cdn.domain}/${version}/`))
|
.pipe(replace(cdnpath, `${aws.cdn.domain}/${version}/`))
|
||||||
@ -406,7 +407,7 @@ if (Object.keys(aws).includes('cdn') && Object.keys(aws).includes('demo')) {
|
|||||||
});
|
});
|
||||||
|
|
||||||
// Do everything
|
// Do everything
|
||||||
gulp.task('publish', () => {
|
gulp.task('publish', callback => {
|
||||||
run('version', tasks.clean, tasks.js, tasks.sass, tasks.sprite, 'cdn', 'demo');
|
run('version', tasks.clean, tasks.js, tasks.sass, tasks.sprite, 'cdn', 'demo', callback);
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
|
@ -1,6 +1,6 @@
|
|||||||
{
|
{
|
||||||
"name": "plyr",
|
"name": "plyr",
|
||||||
"version": "3.2.4",
|
"version": "3.3.0",
|
||||||
"description": "A simple, accessible and customizable HTML5, YouTube and Vimeo media player",
|
"description": "A simple, accessible and customizable HTML5, YouTube and Vimeo media player",
|
||||||
"homepage": "https://plyr.io",
|
"homepage": "https://plyr.io",
|
||||||
"main": "./dist/plyr.js",
|
"main": "./dist/plyr.js",
|
||||||
|
38
readme.md
38
readme.md
@ -128,7 +128,7 @@ See [initialising](#initialising) for more information on advanced setups.
|
|||||||
If you want to use our CDN (provided by [Fastly](https://www.fastly.com/)) for the JavaScript, you can use the following:
|
If you want to use our CDN (provided by [Fastly](https://www.fastly.com/)) for the JavaScript, you can use the following:
|
||||||
|
|
||||||
```html
|
```html
|
||||||
<script src="https://cdn.plyr.io/3.2.4/plyr.js"></script>
|
<script src="https://cdn.plyr.io/3.3.0/plyr.js"></script>
|
||||||
```
|
```
|
||||||
|
|
||||||
_Note_: Be sure to read the [polyfills](#polyfills) section below about browser compatibility
|
_Note_: Be sure to read the [polyfills](#polyfills) section below about browser compatibility
|
||||||
@ -144,13 +144,13 @@ Include the `plyr.css` stylsheet into your `<head>`
|
|||||||
If you want to use our CDN (provided by [Fastly](https://www.fastly.com/)) for the default CSS, you can use the following:
|
If you want to use our CDN (provided by [Fastly](https://www.fastly.com/)) for the default CSS, you can use the following:
|
||||||
|
|
||||||
```html
|
```html
|
||||||
<link rel="stylesheet" href="https://cdn.plyr.io/3.2.4/plyr.css">
|
<link rel="stylesheet" href="https://cdn.plyr.io/3.3.0/plyr.css">
|
||||||
```
|
```
|
||||||
|
|
||||||
### SVG Sprite
|
### SVG Sprite
|
||||||
|
|
||||||
The SVG sprite is loaded automatically from our CDN (provided by [Fastly](https://www.fastly.com/)). To change this, see the [options](#options) below. For
|
The SVG sprite is loaded automatically from our CDN (provided by [Fastly](https://www.fastly.com/)). To change this, see the [options](#options) below. For
|
||||||
reference, the CDN hosted SVG sprite can be found at `https://cdn.plyr.io/3.2.4/plyr.svg`.
|
reference, the CDN hosted SVG sprite can be found at `https://cdn.plyr.io/3.3.0/plyr.svg`.
|
||||||
|
|
||||||
## Ads
|
## Ads
|
||||||
|
|
||||||
@ -279,7 +279,7 @@ Note the single quotes encapsulating the JSON and double quotes on the object ke
|
|||||||
| `clickToPlay` | Boolean | `true` | Click (or tap) of the video container will toggle play/pause. |
|
| `clickToPlay` | Boolean | `true` | Click (or tap) of the video container will toggle play/pause. |
|
||||||
| `disableContextMenu` | Boolean | `true` | Disable right click menu on video to <em>help</em> as very primitive obfuscation to prevent downloads of content. |
|
| `disableContextMenu` | Boolean | `true` | Disable right click menu on video to <em>help</em> as very primitive obfuscation to prevent downloads of content. |
|
||||||
| `hideControls` | Boolean | `true` | Hide video controls automatically after 2s of no mouse or focus movement, on control element blur (tab out), on playback start or entering fullscreen. As soon as the mouse is moved, a control element is focused or playback is paused, the controls reappear instantly. |
|
| `hideControls` | Boolean | `true` | Hide video controls automatically after 2s of no mouse or focus movement, on control element blur (tab out), on playback start or entering fullscreen. As soon as the mouse is moved, a control element is focused or playback is paused, the controls reappear instantly. |
|
||||||
| `showPosterOnEnd` | Boolean | false | This will restore and _reload_ HTML5 video once playback is complete. Note: depending on the browser caching, this may result in the video downloading again (or parts of it). Use with caution. |
|
| `resetOnEnd` | Boolean | false | Reset the playback to the start once playback is complete. |
|
||||||
| `keyboard` | Object | `{ focused: true, global: false }` | Enable [keyboard shortcuts](#shortcuts) for focused players only or globally |
|
| `keyboard` | Object | `{ focused: true, global: false }` | Enable [keyboard shortcuts](#shortcuts) for focused players only or globally |
|
||||||
| `tooltips` | Object | `{ controls: false, seek: true }` | `controls`: Display control labels as tooltips on `:hover` & `:focus` (by default, the labels are screen reader only). `seek`: Display a seek tooltip to indicate on click where the media would seek to. |
|
| `tooltips` | Object | `{ controls: false, seek: true }` | `controls`: Display control labels as tooltips on `:hover` & `:focus` (by default, the labels are screen reader only). `seek`: Display a seek tooltip to indicate on click where the media would seek to. |
|
||||||
| `duration` | Number | `null` | Specify a custom duration for media. |
|
| `duration` | Number | `null` | Specify a custom duration for media. |
|
||||||
@ -374,8 +374,9 @@ player.fullscreen.active; // false;
|
|||||||
| -------------------- | ------ | ------ | ------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------ |
|
| -------------------- | ------ | ------ | ------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------ |
|
||||||
| `isHTML5` | ✓ | - | Returns a boolean indicating if the current player is HTML5. |
|
| `isHTML5` | ✓ | - | Returns a boolean indicating if the current player is HTML5. |
|
||||||
| `isEmbed` | ✓ | - | Returns a boolean indicating if the current player is an embedded player. |
|
| `isEmbed` | ✓ | - | Returns a boolean indicating if the current player is an embedded player. |
|
||||||
| `paused` | ✓ | - | Returns a boolean indicating if the current player is paused. |
|
|
||||||
| `playing` | ✓ | - | Returns a boolean indicating if the current player is playing. |
|
| `playing` | ✓ | - | Returns a boolean indicating if the current player is playing. |
|
||||||
|
| `paused` | ✓ | - | Returns a boolean indicating if the current player is paused. |
|
||||||
|
| `stopped` | ✓ | - | Returns a boolean indicating if the current player is stopped. |
|
||||||
| `ended` | ✓ | - | Returns a boolean indicating if the current player has finished playback. |
|
| `ended` | ✓ | - | Returns a boolean indicating if the current player has finished playback. |
|
||||||
| `buffered` | ✓ | - | Returns a float between 0 and 1 indicating how much of the media is buffered |
|
| `buffered` | ✓ | - | Returns a float between 0 and 1 indicating how much of the media is buffered |
|
||||||
| `currentTime` | ✓ | ✓ | Gets or sets the currentTime for the player. The setter accepts a float in seconds. |
|
| `currentTime` | ✓ | ✓ | Gets or sets the currentTime for the player. The setter accepts a float in seconds. |
|
||||||
@ -388,7 +389,7 @@ player.fullscreen.active; // false;
|
|||||||
| `quality`¹ | ✓ | ✓ | Gets or sets the quality for the player. The setter accepts a value from the options specified in your config. |
|
| `quality`¹ | ✓ | ✓ | Gets or sets the quality for the player. The setter accepts a value from the options specified in your config. |
|
||||||
| `loop` | ✓ | ✓ | Gets or sets the current loop state of the player. The setter accepts a boolean. |
|
| `loop` | ✓ | ✓ | Gets or sets the current loop state of the player. The setter accepts a boolean. |
|
||||||
| `source` | ✓ | ✓ | Gets or sets the current source for the player. The setter accepts an object. See [source setter](#source-setter) below for examples. |
|
| `source` | ✓ | ✓ | Gets or sets the current source for the player. The setter accepts an object. See [source setter](#source-setter) below for examples. |
|
||||||
| `poster`² | ✓ | ✓ | Gets or sets the current poster image for the player. The setter accepts a string; the URL for the updated poster image. |
|
| `poster` | ✓ | ✓ | Gets or sets the current poster image for the player. The setter accepts a string; the URL for the updated poster image. |
|
||||||
| `autoplay` | ✓ | ✓ | Gets or sets the autoplay state of the player. The setter accepts a boolean. |
|
| `autoplay` | ✓ | ✓ | Gets or sets the autoplay state of the player. The setter accepts a boolean. |
|
||||||
| `language` | ✓ | ✓ | Gets or sets the preferred captions language for the player. The setter accepts an ISO two-letter language code. Support for the languages is dependent on the captions you include. |
|
| `language` | ✓ | ✓ | Gets or sets the preferred captions language for the player. The setter accepts an ISO two-letter language code. Support for the languages is dependent on the captions you include. |
|
||||||
| `fullscreen.active` | ✓ | - | Returns a boolean indicating if the current player is in fullscreen mode. |
|
| `fullscreen.active` | ✓ | - | Returns a boolean indicating if the current player is in fullscreen mode. |
|
||||||
@ -599,6 +600,8 @@ Russitto ([@russitto](https://github.com/russitto)) for working on this. Here's
|
|||||||
* Using [Shaka](https://github.com/google/shaka-player) - [Demo](http://codepen.io/sampotts/pen/zBNpVR)
|
* Using [Shaka](https://github.com/google/shaka-player) - [Demo](http://codepen.io/sampotts/pen/zBNpVR)
|
||||||
* Using [dash.js](https://github.com/Dash-Industry-Forum/dash.js) - [Demo](http://codepen.io/sampotts/pen/BzpJXN)
|
* Using [dash.js](https://github.com/Dash-Industry-Forum/dash.js) - [Demo](http://codepen.io/sampotts/pen/BzpJXN)
|
||||||
|
|
||||||
|
_Note_: These need updating to use the new v3 syntax but would still work.
|
||||||
|
|
||||||
## Fullscreen
|
## Fullscreen
|
||||||
|
|
||||||
Fullscreen in Plyr is supported by all browsers that [currently support it](http://caniuse.com/#feat=fullscreen).
|
Fullscreen in Plyr is supported by all browsers that [currently support it](http://caniuse.com/#feat=fullscreen).
|
||||||
@ -607,19 +610,20 @@ Fullscreen in Plyr is supported by all browsers that [currently support it](http
|
|||||||
|
|
||||||
Plyr supports the last 2 versions of most _modern_ browsers.
|
Plyr supports the last 2 versions of most _modern_ browsers.
|
||||||
|
|
||||||
| Browser | Supported |
|
| Browser | Supported |
|
||||||
| ------------- | --------- |
|
| ------------- | ------------- |
|
||||||
| Safari | ✓ |
|
| Safari | ✓ |
|
||||||
| Mobile Safari | ✓¹ |
|
| Mobile Safari | ✓¹ |
|
||||||
| Firefox | ✓ |
|
| Firefox | ✓ |
|
||||||
| Chrome | ✓ |
|
| Chrome | ✓ |
|
||||||
| Opera | ✓ |
|
| Opera | ✓ |
|
||||||
| Edge | ✓ |
|
| Edge | ✓ |
|
||||||
| IE11 | ✓ |
|
| IE11 | ✓³ |
|
||||||
| IE10 | ✓² |
|
| IE10 | ✓²³ |
|
||||||
|
|
||||||
1. Mobile Safari on the iPhone forces the native player for `<video>` unless the `playsinline` attribute is present. Volume controls are also disabled as they are handled device wide.
|
1. Mobile Safari on the iPhone forces the native player for `<video>` unless the `playsinline` attribute is present. Volume controls are also disabled as they are handled device wide.
|
||||||
2. Native player used (no support for `<progress>` or `<input type="range">`) but the API is supported. No native fullscreen support, fallback can be used (see [options](#options))
|
2. Native player used (no support for `<progress>` or `<input type="range">`) but the API is supported. No native fullscreen support, fallback can be used (see [options](#options)).
|
||||||
|
3. Polyfills required. See below.
|
||||||
|
|
||||||
### Polyfills
|
### Polyfills
|
||||||
|
|
||||||
|
@ -3,10 +3,10 @@
|
|||||||
// TODO: Create as class
|
// TODO: Create as class
|
||||||
// ==========================================================================
|
// ==========================================================================
|
||||||
|
|
||||||
import support from './support';
|
|
||||||
import utils from './utils';
|
|
||||||
import controls from './controls';
|
import controls from './controls';
|
||||||
import i18n from './i18n';
|
import i18n from './i18n';
|
||||||
|
import support from './support';
|
||||||
|
import utils from './utils';
|
||||||
|
|
||||||
const captions = {
|
const captions = {
|
||||||
// Setup captions
|
// Setup captions
|
||||||
|
87
src/js/controls.js
vendored
87
src/js/controls.js
vendored
@ -2,12 +2,12 @@
|
|||||||
// Plyr controls
|
// Plyr controls
|
||||||
// ==========================================================================
|
// ==========================================================================
|
||||||
|
|
||||||
import support from './support';
|
|
||||||
import utils from './utils';
|
|
||||||
import ui from './ui';
|
|
||||||
import i18n from './i18n';
|
|
||||||
import captions from './captions';
|
import captions from './captions';
|
||||||
import html5 from './html5';
|
import html5 from './html5';
|
||||||
|
import i18n from './i18n';
|
||||||
|
import support from './support';
|
||||||
|
import ui from './ui';
|
||||||
|
import utils from './utils';
|
||||||
|
|
||||||
// Sniff out the browser
|
// Sniff out the browser
|
||||||
const browser = utils.getBrowser();
|
const browser = utils.getBrowser();
|
||||||
@ -37,17 +37,74 @@ const controls = {
|
|||||||
|
|
||||||
// Get icon URL
|
// Get icon URL
|
||||||
getIconUrl() {
|
getIconUrl() {
|
||||||
|
const url = new URL(this.config.iconUrl, window.location);
|
||||||
|
const cors = url.host !== window.location.host || (browser.isIE && !window.svg4everybody);
|
||||||
|
|
||||||
return {
|
return {
|
||||||
url: this.config.iconUrl,
|
url: this.config.iconUrl,
|
||||||
absolute: this.config.iconUrl.indexOf('http') === 0 || (browser.isIE && !window.svg4everybody),
|
cors,
|
||||||
};
|
};
|
||||||
},
|
},
|
||||||
|
|
||||||
|
// Find the UI controls and store references in custom controls
|
||||||
|
// TODO: Allow settings menus with custom controls
|
||||||
|
findElements() {
|
||||||
|
try {
|
||||||
|
this.elements.controls = utils.getElement.call(this, this.config.selectors.controls.wrapper);
|
||||||
|
|
||||||
|
// Buttons
|
||||||
|
this.elements.buttons = {
|
||||||
|
play: utils.getElements.call(this, this.config.selectors.buttons.play),
|
||||||
|
pause: utils.getElement.call(this, this.config.selectors.buttons.pause),
|
||||||
|
restart: utils.getElement.call(this, this.config.selectors.buttons.restart),
|
||||||
|
rewind: utils.getElement.call(this, this.config.selectors.buttons.rewind),
|
||||||
|
fastForward: utils.getElement.call(this, this.config.selectors.buttons.fastForward),
|
||||||
|
mute: utils.getElement.call(this, this.config.selectors.buttons.mute),
|
||||||
|
pip: utils.getElement.call(this, this.config.selectors.buttons.pip),
|
||||||
|
airplay: utils.getElement.call(this, this.config.selectors.buttons.airplay),
|
||||||
|
settings: utils.getElement.call(this, this.config.selectors.buttons.settings),
|
||||||
|
captions: utils.getElement.call(this, this.config.selectors.buttons.captions),
|
||||||
|
fullscreen: utils.getElement.call(this, this.config.selectors.buttons.fullscreen),
|
||||||
|
};
|
||||||
|
|
||||||
|
// Progress
|
||||||
|
this.elements.progress = utils.getElement.call(this, this.config.selectors.progress);
|
||||||
|
|
||||||
|
// Inputs
|
||||||
|
this.elements.inputs = {
|
||||||
|
seek: utils.getElement.call(this, this.config.selectors.inputs.seek),
|
||||||
|
volume: utils.getElement.call(this, this.config.selectors.inputs.volume),
|
||||||
|
};
|
||||||
|
|
||||||
|
// Display
|
||||||
|
this.elements.display = {
|
||||||
|
buffer: utils.getElement.call(this, this.config.selectors.display.buffer),
|
||||||
|
currentTime: utils.getElement.call(this, this.config.selectors.display.currentTime),
|
||||||
|
duration: utils.getElement.call(this, this.config.selectors.display.duration),
|
||||||
|
};
|
||||||
|
|
||||||
|
// Seek tooltip
|
||||||
|
if (utils.is.element(this.elements.progress)) {
|
||||||
|
this.elements.display.seekTooltip = this.elements.progress.querySelector(`.${this.config.classNames.tooltip}`);
|
||||||
|
}
|
||||||
|
|
||||||
|
return true;
|
||||||
|
} catch (error) {
|
||||||
|
// Log it
|
||||||
|
this.debug.warn('It looks like there is a problem with your custom controls HTML', error);
|
||||||
|
|
||||||
|
// Restore native video controls
|
||||||
|
this.toggleNativeControls(true);
|
||||||
|
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
},
|
||||||
|
|
||||||
// Create <svg> icon
|
// Create <svg> icon
|
||||||
createIcon(type, attributes) {
|
createIcon(type, attributes) {
|
||||||
const namespace = 'http://www.w3.org/2000/svg';
|
const namespace = 'http://www.w3.org/2000/svg';
|
||||||
const iconUrl = controls.getIconUrl.call(this);
|
const iconUrl = controls.getIconUrl.call(this);
|
||||||
const iconPath = `${!iconUrl.absolute ? iconUrl.url : ''}#${this.config.iconPrefix}`;
|
const iconPath = `${!iconUrl.cors ? iconUrl.url : ''}#${this.config.iconPrefix}`;
|
||||||
|
|
||||||
// Create <svg>
|
// Create <svg>
|
||||||
const icon = document.createElementNS(namespace, 'svg');
|
const icon = document.createElementNS(namespace, 'svg');
|
||||||
@ -840,11 +897,9 @@ const controls = {
|
|||||||
},
|
},
|
||||||
|
|
||||||
// Toggle Menu
|
// Toggle Menu
|
||||||
showTab(event) {
|
showTab(target = '') {
|
||||||
const { menu } = this.elements.settings;
|
const { menu } = this.elements.settings;
|
||||||
const tab = event.target;
|
const pane = document.getElementById(target);
|
||||||
const show = tab.getAttribute('aria-expanded') === 'false';
|
|
||||||
const pane = document.getElementById(tab.getAttribute('aria-controls'));
|
|
||||||
|
|
||||||
// Nothing to show, bail
|
// Nothing to show, bail
|
||||||
if (!utils.is.element(pane)) {
|
if (!utils.is.element(pane)) {
|
||||||
@ -907,8 +962,12 @@ const controls = {
|
|||||||
current.setAttribute('tabindex', -1);
|
current.setAttribute('tabindex', -1);
|
||||||
|
|
||||||
// Set attributes on target
|
// Set attributes on target
|
||||||
utils.toggleHidden(pane, !show);
|
utils.toggleHidden(pane, false);
|
||||||
tab.setAttribute('aria-expanded', show);
|
|
||||||
|
const tabs = utils.getElements.call(this, `[aria-controls="${target}"]`);
|
||||||
|
Array.from(tabs).forEach(tab => {
|
||||||
|
tab.setAttribute('aria-expanded', true);
|
||||||
|
});
|
||||||
pane.removeAttribute('tabindex');
|
pane.removeAttribute('tabindex');
|
||||||
|
|
||||||
// Focus the first item
|
// Focus the first item
|
||||||
@ -1183,7 +1242,7 @@ const controls = {
|
|||||||
const icon = controls.getIconUrl.call(this);
|
const icon = controls.getIconUrl.call(this);
|
||||||
|
|
||||||
// Only load external sprite using AJAX
|
// Only load external sprite using AJAX
|
||||||
if (icon.absolute) {
|
if (icon.cors) {
|
||||||
utils.loadSprite(icon.url, 'sprite-plyr');
|
utils.loadSprite(icon.url, 'sprite-plyr');
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@ -1269,7 +1328,7 @@ const controls = {
|
|||||||
|
|
||||||
// Find the elements if need be
|
// Find the elements if need be
|
||||||
if (!utils.is.element(this.elements.controls)) {
|
if (!utils.is.element(this.elements.controls)) {
|
||||||
utils.findElements.call(this);
|
controls.findElements.call(this);
|
||||||
}
|
}
|
||||||
|
|
||||||
// Edge sometimes doesn't finish the paint so force a redraw
|
// Edge sometimes doesn't finish the paint so force a redraw
|
||||||
|
@ -47,8 +47,8 @@ const defaults = {
|
|||||||
// Auto hide the controls
|
// Auto hide the controls
|
||||||
hideControls: true,
|
hideControls: true,
|
||||||
|
|
||||||
// Revert to poster on finish (HTML5 - will cause reload)
|
// Reset to start when playback ended
|
||||||
showPosterOnEnd: false,
|
resetOnEnd: false,
|
||||||
|
|
||||||
// Disable the standard context menu
|
// Disable the standard context menu
|
||||||
disableContextMenu: true,
|
disableContextMenu: true,
|
||||||
@ -56,7 +56,7 @@ const defaults = {
|
|||||||
// Sprite (for icons)
|
// Sprite (for icons)
|
||||||
loadSprite: true,
|
loadSprite: true,
|
||||||
iconPrefix: 'plyr',
|
iconPrefix: 'plyr',
|
||||||
iconUrl: 'https://cdn.plyr.io/3.2.4/plyr.svg',
|
iconUrl: 'https://cdn.plyr.io/3.3.0/plyr.svg',
|
||||||
|
|
||||||
// Blank video (used to prevent errors on source change)
|
// Blank video (used to prevent errors on source change)
|
||||||
blankVideo: 'https://cdn.plyr.io/static/blank.mp4',
|
blankVideo: 'https://cdn.plyr.io/static/blank.mp4',
|
||||||
@ -192,13 +192,17 @@ const defaults = {
|
|||||||
// URLs
|
// URLs
|
||||||
urls: {
|
urls: {
|
||||||
vimeo: {
|
vimeo: {
|
||||||
api: 'https://player.vimeo.com/api/player.js',
|
sdk: 'https://player.vimeo.com/api/player.js',
|
||||||
|
iframe: 'https://player.vimeo.com/video/{0}?{1}',
|
||||||
|
api: 'https://vimeo.com/api/v2/video/{0}.json',
|
||||||
},
|
},
|
||||||
youtube: {
|
youtube: {
|
||||||
api: 'https://www.youtube.com/iframe_api',
|
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',
|
||||||
},
|
},
|
||||||
googleIMA: {
|
googleIMA: {
|
||||||
api: 'https://imasdk.googleapis.com/js/sdkloader/ima3.js',
|
sdk: 'https://imasdk.googleapis.com/js/sdkloader/ima3.js',
|
||||||
},
|
},
|
||||||
},
|
},
|
||||||
|
|
||||||
@ -324,12 +328,14 @@ const defaults = {
|
|||||||
classNames: {
|
classNames: {
|
||||||
video: 'plyr__video-wrapper',
|
video: 'plyr__video-wrapper',
|
||||||
embed: 'plyr__video-embed',
|
embed: 'plyr__video-embed',
|
||||||
|
poster: 'plyr__poster',
|
||||||
ads: 'plyr__ads',
|
ads: 'plyr__ads',
|
||||||
control: 'plyr__control',
|
control: 'plyr__control',
|
||||||
type: 'plyr--{0}',
|
type: 'plyr--{0}',
|
||||||
provider: 'plyr--{0}',
|
provider: 'plyr--{0}',
|
||||||
stopped: 'plyr--stopped',
|
|
||||||
playing: 'plyr--playing',
|
playing: 'plyr--playing',
|
||||||
|
paused: 'plyr--paused',
|
||||||
|
stopped: 'plyr--stopped',
|
||||||
loading: 'plyr--loading',
|
loading: 'plyr--loading',
|
||||||
error: 'plyr--has-error',
|
error: 'plyr--has-error',
|
||||||
hover: 'plyr--hover',
|
hover: 'plyr--hover',
|
||||||
|
@ -2,9 +2,9 @@
|
|||||||
// Plyr Event Listeners
|
// Plyr Event Listeners
|
||||||
// ==========================================================================
|
// ==========================================================================
|
||||||
|
|
||||||
import utils from './utils';
|
|
||||||
import controls from './controls';
|
import controls from './controls';
|
||||||
import ui from './ui';
|
import ui from './ui';
|
||||||
|
import utils from './utils';
|
||||||
|
|
||||||
// Sniff out the browser
|
// Sniff out the browser
|
||||||
const browser = utils.getBrowser();
|
const browser = utils.getBrowser();
|
||||||
@ -265,12 +265,9 @@ class Listeners {
|
|||||||
// Handle the media finishing
|
// Handle the media finishing
|
||||||
utils.on(this.player.media, 'ended', () => {
|
utils.on(this.player.media, 'ended', () => {
|
||||||
// Show poster on end
|
// Show poster on end
|
||||||
if (this.player.isHTML5 && this.player.isVideo && this.player.config.showPosterOnEnd) {
|
if (this.player.isHTML5 && this.player.isVideo && this.player.config.resetOnEnd) {
|
||||||
// Restart
|
// Restart
|
||||||
this.player.restart();
|
this.player.restart();
|
||||||
|
|
||||||
// Re-load media
|
|
||||||
this.player.media.load();
|
|
||||||
}
|
}
|
||||||
});
|
});
|
||||||
|
|
||||||
@ -281,7 +278,7 @@ class Listeners {
|
|||||||
utils.on(this.player.media, 'volumechange', event => ui.updateVolume.call(this.player, event));
|
utils.on(this.player.media, 'volumechange', event => ui.updateVolume.call(this.player, event));
|
||||||
|
|
||||||
// Handle play/pause
|
// Handle play/pause
|
||||||
utils.on(this.player.media, 'playing play pause ended emptied', event => ui.checkPlaying.call(this.player, event));
|
utils.on(this.player.media, 'playing play pause ended emptied timeupdate', event => ui.checkPlaying.call(this.player, event));
|
||||||
|
|
||||||
// Loading state
|
// Loading state
|
||||||
utils.on(this.player.media, 'waiting canplay seeked playing', event => ui.checkLoading.call(this.player, event));
|
utils.on(this.player.media, 'waiting canplay seeked playing', event => ui.checkLoading.call(this.player, event));
|
||||||
@ -492,12 +489,19 @@ class Listeners {
|
|||||||
on(this.player.elements.settings.form, 'click', event => {
|
on(this.player.elements.settings.form, 'click', event => {
|
||||||
event.stopPropagation();
|
event.stopPropagation();
|
||||||
|
|
||||||
|
// Go back to home tab on click
|
||||||
|
const showHomeTab = () => {
|
||||||
|
const id = `plyr-settings-${this.player.id}-home`;
|
||||||
|
controls.showTab.call(this.player, id);
|
||||||
|
};
|
||||||
|
|
||||||
// Settings menu items - use event delegation as items are added/removed
|
// Settings menu items - use event delegation as items are added/removed
|
||||||
if (utils.matches(event.target, this.player.config.selectors.inputs.language)) {
|
if (utils.matches(event.target, this.player.config.selectors.inputs.language)) {
|
||||||
proxy(
|
proxy(
|
||||||
event,
|
event,
|
||||||
() => {
|
() => {
|
||||||
this.player.language = event.target.value;
|
this.player.language = event.target.value;
|
||||||
|
showHomeTab();
|
||||||
},
|
},
|
||||||
'language',
|
'language',
|
||||||
);
|
);
|
||||||
@ -506,6 +510,7 @@ class Listeners {
|
|||||||
event,
|
event,
|
||||||
() => {
|
() => {
|
||||||
this.player.quality = event.target.value;
|
this.player.quality = event.target.value;
|
||||||
|
showHomeTab();
|
||||||
},
|
},
|
||||||
'quality',
|
'quality',
|
||||||
);
|
);
|
||||||
@ -514,11 +519,13 @@ class Listeners {
|
|||||||
event,
|
event,
|
||||||
() => {
|
() => {
|
||||||
this.player.speed = parseFloat(event.target.value);
|
this.player.speed = parseFloat(event.target.value);
|
||||||
|
showHomeTab();
|
||||||
},
|
},
|
||||||
'speed',
|
'speed',
|
||||||
);
|
);
|
||||||
} else {
|
} else {
|
||||||
controls.showTab.call(this.player, event);
|
const tab = event.target;
|
||||||
|
controls.showTab.call(this.player, tab.getAttribute('aria-controls'));
|
||||||
}
|
}
|
||||||
});
|
});
|
||||||
|
|
||||||
|
@ -2,15 +2,10 @@
|
|||||||
// Plyr Media
|
// Plyr Media
|
||||||
// ==========================================================================
|
// ==========================================================================
|
||||||
|
|
||||||
import support from './support';
|
|
||||||
import utils from './utils';
|
|
||||||
import youtube from './plugins/youtube';
|
|
||||||
import vimeo from './plugins/vimeo';
|
|
||||||
import html5 from './html5';
|
import html5 from './html5';
|
||||||
import ui from './ui';
|
import vimeo from './plugins/vimeo';
|
||||||
|
import youtube from './plugins/youtube';
|
||||||
// Sniff out the browser
|
import utils from './utils';
|
||||||
const browser = utils.getBrowser();
|
|
||||||
|
|
||||||
const media = {
|
const media = {
|
||||||
// Setup media
|
// Setup media
|
||||||
@ -33,23 +28,6 @@ const media = {
|
|||||||
utils.toggleClass(this.elements.container, this.config.classNames.type.replace('{0}', 'video'), true);
|
utils.toggleClass(this.elements.container, this.config.classNames.type.replace('{0}', 'video'), true);
|
||||||
}
|
}
|
||||||
|
|
||||||
if (this.supported.ui) {
|
|
||||||
// Check for picture-in-picture support
|
|
||||||
utils.toggleClass(this.elements.container, this.config.classNames.pip.supported, support.pip && this.isHTML5 && this.isVideo);
|
|
||||||
|
|
||||||
// Check for airplay support
|
|
||||||
utils.toggleClass(this.elements.container, this.config.classNames.airplay.supported, support.airplay && this.isHTML5);
|
|
||||||
|
|
||||||
// If there's no autoplay attribute, assume the video is stopped and add state class
|
|
||||||
utils.toggleClass(this.elements.container, this.config.classNames.stopped, this.config.autoplay);
|
|
||||||
|
|
||||||
// Add iOS class
|
|
||||||
utils.toggleClass(this.elements.container, this.config.classNames.isIos, browser.isIos);
|
|
||||||
|
|
||||||
// Add touch class
|
|
||||||
utils.toggleClass(this.elements.container, this.config.classNames.isTouch, this.touch);
|
|
||||||
}
|
|
||||||
|
|
||||||
// Inject the player wrapper
|
// Inject the player wrapper
|
||||||
if (this.isVideo) {
|
if (this.isVideo) {
|
||||||
// Create the wrapper div
|
// Create the wrapper div
|
||||||
@ -59,6 +37,13 @@ const media = {
|
|||||||
|
|
||||||
// Wrap the video in a container
|
// Wrap the video in a container
|
||||||
utils.wrap(this.media, this.elements.wrapper);
|
utils.wrap(this.media, this.elements.wrapper);
|
||||||
|
|
||||||
|
// Faux poster container
|
||||||
|
this.elements.poster = utils.createElement('span', {
|
||||||
|
class: this.config.classNames.poster,
|
||||||
|
});
|
||||||
|
|
||||||
|
this.elements.wrapper.appendChild(this.elements.poster);
|
||||||
}
|
}
|
||||||
|
|
||||||
if (this.isEmbed) {
|
if (this.isEmbed) {
|
||||||
@ -75,8 +60,6 @@ const media = {
|
|||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
} else if (this.isHTML5) {
|
} else if (this.isHTML5) {
|
||||||
ui.setTitle.call(this);
|
|
||||||
|
|
||||||
html5.extend.call(this);
|
html5.extend.call(this);
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
|
@ -6,8 +6,8 @@
|
|||||||
|
|
||||||
/* global google */
|
/* global google */
|
||||||
|
|
||||||
import utils from '../utils';
|
|
||||||
import i18n from '../i18n';
|
import i18n from '../i18n';
|
||||||
|
import utils from '../utils';
|
||||||
|
|
||||||
class Ads {
|
class Ads {
|
||||||
/**
|
/**
|
||||||
@ -52,7 +52,7 @@ class Ads {
|
|||||||
// Check if the Google IMA3 SDK is loaded or load it ourselves
|
// Check if the Google IMA3 SDK is loaded or load it ourselves
|
||||||
if (!utils.is.object(window.google) || !utils.is.object(window.google.ima)) {
|
if (!utils.is.object(window.google) || !utils.is.object(window.google.ima)) {
|
||||||
utils
|
utils
|
||||||
.loadScript(this.player.config.urls.googleIMA.api)
|
.loadScript(this.player.config.urls.googleIMA.sdk)
|
||||||
.then(() => {
|
.then(() => {
|
||||||
this.ready();
|
this.ready();
|
||||||
})
|
})
|
||||||
@ -160,6 +160,9 @@ class Ads {
|
|||||||
// We only overlay ads as we only support video.
|
// We only overlay ads as we only support video.
|
||||||
request.forceNonLinearFullSlot = false;
|
request.forceNonLinearFullSlot = false;
|
||||||
|
|
||||||
|
// Mute based on current state
|
||||||
|
request.setAdWillPlayMuted(!this.player.muted);
|
||||||
|
|
||||||
this.loader.requestAds(request);
|
this.loader.requestAds(request);
|
||||||
} catch (e) {
|
} catch (e) {
|
||||||
this.onAdError(e);
|
this.onAdError(e);
|
||||||
@ -226,7 +229,7 @@ class Ads {
|
|||||||
|
|
||||||
// Get skippable state
|
// Get skippable state
|
||||||
// TODO: Skip button
|
// TODO: Skip button
|
||||||
// this.manager.getAdSkippableState();
|
// this.player.debug.warn(this.manager.getAdSkippableState());
|
||||||
|
|
||||||
// Set volume to match player
|
// Set volume to match player
|
||||||
this.manager.setVolume(this.player.volume);
|
this.manager.setVolume(this.player.volume);
|
||||||
|
@ -2,10 +2,10 @@
|
|||||||
// Vimeo plugin
|
// Vimeo plugin
|
||||||
// ==========================================================================
|
// ==========================================================================
|
||||||
|
|
||||||
import utils from './../utils';
|
|
||||||
import captions from './../captions';
|
import captions from './../captions';
|
||||||
import controls from './../controls';
|
import controls from './../controls';
|
||||||
import ui from './../ui';
|
import ui from './../ui';
|
||||||
|
import utils from './../utils';
|
||||||
|
|
||||||
const vimeo = {
|
const vimeo = {
|
||||||
setup() {
|
setup() {
|
||||||
@ -18,7 +18,7 @@ const vimeo = {
|
|||||||
// Load the API if not already
|
// Load the API if not already
|
||||||
if (!utils.is.object(window.Vimeo)) {
|
if (!utils.is.object(window.Vimeo)) {
|
||||||
utils
|
utils
|
||||||
.loadScript(this.config.urls.vimeo.api)
|
.loadScript(this.config.urls.vimeo.sdk)
|
||||||
.then(() => {
|
.then(() => {
|
||||||
vimeo.ready.call(this);
|
vimeo.ready.call(this);
|
||||||
})
|
})
|
||||||
@ -68,14 +68,14 @@ const vimeo = {
|
|||||||
|
|
||||||
// Get from <div> if needed
|
// Get from <div> if needed
|
||||||
if (utils.is.empty(source)) {
|
if (utils.is.empty(source)) {
|
||||||
source = player.media.getAttribute(this.config.attributes.embed.id);
|
source = player.media.getAttribute(player.config.attributes.embed.id);
|
||||||
}
|
}
|
||||||
|
|
||||||
const id = utils.parseVimeoId(source);
|
const id = utils.parseVimeoId(source);
|
||||||
|
|
||||||
// Build an iframe
|
// Build an iframe
|
||||||
const iframe = utils.createElement('iframe');
|
const iframe = utils.createElement('iframe');
|
||||||
const src = `https://player.vimeo.com/video/${id}?${params}`;
|
const src = utils.format(player.config.urls.vimeo.iframe, id, params);
|
||||||
iframe.setAttribute('src', src);
|
iframe.setAttribute('src', src);
|
||||||
iframe.setAttribute('allowfullscreen', '');
|
iframe.setAttribute('allowfullscreen', '');
|
||||||
iframe.setAttribute('allowtransparency', '');
|
iframe.setAttribute('allowtransparency', '');
|
||||||
@ -86,6 +86,25 @@ const vimeo = {
|
|||||||
wrapper.appendChild(iframe);
|
wrapper.appendChild(iframe);
|
||||||
player.media = utils.replaceElement(wrapper, player.media);
|
player.media = utils.replaceElement(wrapper, player.media);
|
||||||
|
|
||||||
|
// Get poster image
|
||||||
|
utils.fetch(utils.format(player.config.urls.vimeo.api, id), 'json').then(response => {
|
||||||
|
if (utils.is.empty(response)) {
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
// Get the URL for thumbnail
|
||||||
|
const url = new URL(response[0].thumbnail_large);
|
||||||
|
|
||||||
|
// Get original image
|
||||||
|
url.pathname = `${url.pathname.split('_')[0]}.jpg`;
|
||||||
|
|
||||||
|
// Set attribute
|
||||||
|
player.media.setAttribute('poster', url.href);
|
||||||
|
|
||||||
|
// Update
|
||||||
|
ui.setPoster.call(player);
|
||||||
|
});
|
||||||
|
|
||||||
// Setup instance
|
// Setup instance
|
||||||
// https://github.com/vimeo/player.js
|
// https://github.com/vimeo/player.js
|
||||||
player.embed = new window.Vimeo.Player(iframe);
|
player.embed = new window.Vimeo.Player(iframe);
|
||||||
|
@ -2,9 +2,9 @@
|
|||||||
// YouTube plugin
|
// YouTube plugin
|
||||||
// ==========================================================================
|
// ==========================================================================
|
||||||
|
|
||||||
import utils from './../utils';
|
|
||||||
import controls from './../controls';
|
import controls from './../controls';
|
||||||
import ui from './../ui';
|
import ui from './../ui';
|
||||||
|
import utils from './../utils';
|
||||||
|
|
||||||
// Standardise YouTube quality unit
|
// Standardise YouTube quality unit
|
||||||
function mapQualityUnit(input) {
|
function mapQualityUnit(input) {
|
||||||
@ -77,7 +77,7 @@ const youtube = {
|
|||||||
youtube.ready.call(this);
|
youtube.ready.call(this);
|
||||||
} else {
|
} else {
|
||||||
// Load the API
|
// Load the API
|
||||||
utils.loadScript(this.config.urls.youtube.api).catch(error => {
|
utils.loadScript(this.config.urls.youtube.sdk).catch(error => {
|
||||||
this.debug.warn('YouTube API failed to load', error);
|
this.debug.warn('YouTube API failed to load', error);
|
||||||
});
|
});
|
||||||
|
|
||||||
@ -117,7 +117,7 @@ const youtube = {
|
|||||||
// Or via Google API
|
// Or via Google API
|
||||||
const key = this.config.keys.google;
|
const key = this.config.keys.google;
|
||||||
if (utils.is.string(key) && !utils.is.empty(key)) {
|
if (utils.is.string(key) && !utils.is.empty(key)) {
|
||||||
const url = `https://www.googleapis.com/youtube/v3/videos?id=${videoId}&key=${key}&fields=items(snippet(title))&part=snippet`;
|
const url = utils.format(this.config.urls.youtube.api, videoId, key);
|
||||||
|
|
||||||
utils
|
utils
|
||||||
.fetch(url)
|
.fetch(url)
|
||||||
@ -161,6 +161,9 @@ const youtube = {
|
|||||||
const container = utils.createElement('div', { id });
|
const container = utils.createElement('div', { id });
|
||||||
player.media = utils.replaceElement(container, player.media);
|
player.media = utils.replaceElement(container, player.media);
|
||||||
|
|
||||||
|
// Set poster image
|
||||||
|
player.media.setAttribute('poster', utils.format(player.config.urls.youtube.poster, videoId));
|
||||||
|
|
||||||
// Setup instance
|
// Setup instance
|
||||||
// https://developers.google.com/youtube/iframe_api_reference
|
// https://developers.google.com/youtube/iframe_api_reference
|
||||||
player.embed = new window.YT.Player(id, {
|
player.embed = new window.YT.Player(id, {
|
||||||
|
@ -1,26 +1,24 @@
|
|||||||
// ==========================================================================
|
// ==========================================================================
|
||||||
// Plyr
|
// Plyr
|
||||||
// plyr.js v3.2.4
|
// plyr.js v3.3.0
|
||||||
// https://github.com/sampotts/plyr
|
// https://github.com/sampotts/plyr
|
||||||
// License: The MIT License (MIT)
|
// License: The MIT License (MIT)
|
||||||
// ==========================================================================
|
// ==========================================================================
|
||||||
|
|
||||||
import { providers, types } from './types';
|
import captions from './captions';
|
||||||
import defaults from './defaults';
|
|
||||||
import support from './support';
|
|
||||||
import utils from './utils';
|
|
||||||
|
|
||||||
import Console from './console';
|
import Console from './console';
|
||||||
|
import controls from './controls';
|
||||||
|
import defaults from './defaults';
|
||||||
import Fullscreen from './fullscreen';
|
import Fullscreen from './fullscreen';
|
||||||
import Listeners from './listeners';
|
import Listeners from './listeners';
|
||||||
import Storage from './storage';
|
|
||||||
import Ads from './plugins/ads';
|
|
||||||
|
|
||||||
import captions from './captions';
|
|
||||||
import controls from './controls';
|
|
||||||
import media from './media';
|
import media from './media';
|
||||||
|
import Ads from './plugins/ads';
|
||||||
import source from './source';
|
import source from './source';
|
||||||
|
import Storage from './storage';
|
||||||
|
import support from './support';
|
||||||
|
import { providers, types } from './types';
|
||||||
import ui from './ui';
|
import ui from './ui';
|
||||||
|
import utils from './utils';
|
||||||
|
|
||||||
// Private properties
|
// Private properties
|
||||||
// TODO: Use a WeakMap for private globals
|
// TODO: Use a WeakMap for private globals
|
||||||
@ -134,17 +132,9 @@ class Plyr {
|
|||||||
}
|
}
|
||||||
|
|
||||||
// Cache original element state for .destroy()
|
// Cache original element state for .destroy()
|
||||||
// TODO: Investigate a better solution as I suspect this causes reported double load issues?
|
const clone = this.media.cloneNode(true);
|
||||||
setTimeout(() => {
|
clone.autoplay = false;
|
||||||
const clone = this.media.cloneNode(true);
|
this.elements.original = clone;
|
||||||
|
|
||||||
// Prevent the clone autoplaying
|
|
||||||
if (clone.getAttribute('autoplay')) {
|
|
||||||
clone.pause();
|
|
||||||
}
|
|
||||||
|
|
||||||
this.elements.original = clone;
|
|
||||||
}, 0);
|
|
||||||
|
|
||||||
// Set media type based on tag or data attribute
|
// Set media type based on tag or data attribute
|
||||||
// Supported: video, audio, vimeo, youtube
|
// Supported: video, audio, vimeo, youtube
|
||||||
@ -363,6 +353,13 @@ class Plyr {
|
|||||||
this.media.pause();
|
this.media.pause();
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Get playing state
|
||||||
|
*/
|
||||||
|
get playing() {
|
||||||
|
return Boolean(this.ready && !this.paused && !this.ended);
|
||||||
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Get paused state
|
* Get paused state
|
||||||
*/
|
*/
|
||||||
@ -371,10 +368,10 @@ class Plyr {
|
|||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Get playing state
|
* Get stopped state
|
||||||
*/
|
*/
|
||||||
get playing() {
|
get stopped() {
|
||||||
return Boolean(this.ready && !this.paused && !this.ended && (this.isHTML5 ? this.media.readyState > 2 : true));
|
return Boolean(this.paused && this.currentTime === 0);
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
@ -799,17 +796,18 @@ class Plyr {
|
|||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Set the poster image for a HTML5 video
|
* Set the poster image for a video
|
||||||
* @param {input} - the URL for the new poster image
|
* @param {input} - the URL for the new poster image
|
||||||
*/
|
*/
|
||||||
set poster(input) {
|
set poster(input) {
|
||||||
if (!this.isHTML5 || !this.isVideo) {
|
if (!this.isVideo) {
|
||||||
this.debug.warn('Poster can only be set on HTML5 video');
|
this.debug.warn('Poster can only be set for video');
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
if (utils.is.string(input)) {
|
if (utils.is.string(input)) {
|
||||||
this.media.setAttribute('poster', input);
|
this.media.setAttribute('poster', input);
|
||||||
|
ui.setPoster.call(this);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -817,7 +815,7 @@ class Plyr {
|
|||||||
* Get the current poster image
|
* Get the current poster image
|
||||||
*/
|
*/
|
||||||
get poster() {
|
get poster() {
|
||||||
if (!this.isHTML5 || !this.isVideo) {
|
if (!this.isVideo) {
|
||||||
return null;
|
return null;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -1,14 +1,12 @@
|
|||||||
// ==========================================================================
|
// ==========================================================================
|
||||||
// Plyr Polyfilled Build
|
// Plyr Polyfilled Build
|
||||||
// plyr.js v3.2.4
|
// plyr.js v3.3.0
|
||||||
// https://github.com/sampotts/plyr
|
// https://github.com/sampotts/plyr
|
||||||
// License: The MIT License (MIT)
|
// License: The MIT License (MIT)
|
||||||
// ==========================================================================
|
// ==========================================================================
|
||||||
|
|
||||||
import 'babel-polyfill';
|
import 'babel-polyfill';
|
||||||
|
|
||||||
import 'custom-event-polyfill';
|
import 'custom-event-polyfill';
|
||||||
|
|
||||||
import Plyr from './plyr';
|
import Plyr from './plyr';
|
||||||
|
|
||||||
export default Plyr;
|
export default Plyr;
|
||||||
|
38
src/js/ui.js
38
src/js/ui.js
@ -2,10 +2,14 @@
|
|||||||
// Plyr UI
|
// Plyr UI
|
||||||
// ==========================================================================
|
// ==========================================================================
|
||||||
|
|
||||||
import utils from './utils';
|
|
||||||
import captions from './captions';
|
import captions from './captions';
|
||||||
import controls from './controls';
|
import controls from './controls';
|
||||||
import i18n from './i18n';
|
import i18n from './i18n';
|
||||||
|
import support from './support';
|
||||||
|
import utils from './utils';
|
||||||
|
|
||||||
|
// Sniff out the browser
|
||||||
|
const browser = utils.getBrowser();
|
||||||
|
|
||||||
const ui = {
|
const ui = {
|
||||||
addStyleHook() {
|
addStyleHook() {
|
||||||
@ -78,6 +82,18 @@ const ui = {
|
|||||||
// Update the UI
|
// Update the UI
|
||||||
ui.checkPlaying.call(this);
|
ui.checkPlaying.call(this);
|
||||||
|
|
||||||
|
// Check for picture-in-picture support
|
||||||
|
utils.toggleClass(this.elements.container, this.config.classNames.pip.supported, support.pip && this.isHTML5 && this.isVideo);
|
||||||
|
|
||||||
|
// Check for airplay support
|
||||||
|
utils.toggleClass(this.elements.container, this.config.classNames.airplay.supported, support.airplay && this.isHTML5);
|
||||||
|
|
||||||
|
// Add iOS class
|
||||||
|
utils.toggleClass(this.elements.container, this.config.classNames.isIos, browser.isIos);
|
||||||
|
|
||||||
|
// Add touch class
|
||||||
|
utils.toggleClass(this.elements.container, this.config.classNames.isTouch, this.touch);
|
||||||
|
|
||||||
// Ready for API calls
|
// Ready for API calls
|
||||||
this.ready = true;
|
this.ready = true;
|
||||||
|
|
||||||
@ -88,6 +104,9 @@ const ui = {
|
|||||||
|
|
||||||
// Set the title
|
// Set the title
|
||||||
ui.setTitle.call(this);
|
ui.setTitle.call(this);
|
||||||
|
|
||||||
|
// Set the poster image
|
||||||
|
ui.setPoster.call(this);
|
||||||
},
|
},
|
||||||
|
|
||||||
// Setup aria attribute for play and iframe title
|
// Setup aria attribute for play and iframe title
|
||||||
@ -121,16 +140,29 @@ const ui = {
|
|||||||
|
|
||||||
// Default to media type
|
// Default to media type
|
||||||
const title = !utils.is.empty(this.config.title) ? this.config.title : 'video';
|
const title = !utils.is.empty(this.config.title) ? this.config.title : 'video';
|
||||||
|
const format = i18n.get('frameTitle', this.config);
|
||||||
|
|
||||||
iframe.setAttribute('title', i18n.get('frameTitle', this.config));
|
iframe.setAttribute('title', format.replace('{title}', title));
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
|
|
||||||
|
// Set the poster image
|
||||||
|
setPoster() {
|
||||||
|
if (!utils.is.element(this.elements.poster) || utils.is.empty(this.poster)) {
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
// Set the inline style
|
||||||
|
const posters = this.poster.split(',');
|
||||||
|
this.elements.poster.style.backgroundImage = posters.map(p => `url('${p}')`).join(',');
|
||||||
|
},
|
||||||
|
|
||||||
// Check playing state
|
// Check playing state
|
||||||
checkPlaying() {
|
checkPlaying() {
|
||||||
// Class hooks
|
// Class hooks
|
||||||
utils.toggleClass(this.elements.container, this.config.classNames.playing, this.playing);
|
utils.toggleClass(this.elements.container, this.config.classNames.playing, this.playing);
|
||||||
utils.toggleClass(this.elements.container, this.config.classNames.stopped, this.paused);
|
utils.toggleClass(this.elements.container, this.config.classNames.paused, this.paused);
|
||||||
|
utils.toggleClass(this.elements.container, this.config.classNames.stopped, this.stopped);
|
||||||
|
|
||||||
// Set ARIA state
|
// Set ARIA state
|
||||||
utils.toggleState(this.elements.buttons.play, this.playing);
|
utils.toggleState(this.elements.buttons.play, this.playing);
|
||||||
|
@ -3,7 +3,6 @@
|
|||||||
// ==========================================================================
|
// ==========================================================================
|
||||||
|
|
||||||
import loadjs from 'loadjs';
|
import loadjs from 'loadjs';
|
||||||
|
|
||||||
import support from './support';
|
import support from './support';
|
||||||
import { providers } from './types';
|
import { providers } from './types';
|
||||||
|
|
||||||
@ -269,14 +268,14 @@ const utils = {
|
|||||||
parent.appendChild(utils.createElement(type, attributes, text));
|
parent.appendChild(utils.createElement(type, attributes, text));
|
||||||
},
|
},
|
||||||
|
|
||||||
// Remove an element
|
// Remove element(s)
|
||||||
removeElement(element) {
|
removeElement(element) {
|
||||||
if (!utils.is.element(element) || !utils.is.element(element.parentNode)) {
|
if (utils.is.nodeList(element) || utils.is.array(element)) {
|
||||||
|
Array.from(element).forEach(utils.removeElement);
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
if (utils.is.nodeList(element) || utils.is.array(element)) {
|
if (!utils.is.element(element) || !utils.is.element(element.parentNode)) {
|
||||||
Array.from(element).forEach(utils.removeElement);
|
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -435,60 +434,6 @@ const utils = {
|
|||||||
return this.elements.container.querySelector(selector);
|
return this.elements.container.querySelector(selector);
|
||||||
},
|
},
|
||||||
|
|
||||||
// Find the UI controls and store references in custom controls
|
|
||||||
// TODO: Allow settings menus with custom controls
|
|
||||||
findElements() {
|
|
||||||
try {
|
|
||||||
this.elements.controls = utils.getElement.call(this, this.config.selectors.controls.wrapper);
|
|
||||||
|
|
||||||
// Buttons
|
|
||||||
this.elements.buttons = {
|
|
||||||
play: utils.getElements.call(this, this.config.selectors.buttons.play),
|
|
||||||
pause: utils.getElement.call(this, this.config.selectors.buttons.pause),
|
|
||||||
restart: utils.getElement.call(this, this.config.selectors.buttons.restart),
|
|
||||||
rewind: utils.getElement.call(this, this.config.selectors.buttons.rewind),
|
|
||||||
fastForward: utils.getElement.call(this, this.config.selectors.buttons.fastForward),
|
|
||||||
mute: utils.getElement.call(this, this.config.selectors.buttons.mute),
|
|
||||||
pip: utils.getElement.call(this, this.config.selectors.buttons.pip),
|
|
||||||
airplay: utils.getElement.call(this, this.config.selectors.buttons.airplay),
|
|
||||||
settings: utils.getElement.call(this, this.config.selectors.buttons.settings),
|
|
||||||
captions: utils.getElement.call(this, this.config.selectors.buttons.captions),
|
|
||||||
fullscreen: utils.getElement.call(this, this.config.selectors.buttons.fullscreen),
|
|
||||||
};
|
|
||||||
|
|
||||||
// Progress
|
|
||||||
this.elements.progress = utils.getElement.call(this, this.config.selectors.progress);
|
|
||||||
|
|
||||||
// Inputs
|
|
||||||
this.elements.inputs = {
|
|
||||||
seek: utils.getElement.call(this, this.config.selectors.inputs.seek),
|
|
||||||
volume: utils.getElement.call(this, this.config.selectors.inputs.volume),
|
|
||||||
};
|
|
||||||
|
|
||||||
// Display
|
|
||||||
this.elements.display = {
|
|
||||||
buffer: utils.getElement.call(this, this.config.selectors.display.buffer),
|
|
||||||
currentTime: utils.getElement.call(this, this.config.selectors.display.currentTime),
|
|
||||||
duration: utils.getElement.call(this, this.config.selectors.display.duration),
|
|
||||||
};
|
|
||||||
|
|
||||||
// Seek tooltip
|
|
||||||
if (utils.is.element(this.elements.progress)) {
|
|
||||||
this.elements.display.seekTooltip = this.elements.progress.querySelector(`.${this.config.classNames.tooltip}`);
|
|
||||||
}
|
|
||||||
|
|
||||||
return true;
|
|
||||||
} catch (error) {
|
|
||||||
// Log it
|
|
||||||
this.debug.warn('It looks like there is a problem with your custom controls HTML', error);
|
|
||||||
|
|
||||||
// Restore native video controls
|
|
||||||
this.toggleNativeControls(true);
|
|
||||||
|
|
||||||
return false;
|
|
||||||
}
|
|
||||||
},
|
|
||||||
|
|
||||||
// Get the focused element
|
// Get the focused element
|
||||||
getFocusElement() {
|
getFocusElement() {
|
||||||
let focused = document.activeElement;
|
let focused = document.activeElement;
|
||||||
@ -632,6 +577,15 @@ const utils = {
|
|||||||
element.setAttribute('aria-pressed', state);
|
element.setAttribute('aria-pressed', state);
|
||||||
},
|
},
|
||||||
|
|
||||||
|
// Format string
|
||||||
|
format(input, ...args) {
|
||||||
|
if (utils.is.empty(input)) {
|
||||||
|
return input;
|
||||||
|
}
|
||||||
|
|
||||||
|
return input.toString().replace(/{(\d+)}/g, (match, i) => utils.is.string(args[i]) ? args[i] : '');
|
||||||
|
},
|
||||||
|
|
||||||
// Get percentage
|
// Get percentage
|
||||||
getPercentage(current, max) {
|
getPercentage(current, max) {
|
||||||
if (current === 0 || max === 0 || Number.isNaN(current) || Number.isNaN(max)) {
|
if (current === 0 || max === 0 || Number.isNaN(current) || Number.isNaN(max)) {
|
||||||
|
@ -29,6 +29,7 @@
|
|||||||
button {
|
button {
|
||||||
font: inherit;
|
font: inherit;
|
||||||
line-height: inherit;
|
line-height: inherit;
|
||||||
|
width: auto;
|
||||||
}
|
}
|
||||||
|
|
||||||
// Ignore focus
|
// Ignore focus
|
||||||
|
22
src/sass/components/poster.scss
Normal file
22
src/sass/components/poster.scss
Normal file
@ -0,0 +1,22 @@
|
|||||||
|
// --------------------------------------------------------------
|
||||||
|
// Faux poster overlay
|
||||||
|
// --------------------------------------------------------------
|
||||||
|
|
||||||
|
.plyr__poster {
|
||||||
|
background-color: #000;
|
||||||
|
background-position: 50% 50%;
|
||||||
|
background-repeat: no-repeat;
|
||||||
|
background-size: 100% 100%;
|
||||||
|
height: 100%;
|
||||||
|
left: 0;
|
||||||
|
opacity: 0;
|
||||||
|
position: absolute;
|
||||||
|
top: 0;
|
||||||
|
transition: opacity 0.3s ease;
|
||||||
|
width: 100%;
|
||||||
|
z-index: 1;
|
||||||
|
}
|
||||||
|
|
||||||
|
.plyr--stopped .plyr__poster {
|
||||||
|
opacity: 1;
|
||||||
|
}
|
@ -32,6 +32,7 @@
|
|||||||
@import 'components/embed';
|
@import 'components/embed';
|
||||||
@import 'components/menus';
|
@import 'components/menus';
|
||||||
@import 'components/progress';
|
@import 'components/progress';
|
||||||
|
@import 'components/poster';
|
||||||
@import 'components/sliders';
|
@import 'components/sliders';
|
||||||
@import 'components/times';
|
@import 'components/times';
|
||||||
@import 'components/tooltips';
|
@import 'components/tooltips';
|
||||||
|
Loading…
x
Reference in New Issue
Block a user