This commit is contained in:
Sam Potts
2018-06-11 16:45:40 +10:00
parent 1ad76800b0
commit abd1182303
14 changed files with 764 additions and 538 deletions
+1 -1
View File
File diff suppressed because one or more lines are too long
+95 -15
View File
@@ -767,11 +767,12 @@ function getLocationOrigin() {
// Oh dear IE10... // Oh dear IE10...
if (!document.location.origin) { if (!document.location.origin) {
document.location.origin = return (
document.location.protocol + document.location.protocol +
'//' + '//' +
document.location.hostname + document.location.hostname +
(document.location.port ? ':' + document.location.port : ''); (document.location.port ? ':' + document.location.port : '')
);
} }
return document.location.origin; return document.location.origin;
@@ -1866,7 +1867,7 @@ Raven.prototype = {
// webpack (using a build step causes webpack #1617). Grunt verifies that // webpack (using a build step causes webpack #1617). Grunt verifies that
// this value matches package.json during build. // this value matches package.json during build.
// See: https://github.com/getsentry/raven-js/issues/465 // See: https://github.com/getsentry/raven-js/issues/465
VERSION: '3.25.2', VERSION: '3.26.1',
debug: false, debug: false,
@@ -2032,7 +2033,7 @@ Raven.prototype = {
if (isFunction$1(options)) { if (isFunction$1(options)) {
args = func || []; args = func || [];
func = options; func = options;
options = undefined; options = {};
} }
return this.wrap(options, func).apply(this, args); return this.wrap(options, func).apply(this, args);
@@ -2043,7 +2044,7 @@ Raven.prototype = {
* *
* @param {object} options A specific set of options for this context [optional] * @param {object} options A specific set of options for this context [optional]
* @param {function} func The function to be wrapped in a new context * @param {function} func The function to be wrapped in a new context
* @param {function} func A function to call before the try/catch wrapper [optional, private] * @param {function} _before A function to call before the try/catch wrapper [optional, private]
* @return {function} The newly wrapped functions with a context * @return {function} The newly wrapped functions with a context
*/ */
wrap: function(options, func, _before) { wrap: function(options, func, _before) {
@@ -2156,8 +2157,9 @@ Raven.prototype = {
_promiseRejectionHandler: function(event) { _promiseRejectionHandler: function(event) {
this._logDebug('debug', 'Raven caught unhandled promise rejection:', event); this._logDebug('debug', 'Raven caught unhandled promise rejection:', event);
this.captureException(event.reason, { this.captureException(event.reason, {
extra: { mechanism: {
unhandledPromiseRejection: true type: 'onunhandledrejection',
handled: false
} }
}); });
}, },
@@ -2834,7 +2836,15 @@ Raven.prototype = {
} }
var originalCallback = args[0]; var originalCallback = args[0];
if (isFunction$1(originalCallback)) { if (isFunction$1(originalCallback)) {
args[0] = self.wrap(originalCallback); args[0] = self.wrap(
{
mechanism: {
type: 'instrument',
data: {function: orig.name}
}
},
originalCallback
);
} }
// IE < 9 doesn't support .call/.apply on setInterval/setTimeout, but it // IE < 9 doesn't support .call/.apply on setInterval/setTimeout, but it
@@ -2861,7 +2871,15 @@ Raven.prototype = {
// preserve arity // preserve arity
try { try {
if (fn && fn.handleEvent) { if (fn && fn.handleEvent) {
fn.handleEvent = self.wrap(fn.handleEvent); fn.handleEvent = self.wrap(
{
mechanism: {
type: 'instrument',
data: {target: global, function: 'handleEvent', handler: fn.name}
}
},
fn.handleEvent
);
} }
} catch (err) { } catch (err) {
// can sometimes get 'Permission denied to access property "handle Event' // can sometimes get 'Permission denied to access property "handle Event'
@@ -2901,7 +2919,20 @@ Raven.prototype = {
return orig.call( return orig.call(
this, this,
evtName, evtName,
self.wrap(fn, undefined, before), self.wrap(
{
mechanism: {
type: 'instrument',
data: {
target: global,
function: 'addEventListener',
handler: fn.name
}
}
},
fn,
before
),
capture, capture,
secure secure
); );
@@ -2935,7 +2966,17 @@ Raven.prototype = {
'requestAnimationFrame', 'requestAnimationFrame',
function(orig) { function(orig) {
return function(cb) { return function(cb) {
return orig(self.wrap(cb)); return orig(
self.wrap(
{
mechanism: {
type: 'instrument',
data: {function: 'requestAnimationFrame', handler: orig.name}
}
},
cb
)
);
}; };
}, },
wrappedBuiltIns wrappedBuiltIns
@@ -2998,7 +3039,15 @@ Raven.prototype = {
function wrapProp(prop, xhr) { function wrapProp(prop, xhr) {
if (prop in xhr && isFunction$1(xhr[prop])) { if (prop in xhr && isFunction$1(xhr[prop])) {
fill$1(xhr, prop, function(orig) { fill$1(xhr, prop, function(orig) {
return self.wrap(orig); return self.wrap(
{
mechanism: {
type: 'instrument',
data: {function: prop, handler: orig.name}
}
},
orig
);
}); // intentionally don't track filled methods on XHR instances }); // intentionally don't track filled methods on XHR instances
} }
} }
@@ -3063,7 +3112,19 @@ Raven.prototype = {
xhr, xhr,
'onreadystatechange', 'onreadystatechange',
function(orig) { function(orig) {
return self.wrap(orig, undefined, onreadystatechangeHandler); return self.wrap(
{
mechanism: {
type: 'instrument',
data: {
function: 'onreadystatechange',
handler: orig.name
}
}
},
orig,
onreadystatechangeHandler
);
} /* intentionally don't track this instrumentation */ } /* intentionally don't track this instrumentation */
); );
} else { } else {
@@ -3287,10 +3348,16 @@ Raven.prototype = {
return globalServer; return globalServer;
}, },
_handleOnErrorStackInfo: function() { _handleOnErrorStackInfo: function(stackInfo, options) {
options = options || {};
options.mechanism = options.mechanism || {
type: 'onerror',
handled: false
};
// if we are intentionally ignoring errors via onerror, bail out // if we are intentionally ignoring errors via onerror, bail out
if (!this._ignoreOnError) { if (!this._ignoreOnError) {
this._handleStackInfo.apply(this, arguments); this._handleStackInfo(stackInfo, options);
} }
}, },
@@ -3427,6 +3494,19 @@ Raven.prototype = {
options options
); );
// Move mechanism from options to exception interface
// We do this, as requiring user to pass `{exception:{mechanism:{ ... }}}` would be
// too much
if (!data.exception.mechanism && data.mechanism) {
data.exception.mechanism = data.mechanism;
delete data.mechanism;
}
data.exception.mechanism = objectMerge$1(data.exception.mechanism || {}, {
type: 'generic',
handled: true
});
// Fire away! // Fire away!
this._send(data); this._send(data);
}, },
+1 -1
View File
File diff suppressed because one or more lines are too long
+1 -1
View File
File diff suppressed because one or more lines are too long
+1 -1
View File
File diff suppressed because one or more lines are too long
+1 -1
View File
File diff suppressed because one or more lines are too long
+329 -256
View File
@@ -493,61 +493,63 @@ var utils = {
// Check variable types // Check variable types
is: { is: {
object: function object(input) { object: function object(input) {
return this.getConstructor(input) === Object; return utils.getConstructor(input) === Object;
}, },
number: function number(input) { number: function number(input) {
return this.getConstructor(input) === Number && !Number.isNaN(input); return utils.getConstructor(input) === Number && !Number.isNaN(input);
}, },
string: function string(input) { string: function string(input) {
return this.getConstructor(input) === String; return utils.getConstructor(input) === String;
}, },
boolean: function boolean(input) { boolean: function boolean(input) {
return this.getConstructor(input) === Boolean; return utils.getConstructor(input) === Boolean;
}, },
function: function _function(input) { function: function _function(input) {
return this.getConstructor(input) === Function; return utils.getConstructor(input) === Function;
}, },
array: function array(input) { array: function array(input) {
return !this.nullOrUndefined(input) && Array.isArray(input); return !utils.is.nullOrUndefined(input) && Array.isArray(input);
}, },
weakMap: function weakMap(input) { weakMap: function weakMap(input) {
return this.instanceof(input, WeakMap); return utils.is.instanceof(input, WeakMap);
}, },
nodeList: function nodeList(input) { nodeList: function nodeList(input) {
return this.instanceof(input, NodeList); return utils.is.instanceof(input, NodeList);
}, },
element: function element(input) { element: function element(input) {
return this.instanceof(input, Element); return utils.is.instanceof(input, Element);
}, },
textNode: function textNode(input) { textNode: function textNode(input) {
return this.getConstructor(input) === Text; return utils.getConstructor(input) === Text;
}, },
event: function event(input) { event: function event(input) {
return this.instanceof(input, Event); return utils.is.instanceof(input, Event);
}, },
cue: function cue(input) { cue: function cue(input) {
return this.instanceof(input, window.TextTrackCue) || this.instanceof(input, window.VTTCue); return utils.is.instanceof(input, window.TextTrackCue) || utils.is.instanceof(input, window.VTTCue);
}, },
track: function track(input) { track: function track(input) {
return this.instanceof(input, TextTrack) || !this.nullOrUndefined(input) && this.string(input.kind); return utils.is.instanceof(input, TextTrack) || !utils.is.nullOrUndefined(input) && utils.is.string(input.kind);
}, },
url: function url(input) { url: function url(input) {
return !this.nullOrUndefined(input) && /(ftp|http|https):\/\/(\w+:{0,1}\w*@)?(\S+)(:[0-9]+)?(\/|\/([\w#!:.?+=&%@!\-/]))?/.test(input); return !utils.is.nullOrUndefined(input) && /(ftp|http|https):\/\/(\w+:{0,1}\w*@)?(\S+)(:[0-9]+)?(\/|\/([\w#!:.?+=&%@!\-/]))?/.test(input);
}, },
nullOrUndefined: function nullOrUndefined(input) { nullOrUndefined: function nullOrUndefined(input) {
return input === null || typeof input === 'undefined'; return input === null || typeof input === 'undefined';
}, },
empty: function empty(input) { empty: function empty(input) {
return this.nullOrUndefined(input) || (this.string(input) || this.array(input) || this.nodeList(input)) && !input.length || this.object(input) && !Object.keys(input).length; return utils.is.nullOrUndefined(input) || (utils.is.string(input) || utils.is.array(input) || utils.is.nodeList(input)) && !input.length || utils.is.object(input) && !Object.keys(input).length;
}, },
instanceof: function _instanceof$$1(input, constructor) { instanceof: function _instanceof$$1(input, constructor) {
return Boolean(input && constructor && input instanceof constructor); return Boolean(input && constructor && input instanceof constructor);
},
getConstructor: function getConstructor(input) {
return !this.nullOrUndefined(input) ? input.constructor : null;
} }
}, },
getConstructor: function getConstructor(input) {
return !utils.is.nullOrUndefined(input) ? input.constructor : null;
},
// Unfortunately, due to mixed support, UA sniffing is required // Unfortunately, due to mixed support, UA sniffing is required
getBrowser: function getBrowser() { getBrowser: function getBrowser() {
return { return {
@@ -1167,7 +1169,7 @@ var utils = {
// Bail if the value isn't a number // Bail if the value isn't a number
if (!utils.is.number(time)) { if (!utils.is.number(time)) {
return this.formatTime(null, displayHours, inverted); return utils.formatTime(null, displayHours, inverted);
} }
// Format time component to add leading zero // Format time component to add leading zero
@@ -1176,9 +1178,9 @@ var utils = {
}; };
// Breakdown to hours, mins, secs // Breakdown to hours, mins, secs
var hours = this.getHours(time); var hours = utils.getHours(time);
var mins = this.getMinutes(time); var mins = utils.getMinutes(time);
var secs = this.getSeconds(time); var secs = utils.getSeconds(time);
// Do we need to display hours? // Do we need to display hours?
if (displayHours || hours > 0) { if (displayHours || hours > 0) {
@@ -1374,12 +1376,12 @@ var utils = {
// Parse URL if needed // Parse URL if needed
if (input.startsWith('http://') || input.startsWith('https://')) { if (input.startsWith('http://') || input.startsWith('https://')) {
var _parseUrl = this.parseUrl(input); var _utils$parseUrl = utils.parseUrl(input);
search = _parseUrl.search; search = _utils$parseUrl.search;
} }
if (this.is.empty(search)) { if (utils.is.empty(search)) {
return null; return null;
} }
@@ -1418,6 +1420,14 @@ var utils = {
}, },
// Like outerHTML, but also works for DocumentFragment
getHTML: function getHTML(element) {
var wrapper = document.createElement('div');
wrapper.appendChild(element);
return wrapper.innerHTML;
},
// Get aspect ratio for dimensions // Get aspect ratio for dimensions
getAspectRatio: function getAspectRatio(width, height) { getAspectRatio: function getAspectRatio(width, height) {
var getRatio = function getRatio(w, h) { var getRatio = function getRatio(w, h) {
@@ -2159,9 +2169,15 @@ var controls = {
// Create a settings menu item // Create a settings menu item
createMenuItem: function createMenuItem(value, list, type, title) { createMenuItem: function createMenuItem(_ref) {
var badge = arguments.length > 4 && arguments[4] !== undefined ? arguments[4] : null; var value = _ref.value,
var checked = arguments.length > 5 && arguments[5] !== undefined ? arguments[5] : false; list = _ref.list,
type = _ref.type,
title = _ref.title,
_ref$badge = _ref.badge,
badge = _ref$badge === undefined ? null : _ref$badge,
_ref$checked = _ref.checked,
checked = _ref$checked === undefined ? false : _ref$checked;
var item = utils.createElement('li'); var item = utils.createElement('li');
@@ -2477,8 +2493,13 @@ var controls = {
var sorting = _this3.config.quality.options; var sorting = _this3.config.quality.options;
return sorting.indexOf(a) > sorting.indexOf(b) ? 1 : -1; return sorting.indexOf(a) > sorting.indexOf(b) ? 1 : -1;
}).forEach(function (quality) { }).forEach(function (quality) {
var label = controls.getLabel.call(_this3, 'quality', quality); controls.createMenuItem.call(_this3, {
controls.createMenuItem.call(_this3, quality, list, type, label, getBadge(quality)); value: quality,
list: list,
type: type,
title: controls.getLabel.call(_this3, 'quality', quality),
badge: getBadge(quality)
});
}); });
controls.updateSetting.call(this, type, list); controls.updateSetting.call(this, type, list);
@@ -2521,18 +2542,7 @@ var controls = {
switch (setting) { switch (setting) {
case 'captions': case 'captions':
if (this.captions.active) { value = this.currentTrack;
if (this.options.captions.length > 2 || !this.options.captions.some(function (lang) {
return lang === 'enabled';
})) {
value = this.captions.language;
} else {
value = 'enabled';
}
} else {
value = '';
}
break; break;
default: default:
@@ -2627,10 +2637,10 @@ var controls = {
// TODO: Captions or language? Currently it's mixed // TODO: Captions or language? Currently it's mixed
var type = 'captions'; var type = 'captions';
var list = this.elements.settings.panes.captions.querySelector('ul'); var list = this.elements.settings.panes.captions.querySelector('ul');
var tracks = captions.getTracks.call(this);
// Toggle the pane and tab // Toggle the pane and tab
var toggle = captions.getTracks.call(this).length; controls.toggleTab.call(this, type, tracks.length);
controls.toggleTab.call(this, type, toggle);
// Empty the menu // Empty the menu
utils.emptyElement(list); utils.emptyElement(list);
@@ -2639,28 +2649,33 @@ var controls = {
controls.checkMenu.call(this); controls.checkMenu.call(this);
// If there's no captions, bail // If there's no captions, bail
if (!toggle) { if (!tracks.length) {
return; return;
} }
// Re-map the tracks into just the data we need // Generate options data
var tracks = captions.getTracks.call(this).map(function (track) { var options = tracks.map(function (track, value) {
return { return {
language: !utils.is.empty(track.language) ? track.language : 'enabled', value: value,
label: captions.getLabel.call(_this4, track) checked: _this4.captions.active && _this4.currentTrack === value,
title: captions.getLabel.call(_this4, track),
badge: track.language && controls.createBadge.call(_this4, track.language.toUpperCase()),
list: list,
type: 'language'
}; };
}); });
// Add the "Disabled" option to turn off captions // Add the "Disabled" option to turn off captions
tracks.unshift({ options.unshift({
language: '', value: -1,
label: i18n.get('disabled', this.config) checked: !this.captions.active,
title: i18n.get('disabled', this.config),
list: list,
type: 'language'
}); });
// Generate options // Generate options
tracks.forEach(function (track) { options.forEach(controls.createMenuItem.bind(this));
controls.createMenuItem.call(_this4, track.language, list, 'language', track.label, track.language !== 'enabled' ? controls.createBadge.call(_this4, track.language.toUpperCase()) : null, track.language.toLowerCase() === _this4.language);
});
controls.updateSetting.call(this, type, list); controls.updateSetting.call(this, type, list);
}, },
@@ -2714,8 +2729,12 @@ var controls = {
// Create items // Create items
this.options.speed.forEach(function (speed) { this.options.speed.forEach(function (speed) {
var label = controls.getLabel.call(_this5, 'speed', speed); controls.createMenuItem.call(_this5, {
controls.createMenuItem.call(_this5, speed, list, type, label); value: speed,
list: list,
type: type,
title: controls.getLabel.call(_this5, 'speed', speed)
});
}); });
controls.updateSetting.call(this, type, list); controls.updateSetting.call(this, type, list);
@@ -3189,10 +3208,10 @@ var controls = {
var replace = function replace(input) { var replace = function replace(input) {
var result = input; var result = input;
Object.entries(props).forEach(function (_ref) { Object.entries(props).forEach(function (_ref2) {
var _ref2 = slicedToArray(_ref, 2), var _ref3 = slicedToArray(_ref2, 2),
key = _ref2[0], key = _ref3[0],
value = _ref2[1]; value = _ref3[1];
result = utils.replaceAll(result, '{' + key + '}', value); result = utils.replaceAll(result, '{' + key + '}', value);
}); });
@@ -3309,91 +3328,168 @@ var captions = {
active = this.config.captions.active; active = this.config.captions.active;
} }
// Set toggled state // Get language from storage, fallback to config
this.toggleCaptions(active); var language = this.storage.get('language') || this.config.captions.language;
if (language === 'auto') {
var _split = (navigator.language || navigator.userLanguage).split('-');
var _split2 = slicedToArray(_split, 1);
language = _split2[0];
}
// Set language and show if active
captions.setLanguage.call(this, language, active);
// Watch changes to textTracks and update captions menu // Watch changes to textTracks and update captions menu
if (this.config.captions.update) { if (this.isHTML5) {
utils.on(this.media.textTracks, 'addtrack removetrack', captions.update.bind(this)); var trackEvents = this.config.captions.update ? 'addtrack removetrack' : 'removetrack';
utils.on(this.media.textTracks, trackEvents, captions.update.bind(this));
} }
// Update available languages in list next tick (the event must not be triggered before the listeners) // Update available languages in list next tick (the event must not be triggered before the listeners)
setTimeout(captions.update.bind(this), 0); setTimeout(captions.update.bind(this), 0);
}, },
update: function update() { update: function update() {
// Update tracks var _this = this;
var tracks = captions.getTracks.call(this);
this.options.captions = tracks.map(function (_ref) {
var language = _ref.language;
return language;
});
// Set language if it hasn't been set already var tracks = captions.getTracks.call(this, true);
if (!this.language) { // Get the wanted language
var language = this.config.captions.language; var _captions = this.captions,
language = _captions.language,
meta = _captions.meta;
if (language === 'auto') { // Handle tracks (add event listener and "pseudo"-default)
var _split = (navigator.language || navigator.userLanguage).split('-');
var _split2 = slicedToArray(_split, 1); if (this.isHTML5 && this.isVideo) {
tracks.filter(function (track) {
return !meta.get(track);
}).forEach(function (track) {
_this.debug.log('Track added', track);
// Attempt to store if the original dom element was "default"
meta.set(track, {
default: track.mode === 'showing'
});
language = _split2[0]; // Turn off native caption rendering to avoid double captions
} track.mode = 'hidden';
this.language = this.storage.get('language') || (language || '').toLowerCase();
// Add event listener for cue changes
utils.on(track, 'cuechange', function () {
return captions.updateCues.call(_this);
});
});
} }
// Toggle the class hooks var trackRemoved = !tracks.find(function (track) {
utils.toggleClass(this.elements.container, this.config.classNames.captions.enabled, !utils.is.empty(captions.getTracks.call(this))); return track === _this.captions.currentTrackNode;
});
var firstMatch = this.language !== language && tracks.find(function (track) {
return track.language === language;
});
// Update language if removed or first matching track added
if (trackRemoved || firstMatch) {
captions.setLanguage.call(this, language, this.config.captions.active);
}
// Enable or disable captions based on track length
utils.toggleClass(this.elements.container, this.config.classNames.captions.enabled, !utils.is.empty(tracks));
// Update available languages in list // Update available languages in list
if ((this.config.controls || []).includes('settings') && this.config.settings.includes('captions')) { if ((this.config.controls || []).includes('settings') && this.config.settings.includes('captions')) {
controls.setCaptionsMenu.call(this); controls.setCaptionsMenu.call(this);
} }
}, },
set: function set$$1(index) {
var setLanguage = arguments.length > 1 && arguments[1] !== undefined ? arguments[1] : true;
var show = arguments.length > 2 && arguments[2] !== undefined ? arguments[2] : true;
var tracks = captions.getTracks.call(this);
// Set the captions language // Disable captions if setting to -1
setLanguage: function setLanguage() { if (index === -1) {
var _this = this; this.toggleCaptions(false);
return;
// Setup HTML5 track rendering
if (this.isHTML5 && this.isVideo) {
captions.getTracks.call(this).forEach(function (track) {
// Show track
utils.on(track, 'cuechange', function (event) {
return captions.setCue.call(_this, event);
});
// Turn off native caption rendering to avoid double captions
// eslint-disable-next-line
track.mode = 'hidden';
});
// Get current track
var currentTrack = captions.getCurrentTrack.call(this);
// Check if suported kind
if (utils.is.track(currentTrack)) {
// If we change the active track while a cue is already displayed we need to update it
if (Array.from(currentTrack.activeCues || []).length) {
captions.setCue.call(this, currentTrack);
}
}
} else if (this.isVimeo && this.captions.active) {
this.embed.enableTextTrack(this.language);
} }
if (!utils.is.number(index)) {
this.debug.warn('Invalid caption argument', index);
return;
}
if (!(index in tracks)) {
this.debug.warn('Track not found', index);
return;
}
if (this.captions.currentTrack !== index) {
this.captions.currentTrack = index;
var track = captions.getCurrentTrack.call(this);
var _ref = track || {},
language = _ref.language;
// Store reference to node for invalidation on remove
this.captions.currentTrackNode = track;
// Prevent setting language in some cases, since it can violate user's intentions
if (setLanguage) {
this.captions.language = language;
}
// Handle Vimeo captions
if (this.isVimeo) {
this.embed.enableTextTrack(language);
}
// Trigger event
utils.dispatchEvent.call(this, this.media, 'languagechange');
}
if (this.isHTML5 && this.isVideo) {
// If we change the active track while a cue is already displayed we need to update it
captions.updateCues.call(this);
}
// Show captions
if (show) {
this.toggleCaptions(true);
}
},
setLanguage: function setLanguage(language) {
var show = arguments.length > 1 && arguments[1] !== undefined ? arguments[1] : true;
if (!utils.is.string(language)) {
this.debug.warn('Invalid language argument', language);
return;
}
// Normalize
this.captions.language = language.toLowerCase();
// Set currentTrack
var tracks = captions.getTracks.call(this);
var track = captions.getCurrentTrack.call(this, true);
captions.set.call(this, tracks.indexOf(track), false, show);
}, },
// Get the tracks // Get current valid caption tracks
// If update is false it will also ignore tracks without metadata
// This is used to "freeze" the language options when captions.update is false
getTracks: function getTracks() { getTracks: function getTracks() {
// Return empty array at least var _this2 = this;
if (utils.is.nullOrUndefined(this.media)) {
return [];
}
// Only get accepted kinds var update = arguments.length > 0 && arguments[0] !== undefined ? arguments[0] : false;
return Array.from(this.media.textTracks || []).filter(function (track) {
// Handle media or textTracks missing or null
var tracks = Array.from((this.media || {}).textTracks || []);
// For HTML5, use cache instead of current tracks when it exists (if captions.update is false)
// Filter out removed tracks and tracks that aren't captions/subtitles (for example metadata)
return tracks.filter(function (track) {
return !_this2.isHTML5 || update || _this2.captions.meta.has(track);
}).filter(function (track) {
return ['captions', 'subtitles'].includes(track.kind); return ['captions', 'subtitles'].includes(track.kind);
}); });
}, },
@@ -3401,32 +3497,20 @@ var captions = {
// Get the current track for the current language // Get the current track for the current language
getCurrentTrack: function getCurrentTrack() { getCurrentTrack: function getCurrentTrack() {
var _this2 = this; var _this3 = this;
var fromLanguage = arguments.length > 0 && arguments[0] !== undefined ? arguments[0] : false;
var tracks = captions.getTracks.call(this); var tracks = captions.getTracks.call(this);
var sortIsDefault = function sortIsDefault(track) {
if (!tracks.length) { return Number((_this3.captions.meta.get(track) || {}).default);
return null; };
} var sorted = Array.from(tracks).sort(function (a, b) {
return sortIsDefault(b) - sortIsDefault(a);
// Get track based on current language
var track = tracks.find(function (track) {
return track.language.toLowerCase() === _this2.language;
}); });
return !fromLanguage && tracks[this.currentTrack] || sorted.find(function (track) {
// Get the <track> with default attribute return track.language === _this3.captions.language;
if (!track) { }) || sorted[0];
track = utils.getElement.call(this, 'track[default]');
}
// Get the first track
if (!track) {
var _tracks = slicedToArray(tracks, 1);
track = _tracks[0];
}
return track;
}, },
@@ -3454,58 +3538,50 @@ var captions = {
}, },
// Display active caption if it contains text // Update captions using current track's active cues
setCue: function setCue(input) { // Also optional array argument in case there isn't any track (ex: vimeo)
// Get the track from the event if needed updateCues: function updateCues(input) {
var track = utils.is.event(input) ? input.target : input;
var activeCues = track.activeCues;
var active = activeCues.length && activeCues[0];
var currentTrack = captions.getCurrentTrack.call(this);
// Only display current track
if (track !== currentTrack) {
return;
}
// Display a cue, if there is one
if (utils.is.cue(active)) {
captions.setText.call(this, active.getCueAsHTML());
} else {
captions.setText.call(this, null);
}
utils.dispatchEvent.call(this, this.media, 'cuechange');
},
// Set the current caption
setText: function setText(input) {
// Requires UI // Requires UI
if (!this.supported.ui) { if (!this.supported.ui) {
return; return;
} }
if (utils.is.element(this.elements.captions)) { if (!utils.is.element(this.elements.captions)) {
var content = utils.createElement('span');
// Empty the container
utils.emptyElement(this.elements.captions);
// Default to empty
var caption = !utils.is.nullOrUndefined(input) ? input : '';
// Set the span content
if (utils.is.string(caption)) {
content.innerText = caption.trim();
} else {
content.appendChild(caption);
}
// Set new caption text
this.elements.captions.appendChild(content);
} else {
this.debug.warn('No captions element to render to'); this.debug.warn('No captions element to render to');
return;
}
// Only accept array or empty input
if (!utils.is.nullOrUndefined(input) && !Array.isArray(input)) {
this.debug.warn('updateCues: Invalid input', input);
return;
}
var cues = input;
// Get cues from track
if (!cues) {
var track = captions.getCurrentTrack.call(this);
cues = Array.from((track || {}).activeCues || []).map(function (cue) {
return cue.getCueAsHTML();
}).map(utils.getHTML);
}
// Set new caption text
var content = cues.map(function (cueText) {
return cueText.trim();
}).join('\n');
var changed = content !== this.elements.captions.innerHTML;
if (changed) {
// Empty the container and create a new child element
utils.emptyElement(this.elements.captions);
var caption = utils.createElement('span', utils.getAttributesFromSelector(this.config.selectors.caption));
caption.innerHTML = content;
this.elements.captions.appendChild(caption);
// Trigger event
utils.dispatchEvent.call(this, this.media, 'cuechange');
} }
} }
}; };
@@ -3809,6 +3885,7 @@ var defaults$1 = {
}, },
progress: '.plyr__progress', progress: '.plyr__progress',
captions: '.plyr__captions', captions: '.plyr__captions',
caption: '.plyr__caption',
menu: { menu: {
quality: '.js-plyr__menu__list--quality' quality: '.js-plyr__menu__list--quality'
} }
@@ -4787,9 +4864,11 @@ var Listeners = function () {
// Proxy events to container // Proxy events to container
// Bubble up key events for Edge // Bubble up key events for Edge
utils.on(this.player.media, this.player.config.events.concat(['keyup', 'keydown']).join(' '), function (event) { utils.on(this.player.media, this.player.config.events.concat(['keyup', 'keydown']).join(' '), function (event) {
var detail = {}; var _event$detail = event.detail,
detail = _event$detail === undefined ? {} : _event$detail;
// Get error details from media // Get error details from media
if (event.type === 'error') { if (event.type === 'error') {
detail = _this3.player.media.error; detail = _this3.player.media.error;
} }
@@ -4888,7 +4967,7 @@ var Listeners = function () {
// 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, _this4.player.config.selectors.inputs.language)) { if (utils.matches(event.target, _this4.player.config.selectors.inputs.language)) {
proxy(event, function () { proxy(event, function () {
_this4.player.language = event.target.value; _this4.player.currentTrack = Number(event.target.value);
showHomeTab(); showHomeTab();
}, 'language'); }, 'language');
} else if (utils.matches(event.target, _this4.player.config.selectors.inputs.quality)) { } else if (utils.matches(event.target, _this4.player.config.selectors.inputs.quality)) {
@@ -5083,6 +5162,9 @@ var Listeners = function () {
// Set playback state and trigger change (only on actual change) // Set playback state and trigger change (only on actual change)
function assurePlaybackState(play) { function assurePlaybackState(play) {
if (play && !this.embed.hasPlayed) {
this.embed.hasPlayed = true;
}
if (this.media.paused === play) { if (this.media.paused === play) {
this.media.paused = !play; this.media.paused = !play;
utils.dispatchEvent.call(this, this.media, play ? 'play' : 'pause'); utils.dispatchEvent.call(this, this.media, play ? 'play' : 'pause');
@@ -5235,24 +5317,25 @@ var vimeo = {
paused = player.paused, paused = player.paused,
volume = player.volume; volume = player.volume;
// Set seeking state and trigger event var restorePause = paused && !embed.hasPlayed;
// Set seeking state and trigger event
media.seeking = true; media.seeking = true;
utils.dispatchEvent.call(player, media, 'seeking'); utils.dispatchEvent.call(player, media, 'seeking');
// If paused, mute until seek is complete // If paused, mute until seek is complete
Promise.resolve(paused && embed.setVolume(0)) Promise.resolve(restorePause && embed.setVolume(0))
// Seek // Seek
.then(function () { .then(function () {
return embed.setCurrentTime(time); return embed.setCurrentTime(time);
}) })
// Restore paused // Restore paused
.then(function () { .then(function () {
return paused && embed.pause(); return restorePause && embed.pause();
}) })
// Restore volume // Restore volume
.then(function () { .then(function () {
return paused && embed.setVolume(volume); return restorePause && embed.setVolume(volume);
}).catch(function () { }).catch(function () {
// Do nothing // Do nothing
}); });
@@ -5382,17 +5465,25 @@ var vimeo = {
captions.setup.call(player); captions.setup.call(player);
}); });
player.embed.on('cuechange', function (data) { player.embed.on('cuechange', function (_ref) {
var cue = null; var _ref$cues = _ref.cues,
cues = _ref$cues === undefined ? [] : _ref$cues;
if (data.cues.length) { var strippedCues = cues.map(function (cue) {
cue = utils.stripHTML(data.cues[0].text); return utils.stripHTML(cue.text);
} });
captions.updateCues.call(player, strippedCues);
captions.setText.call(player, cue);
}); });
player.embed.on('loaded', function () { player.embed.on('loaded', function () {
// Assure state and events are updated on autoplay
player.embed.getPaused().then(function (paused) {
assurePlaybackState.call(player, !paused);
if (!paused) {
utils.dispatchEvent.call(player, player.media, 'playing');
}
});
if (utils.is.element(player.embed.element) && player.supported.ui) { if (utils.is.element(player.embed.element) && player.supported.ui) {
var frame = player.embed.element; var frame = player.embed.element;
@@ -5522,6 +5613,9 @@ function mapQualityUnits(levels) {
// Set playback state and trigger change (only on actual change) // Set playback state and trigger change (only on actual change)
function assurePlaybackState$1(play) { function assurePlaybackState$1(play) {
if (play && !this.embed.hasPlayed) {
this.embed.hasPlayed = true;
}
if (this.media.paused === play) { if (this.media.paused === play) {
this.media.paused = !play; this.media.paused = !play;
utils.dispatchEvent.call(this, this.media, play ? 'play' : 'pause'); utils.dispatchEvent.call(this, this.media, play ? 'play' : 'pause');
@@ -5935,7 +6029,7 @@ var youtube = {
case 1: case 1:
// Restore paused state (YouTube starts playing on seek if the video hasn't been played yet) // Restore paused state (YouTube starts playing on seek if the video hasn't been played yet)
if (player.media.paused) { if (player.media.paused && !player.embed.hasPlayed) {
player.media.pause(); player.media.pause();
} else { } else {
assurePlaybackState$1.call(player, true); assurePlaybackState$1.call(player, true);
@@ -6926,7 +7020,8 @@ var Plyr = function () {
// Captions // Captions
this.captions = { this.captions = {
active: null, active: null,
currentTrack: null currentTrack: -1,
meta: new WeakMap()
}; };
// Fullscreen // Fullscreen
@@ -6937,8 +7032,7 @@ var Plyr = function () {
// Options // Options
this.options = { this.options = {
speed: [], speed: [],
quality: [], quality: []
captions: []
}; };
// Debugging // Debugging
@@ -7314,8 +7408,8 @@ var Plyr = function () {
} }
/** /**
* Set the captions language * Set the caption track by index
* @param {string} - Two character ISO language code (e.g. EN, FR, PT, etc) * @param {number} - Caption index
*/ */
}, { }, {
@@ -8006,60 +8100,41 @@ var Plyr = function () {
return Boolean(this.config.autoplay); return Boolean(this.config.autoplay);
} }
}, { }, {
key: 'language', key: 'currentTrack',
set: function set$$1(input) { set: function set$$1(input) {
// Nothing specified captions.set.call(this, input);
if (!utils.is.string(input)) {
return;
}
// If empty string is passed, assume disable captions
if (utils.is.empty(input)) {
this.toggleCaptions(false);
return;
}
// Normalize
var language = input.toLowerCase();
// Check for support
if (!this.options.captions.includes(language)) {
this.debug.warn('Unsupported language option: ' + language);
return;
}
// Ensure captions are enabled
this.toggleCaptions(true);
// Enabled only
if (language === 'enabled') {
return;
}
// If nothing to change, bail
if (this.language === language) {
return;
}
// Update config
this.captions.language = language;
// Clear caption
captions.setText.call(this, null);
// Update captions
captions.setLanguage.call(this);
// Trigger an event
utils.dispatchEvent.call(this, this.media, 'languagechange');
} }
/** /**
* Get the current captions language * Get the current caption track index (-1 if disabled)
*/ */
, ,
get: function get$$1() { get: function get$$1() {
return this.captions.language; var _captions = this.captions,
active = _captions.active,
currentTrack = _captions.currentTrack;
return active ? currentTrack : -1;
}
/**
* Set the wanted language for captions
* Since tracks can be added later it won't update the actual caption track until there is a matching track
* @param {string} - Two character ISO language code (e.g. EN, FR, PT, etc)
*/
}, {
key: 'language',
set: function set$$1(input) {
captions.setLanguage.call(this, input);
}
/**
* Get the current track's language
*/
,
get: function get$$1() {
return (captions.getCurrentTrack.call(this) || {}).language;
} }
/** /**
@@ -8135,9 +8210,7 @@ var Plyr = function () {
} else if (utils.is.nodeList(selector)) { } else if (utils.is.nodeList(selector)) {
targets = Array.from(selector); targets = Array.from(selector);
} else if (utils.is.array(selector)) { } else if (utils.is.array(selector)) {
targets = selector.filter(function (i) { targets = selector.filter(utils.is.element);
return utils.is.element(i);
});
} }
if (utils.is.empty(targets)) { if (utils.is.empty(targets)) {
+1 -1
View File
File diff suppressed because one or more lines are too long
+1 -1
View File
File diff suppressed because one or more lines are too long
+1 -1
View File
File diff suppressed because one or more lines are too long
+329 -256
View File
@@ -5876,61 +5876,63 @@ var utils = {
// Check variable types // Check variable types
is: { is: {
object: function object(input) { object: function object(input) {
return this.getConstructor(input) === Object; return utils.getConstructor(input) === Object;
}, },
number: function number(input) { number: function number(input) {
return this.getConstructor(input) === Number && !Number.isNaN(input); return utils.getConstructor(input) === Number && !Number.isNaN(input);
}, },
string: function string(input) { string: function string(input) {
return this.getConstructor(input) === String; return utils.getConstructor(input) === String;
}, },
boolean: function boolean(input) { boolean: function boolean(input) {
return this.getConstructor(input) === Boolean; return utils.getConstructor(input) === Boolean;
}, },
function: function _function(input) { function: function _function(input) {
return this.getConstructor(input) === Function; return utils.getConstructor(input) === Function;
}, },
array: function array(input) { array: function array(input) {
return !this.nullOrUndefined(input) && Array.isArray(input); return !utils.is.nullOrUndefined(input) && Array.isArray(input);
}, },
weakMap: function weakMap(input) { weakMap: function weakMap(input) {
return this.instanceof(input, WeakMap); return utils.is.instanceof(input, WeakMap);
}, },
nodeList: function nodeList(input) { nodeList: function nodeList(input) {
return this.instanceof(input, NodeList); return utils.is.instanceof(input, NodeList);
}, },
element: function element(input) { element: function element(input) {
return this.instanceof(input, Element); return utils.is.instanceof(input, Element);
}, },
textNode: function textNode(input) { textNode: function textNode(input) {
return this.getConstructor(input) === Text; return utils.getConstructor(input) === Text;
}, },
event: function event(input) { event: function event(input) {
return this.instanceof(input, Event); return utils.is.instanceof(input, Event);
}, },
cue: function cue(input) { cue: function cue(input) {
return this.instanceof(input, window.TextTrackCue) || this.instanceof(input, window.VTTCue); return utils.is.instanceof(input, window.TextTrackCue) || utils.is.instanceof(input, window.VTTCue);
}, },
track: function track(input) { track: function track(input) {
return this.instanceof(input, TextTrack) || !this.nullOrUndefined(input) && this.string(input.kind); return utils.is.instanceof(input, TextTrack) || !utils.is.nullOrUndefined(input) && utils.is.string(input.kind);
}, },
url: function url(input) { url: function url(input) {
return !this.nullOrUndefined(input) && /(ftp|http|https):\/\/(\w+:{0,1}\w*@)?(\S+)(:[0-9]+)?(\/|\/([\w#!:.?+=&%@!\-/]))?/.test(input); return !utils.is.nullOrUndefined(input) && /(ftp|http|https):\/\/(\w+:{0,1}\w*@)?(\S+)(:[0-9]+)?(\/|\/([\w#!:.?+=&%@!\-/]))?/.test(input);
}, },
nullOrUndefined: function nullOrUndefined(input) { nullOrUndefined: function nullOrUndefined(input) {
return input === null || typeof input === 'undefined'; return input === null || typeof input === 'undefined';
}, },
empty: function empty(input) { empty: function empty(input) {
return this.nullOrUndefined(input) || (this.string(input) || this.array(input) || this.nodeList(input)) && !input.length || this.object(input) && !Object.keys(input).length; return utils.is.nullOrUndefined(input) || (utils.is.string(input) || utils.is.array(input) || utils.is.nodeList(input)) && !input.length || utils.is.object(input) && !Object.keys(input).length;
}, },
instanceof: function _instanceof$$1(input, constructor) { instanceof: function _instanceof$$1(input, constructor) {
return Boolean(input && constructor && input instanceof constructor); return Boolean(input && constructor && input instanceof constructor);
},
getConstructor: function getConstructor(input) {
return !this.nullOrUndefined(input) ? input.constructor : null;
} }
}, },
getConstructor: function getConstructor(input) {
return !utils.is.nullOrUndefined(input) ? input.constructor : null;
},
// Unfortunately, due to mixed support, UA sniffing is required // Unfortunately, due to mixed support, UA sniffing is required
getBrowser: function getBrowser() { getBrowser: function getBrowser() {
return { return {
@@ -6550,7 +6552,7 @@ var utils = {
// Bail if the value isn't a number // Bail if the value isn't a number
if (!utils.is.number(time)) { if (!utils.is.number(time)) {
return this.formatTime(null, displayHours, inverted); return utils.formatTime(null, displayHours, inverted);
} }
// Format time component to add leading zero // Format time component to add leading zero
@@ -6559,9 +6561,9 @@ var utils = {
}; };
// Breakdown to hours, mins, secs // Breakdown to hours, mins, secs
var hours = this.getHours(time); var hours = utils.getHours(time);
var mins = this.getMinutes(time); var mins = utils.getMinutes(time);
var secs = this.getSeconds(time); var secs = utils.getSeconds(time);
// Do we need to display hours? // Do we need to display hours?
if (displayHours || hours > 0) { if (displayHours || hours > 0) {
@@ -6757,12 +6759,12 @@ var utils = {
// Parse URL if needed // Parse URL if needed
if (input.startsWith('http://') || input.startsWith('https://')) { if (input.startsWith('http://') || input.startsWith('https://')) {
var _parseUrl = this.parseUrl(input); var _utils$parseUrl = utils.parseUrl(input);
search = _parseUrl.search; search = _utils$parseUrl.search;
} }
if (this.is.empty(search)) { if (utils.is.empty(search)) {
return null; return null;
} }
@@ -6801,6 +6803,14 @@ var utils = {
}, },
// Like outerHTML, but also works for DocumentFragment
getHTML: function getHTML(element) {
var wrapper = document.createElement('div');
wrapper.appendChild(element);
return wrapper.innerHTML;
},
// Get aspect ratio for dimensions // Get aspect ratio for dimensions
getAspectRatio: function getAspectRatio(width, height) { getAspectRatio: function getAspectRatio(width, height) {
var getRatio = function getRatio(w, h) { var getRatio = function getRatio(w, h) {
@@ -7542,9 +7552,15 @@ var controls = {
// Create a settings menu item // Create a settings menu item
createMenuItem: function createMenuItem(value, list, type, title) { createMenuItem: function createMenuItem(_ref) {
var badge = arguments.length > 4 && arguments[4] !== undefined ? arguments[4] : null; var value = _ref.value,
var checked = arguments.length > 5 && arguments[5] !== undefined ? arguments[5] : false; list = _ref.list,
type = _ref.type,
title = _ref.title,
_ref$badge = _ref.badge,
badge = _ref$badge === undefined ? null : _ref$badge,
_ref$checked = _ref.checked,
checked = _ref$checked === undefined ? false : _ref$checked;
var item = utils.createElement('li'); var item = utils.createElement('li');
@@ -7860,8 +7876,13 @@ var controls = {
var sorting = _this3.config.quality.options; var sorting = _this3.config.quality.options;
return sorting.indexOf(a) > sorting.indexOf(b) ? 1 : -1; return sorting.indexOf(a) > sorting.indexOf(b) ? 1 : -1;
}).forEach(function (quality) { }).forEach(function (quality) {
var label = controls.getLabel.call(_this3, 'quality', quality); controls.createMenuItem.call(_this3, {
controls.createMenuItem.call(_this3, quality, list, type, label, getBadge(quality)); value: quality,
list: list,
type: type,
title: controls.getLabel.call(_this3, 'quality', quality),
badge: getBadge(quality)
});
}); });
controls.updateSetting.call(this, type, list); controls.updateSetting.call(this, type, list);
@@ -7904,18 +7925,7 @@ var controls = {
switch (setting) { switch (setting) {
case 'captions': case 'captions':
if (this.captions.active) { value = this.currentTrack;
if (this.options.captions.length > 2 || !this.options.captions.some(function (lang) {
return lang === 'enabled';
})) {
value = this.captions.language;
} else {
value = 'enabled';
}
} else {
value = '';
}
break; break;
default: default:
@@ -8010,10 +8020,10 @@ var controls = {
// TODO: Captions or language? Currently it's mixed // TODO: Captions or language? Currently it's mixed
var type = 'captions'; var type = 'captions';
var list = this.elements.settings.panes.captions.querySelector('ul'); var list = this.elements.settings.panes.captions.querySelector('ul');
var tracks = captions.getTracks.call(this);
// Toggle the pane and tab // Toggle the pane and tab
var toggle = captions.getTracks.call(this).length; controls.toggleTab.call(this, type, tracks.length);
controls.toggleTab.call(this, type, toggle);
// Empty the menu // Empty the menu
utils.emptyElement(list); utils.emptyElement(list);
@@ -8022,28 +8032,33 @@ var controls = {
controls.checkMenu.call(this); controls.checkMenu.call(this);
// If there's no captions, bail // If there's no captions, bail
if (!toggle) { if (!tracks.length) {
return; return;
} }
// Re-map the tracks into just the data we need // Generate options data
var tracks = captions.getTracks.call(this).map(function (track) { var options = tracks.map(function (track, value) {
return { return {
language: !utils.is.empty(track.language) ? track.language : 'enabled', value: value,
label: captions.getLabel.call(_this4, track) checked: _this4.captions.active && _this4.currentTrack === value,
title: captions.getLabel.call(_this4, track),
badge: track.language && controls.createBadge.call(_this4, track.language.toUpperCase()),
list: list,
type: 'language'
}; };
}); });
// Add the "Disabled" option to turn off captions // Add the "Disabled" option to turn off captions
tracks.unshift({ options.unshift({
language: '', value: -1,
label: i18n.get('disabled', this.config) checked: !this.captions.active,
title: i18n.get('disabled', this.config),
list: list,
type: 'language'
}); });
// Generate options // Generate options
tracks.forEach(function (track) { options.forEach(controls.createMenuItem.bind(this));
controls.createMenuItem.call(_this4, track.language, list, 'language', track.label, track.language !== 'enabled' ? controls.createBadge.call(_this4, track.language.toUpperCase()) : null, track.language.toLowerCase() === _this4.language);
});
controls.updateSetting.call(this, type, list); controls.updateSetting.call(this, type, list);
}, },
@@ -8097,8 +8112,12 @@ var controls = {
// Create items // Create items
this.options.speed.forEach(function (speed) { this.options.speed.forEach(function (speed) {
var label = controls.getLabel.call(_this5, 'speed', speed); controls.createMenuItem.call(_this5, {
controls.createMenuItem.call(_this5, speed, list, type, label); value: speed,
list: list,
type: type,
title: controls.getLabel.call(_this5, 'speed', speed)
});
}); });
controls.updateSetting.call(this, type, list); controls.updateSetting.call(this, type, list);
@@ -8572,10 +8591,10 @@ var controls = {
var replace = function replace(input) { var replace = function replace(input) {
var result = input; var result = input;
Object.entries(props).forEach(function (_ref) { Object.entries(props).forEach(function (_ref2) {
var _ref2 = slicedToArray(_ref, 2), var _ref3 = slicedToArray(_ref2, 2),
key = _ref2[0], key = _ref3[0],
value = _ref2[1]; value = _ref3[1];
result = utils.replaceAll(result, '{' + key + '}', value); result = utils.replaceAll(result, '{' + key + '}', value);
}); });
@@ -8692,91 +8711,168 @@ var captions = {
active = this.config.captions.active; active = this.config.captions.active;
} }
// Set toggled state // Get language from storage, fallback to config
this.toggleCaptions(active); var language = this.storage.get('language') || this.config.captions.language;
if (language === 'auto') {
var _split = (navigator.language || navigator.userLanguage).split('-');
var _split2 = slicedToArray(_split, 1);
language = _split2[0];
}
// Set language and show if active
captions.setLanguage.call(this, language, active);
// Watch changes to textTracks and update captions menu // Watch changes to textTracks and update captions menu
if (this.config.captions.update) { if (this.isHTML5) {
utils.on(this.media.textTracks, 'addtrack removetrack', captions.update.bind(this)); var trackEvents = this.config.captions.update ? 'addtrack removetrack' : 'removetrack';
utils.on(this.media.textTracks, trackEvents, captions.update.bind(this));
} }
// Update available languages in list next tick (the event must not be triggered before the listeners) // Update available languages in list next tick (the event must not be triggered before the listeners)
setTimeout(captions.update.bind(this), 0); setTimeout(captions.update.bind(this), 0);
}, },
update: function update() { update: function update() {
// Update tracks var _this = this;
var tracks = captions.getTracks.call(this);
this.options.captions = tracks.map(function (_ref) {
var language = _ref.language;
return language;
});
// Set language if it hasn't been set already var tracks = captions.getTracks.call(this, true);
if (!this.language) { // Get the wanted language
var language = this.config.captions.language; var _captions = this.captions,
language = _captions.language,
meta = _captions.meta;
if (language === 'auto') { // Handle tracks (add event listener and "pseudo"-default)
var _split = (navigator.language || navigator.userLanguage).split('-');
var _split2 = slicedToArray(_split, 1); if (this.isHTML5 && this.isVideo) {
tracks.filter(function (track) {
return !meta.get(track);
}).forEach(function (track) {
_this.debug.log('Track added', track);
// Attempt to store if the original dom element was "default"
meta.set(track, {
default: track.mode === 'showing'
});
language = _split2[0]; // Turn off native caption rendering to avoid double captions
} track.mode = 'hidden';
this.language = this.storage.get('language') || (language || '').toLowerCase();
// Add event listener for cue changes
utils.on(track, 'cuechange', function () {
return captions.updateCues.call(_this);
});
});
} }
// Toggle the class hooks var trackRemoved = !tracks.find(function (track) {
utils.toggleClass(this.elements.container, this.config.classNames.captions.enabled, !utils.is.empty(captions.getTracks.call(this))); return track === _this.captions.currentTrackNode;
});
var firstMatch = this.language !== language && tracks.find(function (track) {
return track.language === language;
});
// Update language if removed or first matching track added
if (trackRemoved || firstMatch) {
captions.setLanguage.call(this, language, this.config.captions.active);
}
// Enable or disable captions based on track length
utils.toggleClass(this.elements.container, this.config.classNames.captions.enabled, !utils.is.empty(tracks));
// Update available languages in list // Update available languages in list
if ((this.config.controls || []).includes('settings') && this.config.settings.includes('captions')) { if ((this.config.controls || []).includes('settings') && this.config.settings.includes('captions')) {
controls.setCaptionsMenu.call(this); controls.setCaptionsMenu.call(this);
} }
}, },
set: function set(index) {
var setLanguage = arguments.length > 1 && arguments[1] !== undefined ? arguments[1] : true;
var show = arguments.length > 2 && arguments[2] !== undefined ? arguments[2] : true;
var tracks = captions.getTracks.call(this);
// Set the captions language // Disable captions if setting to -1
setLanguage: function setLanguage() { if (index === -1) {
var _this = this; this.toggleCaptions(false);
return;
// Setup HTML5 track rendering
if (this.isHTML5 && this.isVideo) {
captions.getTracks.call(this).forEach(function (track) {
// Show track
utils.on(track, 'cuechange', function (event) {
return captions.setCue.call(_this, event);
});
// Turn off native caption rendering to avoid double captions
// eslint-disable-next-line
track.mode = 'hidden';
});
// Get current track
var currentTrack = captions.getCurrentTrack.call(this);
// Check if suported kind
if (utils.is.track(currentTrack)) {
// If we change the active track while a cue is already displayed we need to update it
if (Array.from(currentTrack.activeCues || []).length) {
captions.setCue.call(this, currentTrack);
}
}
} else if (this.isVimeo && this.captions.active) {
this.embed.enableTextTrack(this.language);
} }
if (!utils.is.number(index)) {
this.debug.warn('Invalid caption argument', index);
return;
}
if (!(index in tracks)) {
this.debug.warn('Track not found', index);
return;
}
if (this.captions.currentTrack !== index) {
this.captions.currentTrack = index;
var track = captions.getCurrentTrack.call(this);
var _ref = track || {},
language = _ref.language;
// Store reference to node for invalidation on remove
this.captions.currentTrackNode = track;
// Prevent setting language in some cases, since it can violate user's intentions
if (setLanguage) {
this.captions.language = language;
}
// Handle Vimeo captions
if (this.isVimeo) {
this.embed.enableTextTrack(language);
}
// Trigger event
utils.dispatchEvent.call(this, this.media, 'languagechange');
}
if (this.isHTML5 && this.isVideo) {
// If we change the active track while a cue is already displayed we need to update it
captions.updateCues.call(this);
}
// Show captions
if (show) {
this.toggleCaptions(true);
}
},
setLanguage: function setLanguage(language) {
var show = arguments.length > 1 && arguments[1] !== undefined ? arguments[1] : true;
if (!utils.is.string(language)) {
this.debug.warn('Invalid language argument', language);
return;
}
// Normalize
this.captions.language = language.toLowerCase();
// Set currentTrack
var tracks = captions.getTracks.call(this);
var track = captions.getCurrentTrack.call(this, true);
captions.set.call(this, tracks.indexOf(track), false, show);
}, },
// Get the tracks // Get current valid caption tracks
// If update is false it will also ignore tracks without metadata
// This is used to "freeze" the language options when captions.update is false
getTracks: function getTracks() { getTracks: function getTracks() {
// Return empty array at least var _this2 = this;
if (utils.is.nullOrUndefined(this.media)) {
return [];
}
// Only get accepted kinds var update = arguments.length > 0 && arguments[0] !== undefined ? arguments[0] : false;
return Array.from(this.media.textTracks || []).filter(function (track) {
// Handle media or textTracks missing or null
var tracks = Array.from((this.media || {}).textTracks || []);
// For HTML5, use cache instead of current tracks when it exists (if captions.update is false)
// Filter out removed tracks and tracks that aren't captions/subtitles (for example metadata)
return tracks.filter(function (track) {
return !_this2.isHTML5 || update || _this2.captions.meta.has(track);
}).filter(function (track) {
return ['captions', 'subtitles'].includes(track.kind); return ['captions', 'subtitles'].includes(track.kind);
}); });
}, },
@@ -8784,32 +8880,20 @@ var captions = {
// Get the current track for the current language // Get the current track for the current language
getCurrentTrack: function getCurrentTrack() { getCurrentTrack: function getCurrentTrack() {
var _this2 = this; var _this3 = this;
var fromLanguage = arguments.length > 0 && arguments[0] !== undefined ? arguments[0] : false;
var tracks = captions.getTracks.call(this); var tracks = captions.getTracks.call(this);
var sortIsDefault = function sortIsDefault(track) {
if (!tracks.length) { return Number((_this3.captions.meta.get(track) || {}).default);
return null; };
} var sorted = Array.from(tracks).sort(function (a, b) {
return sortIsDefault(b) - sortIsDefault(a);
// Get track based on current language
var track = tracks.find(function (track) {
return track.language.toLowerCase() === _this2.language;
}); });
return !fromLanguage && tracks[this.currentTrack] || sorted.find(function (track) {
// Get the <track> with default attribute return track.language === _this3.captions.language;
if (!track) { }) || sorted[0];
track = utils.getElement.call(this, 'track[default]');
}
// Get the first track
if (!track) {
var _tracks = slicedToArray(tracks, 1);
track = _tracks[0];
}
return track;
}, },
@@ -8837,58 +8921,50 @@ var captions = {
}, },
// Display active caption if it contains text // Update captions using current track's active cues
setCue: function setCue(input) { // Also optional array argument in case there isn't any track (ex: vimeo)
// Get the track from the event if needed updateCues: function updateCues(input) {
var track = utils.is.event(input) ? input.target : input;
var activeCues = track.activeCues;
var active = activeCues.length && activeCues[0];
var currentTrack = captions.getCurrentTrack.call(this);
// Only display current track
if (track !== currentTrack) {
return;
}
// Display a cue, if there is one
if (utils.is.cue(active)) {
captions.setText.call(this, active.getCueAsHTML());
} else {
captions.setText.call(this, null);
}
utils.dispatchEvent.call(this, this.media, 'cuechange');
},
// Set the current caption
setText: function setText(input) {
// Requires UI // Requires UI
if (!this.supported.ui) { if (!this.supported.ui) {
return; return;
} }
if (utils.is.element(this.elements.captions)) { if (!utils.is.element(this.elements.captions)) {
var content = utils.createElement('span');
// Empty the container
utils.emptyElement(this.elements.captions);
// Default to empty
var caption = !utils.is.nullOrUndefined(input) ? input : '';
// Set the span content
if (utils.is.string(caption)) {
content.innerText = caption.trim();
} else {
content.appendChild(caption);
}
// Set new caption text
this.elements.captions.appendChild(content);
} else {
this.debug.warn('No captions element to render to'); this.debug.warn('No captions element to render to');
return;
}
// Only accept array or empty input
if (!utils.is.nullOrUndefined(input) && !Array.isArray(input)) {
this.debug.warn('updateCues: Invalid input', input);
return;
}
var cues = input;
// Get cues from track
if (!cues) {
var track = captions.getCurrentTrack.call(this);
cues = Array.from((track || {}).activeCues || []).map(function (cue) {
return cue.getCueAsHTML();
}).map(utils.getHTML);
}
// Set new caption text
var content = cues.map(function (cueText) {
return cueText.trim();
}).join('\n');
var changed = content !== this.elements.captions.innerHTML;
if (changed) {
// Empty the container and create a new child element
utils.emptyElement(this.elements.captions);
var caption = utils.createElement('span', utils.getAttributesFromSelector(this.config.selectors.caption));
caption.innerHTML = content;
this.elements.captions.appendChild(caption);
// Trigger event
utils.dispatchEvent.call(this, this.media, 'cuechange');
} }
} }
}; };
@@ -9192,6 +9268,7 @@ var defaults$1 = {
}, },
progress: '.plyr__progress', progress: '.plyr__progress',
captions: '.plyr__captions', captions: '.plyr__captions',
caption: '.plyr__caption',
menu: { menu: {
quality: '.js-plyr__menu__list--quality' quality: '.js-plyr__menu__list--quality'
} }
@@ -10170,9 +10247,11 @@ var Listeners = function () {
// Proxy events to container // Proxy events to container
// Bubble up key events for Edge // Bubble up key events for Edge
utils.on(this.player.media, this.player.config.events.concat(['keyup', 'keydown']).join(' '), function (event) { utils.on(this.player.media, this.player.config.events.concat(['keyup', 'keydown']).join(' '), function (event) {
var detail = {}; var _event$detail = event.detail,
detail = _event$detail === undefined ? {} : _event$detail;
// Get error details from media // Get error details from media
if (event.type === 'error') { if (event.type === 'error') {
detail = _this3.player.media.error; detail = _this3.player.media.error;
} }
@@ -10271,7 +10350,7 @@ var Listeners = function () {
// 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, _this4.player.config.selectors.inputs.language)) { if (utils.matches(event.target, _this4.player.config.selectors.inputs.language)) {
proxy(event, function () { proxy(event, function () {
_this4.player.language = event.target.value; _this4.player.currentTrack = Number(event.target.value);
showHomeTab(); showHomeTab();
}, 'language'); }, 'language');
} else if (utils.matches(event.target, _this4.player.config.selectors.inputs.quality)) { } else if (utils.matches(event.target, _this4.player.config.selectors.inputs.quality)) {
@@ -10466,6 +10545,9 @@ var Listeners = function () {
// Set playback state and trigger change (only on actual change) // Set playback state and trigger change (only on actual change)
function assurePlaybackState(play) { function assurePlaybackState(play) {
if (play && !this.embed.hasPlayed) {
this.embed.hasPlayed = true;
}
if (this.media.paused === play) { if (this.media.paused === play) {
this.media.paused = !play; this.media.paused = !play;
utils.dispatchEvent.call(this, this.media, play ? 'play' : 'pause'); utils.dispatchEvent.call(this, this.media, play ? 'play' : 'pause');
@@ -10618,24 +10700,25 @@ var vimeo = {
paused = player.paused, paused = player.paused,
volume = player.volume; volume = player.volume;
// Set seeking state and trigger event var restorePause = paused && !embed.hasPlayed;
// Set seeking state and trigger event
media.seeking = true; media.seeking = true;
utils.dispatchEvent.call(player, media, 'seeking'); utils.dispatchEvent.call(player, media, 'seeking');
// If paused, mute until seek is complete // If paused, mute until seek is complete
Promise.resolve(paused && embed.setVolume(0)) Promise.resolve(restorePause && embed.setVolume(0))
// Seek // Seek
.then(function () { .then(function () {
return embed.setCurrentTime(time); return embed.setCurrentTime(time);
}) })
// Restore paused // Restore paused
.then(function () { .then(function () {
return paused && embed.pause(); return restorePause && embed.pause();
}) })
// Restore volume // Restore volume
.then(function () { .then(function () {
return paused && embed.setVolume(volume); return restorePause && embed.setVolume(volume);
}).catch(function () { }).catch(function () {
// Do nothing // Do nothing
}); });
@@ -10765,17 +10848,25 @@ var vimeo = {
captions.setup.call(player); captions.setup.call(player);
}); });
player.embed.on('cuechange', function (data) { player.embed.on('cuechange', function (_ref) {
var cue = null; var _ref$cues = _ref.cues,
cues = _ref$cues === undefined ? [] : _ref$cues;
if (data.cues.length) { var strippedCues = cues.map(function (cue) {
cue = utils.stripHTML(data.cues[0].text); return utils.stripHTML(cue.text);
} });
captions.updateCues.call(player, strippedCues);
captions.setText.call(player, cue);
}); });
player.embed.on('loaded', function () { player.embed.on('loaded', function () {
// Assure state and events are updated on autoplay
player.embed.getPaused().then(function (paused) {
assurePlaybackState.call(player, !paused);
if (!paused) {
utils.dispatchEvent.call(player, player.media, 'playing');
}
});
if (utils.is.element(player.embed.element) && player.supported.ui) { if (utils.is.element(player.embed.element) && player.supported.ui) {
var frame = player.embed.element; var frame = player.embed.element;
@@ -10905,6 +10996,9 @@ function mapQualityUnits(levels) {
// Set playback state and trigger change (only on actual change) // Set playback state and trigger change (only on actual change)
function assurePlaybackState$1(play) { function assurePlaybackState$1(play) {
if (play && !this.embed.hasPlayed) {
this.embed.hasPlayed = true;
}
if (this.media.paused === play) { if (this.media.paused === play) {
this.media.paused = !play; this.media.paused = !play;
utils.dispatchEvent.call(this, this.media, play ? 'play' : 'pause'); utils.dispatchEvent.call(this, this.media, play ? 'play' : 'pause');
@@ -11318,7 +11412,7 @@ var youtube = {
case 1: case 1:
// Restore paused state (YouTube starts playing on seek if the video hasn't been played yet) // Restore paused state (YouTube starts playing on seek if the video hasn't been played yet)
if (player.media.paused) { if (player.media.paused && !player.embed.hasPlayed) {
player.media.pause(); player.media.pause();
} else { } else {
assurePlaybackState$1.call(player, true); assurePlaybackState$1.call(player, true);
@@ -12309,7 +12403,8 @@ var Plyr = function () {
// Captions // Captions
this.captions = { this.captions = {
active: null, active: null,
currentTrack: null currentTrack: -1,
meta: new WeakMap()
}; };
// Fullscreen // Fullscreen
@@ -12320,8 +12415,7 @@ var Plyr = function () {
// Options // Options
this.options = { this.options = {
speed: [], speed: [],
quality: [], quality: []
captions: []
}; };
// Debugging // Debugging
@@ -12697,8 +12791,8 @@ var Plyr = function () {
} }
/** /**
* Set the captions language * Set the caption track by index
* @param {string} - Two character ISO language code (e.g. EN, FR, PT, etc) * @param {number} - Caption index
*/ */
}, { }, {
@@ -13389,60 +13483,41 @@ var Plyr = function () {
return Boolean(this.config.autoplay); return Boolean(this.config.autoplay);
} }
}, { }, {
key: 'language', key: 'currentTrack',
set: function set(input) { set: function set(input) {
// Nothing specified captions.set.call(this, input);
if (!utils.is.string(input)) {
return;
}
// If empty string is passed, assume disable captions
if (utils.is.empty(input)) {
this.toggleCaptions(false);
return;
}
// Normalize
var language = input.toLowerCase();
// Check for support
if (!this.options.captions.includes(language)) {
this.debug.warn('Unsupported language option: ' + language);
return;
}
// Ensure captions are enabled
this.toggleCaptions(true);
// Enabled only
if (language === 'enabled') {
return;
}
// If nothing to change, bail
if (this.language === language) {
return;
}
// Update config
this.captions.language = language;
// Clear caption
captions.setText.call(this, null);
// Update captions
captions.setLanguage.call(this);
// Trigger an event
utils.dispatchEvent.call(this, this.media, 'languagechange');
} }
/** /**
* Get the current captions language * Get the current caption track index (-1 if disabled)
*/ */
, ,
get: function get() { get: function get() {
return this.captions.language; var _captions = this.captions,
active = _captions.active,
currentTrack = _captions.currentTrack;
return active ? currentTrack : -1;
}
/**
* Set the wanted language for captions
* Since tracks can be added later it won't update the actual caption track until there is a matching track
* @param {string} - Two character ISO language code (e.g. EN, FR, PT, etc)
*/
}, {
key: 'language',
set: function set(input) {
captions.setLanguage.call(this, input);
}
/**
* Get the current track's language
*/
,
get: function get() {
return (captions.getCurrentTrack.call(this) || {}).language;
} }
/** /**
@@ -13518,9 +13593,7 @@ var Plyr = function () {
} else if (utils.is.nodeList(selector)) { } else if (utils.is.nodeList(selector)) {
targets = Array.from(selector); targets = Array.from(selector);
} else if (utils.is.array(selector)) { } else if (utils.is.array(selector)) {
targets = selector.filter(function (i) { targets = selector.filter(utils.is.element);
return utils.is.element(i);
});
} }
if (utils.is.empty(targets)) { if (utils.is.empty(targets)) {
+1 -1
View File
File diff suppressed because one or more lines are too long
+1 -1
View File
File diff suppressed because one or more lines are too long
+1 -1
View File
File diff suppressed because one or more lines are too long