commit
fb22a90d33
10
.github/pull_request_template.md
vendored
10
.github/pull_request_template.md
vendored
@ -1,8 +1,8 @@
|
||||
### Link to related issue (if applicable)
|
||||
|
||||
### Sumary of proposed changes
|
||||
### Summary of proposed changes
|
||||
|
||||
### Task list
|
||||
|
||||
- [ ] Tested on [supported browsers](https://github.com/sampotts/plyr#browser-support)
|
||||
- [ ] Gulp build completed
|
||||
### Checklist
|
||||
- [ ] Use `develop` as the base branch
|
||||
- [ ] Exclude the gulp build from the PR
|
||||
- [ ] Test on [supported browsers](https://github.com/sampotts/plyr#browser-support)
|
||||
|
7
.travis.yml
Normal file
7
.travis.yml
Normal file
@ -0,0 +1,7 @@
|
||||
language: node_js
|
||||
node_js:
|
||||
- 'lts/*'
|
||||
|
||||
script:
|
||||
- npm run lint
|
||||
- npm run build
|
2
demo/dist/demo.css
vendored
2
demo/dist/demo.css
vendored
File diff suppressed because one or more lines are too long
2
dist/plyr.css
vendored
2
dist/plyr.css
vendored
File diff suppressed because one or more lines are too long
215
dist/plyr.js
vendored
215
dist/plyr.js
vendored
@ -1300,6 +1300,14 @@ var utils = {
|
||||
},
|
||||
|
||||
|
||||
// Get a nested value in an object
|
||||
getDeep: function getDeep(object, path) {
|
||||
return path.split('.').reduce(function (obj, key) {
|
||||
return obj && obj[key];
|
||||
}, object);
|
||||
},
|
||||
|
||||
|
||||
// Get the closest value in an array
|
||||
closest: function closest(array, value) {
|
||||
if (!utils.is.array(array) || !array.length) {
|
||||
@ -1719,6 +1727,13 @@ var html5 = {
|
||||
|
||||
player.media.src = supported[0].getAttribute('src');
|
||||
|
||||
// Restore time
|
||||
var onLoadedMetaData = function onLoadedMetaData() {
|
||||
player.currentTime = currentTime;
|
||||
player.off('loadedmetadata', onLoadedMetaData);
|
||||
};
|
||||
player.on('loadedmetadata', onLoadedMetaData);
|
||||
|
||||
// Load new source
|
||||
player.media.load();
|
||||
|
||||
@ -1727,9 +1742,6 @@ var html5 = {
|
||||
player.play();
|
||||
}
|
||||
|
||||
// Restore time
|
||||
player.currentTime = currentTime;
|
||||
|
||||
// Trigger change event
|
||||
utils.dispatchEvent.call(player, player.media, 'qualitychange', false, {
|
||||
quality: input
|
||||
@ -1771,11 +1783,15 @@ var i18n = {
|
||||
var key = arguments.length > 0 && arguments[0] !== undefined ? arguments[0] : '';
|
||||
var config = arguments.length > 1 && arguments[1] !== undefined ? arguments[1] : {};
|
||||
|
||||
if (utils.is.empty(key) || utils.is.empty(config) || !Object.keys(config.i18n).includes(key)) {
|
||||
if (utils.is.empty(key) || utils.is.empty(config)) {
|
||||
return '';
|
||||
}
|
||||
|
||||
var string = config.i18n[key];
|
||||
var string = utils.getDeep(config.i18n, key);
|
||||
|
||||
if (utils.is.empty(string)) {
|
||||
return '';
|
||||
}
|
||||
|
||||
var replace = {
|
||||
'{seektime}': config.seekTime,
|
||||
@ -2449,27 +2465,7 @@ var controls = {
|
||||
|
||||
// Get the badge HTML for HD, 4K etc
|
||||
var getBadge = function getBadge(quality) {
|
||||
var label = '';
|
||||
|
||||
switch (quality) {
|
||||
case 2160:
|
||||
label = '4K';
|
||||
break;
|
||||
|
||||
case 1440:
|
||||
case 1080:
|
||||
case 720:
|
||||
label = 'HD';
|
||||
break;
|
||||
|
||||
case 576:
|
||||
case 480:
|
||||
label = 'SD';
|
||||
break;
|
||||
|
||||
default:
|
||||
break;
|
||||
}
|
||||
var label = i18n.get('qualityBadge.' + quality, _this3.config);
|
||||
|
||||
if (!label.length) {
|
||||
return null;
|
||||
@ -2492,7 +2488,6 @@ var controls = {
|
||||
|
||||
|
||||
// Translate a value into a nice label
|
||||
// TODO: Localisation
|
||||
getLabel: function getLabel(setting, value) {
|
||||
switch (setting) {
|
||||
case 'speed':
|
||||
@ -2500,9 +2495,15 @@ var controls = {
|
||||
|
||||
case 'quality':
|
||||
if (utils.is.number(value)) {
|
||||
var label = i18n.get('qualityLabel.' + value, this.config);
|
||||
|
||||
if (!label.length) {
|
||||
return value + 'p';
|
||||
}
|
||||
|
||||
return label;
|
||||
}
|
||||
|
||||
return utils.toTitleCase(value);
|
||||
|
||||
case 'captions':
|
||||
@ -2660,12 +2661,7 @@ var controls = {
|
||||
|
||||
// Generate options
|
||||
tracks.forEach(function (track) {
|
||||
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.captions.language.toLowerCase());
|
||||
});
|
||||
|
||||
// Store reference
|
||||
this.options.captions = tracks.map(function (track) {
|
||||
return track.language;
|
||||
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);
|
||||
@ -3268,28 +3264,6 @@ var captions = {
|
||||
return;
|
||||
}
|
||||
|
||||
// Set default language if not set
|
||||
var stored = this.storage.get('language');
|
||||
|
||||
if (!utils.is.empty(stored)) {
|
||||
this.captions.language = stored;
|
||||
}
|
||||
|
||||
if (utils.is.empty(this.captions.language)) {
|
||||
this.captions.language = this.config.captions.language.toLowerCase();
|
||||
}
|
||||
|
||||
// Set captions enabled state if not set
|
||||
if (!utils.is.boolean(this.captions.active)) {
|
||||
var active = this.storage.get('captions');
|
||||
|
||||
if (utils.is.boolean(active)) {
|
||||
this.captions.active = active;
|
||||
} else {
|
||||
this.captions.active = this.config.captions.active;
|
||||
}
|
||||
}
|
||||
|
||||
// Only Vimeo and HTML5 video supported at this point
|
||||
if (!this.isVideo || this.isYouTube || this.isHTML5 && !support.textTracks) {
|
||||
// Clear menu and hide
|
||||
@ -3307,17 +3281,6 @@ var captions = {
|
||||
utils.insertAfter(this.elements.captions, this.elements.wrapper);
|
||||
}
|
||||
|
||||
// Set the class hook
|
||||
utils.toggleClass(this.elements.container, this.config.classNames.captions.enabled, !utils.is.empty(captions.getTracks.call(this)));
|
||||
|
||||
// Get tracks
|
||||
var tracks = captions.getTracks.call(this);
|
||||
|
||||
// If no caption file exists, hide container for caption text
|
||||
if (utils.is.empty(tracks)) {
|
||||
return;
|
||||
}
|
||||
|
||||
// Get browser info
|
||||
var browser = utils.getBrowser();
|
||||
|
||||
@ -3340,14 +3303,52 @@ var captions = {
|
||||
});
|
||||
}
|
||||
|
||||
// Set language
|
||||
captions.setLanguage.call(this);
|
||||
// Try to load the value from storage
|
||||
var active = this.storage.get('captions');
|
||||
|
||||
// Enable UI
|
||||
captions.show.call(this);
|
||||
// Otherwise fall back to the default config
|
||||
if (!utils.is.boolean(active)) {
|
||||
active = this.config.captions.active;
|
||||
}
|
||||
|
||||
// Set available languages in list
|
||||
if (utils.is.array(this.config.controls) && this.config.controls.includes('settings') && this.config.settings.includes('captions')) {
|
||||
// Set toggled state
|
||||
this.toggleCaptions(active);
|
||||
|
||||
// Watch changes to textTracks and update captions menu
|
||||
if (this.config.captions.update) {
|
||||
utils.on(this.media.textTracks, 'addtrack removetrack', captions.update.bind(this));
|
||||
}
|
||||
|
||||
// Update available languages in list next tick (the event must not be triggered before the listeners)
|
||||
setTimeout(captions.update.bind(this), 0);
|
||||
},
|
||||
update: function update() {
|
||||
// Update tracks
|
||||
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
|
||||
if (!this.language) {
|
||||
var language = this.config.captions.language;
|
||||
|
||||
if (language === 'auto') {
|
||||
var _split = (navigator.language || navigator.userLanguage).split('-');
|
||||
|
||||
var _split2 = slicedToArray(_split, 1);
|
||||
|
||||
language = _split2[0];
|
||||
}
|
||||
this.language = this.storage.get('language') || (language || '').toLowerCase();
|
||||
}
|
||||
|
||||
// Toggle the class hooks
|
||||
utils.toggleClass(this.elements.container, this.config.classNames.captions.enabled, !utils.is.empty(captions.getTracks.call(this)));
|
||||
|
||||
// Update available languages in list
|
||||
if ((this.config.controls || []).includes('settings') && this.config.settings.includes('captions')) {
|
||||
controls.setCaptionsMenu.call(this);
|
||||
}
|
||||
},
|
||||
@ -3508,25 +3509,6 @@ var captions = {
|
||||
} else {
|
||||
this.debug.warn('No captions element to render to');
|
||||
}
|
||||
},
|
||||
|
||||
|
||||
// Display captions container and button (for initialization)
|
||||
show: function show() {
|
||||
// Try to load the value from storage
|
||||
var active = this.storage.get('captions');
|
||||
|
||||
// Otherwise fall back to the default config
|
||||
if (!utils.is.boolean(active)) {
|
||||
active = this.config.captions.active;
|
||||
} else {
|
||||
this.captions.active = active;
|
||||
}
|
||||
|
||||
if (active) {
|
||||
utils.toggleClass(this.elements.container, this.config.classNames.captions.active, true);
|
||||
utils.toggleState(this.elements.buttons.captions, true);
|
||||
}
|
||||
}
|
||||
};
|
||||
|
||||
@ -3667,7 +3649,10 @@ var defaults$1 = {
|
||||
// Captions settings
|
||||
captions: {
|
||||
active: false,
|
||||
language: (navigator.language || navigator.userLanguage).split('-')[0]
|
||||
language: 'auto',
|
||||
// Listen to new tracks added after Plyr is initialized.
|
||||
// This is needed for streaming captions, but may result in unselectable options
|
||||
update: false
|
||||
},
|
||||
|
||||
// Fullscreen settings
|
||||
@ -3724,7 +3709,15 @@ var defaults$1 = {
|
||||
reset: 'Reset',
|
||||
disabled: 'Disabled',
|
||||
enabled: 'Enabled',
|
||||
advertisement: 'Ad'
|
||||
advertisement: 'Ad',
|
||||
qualityBadge: {
|
||||
2160: '4K',
|
||||
1440: 'HD',
|
||||
1080: 'HD',
|
||||
720: 'HD',
|
||||
576: 'SD',
|
||||
480: 'SD'
|
||||
}
|
||||
},
|
||||
|
||||
// URLs
|
||||
@ -3812,9 +3805,8 @@ var defaults$1 = {
|
||||
display: {
|
||||
currentTime: '.plyr__time--current',
|
||||
duration: '.plyr__time--duration',
|
||||
buffer: '.plyr__progress--buffer',
|
||||
played: '.plyr__progress--played',
|
||||
loop: '.plyr__progress--loop',
|
||||
buffer: '.plyr__progress__buffer',
|
||||
loop: '.plyr__progress__loop', // Used later
|
||||
volume: '.plyr__volume--display'
|
||||
},
|
||||
progress: '.plyr__progress',
|
||||
@ -4183,8 +4175,10 @@ var ui = {
|
||||
// Remove native controls
|
||||
ui.toggleNativeControls.call(this);
|
||||
|
||||
// Captions
|
||||
// Setup captions for HTML5
|
||||
if (this.isHTML5) {
|
||||
captions.setup.call(this);
|
||||
}
|
||||
|
||||
// Reset volume
|
||||
this.volume = null;
|
||||
@ -4237,6 +4231,12 @@ var ui = {
|
||||
if (this.poster && this.elements.poster && !this.elements.poster.style.backgroundImage) {
|
||||
ui.setPoster.call(this, this.poster);
|
||||
}
|
||||
|
||||
// Manually set the duration if user has overridden it.
|
||||
// The event listeners for it doesn't get called if preload is disabled (#701)
|
||||
if (this.config.duration) {
|
||||
controls.durationUpdate.call(this);
|
||||
}
|
||||
},
|
||||
|
||||
|
||||
@ -7294,25 +7294,20 @@ var Plyr = function () {
|
||||
}
|
||||
|
||||
// If the method is called without parameter, toggle based on current value
|
||||
var show = utils.is.boolean(input) ? input : !this.elements.container.classList.contains(this.config.classNames.captions.active);
|
||||
|
||||
// Nothing to change...
|
||||
if (this.captions.active === show) {
|
||||
return;
|
||||
}
|
||||
|
||||
// Set global
|
||||
this.captions.active = show;
|
||||
var active = utils.is.boolean(input) ? input : !this.elements.container.classList.contains(this.config.classNames.captions.active);
|
||||
|
||||
// Toggle state
|
||||
utils.toggleState(this.elements.buttons.captions, this.captions.active);
|
||||
utils.toggleState(this.elements.buttons.captions, active);
|
||||
|
||||
// Add class hook
|
||||
utils.toggleClass(this.elements.container, this.config.classNames.captions.active, this.captions.active);
|
||||
utils.toggleClass(this.elements.container, this.config.classNames.captions.active, active);
|
||||
|
||||
// Trigger an event
|
||||
// Update state and trigger event
|
||||
if (active !== this.captions.active) {
|
||||
this.captions.active = active;
|
||||
utils.dispatchEvent.call(this, this.media, this.captions.active ? 'captionsenabled' : 'captionsdisabled');
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Set the captions language
|
||||
@ -7843,7 +7838,7 @@ var Plyr = function () {
|
||||
quality = Number(input);
|
||||
}
|
||||
|
||||
if (!utils.is.number(quality) || quality === 0) {
|
||||
if (!utils.is.number(quality)) {
|
||||
quality = this.storage.get('quality');
|
||||
}
|
||||
|
||||
|
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
265
dist/plyr.polyfilled.js
vendored
265
dist/plyr.polyfilled.js
vendored
@ -20,7 +20,7 @@ if (typeof __g == 'number') __g = global; // eslint-disable-line no-undef
|
||||
});
|
||||
|
||||
var _core = createCommonjsModule(function (module) {
|
||||
var core = module.exports = { version: '2.5.6' };
|
||||
var core = module.exports = { version: '2.5.3' };
|
||||
if (typeof __e == 'number') __e = core; // eslint-disable-line no-undef
|
||||
});
|
||||
var _core_1 = _core.version;
|
||||
@ -333,18 +333,11 @@ var _arrayIncludes = function (IS_INCLUDES) {
|
||||
};
|
||||
};
|
||||
|
||||
var _shared = createCommonjsModule(function (module) {
|
||||
var SHARED = '__core-js_shared__';
|
||||
var store = _global[SHARED] || (_global[SHARED] = {});
|
||||
|
||||
(module.exports = function (key, value) {
|
||||
return store[key] || (store[key] = value !== undefined ? value : {});
|
||||
})('versions', []).push({
|
||||
version: _core.version,
|
||||
mode: _library ? 'pure' : 'global',
|
||||
copyright: '© 2018 Denis Pushkarev (zloirock.ru)'
|
||||
});
|
||||
});
|
||||
var _shared = function (key) {
|
||||
return store[key] || (store[key] = {});
|
||||
};
|
||||
|
||||
var shared = _shared('keys');
|
||||
|
||||
@ -998,7 +991,7 @@ var _iterDefine = function (Base, NAME, Constructor, next, DEFAULT, IS_SET, FORC
|
||||
var VALUES_BUG = false;
|
||||
var proto = Base.prototype;
|
||||
var $native = proto[ITERATOR$2] || proto[FF_ITERATOR] || DEFAULT && proto[DEFAULT];
|
||||
var $default = $native || getMethod(DEFAULT);
|
||||
var $default = (!BUGGY && $native) || getMethod(DEFAULT);
|
||||
var $entries = DEFAULT ? !DEF_VALUES ? $default : getMethod('entries') : undefined;
|
||||
var $anyNative = NAME == 'Array' ? proto.entries || $native : $native;
|
||||
var methods, key, IteratorPrototype;
|
||||
@ -1009,7 +1002,7 @@ var _iterDefine = function (Base, NAME, Constructor, next, DEFAULT, IS_SET, FORC
|
||||
// Set @@toStringTag to native iterators
|
||||
_setToStringTag(IteratorPrototype, TAG, true);
|
||||
// fix for some old engines
|
||||
if (!_library && typeof IteratorPrototype[ITERATOR$2] != 'function') _hide(IteratorPrototype, ITERATOR$2, returnThis);
|
||||
if (!_library && !_has(IteratorPrototype, ITERATOR$2)) _hide(IteratorPrototype, ITERATOR$2, returnThis);
|
||||
}
|
||||
}
|
||||
// fix Array#{values, @@iterator}.name in V8 / FF
|
||||
@ -2503,11 +2496,9 @@ function set(target, propertyKey, V /* , receiver */) {
|
||||
}
|
||||
if (_has(ownDesc, 'value')) {
|
||||
if (ownDesc.writable === false || !_isObject(receiver)) return false;
|
||||
if (existingDescriptor = _objectGopd.f(receiver, propertyKey)) {
|
||||
if (existingDescriptor.get || existingDescriptor.set || existingDescriptor.writable === false) return false;
|
||||
existingDescriptor = _objectGopd.f(receiver, propertyKey) || _propertyDesc(0);
|
||||
existingDescriptor.value = V;
|
||||
_objectDp.f(receiver, propertyKey, existingDescriptor);
|
||||
} else _objectDp.f(receiver, propertyKey, _propertyDesc(0, V));
|
||||
return true;
|
||||
}
|
||||
return ownDesc.set === undefined ? false : (ownDesc.set.call(receiver, V), true);
|
||||
@ -2652,8 +2643,7 @@ var _microtask = function () {
|
||||
};
|
||||
// environments with maybe non-completely correct, but existent Promise
|
||||
} else if (Promise$1 && Promise$1.resolve) {
|
||||
// Promise.resolve without an argument throws an error in LG WebOS 2
|
||||
var promise = Promise$1.resolve(undefined);
|
||||
var promise = Promise$1.resolve();
|
||||
notify = function () {
|
||||
promise.then(flush);
|
||||
};
|
||||
@ -2710,10 +2700,6 @@ var _perform = function (exec) {
|
||||
}
|
||||
};
|
||||
|
||||
var navigator$1 = _global.navigator;
|
||||
|
||||
var _userAgent = navigator$1 && navigator$1.userAgent || '';
|
||||
|
||||
var _promiseResolve = function (C, x) {
|
||||
_anObject(C);
|
||||
if (_isObject(x) && x.constructor === C) return x;
|
||||
@ -2728,12 +2714,9 @@ var microtask = _microtask();
|
||||
|
||||
|
||||
|
||||
|
||||
var PROMISE = 'Promise';
|
||||
var TypeError$1 = _global.TypeError;
|
||||
var process$2 = _global.process;
|
||||
var versions = process$2 && process$2.versions;
|
||||
var v8 = versions && versions.v8 || '';
|
||||
var $Promise = _global[PROMISE];
|
||||
var isNode$1 = _classof(process$2) == 'process';
|
||||
var empty = function () { /* empty */ };
|
||||
@ -2748,13 +2731,7 @@ var USE_NATIVE = !!function () {
|
||||
exec(empty, empty);
|
||||
};
|
||||
// unhandled rejections tracking support, NodeJS Promise without it fails @@species test
|
||||
return (isNode$1 || typeof PromiseRejectionEvent == 'function')
|
||||
&& promise.then(empty) instanceof FakePromise
|
||||
// v8 6.6 (Node 10 and Chrome 66) have a bug with resolving custom thenables
|
||||
// https://bugs.chromium.org/p/chromium/issues/detail?id=830565
|
||||
// we can't detect it synchronously, so just check versions
|
||||
&& v8.indexOf('6.6') !== 0
|
||||
&& _userAgent.indexOf('Chrome/66') === -1;
|
||||
return (isNode$1 || typeof PromiseRejectionEvent == 'function') && promise.then(empty) instanceof FakePromise;
|
||||
} catch (e) { /* empty */ }
|
||||
}();
|
||||
|
||||
@ -2776,7 +2753,7 @@ var notify = function (promise, isReject) {
|
||||
var resolve = reaction.resolve;
|
||||
var reject = reaction.reject;
|
||||
var domain = reaction.domain;
|
||||
var result, then, exited;
|
||||
var result, then;
|
||||
try {
|
||||
if (handler) {
|
||||
if (!ok) {
|
||||
@ -2786,11 +2763,8 @@ var notify = function (promise, isReject) {
|
||||
if (handler === true) result = value;
|
||||
else {
|
||||
if (domain) domain.enter();
|
||||
result = handler(value); // may throw
|
||||
if (domain) {
|
||||
domain.exit();
|
||||
exited = true;
|
||||
}
|
||||
result = handler(value);
|
||||
if (domain) domain.exit();
|
||||
}
|
||||
if (result === reaction.promise) {
|
||||
reject(TypeError$1('Promise-chain cycle'));
|
||||
@ -2799,7 +2773,6 @@ var notify = function (promise, isReject) {
|
||||
} else resolve(result);
|
||||
} else reject(value);
|
||||
} catch (e) {
|
||||
if (domain && !exited) domain.exit();
|
||||
reject(e);
|
||||
}
|
||||
};
|
||||
@ -4182,6 +4155,10 @@ var _stringPad = function (that, maxLength, fillString, left) {
|
||||
return left ? stringFiller + S : S + stringFiller;
|
||||
};
|
||||
|
||||
var navigator$1 = _global.navigator;
|
||||
|
||||
var _userAgent = navigator$1 && navigator$1.userAgent || '';
|
||||
|
||||
// https://github.com/tc39/proposal-string-pad-start-end
|
||||
|
||||
|
||||
@ -6706,6 +6683,14 @@ var utils = {
|
||||
},
|
||||
|
||||
|
||||
// Get a nested value in an object
|
||||
getDeep: function getDeep(object, path) {
|
||||
return path.split('.').reduce(function (obj, key) {
|
||||
return obj && obj[key];
|
||||
}, object);
|
||||
},
|
||||
|
||||
|
||||
// Get the closest value in an array
|
||||
closest: function closest(array, value) {
|
||||
if (!utils.is.array(array) || !array.length) {
|
||||
@ -7125,6 +7110,13 @@ var html5 = {
|
||||
|
||||
player.media.src = supported[0].getAttribute('src');
|
||||
|
||||
// Restore time
|
||||
var onLoadedMetaData = function onLoadedMetaData() {
|
||||
player.currentTime = currentTime;
|
||||
player.off('loadedmetadata', onLoadedMetaData);
|
||||
};
|
||||
player.on('loadedmetadata', onLoadedMetaData);
|
||||
|
||||
// Load new source
|
||||
player.media.load();
|
||||
|
||||
@ -7133,9 +7125,6 @@ var html5 = {
|
||||
player.play();
|
||||
}
|
||||
|
||||
// Restore time
|
||||
player.currentTime = currentTime;
|
||||
|
||||
// Trigger change event
|
||||
utils.dispatchEvent.call(player, player.media, 'qualitychange', false, {
|
||||
quality: input
|
||||
@ -7177,11 +7166,15 @@ var i18n = {
|
||||
var key = arguments.length > 0 && arguments[0] !== undefined ? arguments[0] : '';
|
||||
var config = arguments.length > 1 && arguments[1] !== undefined ? arguments[1] : {};
|
||||
|
||||
if (utils.is.empty(key) || utils.is.empty(config) || !Object.keys(config.i18n).includes(key)) {
|
||||
if (utils.is.empty(key) || utils.is.empty(config)) {
|
||||
return '';
|
||||
}
|
||||
|
||||
var string = config.i18n[key];
|
||||
var string = utils.getDeep(config.i18n, key);
|
||||
|
||||
if (utils.is.empty(string)) {
|
||||
return '';
|
||||
}
|
||||
|
||||
var replace = {
|
||||
'{seektime}': config.seekTime,
|
||||
@ -7855,27 +7848,7 @@ var controls = {
|
||||
|
||||
// Get the badge HTML for HD, 4K etc
|
||||
var getBadge = function getBadge(quality) {
|
||||
var label = '';
|
||||
|
||||
switch (quality) {
|
||||
case 2160:
|
||||
label = '4K';
|
||||
break;
|
||||
|
||||
case 1440:
|
||||
case 1080:
|
||||
case 720:
|
||||
label = 'HD';
|
||||
break;
|
||||
|
||||
case 576:
|
||||
case 480:
|
||||
label = 'SD';
|
||||
break;
|
||||
|
||||
default:
|
||||
break;
|
||||
}
|
||||
var label = i18n.get('qualityBadge.' + quality, _this3.config);
|
||||
|
||||
if (!label.length) {
|
||||
return null;
|
||||
@ -7898,7 +7871,6 @@ var controls = {
|
||||
|
||||
|
||||
// Translate a value into a nice label
|
||||
// TODO: Localisation
|
||||
getLabel: function getLabel(setting, value) {
|
||||
switch (setting) {
|
||||
case 'speed':
|
||||
@ -7906,9 +7878,15 @@ var controls = {
|
||||
|
||||
case 'quality':
|
||||
if (utils.is.number(value)) {
|
||||
var label = i18n.get('qualityLabel.' + value, this.config);
|
||||
|
||||
if (!label.length) {
|
||||
return value + 'p';
|
||||
}
|
||||
|
||||
return label;
|
||||
}
|
||||
|
||||
return utils.toTitleCase(value);
|
||||
|
||||
case 'captions':
|
||||
@ -8066,12 +8044,7 @@ var controls = {
|
||||
|
||||
// Generate options
|
||||
tracks.forEach(function (track) {
|
||||
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.captions.language.toLowerCase());
|
||||
});
|
||||
|
||||
// Store reference
|
||||
this.options.captions = tracks.map(function (track) {
|
||||
return track.language;
|
||||
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);
|
||||
@ -8674,28 +8647,6 @@ var captions = {
|
||||
return;
|
||||
}
|
||||
|
||||
// Set default language if not set
|
||||
var stored = this.storage.get('language');
|
||||
|
||||
if (!utils.is.empty(stored)) {
|
||||
this.captions.language = stored;
|
||||
}
|
||||
|
||||
if (utils.is.empty(this.captions.language)) {
|
||||
this.captions.language = this.config.captions.language.toLowerCase();
|
||||
}
|
||||
|
||||
// Set captions enabled state if not set
|
||||
if (!utils.is.boolean(this.captions.active)) {
|
||||
var active = this.storage.get('captions');
|
||||
|
||||
if (utils.is.boolean(active)) {
|
||||
this.captions.active = active;
|
||||
} else {
|
||||
this.captions.active = this.config.captions.active;
|
||||
}
|
||||
}
|
||||
|
||||
// Only Vimeo and HTML5 video supported at this point
|
||||
if (!this.isVideo || this.isYouTube || this.isHTML5 && !support.textTracks) {
|
||||
// Clear menu and hide
|
||||
@ -8713,17 +8664,6 @@ var captions = {
|
||||
utils.insertAfter(this.elements.captions, this.elements.wrapper);
|
||||
}
|
||||
|
||||
// Set the class hook
|
||||
utils.toggleClass(this.elements.container, this.config.classNames.captions.enabled, !utils.is.empty(captions.getTracks.call(this)));
|
||||
|
||||
// Get tracks
|
||||
var tracks = captions.getTracks.call(this);
|
||||
|
||||
// If no caption file exists, hide container for caption text
|
||||
if (utils.is.empty(tracks)) {
|
||||
return;
|
||||
}
|
||||
|
||||
// Get browser info
|
||||
var browser = utils.getBrowser();
|
||||
|
||||
@ -8746,14 +8686,52 @@ var captions = {
|
||||
});
|
||||
}
|
||||
|
||||
// Set language
|
||||
captions.setLanguage.call(this);
|
||||
// Try to load the value from storage
|
||||
var active = this.storage.get('captions');
|
||||
|
||||
// Enable UI
|
||||
captions.show.call(this);
|
||||
// Otherwise fall back to the default config
|
||||
if (!utils.is.boolean(active)) {
|
||||
active = this.config.captions.active;
|
||||
}
|
||||
|
||||
// Set available languages in list
|
||||
if (utils.is.array(this.config.controls) && this.config.controls.includes('settings') && this.config.settings.includes('captions')) {
|
||||
// Set toggled state
|
||||
this.toggleCaptions(active);
|
||||
|
||||
// Watch changes to textTracks and update captions menu
|
||||
if (this.config.captions.update) {
|
||||
utils.on(this.media.textTracks, 'addtrack removetrack', captions.update.bind(this));
|
||||
}
|
||||
|
||||
// Update available languages in list next tick (the event must not be triggered before the listeners)
|
||||
setTimeout(captions.update.bind(this), 0);
|
||||
},
|
||||
update: function update() {
|
||||
// Update tracks
|
||||
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
|
||||
if (!this.language) {
|
||||
var language = this.config.captions.language;
|
||||
|
||||
if (language === 'auto') {
|
||||
var _split = (navigator.language || navigator.userLanguage).split('-');
|
||||
|
||||
var _split2 = slicedToArray(_split, 1);
|
||||
|
||||
language = _split2[0];
|
||||
}
|
||||
this.language = this.storage.get('language') || (language || '').toLowerCase();
|
||||
}
|
||||
|
||||
// Toggle the class hooks
|
||||
utils.toggleClass(this.elements.container, this.config.classNames.captions.enabled, !utils.is.empty(captions.getTracks.call(this)));
|
||||
|
||||
// Update available languages in list
|
||||
if ((this.config.controls || []).includes('settings') && this.config.settings.includes('captions')) {
|
||||
controls.setCaptionsMenu.call(this);
|
||||
}
|
||||
},
|
||||
@ -8914,25 +8892,6 @@ var captions = {
|
||||
} else {
|
||||
this.debug.warn('No captions element to render to');
|
||||
}
|
||||
},
|
||||
|
||||
|
||||
// Display captions container and button (for initialization)
|
||||
show: function show() {
|
||||
// Try to load the value from storage
|
||||
var active = this.storage.get('captions');
|
||||
|
||||
// Otherwise fall back to the default config
|
||||
if (!utils.is.boolean(active)) {
|
||||
active = this.config.captions.active;
|
||||
} else {
|
||||
this.captions.active = active;
|
||||
}
|
||||
|
||||
if (active) {
|
||||
utils.toggleClass(this.elements.container, this.config.classNames.captions.active, true);
|
||||
utils.toggleState(this.elements.buttons.captions, true);
|
||||
}
|
||||
}
|
||||
};
|
||||
|
||||
@ -9073,7 +9032,10 @@ var defaults$1 = {
|
||||
// Captions settings
|
||||
captions: {
|
||||
active: false,
|
||||
language: (navigator.language || navigator.userLanguage).split('-')[0]
|
||||
language: 'auto',
|
||||
// Listen to new tracks added after Plyr is initialized.
|
||||
// This is needed for streaming captions, but may result in unselectable options
|
||||
update: false
|
||||
},
|
||||
|
||||
// Fullscreen settings
|
||||
@ -9130,7 +9092,15 @@ var defaults$1 = {
|
||||
reset: 'Reset',
|
||||
disabled: 'Disabled',
|
||||
enabled: 'Enabled',
|
||||
advertisement: 'Ad'
|
||||
advertisement: 'Ad',
|
||||
qualityBadge: {
|
||||
2160: '4K',
|
||||
1440: 'HD',
|
||||
1080: 'HD',
|
||||
720: 'HD',
|
||||
576: 'SD',
|
||||
480: 'SD'
|
||||
}
|
||||
},
|
||||
|
||||
// URLs
|
||||
@ -9589,8 +9559,10 @@ var ui = {
|
||||
// Remove native controls
|
||||
ui.toggleNativeControls.call(this);
|
||||
|
||||
// Captions
|
||||
// Setup captions for HTML5
|
||||
if (this.isHTML5) {
|
||||
captions.setup.call(this);
|
||||
}
|
||||
|
||||
// Reset volume
|
||||
this.volume = null;
|
||||
@ -9643,6 +9615,12 @@ var ui = {
|
||||
if (this.poster && this.elements.poster && !this.elements.poster.style.backgroundImage) {
|
||||
ui.setPoster.call(this, this.poster);
|
||||
}
|
||||
|
||||
// Manually set the duration if user has overridden it.
|
||||
// The event listeners for it doesn't get called if preload is disabled (#701)
|
||||
if (this.config.duration) {
|
||||
controls.durationUpdate.call(this);
|
||||
}
|
||||
},
|
||||
|
||||
|
||||
@ -12700,25 +12678,20 @@ var Plyr = function () {
|
||||
}
|
||||
|
||||
// If the method is called without parameter, toggle based on current value
|
||||
var show = utils.is.boolean(input) ? input : !this.elements.container.classList.contains(this.config.classNames.captions.active);
|
||||
|
||||
// Nothing to change...
|
||||
if (this.captions.active === show) {
|
||||
return;
|
||||
}
|
||||
|
||||
// Set global
|
||||
this.captions.active = show;
|
||||
var active = utils.is.boolean(input) ? input : !this.elements.container.classList.contains(this.config.classNames.captions.active);
|
||||
|
||||
// Toggle state
|
||||
utils.toggleState(this.elements.buttons.captions, this.captions.active);
|
||||
utils.toggleState(this.elements.buttons.captions, active);
|
||||
|
||||
// Add class hook
|
||||
utils.toggleClass(this.elements.container, this.config.classNames.captions.active, this.captions.active);
|
||||
utils.toggleClass(this.elements.container, this.config.classNames.captions.active, active);
|
||||
|
||||
// Trigger an event
|
||||
// Update state and trigger event
|
||||
if (active !== this.captions.active) {
|
||||
this.captions.active = active;
|
||||
utils.dispatchEvent.call(this, this.media, this.captions.active ? 'captionsenabled' : 'captionsdisabled');
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Set the captions language
|
||||
@ -13249,7 +13222,7 @@ var Plyr = function () {
|
||||
quality = Number(input);
|
||||
}
|
||||
|
||||
if (!utils.is.number(quality) || quality === 0) {
|
||||
if (!utils.is.number(quality)) {
|
||||
quality = this.storage.get('quality');
|
||||
}
|
||||
|
||||
|
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
@ -226,9 +226,14 @@ gulp.task('watch', () => {
|
||||
gulp.watch(paths.demo.src.sass, tasks.sass);
|
||||
});
|
||||
|
||||
// Build distribution
|
||||
gulp.task('build', () => {
|
||||
run(tasks.clean, tasks.js, tasks.sass, tasks.sprite);
|
||||
});
|
||||
|
||||
// Default gulp task
|
||||
gulp.task('default', () => {
|
||||
run(tasks.clean, tasks.js, tasks.sass, tasks.sprite, 'watch');
|
||||
run('build', 'watch');
|
||||
});
|
||||
|
||||
// Publish a version to CDN and demo
|
||||
|
@ -65,6 +65,8 @@
|
||||
"doc": "readme.md"
|
||||
},
|
||||
"scripts": {
|
||||
"build": "gulp build",
|
||||
"lint": "eslint src/js",
|
||||
"test": "echo \"Error: no test specified\" && exit 1"
|
||||
},
|
||||
"author": "Sam Potts <sam@potts.es>",
|
||||
|
@ -303,7 +303,7 @@ Note the single quotes encapsulating the JSON and double quotes on the object ke
|
||||
| `invertTime` | Boolean | `true` | Display the current time as a countdown rather than an incremental counter. |
|
||||
| `toggleInvert` | Boolean | `true` | Allow users to click to toggle the above. |
|
||||
| `listeners` | Object | `null` | Allows binding of event listeners to the controls before the default handlers. See the `defaults.js` for available listeners. If your handler prevents default on the event (`event.preventDefault()`), the default handler will not fire. |
|
||||
| `captions` | Object | `{ active: false, language: window.navigator.language.split('-')[0] }` | `active`: Toggles if captions should be active by default. `language`: Sets the default language to load (if available). |
|
||||
| `captions` | Object | `{ active: false, language: 'auto', update: false }` | `active`: Toggles if captions should be active by default. `language`: Sets the default language to load (if available). 'auto' uses the browser language. `update`: Listen to changes to tracks and update menu. This is needed for some streaming libraries, but can result in unselectable language options). |
|
||||
| `fullscreen` | Object | `{ enabled: true, fallback: true, iosNative: false }` | `enabled`: Toggles whether fullscreen should be enabled. `fallback`: Allow fallback to a full-window solution. `iosNative`: whether to use native iOS fullscreen when entering fullscreen (no custom controls) |
|
||||
| `ratio` | String | `16:9` | The aspect ratio you want to use for embedded players. |
|
||||
| `storage` | Object | `{ enabled: true, key: 'plyr' }` | `enabled`: Allow use of local storage to store user settings. `key`: The key name to use. |
|
||||
|
@ -16,28 +16,6 @@ const captions = {
|
||||
return;
|
||||
}
|
||||
|
||||
// Set default language if not set
|
||||
const stored = this.storage.get('language');
|
||||
|
||||
if (!utils.is.empty(stored)) {
|
||||
this.captions.language = stored;
|
||||
}
|
||||
|
||||
if (utils.is.empty(this.captions.language)) {
|
||||
this.captions.language = this.config.captions.language.toLowerCase();
|
||||
}
|
||||
|
||||
// Set captions enabled state if not set
|
||||
if (!utils.is.boolean(this.captions.active)) {
|
||||
const active = this.storage.get('captions');
|
||||
|
||||
if (utils.is.boolean(active)) {
|
||||
this.captions.active = active;
|
||||
} else {
|
||||
this.captions.active = this.config.captions.active;
|
||||
}
|
||||
}
|
||||
|
||||
// Only Vimeo and HTML5 video supported at this point
|
||||
if (!this.isVideo || this.isYouTube || (this.isHTML5 && !support.textTracks)) {
|
||||
// Clear menu and hide
|
||||
@ -55,17 +33,6 @@ const captions = {
|
||||
utils.insertAfter(this.elements.captions, this.elements.wrapper);
|
||||
}
|
||||
|
||||
// Set the class hook
|
||||
utils.toggleClass(this.elements.container, this.config.classNames.captions.enabled, !utils.is.empty(captions.getTracks.call(this)));
|
||||
|
||||
// Get tracks
|
||||
const tracks = captions.getTracks.call(this);
|
||||
|
||||
// If no caption file exists, hide container for caption text
|
||||
if (utils.is.empty(tracks)) {
|
||||
return;
|
||||
}
|
||||
|
||||
// Get browser info
|
||||
const browser = utils.getBrowser();
|
||||
|
||||
@ -94,14 +61,45 @@ const captions = {
|
||||
});
|
||||
}
|
||||
|
||||
// Set language
|
||||
captions.setLanguage.call(this);
|
||||
// Try to load the value from storage
|
||||
let active = this.storage.get('captions');
|
||||
|
||||
// Enable UI
|
||||
captions.show.call(this);
|
||||
// Otherwise fall back to the default config
|
||||
if (!utils.is.boolean(active)) {
|
||||
({ active } = this.config.captions);
|
||||
}
|
||||
|
||||
// Set available languages in list
|
||||
if (utils.is.array(this.config.controls) && this.config.controls.includes('settings') && this.config.settings.includes('captions')) {
|
||||
// Set toggled state
|
||||
this.toggleCaptions(active);
|
||||
|
||||
// Watch changes to textTracks and update captions menu
|
||||
if (this.config.captions.update) {
|
||||
utils.on(this.media.textTracks, 'addtrack removetrack', captions.update.bind(this));
|
||||
}
|
||||
|
||||
// Update available languages in list next tick (the event must not be triggered before the listeners)
|
||||
setTimeout(captions.update.bind(this), 0);
|
||||
},
|
||||
|
||||
update() {
|
||||
// Update tracks
|
||||
const tracks = captions.getTracks.call(this);
|
||||
this.options.captions = tracks.map(({language}) => language);
|
||||
|
||||
// Set language if it hasn't been set already
|
||||
if (!this.language) {
|
||||
let { language } = this.config.captions;
|
||||
if (language === 'auto') {
|
||||
[ language ] = (navigator.language || navigator.userLanguage).split('-');
|
||||
}
|
||||
this.language = this.storage.get('language') || (language || '').toLowerCase();
|
||||
}
|
||||
|
||||
// Toggle the class hooks
|
||||
utils.toggleClass(this.elements.container, this.config.classNames.captions.enabled, !utils.is.empty(captions.getTracks.call(this)));
|
||||
|
||||
// Update available languages in list
|
||||
if ((this.config.controls || []).includes('settings') && this.config.settings.includes('captions')) {
|
||||
controls.setCaptionsMenu.call(this);
|
||||
}
|
||||
},
|
||||
@ -247,24 +245,6 @@ const captions = {
|
||||
this.debug.warn('No captions element to render to');
|
||||
}
|
||||
},
|
||||
|
||||
// Display captions container and button (for initialization)
|
||||
show() {
|
||||
// Try to load the value from storage
|
||||
let active = this.storage.get('captions');
|
||||
|
||||
// Otherwise fall back to the default config
|
||||
if (!utils.is.boolean(active)) {
|
||||
({ active } = this.config.captions);
|
||||
} else {
|
||||
this.captions.active = active;
|
||||
}
|
||||
|
||||
if (active) {
|
||||
utils.toggleClass(this.elements.container, this.config.classNames.captions.active, true);
|
||||
utils.toggleState(this.elements.buttons.captions, true);
|
||||
}
|
||||
},
|
||||
};
|
||||
|
||||
export default captions;
|
||||
|
34
src/js/controls.js
vendored
34
src/js/controls.js
vendored
@ -664,27 +664,7 @@ const controls = {
|
||||
|
||||
// Get the badge HTML for HD, 4K etc
|
||||
const getBadge = quality => {
|
||||
let label = '';
|
||||
|
||||
switch (quality) {
|
||||
case 2160:
|
||||
label = '4K';
|
||||
break;
|
||||
|
||||
case 1440:
|
||||
case 1080:
|
||||
case 720:
|
||||
label = 'HD';
|
||||
break;
|
||||
|
||||
case 576:
|
||||
case 480:
|
||||
label = 'SD';
|
||||
break;
|
||||
|
||||
default:
|
||||
break;
|
||||
}
|
||||
const label = i18n.get(`qualityBadge.${quality}`, this.config);
|
||||
|
||||
if (!label.length) {
|
||||
return null;
|
||||
@ -708,7 +688,6 @@ const controls = {
|
||||
},
|
||||
|
||||
// Translate a value into a nice label
|
||||
// TODO: Localisation
|
||||
getLabel(setting, value) {
|
||||
switch (setting) {
|
||||
case 'speed':
|
||||
@ -716,9 +695,15 @@ const controls = {
|
||||
|
||||
case 'quality':
|
||||
if (utils.is.number(value)) {
|
||||
const label = i18n.get(`qualityLabel.${value}`, this.config);
|
||||
|
||||
if (!label.length) {
|
||||
return `${value}p`;
|
||||
}
|
||||
|
||||
return label;
|
||||
}
|
||||
|
||||
return utils.toTitleCase(value);
|
||||
|
||||
case 'captions':
|
||||
@ -883,13 +868,10 @@ const controls = {
|
||||
'language',
|
||||
track.label,
|
||||
track.language !== 'enabled' ? controls.createBadge.call(this, track.language.toUpperCase()) : null,
|
||||
track.language.toLowerCase() === this.captions.language.toLowerCase(),
|
||||
track.language.toLowerCase() === this.language,
|
||||
);
|
||||
});
|
||||
|
||||
// Store reference
|
||||
this.options.captions = tracks.map(track => track.language);
|
||||
|
||||
controls.updateSetting.call(this, type, list);
|
||||
},
|
||||
|
||||
|
@ -115,7 +115,10 @@ const defaults = {
|
||||
// Captions settings
|
||||
captions: {
|
||||
active: false,
|
||||
language: (navigator.language || navigator.userLanguage).split('-')[0],
|
||||
language: 'auto',
|
||||
// Listen to new tracks added after Plyr is initialized.
|
||||
// This is needed for streaming captions, but may result in unselectable options
|
||||
update: false,
|
||||
},
|
||||
|
||||
// Fullscreen settings
|
||||
@ -187,6 +190,14 @@ const defaults = {
|
||||
disabled: 'Disabled',
|
||||
enabled: 'Enabled',
|
||||
advertisement: 'Ad',
|
||||
qualityBadge: {
|
||||
2160: '4K',
|
||||
1440: 'HD',
|
||||
1080: 'HD',
|
||||
720: 'HD',
|
||||
576: 'SD',
|
||||
480: 'SD',
|
||||
},
|
||||
},
|
||||
|
||||
// URLs
|
||||
@ -311,9 +322,8 @@ const defaults = {
|
||||
display: {
|
||||
currentTime: '.plyr__time--current',
|
||||
duration: '.plyr__time--duration',
|
||||
buffer: '.plyr__progress--buffer',
|
||||
played: '.plyr__progress--played',
|
||||
loop: '.plyr__progress--loop',
|
||||
buffer: '.plyr__progress__buffer',
|
||||
loop: '.plyr__progress__loop', // Used later
|
||||
volume: '.plyr__volume--display',
|
||||
},
|
||||
progress: '.plyr__progress',
|
||||
|
@ -99,6 +99,13 @@ const html5 = {
|
||||
// Set new source
|
||||
player.media.src = supported[0].getAttribute('src');
|
||||
|
||||
// Restore time
|
||||
const onLoadedMetaData = () => {
|
||||
player.currentTime = currentTime;
|
||||
player.off('loadedmetadata', onLoadedMetaData);
|
||||
};
|
||||
player.on('loadedmetadata', onLoadedMetaData);
|
||||
|
||||
// Load new source
|
||||
player.media.load();
|
||||
|
||||
@ -107,9 +114,6 @@ const html5 = {
|
||||
player.play();
|
||||
}
|
||||
|
||||
// Restore time
|
||||
player.currentTime = currentTime;
|
||||
|
||||
// Trigger change event
|
||||
utils.dispatchEvent.call(player, player.media, 'qualitychange', false, {
|
||||
quality: input,
|
||||
|
@ -6,11 +6,15 @@ import utils from './utils';
|
||||
|
||||
const i18n = {
|
||||
get(key = '', config = {}) {
|
||||
if (utils.is.empty(key) || utils.is.empty(config) || !Object.keys(config.i18n).includes(key)) {
|
||||
if (utils.is.empty(key) || utils.is.empty(config)) {
|
||||
return '';
|
||||
}
|
||||
|
||||
let string = config.i18n[key];
|
||||
let string = utils.getDeep(config.i18n, key);
|
||||
|
||||
if (utils.is.empty(string)) {
|
||||
return '';
|
||||
}
|
||||
|
||||
const replace = {
|
||||
'{seektime}': config.seekTime,
|
||||
|
@ -675,7 +675,7 @@ class Plyr {
|
||||
quality = Number(input);
|
||||
}
|
||||
|
||||
if (!utils.is.number(quality) || quality === 0) {
|
||||
if (!utils.is.number(quality)) {
|
||||
quality = this.storage.get('quality');
|
||||
}
|
||||
|
||||
@ -838,25 +838,20 @@ class Plyr {
|
||||
}
|
||||
|
||||
// If the method is called without parameter, toggle based on current value
|
||||
const show = utils.is.boolean(input) ? input : !this.elements.container.classList.contains(this.config.classNames.captions.active);
|
||||
|
||||
// Nothing to change...
|
||||
if (this.captions.active === show) {
|
||||
return;
|
||||
}
|
||||
|
||||
// Set global
|
||||
this.captions.active = show;
|
||||
const active = utils.is.boolean(input) ? input : !this.elements.container.classList.contains(this.config.classNames.captions.active);
|
||||
|
||||
// Toggle state
|
||||
utils.toggleState(this.elements.buttons.captions, this.captions.active);
|
||||
utils.toggleState(this.elements.buttons.captions, active);
|
||||
|
||||
// Add class hook
|
||||
utils.toggleClass(this.elements.container, this.config.classNames.captions.active, this.captions.active);
|
||||
utils.toggleClass(this.elements.container, this.config.classNames.captions.active, active);
|
||||
|
||||
// Trigger an event
|
||||
// Update state and trigger event
|
||||
if (active !== this.captions.active) {
|
||||
this.captions.active = active;
|
||||
utils.dispatchEvent.call(this, this.media, this.captions.active ? 'captionsenabled' : 'captionsdisabled');
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Set the captions language
|
||||
|
10
src/js/ui.js
10
src/js/ui.js
@ -55,8 +55,10 @@ const ui = {
|
||||
// Remove native controls
|
||||
ui.toggleNativeControls.call(this);
|
||||
|
||||
// Captions
|
||||
// Setup captions for HTML5
|
||||
if (this.isHTML5) {
|
||||
captions.setup.call(this);
|
||||
}
|
||||
|
||||
// Reset volume
|
||||
this.volume = null;
|
||||
@ -109,6 +111,12 @@ const ui = {
|
||||
if (this.poster && this.elements.poster && !this.elements.poster.style.backgroundImage) {
|
||||
ui.setPoster.call(this, this.poster);
|
||||
}
|
||||
|
||||
// Manually set the duration if user has overridden it.
|
||||
// The event listeners for it doesn't get called if preload is disabled (#701)
|
||||
if (this.config.duration) {
|
||||
controls.durationUpdate.call(this);
|
||||
}
|
||||
},
|
||||
|
||||
// Setup aria attribute for play and iframe title
|
||||
|
@ -728,6 +728,11 @@ const utils = {
|
||||
return JSON.parse(JSON.stringify(object));
|
||||
},
|
||||
|
||||
// Get a nested value in an object
|
||||
getDeep(object, path) {
|
||||
return path.split('.').reduce((obj, key) => obj && obj[key], object);
|
||||
},
|
||||
|
||||
// Get the closest value in an array
|
||||
closest(array, value) {
|
||||
if (!utils.is.array(array) || !array.length) {
|
||||
|
@ -5,16 +5,21 @@
|
||||
.plyr__progress {
|
||||
display: flex;
|
||||
flex: 1;
|
||||
position: relative;
|
||||
margin-right: $plyr-range-thumb-height;
|
||||
left: $plyr-range-thumb-height / 2;
|
||||
margin-right: $plyr-range-thumb-height;
|
||||
position: relative;
|
||||
|
||||
input[type='range'],
|
||||
&__buffer {
|
||||
margin-left: -($plyr-range-thumb-height / 2);
|
||||
margin-right: -($plyr-range-thumb-height / 2);
|
||||
// Offset the range thumb in order to be able to calculate the relative progress (#954)
|
||||
width: calc(100% + #{$plyr-range-thumb-height});
|
||||
}
|
||||
|
||||
input[type='range'] {
|
||||
position: relative;
|
||||
z-index: 2;
|
||||
// Offset the range thumb in order to be able to calculate the relative progress (#954)
|
||||
width: calc(100% + #{$plyr-range-thumb-height}) !important;
|
||||
margin: 0 -#{$plyr-range-thumb-height / 2} !important;
|
||||
}
|
||||
|
||||
// Seek tooltip to show time
|
||||
@ -24,18 +29,17 @@
|
||||
}
|
||||
}
|
||||
|
||||
.plyr__progress--buffer {
|
||||
.plyr__progress__buffer {
|
||||
-webkit-appearance: none; /* stylelint-disable-line */
|
||||
background: transparent;
|
||||
border: 0;
|
||||
border-radius: 100px;
|
||||
height: $plyr-range-track-height;
|
||||
left: 0;
|
||||
margin: -($plyr-range-track-height / 2) 0 0;
|
||||
margin-top: -($plyr-range-track-height / 2);
|
||||
padding: 0;
|
||||
position: absolute;
|
||||
top: 50%;
|
||||
width: 100%;
|
||||
|
||||
&::-webkit-progress-bar {
|
||||
background: transparent;
|
||||
@ -63,17 +67,17 @@
|
||||
}
|
||||
}
|
||||
|
||||
.plyr--video .plyr__progress--buffer {
|
||||
.plyr--video .plyr__progress__buffer {
|
||||
box-shadow: 0 1px 1px rgba(#000, 0.15);
|
||||
color: $plyr-video-progress-buffered-bg;
|
||||
}
|
||||
|
||||
.plyr--audio .plyr__progress--buffer {
|
||||
.plyr--audio .plyr__progress__buffer {
|
||||
color: $plyr-audio-progress-buffered-bg;
|
||||
}
|
||||
|
||||
// Loading state
|
||||
.plyr--loading .plyr__progress--buffer {
|
||||
.plyr--loading .plyr__progress__buffer {
|
||||
animation: plyr-progress 1s linear infinite;
|
||||
background-image: linear-gradient(
|
||||
-45deg,
|
||||
@ -90,10 +94,10 @@
|
||||
color: transparent;
|
||||
}
|
||||
|
||||
.plyr--video.plyr--loading .plyr__progress--buffer {
|
||||
.plyr--video.plyr--loading .plyr__progress__buffer {
|
||||
background-color: $plyr-video-progress-buffered-bg;
|
||||
}
|
||||
|
||||
.plyr--audio.plyr--loading .plyr__progress--buffer {
|
||||
.plyr--audio.plyr--loading .plyr__progress__buffer {
|
||||
background-color: $plyr-audio-progress-buffered-bg;
|
||||
}
|
||||
|
@ -31,12 +31,12 @@
|
||||
@import 'components/controls';
|
||||
@import 'components/embed';
|
||||
@import 'components/menus';
|
||||
@import 'components/progress';
|
||||
@import 'components/poster';
|
||||
@import 'components/sliders';
|
||||
@import 'components/poster';
|
||||
@import 'components/times';
|
||||
@import 'components/tooltips';
|
||||
@import 'components/video';
|
||||
@import 'components/progress';
|
||||
@import 'components/volume';
|
||||
|
||||
@import 'states/fullscreen';
|
||||
|
Loading…
x
Reference in New Issue
Block a user