-   Accessibility improvements (see #905)
-   Improvements to the way the controls work on iOS
-   Demo code clean up
-   YouTube quality selection removed due to their poor support for it. As a result, the `qualityrequested` event has been removed
-   Controls spacing improvements
-   Fix for pressed property missing with custom controls (Fixes #1062)
-   Fix #1153: Captions language fallback (thanks @friday)
-   Fix for setting pressed property of undefined (Fixes #1102)
This commit is contained in:
Sam Potts
2018-08-14 00:02:01 +10:00
parent 48bf368316
commit b57b7b2153
18 changed files with 242 additions and 317 deletions
+1 -1
View File
File diff suppressed because one or more lines are too long
+3 -2
View File
@@ -4118,9 +4118,10 @@ typeof navigator === "object" && (function () {
// Remove class on blur // Remove class on blur
document.addEventListener('focusout', function (event) { document.addEventListener('focusout', function (event) {
if (container.contains(event.target)) { if (!event.target.classList || container.contains(event.target)) {
return; return;
} }
event.target.classList.remove(tabClassName); event.target.classList.remove(tabClassName);
}); });
@@ -4135,7 +4136,7 @@ typeof navigator === "object" && (function () {
setTimeout(function () { setTimeout(function () {
var focused = document.activeElement; var focused = document.activeElement;
if (!focused || container.contains(focused)) { if (!focused || !focused.classList || container.contains(focused)) {
return; return;
} }
+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
+66 -119
View File
@@ -886,6 +886,9 @@ typeof navigator === "object" && (function (global, factory) {
triggerEvent.call(player, player.media, 'qualitychange', false, { triggerEvent.call(player, player.media, 'qualitychange', false, {
quality: input quality: input
}); });
// Save to storage
player.storage.set({ quality: input });
} }
}); });
}, },
@@ -918,6 +921,30 @@ typeof navigator === "object" && (function (global, factory) {
// ========================================================================== // ==========================================================================
// Remove duplicates in an array
function dedupe(array) {
if (!is.array(array)) {
return array;
}
return array.filter(function (item, index) {
return array.indexOf(item) === index;
});
}
// Get the closest value in an array
function closest(array, value) {
if (!is.array(array) || !array.length) {
return null;
}
return array.reduce(function (prev, curr) {
return Math.abs(curr - value) < Math.abs(prev - value) ? curr : prev;
});
}
// ==========================================================================
// Clone nested objects // Clone nested objects
function cloneDeep(object) { function cloneDeep(object) {
return JSON.parse(JSON.stringify(object)); return JSON.parse(JSON.stringify(object));
@@ -1096,30 +1123,6 @@ typeof navigator === "object" && (function (global, factory) {
// ========================================================================== // ==========================================================================
// Remove duplicates in an array
function dedupe(array) {
if (!is.array(array)) {
return array;
}
return array.filter(function (item, index) {
return array.indexOf(item) === index;
});
}
// Get the closest value in an array
function closest(array, value) {
if (!is.array(array) || !array.length) {
return null;
}
return array.reduce(function (prev, curr) {
return Math.abs(curr - value) < Math.abs(prev - value) ? curr : prev;
});
}
// ==========================================================================
var Storage = function () { var Storage = function () {
function Storage(player) { function Storage(player) {
classCallCheck(this, Storage); classCallCheck(this, Storage);
@@ -1604,20 +1607,6 @@ typeof navigator === "object" && (function (global, factory) {
this.elements.buttons[type] = button; this.elements.buttons[type] = button;
} }
// Toggle classname when pressed property is set
var className = this.config.classNames.controlPressed;
Object.defineProperty(button, 'pressed', {
enumerable: true,
get: function get$$1() {
return hasClass(button, className);
},
set: function set$$1() {
var pressed = arguments.length > 0 && arguments[0] !== undefined ? arguments[0] : false;
toggleClass(button, className, pressed);
}
});
return button; return button;
}, },
@@ -2490,9 +2479,8 @@ typeof navigator === "object" && (function (global, factory) {
// Focus the first item if key interaction // Focus the first item if key interaction
if (show && is.keyboardEvent(input)) { if (show && is.keyboardEvent(input)) {
controls.focusFirstMenuItem.call(this, null, true); controls.focusFirstMenuItem.call(this, null, true);
} } else if (!show && !hidden) {
// If closing, re-focus the button // If closing, re-focus the button
else if (!show && !hidden) {
setFocus.call(this, button, is.keyboardEvent(input)); setFocus.call(this, button, is.keyboardEvent(input));
} }
}, },
@@ -2651,17 +2639,19 @@ typeof navigator === "object" && (function (global, factory) {
container.appendChild(controls.createTime.call(this, 'duration')); container.appendChild(controls.createTime.call(this, 'duration'));
} }
// Toggle mute button // Volume controls
if (this.config.controls.includes('mute')) { if (this.config.controls.includes('mute') || this.config.controls.includes('volume')) {
container.appendChild(controls.createButton.call(this, 'mute'));
}
// Volume range control
if (this.config.controls.includes('volume')) {
var volume = createElement('div', { var volume = createElement('div', {
class: 'plyr__volume' class: 'plyr__volume'
}); });
// Toggle mute button
if (this.config.controls.includes('mute')) {
volume.appendChild(controls.createButton.call(this, 'mute'));
}
// Volume range control
if (this.config.controls.includes('volume')) {
// Set the attributes // Set the attributes
var attributes = { var attributes = {
max: 1, max: 1,
@@ -2675,6 +2665,7 @@ typeof navigator === "object" && (function (global, factory) {
}))); })));
this.elements.volume = volume; this.elements.volume = volume;
}
container.appendChild(volume); container.appendChild(volume);
} }
@@ -2836,6 +2827,7 @@ typeof navigator === "object" && (function (global, factory) {
this.elements.controls = container; this.elements.controls = container;
// Set available quality levels
if (this.isHTML5) { if (this.isHTML5) {
controls.setQualityMenu.call(this, html5.getQualityOptions.call(this)); controls.setQualityMenu.call(this, html5.getQualityOptions.call(this));
} }
@@ -2948,6 +2940,25 @@ typeof navigator === "object" && (function (global, factory) {
controls.findElements.call(this); controls.findElements.call(this);
} }
// Add pressed property to buttons
if (!is.empty(this.elements.buttons)) {
// Toggle classname when pressed property is set
Object.values(this.elements.buttons).forEach(function (button) {
var className = _this10.config.classNames.controlPressed;
Object.defineProperty(button, 'pressed', {
enumerable: true,
get: function get$$1() {
return hasClass(button, className);
},
set: function set$$1() {
var pressed = arguments.length > 0 && arguments[0] !== undefined ? arguments[0] : false;
toggleClass(button, className, pressed);
}
});
});
}
// Edge sometimes doesn't finish the paint so force a redraw // Edge sometimes doesn't finish the paint so force a redraw
if (window.navigator.userAgent.includes('Edge')) { if (window.navigator.userAgent.includes('Edge')) {
repaint(target); repaint(target);
@@ -3065,7 +3076,8 @@ typeof navigator === "object" && (function (global, factory) {
// * active: The state preferred by user settings or config // * active: The state preferred by user settings or config
// * toggled: The real captions state // * toggled: The real captions state
var languages = dedupe(Array.from(navigator.languages || navigator.language || navigator.userLanguage).map(function (language) { var browserLanguages = navigator.languages || [navigator.language || navigator.userLanguage || 'en'];
var languages = dedupe(browserLanguages.map(function (language) {
return language.split('-')[0]; return language.split('-')[0];
})); }));
@@ -3488,7 +3500,7 @@ typeof navigator === "object" && (function (global, factory) {
// Quality default // Quality default
quality: { quality: {
default: 576, default: 576,
options: [4320, 2880, 2160, 1440, 1080, 720, 576, 480, 360, 240, 'default'] options: [4320, 2880, 2160, 1440, 1080, 720, 576, 480, 360, 240]
}, },
// Set loops // Set loops
@@ -3638,7 +3650,10 @@ typeof navigator === "object" && (function (global, factory) {
'enterfullscreen', 'exitfullscreen', 'captionsenabled', 'captionsdisabled', 'languagechange', 'controlshidden', 'controlsshown', 'ready', 'enterfullscreen', 'exitfullscreen', 'captionsenabled', 'captionsdisabled', 'languagechange', 'controlshidden', 'controlsshown', 'ready',
// YouTube // YouTube
'statechange', 'qualitychange', 'qualityrequested', 'statechange',
// Quality
'qualitychange',
// Ads // Ads
'adsloaded', 'adscontentpause', 'adscontentresume', 'adstarted', 'adsmidpoint', 'adscomplete', 'adsallcomplete', 'adsimpression', 'adsclick'], 'adsloaded', 'adscontentpause', 'adscontentresume', 'adstarted', 'adsmidpoint', 'adscomplete', 'adsallcomplete', 'adsimpression', 'adsclick'],
@@ -3947,9 +3962,7 @@ typeof navigator === "object" && (function (global, factory) {
// iOS native fullscreen doesn't need the request step // iOS native fullscreen doesn't need the request step
if (browser.isIos && this.player.config.fullscreen.iosNative) { if (browser.isIos && this.player.config.fullscreen.iosNative) {
if (this.player.playing) {
this.target.webkitEnterFullscreen(); this.target.webkitEnterFullscreen();
}
} else if (!Fullscreen.native) { } else if (!Fullscreen.native) {
toggleFallback.call(this, true); toggleFallback.call(this, true);
} else if (!this.prefix) { } else if (!this.prefix) {
@@ -4636,7 +4649,7 @@ typeof navigator === "object" && (function (global, factory) {
// Remove button states for fullscreen // Remove button states for fullscreen
if (event.type === 'enterfullscreen') { if (controls$$1 && event.type === 'enterfullscreen') {
controls$$1.pressed = false; controls$$1.pressed = false;
controls$$1.hover = false; controls$$1.hover = false;
} }
@@ -4794,12 +4807,6 @@ typeof navigator === "object" && (function (global, factory) {
player.storage.set({ speed: player.speed }); player.storage.set({ speed: player.speed });
}); });
// Quality request
on.call(player, player.media, 'qualityrequested', function (event) {
// Save to storage
player.storage.set({ quality: event.detail.quality });
});
// Quality change // Quality change
on.call(player, player.media, 'qualitychange', function (event) { on.call(player, player.media, 'qualitychange', function (event) {
// Update UI // Update UI
@@ -5879,43 +5886,6 @@ typeof navigator === "object" && (function (global, factory) {
return url.match(regex) ? RegExp.$2 : url; return url.match(regex) ? RegExp.$2 : url;
} }
// Standardise YouTube quality unit
function mapQualityUnit(input) {
var qualities = {
hd2160: 2160,
hd1440: 1440,
hd1080: 1080,
hd720: 720,
large: 480,
medium: 360,
small: 240,
tiny: 144
};
var entry = Object.entries(qualities).find(function (entry) {
return entry.includes(input);
});
if (entry) {
// Get the match corresponding to the input
return entry.find(function (value) {
return value !== input;
});
}
return 'default';
}
function mapQualityUnits(levels) {
if (is.empty(levels)) {
return levels;
}
return dedupe(levels.map(function (level) {
return mapQualityUnit(level);
}));
}
// 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) { if (play && !this.embed.hasPlayed) {
@@ -6099,11 +6069,6 @@ typeof navigator === "object" && (function (global, factory) {
triggerEvent.call(player, player.media, 'error'); triggerEvent.call(player, player.media, 'error');
} }
}, },
onPlaybackQualityChange: function onPlaybackQualityChange() {
triggerEvent.call(player, player.media, 'qualitychange', false, {
quality: player.media.quality
});
},
onPlaybackRateChange: function onPlaybackRateChange(event) { onPlaybackRateChange: function onPlaybackRateChange(event) {
// Get the instance // Get the instance
var instance = event.target; var instance = event.target;
@@ -6173,16 +6138,6 @@ typeof navigator === "object" && (function (global, factory) {
} }
}); });
// Quality
Object.defineProperty(player.media, 'quality', {
get: function get() {
return mapQualityUnit(instance.getPlaybackQuality());
},
set: function set(input) {
instance.setPlaybackQuality(mapQualityUnit(input));
}
});
// Volume // Volume
var volume = player.config.volume; var volume = player.config.volume;
@@ -6335,9 +6290,6 @@ typeof navigator === "object" && (function (global, factory) {
player.media.duration = instance.getDuration(); player.media.duration = instance.getDuration();
triggerEvent.call(player, player.media, 'durationchange'); triggerEvent.call(player, player.media, 'durationchange');
} }
// Get quality
controls.setQualityMenu.call(player, mapQualityUnits(instance.getAvailableQualityLevels()));
} }
break; break;
@@ -8203,11 +8155,6 @@ typeof navigator === "object" && (function (global, factory) {
quality = value; quality = value;
} }
// Trigger request event
triggerEvent.call(this, this.media, 'qualityrequested', false, {
quality: quality
});
// Update config // Update config
config.selected = quality; config.selected = quality;
+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
+123 -146
View File
@@ -20,7 +20,7 @@ typeof navigator === "object" && (function (global, factory) {
}); });
var _core = createCommonjsModule(function (module) { var _core = createCommonjsModule(function (module) {
var core = module.exports = { version: '2.5.3' }; var core = module.exports = { version: '2.5.7' };
if (typeof __e == 'number') __e = core; // eslint-disable-line no-undef if (typeof __e == 'number') __e = core; // eslint-disable-line no-undef
}); });
var _core_1 = _core.version; var _core_1 = _core.version;
@@ -333,11 +333,18 @@ typeof navigator === "object" && (function (global, factory) {
}; };
}; };
var _shared = createCommonjsModule(function (module) {
var SHARED = '__core-js_shared__'; var SHARED = '__core-js_shared__';
var store = _global[SHARED] || (_global[SHARED] = {}); var store = _global[SHARED] || (_global[SHARED] = {});
var _shared = function (key) {
return store[key] || (store[key] = {}); (module.exports = function (key, value) {
}; return store[key] || (store[key] = value !== undefined ? value : {});
})('versions', []).push({
version: _core.version,
mode: 'global',
copyright: '© 2018 Denis Pushkarev (zloirock.ru)'
});
});
var shared = _shared('keys'); var shared = _shared('keys');
@@ -741,12 +748,12 @@ typeof navigator === "object" && (function (global, factory) {
if ($slice !== undefined && end === undefined) return $slice.call(_anObject(this), start); // FF fix if ($slice !== undefined && end === undefined) return $slice.call(_anObject(this), start); // FF fix
var len = _anObject(this).byteLength; var len = _anObject(this).byteLength;
var first = _toAbsoluteIndex(start, len); var first = _toAbsoluteIndex(start, len);
var final = _toAbsoluteIndex(end === undefined ? len : end, len); var fin = _toAbsoluteIndex(end === undefined ? len : end, len);
var result = new (_speciesConstructor(this, $ArrayBuffer))(_toLength(final - first)); var result = new (_speciesConstructor(this, $ArrayBuffer))(_toLength(fin - first));
var viewS = new $DataView(this); var viewS = new $DataView(this);
var viewT = new $DataView(result); var viewT = new $DataView(result);
var index = 0; var index = 0;
while (first < final) { while (first < fin) {
viewT.setUint8(index++, viewS.getUint8(first++)); viewT.setUint8(index++, viewS.getUint8(first++));
} return result; } return result;
} }
@@ -991,7 +998,7 @@ typeof navigator === "object" && (function (global, factory) {
var VALUES_BUG = false; var VALUES_BUG = false;
var proto = Base.prototype; var proto = Base.prototype;
var $native = proto[ITERATOR$2] || proto[FF_ITERATOR] || DEFAULT && proto[DEFAULT]; var $native = proto[ITERATOR$2] || proto[FF_ITERATOR] || DEFAULT && proto[DEFAULT];
var $default = (!BUGGY && $native) || getMethod(DEFAULT); var $default = $native || getMethod(DEFAULT);
var $entries = DEFAULT ? !DEF_VALUES ? $default : getMethod('entries') : undefined; var $entries = DEFAULT ? !DEF_VALUES ? $default : getMethod('entries') : undefined;
var $anyNative = NAME == 'Array' ? proto.entries || $native : $native; var $anyNative = NAME == 'Array' ? proto.entries || $native : $native;
var methods, key, IteratorPrototype; var methods, key, IteratorPrototype;
@@ -1002,7 +1009,7 @@ typeof navigator === "object" && (function (global, factory) {
// Set @@toStringTag to native iterators // Set @@toStringTag to native iterators
_setToStringTag(IteratorPrototype, TAG, true); _setToStringTag(IteratorPrototype, TAG, true);
// fix for some old engines // fix for some old engines
if (!_has(IteratorPrototype, ITERATOR$2)) _hide(IteratorPrototype, ITERATOR$2, returnThis); if (typeof IteratorPrototype[ITERATOR$2] != 'function') _hide(IteratorPrototype, ITERATOR$2, returnThis);
} }
} }
// fix Array#{values, @@iterator}.name in V8 / FF // fix Array#{values, @@iterator}.name in V8 / FF
@@ -2495,9 +2502,11 @@ typeof navigator === "object" && (function (global, factory) {
} }
if (_has(ownDesc, 'value')) { if (_has(ownDesc, 'value')) {
if (ownDesc.writable === false || !_isObject(receiver)) return false; if (ownDesc.writable === false || !_isObject(receiver)) return false;
existingDescriptor = _objectGopd.f(receiver, propertyKey) || _propertyDesc(0); if (existingDescriptor = _objectGopd.f(receiver, propertyKey)) {
if (existingDescriptor.get || existingDescriptor.set || existingDescriptor.writable === false) return false;
existingDescriptor.value = V; existingDescriptor.value = V;
_objectDp.f(receiver, propertyKey, existingDescriptor); _objectDp.f(receiver, propertyKey, existingDescriptor);
} else _objectDp.f(receiver, propertyKey, _propertyDesc(0, V));
return true; return true;
} }
return ownDesc.set === undefined ? false : (ownDesc.set.call(receiver, V), true); return ownDesc.set === undefined ? false : (ownDesc.set.call(receiver, V), true);
@@ -2642,7 +2651,8 @@ typeof navigator === "object" && (function (global, factory) {
}; };
// environments with maybe non-completely correct, but existent Promise // environments with maybe non-completely correct, but existent Promise
} else if (Promise$1 && Promise$1.resolve) { } else if (Promise$1 && Promise$1.resolve) {
var promise = Promise$1.resolve(); // Promise.resolve without an argument throws an error in LG WebOS 2
var promise = Promise$1.resolve(undefined);
notify = function () { notify = function () {
promise.then(flush); promise.then(flush);
}; };
@@ -2699,6 +2709,10 @@ typeof navigator === "object" && (function (global, factory) {
} }
}; };
var navigator$1 = _global.navigator;
var _userAgent = navigator$1 && navigator$1.userAgent || '';
var _promiseResolve = function (C, x) { var _promiseResolve = function (C, x) {
_anObject(C); _anObject(C);
if (_isObject(x) && x.constructor === C) return x; if (_isObject(x) && x.constructor === C) return x;
@@ -2713,9 +2727,12 @@ typeof navigator === "object" && (function (global, factory) {
var PROMISE = 'Promise'; var PROMISE = 'Promise';
var TypeError$1 = _global.TypeError; var TypeError$1 = _global.TypeError;
var process$2 = _global.process; var process$2 = _global.process;
var versions = process$2 && process$2.versions;
var v8 = versions && versions.v8 || '';
var $Promise = _global[PROMISE]; var $Promise = _global[PROMISE];
var isNode$1 = _classof(process$2) == 'process'; var isNode$1 = _classof(process$2) == 'process';
var empty = function () { /* empty */ }; var empty = function () { /* empty */ };
@@ -2730,7 +2747,13 @@ typeof navigator === "object" && (function (global, factory) {
exec(empty, empty); exec(empty, empty);
}; };
// unhandled rejections tracking support, NodeJS Promise without it fails @@species test // unhandled rejections tracking support, NodeJS Promise without it fails @@species test
return (isNode$1 || typeof PromiseRejectionEvent == 'function') && promise.then(empty) instanceof FakePromise; 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;
} catch (e) { /* empty */ } } catch (e) { /* empty */ }
}(); }();
@@ -2752,7 +2775,7 @@ typeof navigator === "object" && (function (global, factory) {
var resolve = reaction.resolve; var resolve = reaction.resolve;
var reject = reaction.reject; var reject = reaction.reject;
var domain = reaction.domain; var domain = reaction.domain;
var result, then; var result, then, exited;
try { try {
if (handler) { if (handler) {
if (!ok) { if (!ok) {
@@ -2762,8 +2785,11 @@ typeof navigator === "object" && (function (global, factory) {
if (handler === true) result = value; if (handler === true) result = value;
else { else {
if (domain) domain.enter(); if (domain) domain.enter();
result = handler(value); result = handler(value); // may throw
if (domain) domain.exit(); if (domain) {
domain.exit();
exited = true;
}
} }
if (result === reaction.promise) { if (result === reaction.promise) {
reject(TypeError$1('Promise-chain cycle')); reject(TypeError$1('Promise-chain cycle'));
@@ -2772,6 +2798,7 @@ typeof navigator === "object" && (function (global, factory) {
} else resolve(result); } else resolve(result);
} else reject(value); } else reject(value);
} catch (e) { } catch (e) {
if (domain && !exited) domain.exit();
reject(e); reject(e);
} }
}; };
@@ -4154,10 +4181,6 @@ typeof navigator === "object" && (function (global, factory) {
return left ? stringFiller + S : S + stringFiller; 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 // https://github.com/tc39/proposal-string-pad-start-end
@@ -5190,12 +5213,11 @@ typeof navigator === "object" && (function (global, factory) {
} }
proto.toString = function() { proto.toString = function() {
var searchString = ''; var searchArray = [];
this.forEach(function(value, name) { this.forEach(function(value, name) {
if(searchString.length > 0) searchString+= '&'; searchArray.push(serializeParam(name) + '=' + serializeParam(value));
searchString += serializeParam(name) + '=' + serializeParam(value);
}); });
return searchString; return searchArray.join("&");
}; };
global.URLSearchParams = URLSearchParams; global.URLSearchParams = URLSearchParams;
@@ -5237,18 +5259,26 @@ typeof navigator === "object" && (function (global, factory) {
var URL = function(url, base) { var URL = function(url, base) {
if(typeof url !== 'string') url = String(url); if(typeof url !== 'string') url = String(url);
var doc = document.implementation.createHTMLDocument(''); // Only create another document if the base is different from current location.
window.doc = doc; var doc = document, baseElement;
if(base) { if(base && (global.location === void 0 || base !== global.location.href)) {
var baseElement = doc.createElement('base'); doc = document.implementation.createHTMLDocument('');
baseElement = doc.createElement('base');
baseElement.href = base; baseElement.href = base;
doc.head.appendChild(baseElement); doc.head.appendChild(baseElement);
try {
if(baseElement.href.indexOf(base) !== 0) throw new Error(baseElement.href);
} catch (err) {
throw new Error("URL unable to set base " + base + " due to " + err);
}
} }
var anchorElement = doc.createElement('a'); var anchorElement = doc.createElement('a');
anchorElement.href = url; anchorElement.href = url;
if (baseElement) {
doc.body.appendChild(anchorElement); doc.body.appendChild(anchorElement);
anchorElement.href = anchorElement.href; // force href to refresh anchorElement.href = anchorElement.href; // force href to refresh
}
if(anchorElement.protocol === ':' || !/:/.test(anchorElement.href)) { if(anchorElement.protocol === ':' || !/:/.test(anchorElement.href)) {
throw new TypeError('Invalid URL'); throw new TypeError('Invalid URL');
@@ -6283,6 +6313,9 @@ typeof navigator === "object" && (function (global, factory) {
triggerEvent.call(player, player.media, 'qualitychange', false, { triggerEvent.call(player, player.media, 'qualitychange', false, {
quality: input quality: input
}); });
// Save to storage
player.storage.set({ quality: input });
} }
}); });
}, },
@@ -6315,6 +6348,30 @@ typeof navigator === "object" && (function (global, factory) {
// ========================================================================== // ==========================================================================
// Remove duplicates in an array
function dedupe(array) {
if (!is$1.array(array)) {
return array;
}
return array.filter(function (item, index) {
return array.indexOf(item) === index;
});
}
// Get the closest value in an array
function closest(array, value) {
if (!is$1.array(array) || !array.length) {
return null;
}
return array.reduce(function (prev, curr) {
return Math.abs(curr - value) < Math.abs(prev - value) ? curr : prev;
});
}
// ==========================================================================
// Clone nested objects // Clone nested objects
function cloneDeep(object) { function cloneDeep(object) {
return JSON.parse(JSON.stringify(object)); return JSON.parse(JSON.stringify(object));
@@ -6493,30 +6550,6 @@ typeof navigator === "object" && (function (global, factory) {
// ========================================================================== // ==========================================================================
// Remove duplicates in an array
function dedupe(array) {
if (!is$1.array(array)) {
return array;
}
return array.filter(function (item, index) {
return array.indexOf(item) === index;
});
}
// Get the closest value in an array
function closest(array, value) {
if (!is$1.array(array) || !array.length) {
return null;
}
return array.reduce(function (prev, curr) {
return Math.abs(curr - value) < Math.abs(prev - value) ? curr : prev;
});
}
// ==========================================================================
var Storage = function () { var Storage = function () {
function Storage(player) { function Storage(player) {
classCallCheck(this, Storage); classCallCheck(this, Storage);
@@ -7001,20 +7034,6 @@ typeof navigator === "object" && (function (global, factory) {
this.elements.buttons[type] = button; this.elements.buttons[type] = button;
} }
// Toggle classname when pressed property is set
var className = this.config.classNames.controlPressed;
Object.defineProperty(button, 'pressed', {
enumerable: true,
get: function get() {
return hasClass(button, className);
},
set: function set() {
var pressed = arguments.length > 0 && arguments[0] !== undefined ? arguments[0] : false;
toggleClass(button, className, pressed);
}
});
return button; return button;
}, },
@@ -7887,9 +7906,8 @@ typeof navigator === "object" && (function (global, factory) {
// Focus the first item if key interaction // Focus the first item if key interaction
if (show && is$1.keyboardEvent(input)) { if (show && is$1.keyboardEvent(input)) {
controls.focusFirstMenuItem.call(this, null, true); controls.focusFirstMenuItem.call(this, null, true);
} } else if (!show && !hidden) {
// If closing, re-focus the button // If closing, re-focus the button
else if (!show && !hidden) {
setFocus.call(this, button, is$1.keyboardEvent(input)); setFocus.call(this, button, is$1.keyboardEvent(input));
} }
}, },
@@ -8048,17 +8066,19 @@ typeof navigator === "object" && (function (global, factory) {
container.appendChild(controls.createTime.call(this, 'duration')); container.appendChild(controls.createTime.call(this, 'duration'));
} }
// Toggle mute button // Volume controls
if (this.config.controls.includes('mute')) { if (this.config.controls.includes('mute') || this.config.controls.includes('volume')) {
container.appendChild(controls.createButton.call(this, 'mute'));
}
// Volume range control
if (this.config.controls.includes('volume')) {
var volume = createElement('div', { var volume = createElement('div', {
class: 'plyr__volume' class: 'plyr__volume'
}); });
// Toggle mute button
if (this.config.controls.includes('mute')) {
volume.appendChild(controls.createButton.call(this, 'mute'));
}
// Volume range control
if (this.config.controls.includes('volume')) {
// Set the attributes // Set the attributes
var attributes = { var attributes = {
max: 1, max: 1,
@@ -8072,6 +8092,7 @@ typeof navigator === "object" && (function (global, factory) {
}))); })));
this.elements.volume = volume; this.elements.volume = volume;
}
container.appendChild(volume); container.appendChild(volume);
} }
@@ -8233,6 +8254,7 @@ typeof navigator === "object" && (function (global, factory) {
this.elements.controls = container; this.elements.controls = container;
// Set available quality levels
if (this.isHTML5) { if (this.isHTML5) {
controls.setQualityMenu.call(this, html5.getQualityOptions.call(this)); controls.setQualityMenu.call(this, html5.getQualityOptions.call(this));
} }
@@ -8345,6 +8367,25 @@ typeof navigator === "object" && (function (global, factory) {
controls.findElements.call(this); controls.findElements.call(this);
} }
// Add pressed property to buttons
if (!is$1.empty(this.elements.buttons)) {
// Toggle classname when pressed property is set
Object.values(this.elements.buttons).forEach(function (button) {
var className = _this10.config.classNames.controlPressed;
Object.defineProperty(button, 'pressed', {
enumerable: true,
get: function get() {
return hasClass(button, className);
},
set: function set() {
var pressed = arguments.length > 0 && arguments[0] !== undefined ? arguments[0] : false;
toggleClass(button, className, pressed);
}
});
});
}
// Edge sometimes doesn't finish the paint so force a redraw // Edge sometimes doesn't finish the paint so force a redraw
if (window.navigator.userAgent.includes('Edge')) { if (window.navigator.userAgent.includes('Edge')) {
repaint(target); repaint(target);
@@ -8462,7 +8503,8 @@ typeof navigator === "object" && (function (global, factory) {
// * active: The state preferred by user settings or config // * active: The state preferred by user settings or config
// * toggled: The real captions state // * toggled: The real captions state
var languages = dedupe(Array.from(navigator.languages || navigator.language || navigator.userLanguage).map(function (language) { var browserLanguages = navigator.languages || [navigator.language || navigator.userLanguage || 'en'];
var languages = dedupe(browserLanguages.map(function (language) {
return language.split('-')[0]; return language.split('-')[0];
})); }));
@@ -8885,7 +8927,7 @@ typeof navigator === "object" && (function (global, factory) {
// Quality default // Quality default
quality: { quality: {
default: 576, default: 576,
options: [4320, 2880, 2160, 1440, 1080, 720, 576, 480, 360, 240, 'default'] options: [4320, 2880, 2160, 1440, 1080, 720, 576, 480, 360, 240]
}, },
// Set loops // Set loops
@@ -9035,7 +9077,10 @@ typeof navigator === "object" && (function (global, factory) {
'enterfullscreen', 'exitfullscreen', 'captionsenabled', 'captionsdisabled', 'languagechange', 'controlshidden', 'controlsshown', 'ready', 'enterfullscreen', 'exitfullscreen', 'captionsenabled', 'captionsdisabled', 'languagechange', 'controlshidden', 'controlsshown', 'ready',
// YouTube // YouTube
'statechange', 'qualitychange', 'qualityrequested', 'statechange',
// Quality
'qualitychange',
// Ads // Ads
'adsloaded', 'adscontentpause', 'adscontentresume', 'adstarted', 'adsmidpoint', 'adscomplete', 'adsallcomplete', 'adsimpression', 'adsclick'], 'adsloaded', 'adscontentpause', 'adscontentresume', 'adstarted', 'adsmidpoint', 'adscomplete', 'adsallcomplete', 'adsimpression', 'adsclick'],
@@ -9344,9 +9389,7 @@ typeof navigator === "object" && (function (global, factory) {
// iOS native fullscreen doesn't need the request step // iOS native fullscreen doesn't need the request step
if (browser.isIos && this.player.config.fullscreen.iosNative) { if (browser.isIos && this.player.config.fullscreen.iosNative) {
if (this.player.playing) {
this.target.webkitEnterFullscreen(); this.target.webkitEnterFullscreen();
}
} else if (!Fullscreen.native) { } else if (!Fullscreen.native) {
toggleFallback.call(this, true); toggleFallback.call(this, true);
} else if (!this.prefix) { } else if (!this.prefix) {
@@ -10033,7 +10076,7 @@ typeof navigator === "object" && (function (global, factory) {
// Remove button states for fullscreen // Remove button states for fullscreen
if (event.type === 'enterfullscreen') { if (controls$$1 && event.type === 'enterfullscreen') {
controls$$1.pressed = false; controls$$1.pressed = false;
controls$$1.hover = false; controls$$1.hover = false;
} }
@@ -10191,12 +10234,6 @@ typeof navigator === "object" && (function (global, factory) {
player.storage.set({ speed: player.speed }); player.storage.set({ speed: player.speed });
}); });
// Quality request
on.call(player, player.media, 'qualityrequested', function (event) {
// Save to storage
player.storage.set({ quality: event.detail.quality });
});
// Quality change // Quality change
on.call(player, player.media, 'qualitychange', function (event) { on.call(player, player.media, 'qualitychange', function (event) {
// Update UI // Update UI
@@ -11270,43 +11307,6 @@ typeof navigator === "object" && (function (global, factory) {
return url.match(regex) ? RegExp.$2 : url; return url.match(regex) ? RegExp.$2 : url;
} }
// Standardise YouTube quality unit
function mapQualityUnit(input) {
var qualities = {
hd2160: 2160,
hd1440: 1440,
hd1080: 1080,
hd720: 720,
large: 480,
medium: 360,
small: 240,
tiny: 144
};
var entry = Object.entries(qualities).find(function (entry) {
return entry.includes(input);
});
if (entry) {
// Get the match corresponding to the input
return entry.find(function (value) {
return value !== input;
});
}
return 'default';
}
function mapQualityUnits(levels) {
if (is$1.empty(levels)) {
return levels;
}
return dedupe(levels.map(function (level) {
return mapQualityUnit(level);
}));
}
// 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) { if (play && !this.embed.hasPlayed) {
@@ -11490,11 +11490,6 @@ typeof navigator === "object" && (function (global, factory) {
triggerEvent.call(player, player.media, 'error'); triggerEvent.call(player, player.media, 'error');
} }
}, },
onPlaybackQualityChange: function onPlaybackQualityChange() {
triggerEvent.call(player, player.media, 'qualitychange', false, {
quality: player.media.quality
});
},
onPlaybackRateChange: function onPlaybackRateChange(event) { onPlaybackRateChange: function onPlaybackRateChange(event) {
// Get the instance // Get the instance
var instance = event.target; var instance = event.target;
@@ -11564,16 +11559,6 @@ typeof navigator === "object" && (function (global, factory) {
} }
}); });
// Quality
Object.defineProperty(player.media, 'quality', {
get: function get() {
return mapQualityUnit(instance.getPlaybackQuality());
},
set: function set(input) {
instance.setPlaybackQuality(mapQualityUnit(input));
}
});
// Volume // Volume
var volume = player.config.volume; var volume = player.config.volume;
@@ -11726,9 +11711,6 @@ typeof navigator === "object" && (function (global, factory) {
player.media.duration = instance.getDuration(); player.media.duration = instance.getDuration();
triggerEvent.call(player, player.media, 'durationchange'); triggerEvent.call(player, player.media, 'durationchange');
} }
// Get quality
controls.setQualityMenu.call(player, mapQualityUnits(instance.getAvailableQualityLevels()));
} }
break; break;
@@ -13594,11 +13576,6 @@ typeof navigator === "object" && (function (global, factory) {
quality = value; quality = value;
} }
// Trigger request event
triggerEvent.call(this, this.media, 'qualityrequested', false, {
quality: quality
});
// Update config // Update config
config.selected = quality; config.selected = quality;
+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
@@ -1,6 +1,6 @@
{ {
"name": "plyr", "name": "plyr",
"version": "3.4.0-beta.2", "version": "3.4.0",
"description": "A simple, accessible and customizable HTML5, YouTube and Vimeo media player", "description": "A simple, accessible and customizable HTML5, YouTube and Vimeo media player",
"homepage": "https://plyr.io", "homepage": "https://plyr.io",
"author": "Sam Potts <sam@potts.es>", "author": "Sam Potts <sam@potts.es>",
+4 -4
View File
@@ -132,13 +132,13 @@ See [initialising](#initialising) for more information on advanced setups.
You can use our CDN (provided by [Fastly](https://www.fastly.com/)) for the JavaScript. There's 2 versions; one with and one without [polyfills](#polyfills). My recommendation would be to manage polyfills seperately as part of your application but to make life easier you can use the polyfilled build. You can use our CDN (provided by [Fastly](https://www.fastly.com/)) for the JavaScript. There's 2 versions; one with and one without [polyfills](#polyfills). My recommendation would be to manage polyfills seperately as part of your application but to make life easier you can use the polyfilled build.
```html ```html
<script src="https://cdn.plyr.io/3.4.0-beta.2/plyr.js"></script> <script src="https://cdn.plyr.io/3.4.0/plyr.js"></script>
``` ```
...or... ...or...
```html ```html
<script src="https://cdn.plyr.io/3.4.0-beta.2/plyr.polyfilled.js"></script> <script src="https://cdn.plyr.io/3.4.0/plyr.polyfilled.js"></script>
``` ```
### CSS ### CSS
@@ -152,13 +152,13 @@ Include the `plyr.css` stylsheet into your `<head>`
If you want to use our CDN (provided by [Fastly](https://www.fastly.com/)) for the default CSS, you can use the following: If you want to use our CDN (provided by [Fastly](https://www.fastly.com/)) for the default CSS, you can use the following:
```html ```html
<link rel="stylesheet" href="https://cdn.plyr.io/3.4.0-beta.2/plyr.css"> <link rel="stylesheet" href="https://cdn.plyr.io/3.4.0/plyr.css">
``` ```
### SVG Sprite ### SVG Sprite
The SVG sprite is loaded automatically from our CDN (provided by [Fastly](https://www.fastly.com/)). To change this, see the [options](#options) below. For The SVG sprite is loaded automatically from our CDN (provided by [Fastly](https://www.fastly.com/)). To change this, see the [options](#options) below. For
reference, the CDN hosted SVG sprite can be found at `https://cdn.plyr.io/3.4.0-beta.2/plyr.svg`. reference, the CDN hosted SVG sprite can be found at `https://cdn.plyr.io/3.4.0/plyr.svg`.
## Ads ## Ads
+1 -1
View File
@@ -1,6 +1,6 @@
// ========================================================================== // ==========================================================================
// Plyr // Plyr
// plyr.js v3.4.0-beta.2 // plyr.js v3.4.0
// https://github.com/sampotts/plyr // https://github.com/sampotts/plyr
// License: The MIT License (MIT) // License: The MIT License (MIT)
// ========================================================================== // ==========================================================================
+1 -1
View File
@@ -1,6 +1,6 @@
// ========================================================================== // ==========================================================================
// Plyr Polyfilled Build // Plyr Polyfilled Build
// plyr.js v3.4.0-beta.2 // plyr.js v3.4.0
// https://github.com/sampotts/plyr // https://github.com/sampotts/plyr
// License: The MIT License (MIT) // License: The MIT License (MIT)
// ========================================================================== // ==========================================================================