Work on menus

This commit is contained in:
Sam Potts
2018-06-21 09:01:16 +10:00
parent bb546fe43f
commit 1f1d74ba50
18 changed files with 797 additions and 755 deletions
+1 -1
View File
@@ -6,6 +6,6 @@ aws.json
index-*.html index-*.html
npm-debug.log npm-debug.log
*.webm *.webm
/package-lock.json package-lock.json
.idea/ .idea/
+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
@@ -166,7 +166,7 @@
</svg> </svg>
<p>If you think Plyr's good, <p>If you think Plyr's good,
<a href="https://twitter.com/intent/tweet?text=A+simple+HTML5+media+player+with+custom+controls+and+WebVTT+captions.&amp;url=http%3A%2F%2Fplyr.io&amp;via=Sam_Potts" <a href="https://twitter.com/intent/tweet?text=A+simple+HTML5+media+player+with+custom+controls+and+WebVTT+captions.&amp;url=http%3A%2F%2Fplyr.io&amp;via=Sam_Potts"
target="_blank" data-shr-network="twitter">tweet it</a> target="_blank" data-shr-network="twitter">tweet it</a> 👍
</p> </p>
</aside> </aside>
+2 -1
View File
@@ -2,7 +2,8 @@
// Typography // Typography
// ========================================================================== // ==========================================================================
$font-sans-serif: 'Gordita', 'Avenir', 'Helvetica Neue', sans-serif; $font-sans-serif: 'Gordita', 'Avenir', 'Helvetica Neue', sans-serif, 'Apple Color Emoji', 'Segoe UI Emoji',
'Segoe UI Symbol';
$font-size-base: 15; $font-size-base: 15;
$font-size-small: 13; $font-size-small: 13;
+1 -1
View File
File diff suppressed because one or more lines are too long
+335 -296
View File
@@ -11,60 +11,92 @@ typeof navigator === "object" && (function (global, factory) {
var getConstructor = function getConstructor(input) { var getConstructor = function getConstructor(input) {
return input !== null && typeof input !== 'undefined' ? input.constructor : null; return input !== null && typeof input !== 'undefined' ? input.constructor : null;
}; };
var instanceOf = function instanceOf(input, constructor) { var instanceOf = function instanceOf(input, constructor) {
return Boolean(input && constructor && input instanceof constructor); return Boolean(input && constructor && input instanceof constructor);
}; };
var isNullOrUndefined = function isNullOrUndefined(input) {
return input === null || typeof input === 'undefined';
};
var isObject = function isObject(input) {
return getConstructor(input) === Object;
};
var isNumber = function isNumber(input) {
return getConstructor(input) === Number && !Number.isNaN(input);
};
var isString = function isString(input) {
return getConstructor(input) === String;
};
var isBoolean = function isBoolean(input) {
return getConstructor(input) === Boolean;
};
var isFunction = function isFunction(input) {
return getConstructor(input) === Function;
};
var isArray = function isArray(input) {
return Array.isArray(input);
};
var isWeakMap = function isWeakMap(input) {
return instanceOf(input, WeakMap);
};
var isNodeList = function isNodeList(input) {
return instanceOf(input, NodeList);
};
var isElement = function isElement(input) {
return instanceOf(input, Element);
};
var isTextNode = function isTextNode(input) {
return getConstructor(input) === Text;
};
var isEvent = function isEvent(input) {
return instanceOf(input, Event);
};
var isCue = function isCue(input) {
return instanceOf(input, window.TextTrackCue) || instanceOf(input, window.VTTCue);
};
var isTrack = function isTrack(input) {
return instanceOf(input, TextTrack) || !isNullOrUndefined(input) && isString(input.kind);
};
var isEmpty = function isEmpty(input) {
return isNullOrUndefined(input) || (isString(input) || isArray(input) || isNodeList(input)) && !input.length || isObject(input) && !Object.keys(input).length;
};
var isUrl = function isUrl(input) {
// Accept a URL object
if (instanceOf(input, window.URL)) {
return true;
}
// Add the protocol if required
var string = input;
if (!input.startsWith('http://') || !input.startsWith('https://')) {
string = 'http://' + input;
}
try {
return !isEmpty(new URL(string).hostname);
} catch (e) {
return false;
}
};
var is = { var is = {
object: function object(input) { nullOrUndefined: isNullOrUndefined,
return getConstructor(input) === Object; object: isObject,
}, number: isNumber,
number: function number(input) { string: isString,
return getConstructor(input) === Number && !Number.isNaN(input); boolean: isBoolean,
}, function: isFunction,
string: function string(input) { array: isArray,
return getConstructor(input) === String; weakMap: isWeakMap,
}, nodeList: isNodeList,
boolean: function boolean(input) { element: isElement,
return getConstructor(input) === Boolean; textNode: isTextNode,
}, event: isEvent,
function: function _function(input) { cue: isCue,
return getConstructor(input) === Function; track: isTrack,
}, url: isUrl,
array: function array(input) { empty: isEmpty
return !is.nullOrUndefined(input) && Array.isArray(input);
},
weakMap: function weakMap(input) {
return instanceOf(input, WeakMap);
},
nodeList: function nodeList(input) {
return instanceOf(input, NodeList);
},
element: function element(input) {
return instanceOf(input, Element);
},
textNode: function textNode(input) {
return getConstructor(input) === Text;
},
event: function event(input) {
return instanceOf(input, Event);
},
cue: function cue(input) {
return instanceOf(input, window.TextTrackCue) || instanceOf(input, window.VTTCue);
},
track: function track(input) {
return instanceOf(input, TextTrack) || !is.nullOrUndefined(input) && is.string(input.kind);
},
url: function url(input) {
return !is.nullOrUndefined(input) && /(ftp|http|https):\/\/(\w+:{0,1}\w*@)?(\S+)(:[0-9]+)?(\/|\/([\w#!:.?+=&%@!\-/]))?/.test(input);
},
nullOrUndefined: function nullOrUndefined(input) {
return input === null || typeof input === 'undefined';
},
empty: function empty(input) {
return is.nullOrUndefined(input) || (is.string(input) || is.array(input) || is.nodeList(input)) && !input.length || is.object(input) && !Object.keys(input).length;
}
}; };
// ========================================================================== // ==========================================================================
@@ -1637,6 +1669,8 @@ typeof navigator === "object" && (function (global, factory) {
// Create a settings menu item // Create a settings menu item
createMenuItem: function createMenuItem(_ref) { createMenuItem: function createMenuItem(_ref) {
var _this = this;
var value = _ref.value, var value = _ref.value,
list = _ref.list, list = _ref.list,
type = _ref.type, type = _ref.type,
@@ -1652,17 +1686,21 @@ typeof navigator === "object" && (function (global, factory) {
type: 'button', type: 'button',
role: 'menuitemradio', role: 'menuitemradio',
class: (this.config.classNames.control + ' ' + (attributes.class ? attributes.class : '')).trim(), class: (this.config.classNames.control + ' ' + (attributes.class ? attributes.class : '')).trim(),
value: value, 'aria-checked': checked,
'aria-checked': checked value: value
})); }));
var flex = createElement('span');
// We have to set as HTML incase of special characters // We have to set as HTML incase of special characters
item.innerHTML = title; flex.innerHTML = title;
if (is.element(badge)) { if (is.element(badge)) {
item.appendChild(badge); flex.appendChild(badge);
} }
item.appendChild(flex);
Object.defineProperty(item, 'checked', { Object.defineProperty(item, 'checked', {
enumerable: true, enumerable: true,
get: function get$$1() { get: function get$$1() {
@@ -1682,6 +1720,29 @@ typeof navigator === "object" && (function (global, factory) {
} }
}); });
this.listeners.bind(item, 'click', function () {
item.checked = true;
switch (type) {
case 'language':
_this.currentTrack = Number(value);
break;
case 'quality':
_this.quality = value;
break;
case 'speed':
_this.speed = parseFloat(value);
break;
default:
break;
}
controls.showMenuPanel.call(_this, 'home');
}, type);
list.appendChild(item); list.appendChild(item);
}, },
@@ -1755,7 +1816,7 @@ typeof navigator === "object" && (function (global, factory) {
// Update <progress> elements // Update <progress> elements
updateProgress: function updateProgress(event) { updateProgress: function updateProgress(event) {
var _this = this; var _this2 = this;
if (!this.supported.ui || !is.event(event)) { if (!this.supported.ui || !is.event(event)) {
return; return;
@@ -1765,7 +1826,7 @@ typeof navigator === "object" && (function (global, factory) {
var setProgress = function setProgress(target, input) { var setProgress = function setProgress(target, input) {
var value = is.number(input) ? input : 0; var value = is.number(input) ? input : 0;
var progress = is.element(target) ? target : _this.elements.display.buffer; var progress = is.element(target) ? target : _this2.elements.display.buffer;
// Update value and label // Update value and label
if (is.element(progress)) { if (is.element(progress)) {
@@ -1845,7 +1906,7 @@ typeof navigator === "object" && (function (global, factory) {
// Update hover tooltip for seeking // Update hover tooltip for seeking
updateSeekTooltip: function updateSeekTooltip(event) { updateSeekTooltip: function updateSeekTooltip(event) {
var _this2 = this; var _this3 = this;
// Bail if setting not true // Bail if setting not true
if (!this.config.tooltips.seek || !is.element(this.elements.inputs.seek) || !is.element(this.elements.display.seekTooltip) || this.duration === 0) { if (!this.config.tooltips.seek || !is.element(this.elements.inputs.seek) || !is.element(this.elements.display.seekTooltip) || this.duration === 0) {
@@ -1858,7 +1919,7 @@ typeof navigator === "object" && (function (global, factory) {
var visible = this.config.classNames.tooltip + '--visible'; var visible = this.config.classNames.tooltip + '--visible';
var toggle = function toggle(_toggle) { var toggle = function toggle(_toggle) {
toggleClass(_this2.elements.display.seekTooltip, visible, _toggle); toggleClass(_this3.elements.display.seekTooltip, visible, _toggle);
}; };
// Hide on touch // Hide on touch
@@ -1951,99 +2012,6 @@ typeof navigator === "object" && (function (global, factory) {
}, },
// Set the quality menu
setQualityMenu: function setQualityMenu(options) {
var _this3 = this;
// Menu required
if (!is.element(this.elements.settings.panels.quality)) {
console.warn('Not an element');
return;
}
var type = 'quality';
var list = this.elements.settings.panels.quality.querySelector('[role="menu"]');
// Set options if passed and filter based on uniqueness and config
if (is.array(options)) {
this.options.quality = dedupe(options).filter(function (quality) {
return _this3.config.quality.options.includes(quality);
});
}
// Toggle the pane and tab
console.warn(this.options.quality);
var toggle = !is.empty(this.options.quality) && this.options.quality.length > 1;
controls.toggleMenuButton.call(this, type, toggle);
// Check if we need to toggle the parent
controls.checkMenu.call(this);
// If we're hiding, nothing more to do
if (!toggle) {
return;
}
// Empty the menu
emptyElement(list);
// Get the badge HTML for HD, 4K etc
var getBadge = function getBadge(quality) {
var label = i18n.get('qualityBadge.' + quality, _this3.config);
if (!label.length) {
return null;
}
return controls.createBadge.call(_this3, label);
};
// Sort options by the config and then render options
this.options.quality.sort(function (a, b) {
var sorting = _this3.config.quality.options;
return sorting.indexOf(a) > sorting.indexOf(b) ? 1 : -1;
}).forEach(function (quality) {
controls.createMenuItem.call(_this3, {
value: quality,
list: list,
type: type,
title: controls.getLabel.call(_this3, 'quality', quality),
badge: getBadge(quality)
});
});
controls.updateSetting.call(this, type, list);
},
// Translate a value into a nice label
getLabel: function getLabel(setting, value) {
switch (setting) {
case 'speed':
return value === 1 ? i18n.get('normal', this.config) : value + '&times;';
case 'quality':
if (is.number(value)) {
var label = i18n.get('qualityLabel.' + value, this.config);
if (!label.length) {
return value + 'p';
}
return label;
}
return toTitleCase(value);
case 'captions':
return captions.getLabel.call(this);
default:
return null;
}
},
// Update the selected setting // Update the selected setting
updateSetting: function updateSetting(setting, container, input) { updateSetting: function updateSetting(setting, container, input) {
var pane = this.elements.settings.panels[setting]; var pane = this.elements.settings.panels[setting];
@@ -2096,6 +2064,97 @@ typeof navigator === "object" && (function (global, factory) {
}, },
// Translate a value into a nice label
getLabel: function getLabel(setting, value) {
switch (setting) {
case 'speed':
return value === 1 ? i18n.get('normal', this.config) : value + '&times;';
case 'quality':
if (is.number(value)) {
var label = i18n.get('qualityLabel.' + value, this.config);
if (!label.length) {
return value + 'p';
}
return label;
}
return toTitleCase(value);
case 'captions':
return captions.getLabel.call(this);
default:
return null;
}
},
// Set the quality menu
setQualityMenu: function setQualityMenu(options) {
var _this4 = this;
// Menu required
if (!is.element(this.elements.settings.panels.quality)) {
return;
}
var type = 'quality';
var list = this.elements.settings.panels.quality.querySelector('[role="menu"]');
// Set options if passed and filter based on uniqueness and config
if (is.array(options)) {
this.options.quality = dedupe(options).filter(function (quality) {
return _this4.config.quality.options.includes(quality);
});
}
// Toggle the pane and tab
var toggle = !is.empty(this.options.quality) && this.options.quality.length > 1;
controls.toggleMenuButton.call(this, type, toggle);
// Empty the menu
emptyElement(list);
// Check if we need to toggle the parent
controls.checkMenu.call(this);
// If we're hiding, nothing more to do
if (!toggle) {
return;
}
// Get the badge HTML for HD, 4K etc
var getBadge = function getBadge(quality) {
var label = i18n.get('qualityBadge.' + quality, _this4.config);
if (!label.length) {
return null;
}
return controls.createBadge.call(_this4, label);
};
// Sort options by the config and then render options
this.options.quality.sort(function (a, b) {
var sorting = _this4.config.quality.options;
return sorting.indexOf(a) > sorting.indexOf(b) ? 1 : -1;
}).forEach(function (quality) {
controls.createMenuItem.call(_this4, {
value: quality,
list: list,
type: type,
title: controls.getLabel.call(_this4, 'quality', quality),
badge: getBadge(quality)
});
});
controls.updateSetting.call(this, type, list);
},
// Set the looping options // Set the looping options
/* setLoopMenu() { /* setLoopMenu() {
// Menu required // Menu required
@@ -2137,15 +2196,21 @@ typeof navigator === "object" && (function (global, factory) {
// Set a list of available captions languages // Set a list of available captions languages
setCaptionsMenu: function setCaptionsMenu() { setCaptionsMenu: function setCaptionsMenu() {
var _this4 = this; var _this5 = this;
// Menu required
if (!is.element(this.elements.settings.panels.captions)) {
return;
}
// 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.panels.captions.querySelector('[role="menu"]'); var list = this.elements.settings.panels.captions.querySelector('[role="menu"]');
var tracks = captions.getTracks.call(this); var tracks = captions.getTracks.call(this);
var toggle = Boolean(tracks.length);
// Toggle the pane and tab // Toggle the pane and tab
controls.toggleMenuButton.call(this, type, tracks.length); controls.toggleMenuButton.call(this, type, toggle);
// Empty the menu // Empty the menu
emptyElement(list); emptyElement(list);
@@ -2154,7 +2219,7 @@ typeof navigator === "object" && (function (global, factory) {
controls.checkMenu.call(this); controls.checkMenu.call(this);
// If there's no captions, bail // If there's no captions, bail
if (!tracks.length) { if (!toggle) {
return; return;
} }
@@ -2162,9 +2227,9 @@ typeof navigator === "object" && (function (global, factory) {
var options = tracks.map(function (track, value) { var options = tracks.map(function (track, value) {
return { return {
value: value, value: value,
checked: _this4.captions.toggled && _this4.currentTrack === value, checked: _this5.captions.toggled && _this5.currentTrack === value,
title: captions.getLabel.call(_this4, track), title: captions.getLabel.call(_this5, track),
badge: track.language && controls.createBadge.call(_this4, track.language.toUpperCase()), badge: track.language && controls.createBadge.call(_this5, track.language.toUpperCase()),
list: list, list: list,
type: 'language' type: 'language'
}; };
@@ -2188,12 +2253,7 @@ typeof navigator === "object" && (function (global, factory) {
// Set a list of available captions languages // Set a list of available captions languages
setSpeedMenu: function setSpeedMenu(options) { setSpeedMenu: function setSpeedMenu(options) {
var _this5 = this; var _this6 = this;
// Do nothing if not selected
if (!this.config.controls.includes('settings') || !this.config.settings.includes('speed')) {
return;
}
// Menu required // Menu required
if (!is.element(this.elements.settings.panels.speed)) { if (!is.element(this.elements.settings.panels.speed)) {
@@ -2201,6 +2261,7 @@ typeof navigator === "object" && (function (global, factory) {
} }
var type = 'speed'; var type = 'speed';
var list = this.elements.settings.panels.speed.querySelector('[role="menu"]');
// Set the speed options // Set the speed options
if (is.array(options)) { if (is.array(options)) {
@@ -2211,13 +2272,16 @@ typeof navigator === "object" && (function (global, factory) {
// Set options if passed and filter based on config // Set options if passed and filter based on config
this.options.speed = this.options.speed.filter(function (speed) { this.options.speed = this.options.speed.filter(function (speed) {
return _this5.config.speed.options.includes(speed); return _this6.config.speed.options.includes(speed);
}); });
// Toggle the pane and tab // Toggle the pane and tab
var toggle = !is.empty(this.options.speed) && this.options.speed.length > 1; var toggle = !is.empty(this.options.speed) && this.options.speed.length > 1;
controls.toggleMenuButton.call(this, type, toggle); controls.toggleMenuButton.call(this, type, toggle);
// Empty the menu
emptyElement(list);
// Check if we need to toggle the parent // Check if we need to toggle the parent
controls.checkMenu.call(this); controls.checkMenu.call(this);
@@ -2226,19 +2290,13 @@ typeof navigator === "object" && (function (global, factory) {
return; return;
} }
// Get the list to populate
var list = this.elements.settings.panels.speed.querySelector('[role="menu"]');
// Empty the menu
emptyElement(list);
// Create items // Create items
this.options.speed.forEach(function (speed) { this.options.speed.forEach(function (speed) {
controls.createMenuItem.call(_this5, { controls.createMenuItem.call(_this6, {
value: speed, value: speed,
list: list, list: list,
type: type, type: type,
title: controls.getLabel.call(_this5, 'speed', speed) title: controls.getLabel.call(_this6, 'speed', speed)
}); });
}); });
@@ -2332,7 +2390,7 @@ typeof navigator === "object" && (function (global, factory) {
// Show a panel in the menu // Show a panel in the menu
showMenuPanel: function showMenuPanel() { showMenuPanel: function showMenuPanel() {
var _this6 = this; var _this7 = this;
var type = arguments.length > 0 && arguments[0] !== undefined ? arguments[0] : ''; var type = arguments.length > 0 && arguments[0] !== undefined ? arguments[0] : '';
@@ -2370,7 +2428,7 @@ typeof navigator === "object" && (function (global, factory) {
container.style.height = ''; container.style.height = '';
// Only listen once // Only listen once
off.call(_this6, container, transitionEndEvent, restore); off.call(_this7, container, transitionEndEvent, restore);
}; };
// Listen for the transition finishing and restore auto height/width // Listen for the transition finishing and restore auto height/width
@@ -2383,7 +2441,6 @@ typeof navigator === "object" && (function (global, factory) {
// Set attributes on current tab // Set attributes on current tab
toggleHidden(current, true); toggleHidden(current, true);
// current.setAttribute('tabindex', -1);
// Set attributes on target // Set attributes on target
toggleHidden(target, false); toggleHidden(target, false);
@@ -2399,7 +2456,7 @@ typeof navigator === "object" && (function (global, factory) {
// Build the default HTML // Build the default HTML
// TODO: Set order based on order in the config.controls array? // TODO: Set order based on order in the config.controls array?
create: function create(data) { create: function create(data) {
var _this7 = this; var _this8 = this;
// Do nothing if we want no controls // Do nothing if we want no controls
if (is.empty(this.config.controls)) { if (is.empty(this.config.controls)) {
@@ -2534,17 +2591,18 @@ typeof navigator === "object" && (function (global, factory) {
// Build the menu items // Build the menu items
this.config.settings.forEach(function (type) { this.config.settings.forEach(function (type) {
var menuItem = createElement('button', extend(getAttributesFromSelector(_this7.config.selectors.buttons.settings), { var menuItem = createElement('button', extend(getAttributesFromSelector(_this8.config.selectors.buttons.settings), {
type: 'button', type: 'button',
class: _this7.config.classNames.control + ' ' + _this7.config.classNames.control + '--forward', class: _this8.config.classNames.control + ' ' + _this8.config.classNames.control + '--forward',
role: 'menuitem', role: 'menuitem',
'aria-haspopup': true 'aria-haspopup': true,
hidden: ''
})); }));
var flex = createElement('span', null, i18n.get(type, _this7.config)); var flex = createElement('span', null, i18n.get(type, _this8.config));
var value = createElement('span', { var value = createElement('span', {
class: _this7.config.classNames.menu.value class: _this8.config.classNames.menu.value
}); });
// Speed contains HTML entities // Speed contains HTML entities
@@ -2563,10 +2621,10 @@ typeof navigator === "object" && (function (global, factory) {
// Back button // Back button
var back = createElement('button', { var back = createElement('button', {
type: 'button', type: 'button',
class: _this7.config.classNames.control + ' ' + _this7.config.classNames.control + '--back' class: _this8.config.classNames.control + ' ' + _this8.config.classNames.control + '--back'
}, i18n.get(type, _this7.config)); }, i18n.get(type, _this8.config));
back.addEventListener('click', function () { back.addEventListener('click', function () {
controls.showMenuPanel.call(_this7, 'home'); controls.showMenuPanel.call(_this8, 'home');
}); });
pane.appendChild(back); pane.appendChild(back);
@@ -2578,11 +2636,11 @@ typeof navigator === "object" && (function (global, factory) {
inner.appendChild(pane); inner.appendChild(pane);
menuItem.addEventListener('click', function () { menuItem.addEventListener('click', function () {
controls.showMenuPanel.call(_this7, type); controls.showMenuPanel.call(_this8, type);
}); });
_this7.elements.settings.buttons[type] = menuItem; _this8.elements.settings.buttons[type] = menuItem;
_this7.elements.settings.panels[type] = pane; _this8.elements.settings.panels[type] = pane;
}); });
home.appendChild(menu); home.appendChild(menu);
@@ -2630,7 +2688,7 @@ typeof navigator === "object" && (function (global, factory) {
// Insert controls // Insert controls
inject: function inject() { inject: function inject() {
var _this8 = this; var _this9 = this;
// Sprite // Sprite
if (this.config.loadSprite) { if (this.config.loadSprite) {
@@ -2742,8 +2800,8 @@ typeof navigator === "object" && (function (global, factory) {
var labels = getElements.call(this, selector); var labels = getElements.call(this, selector);
Array.from(labels).forEach(function (label) { Array.from(labels).forEach(function (label) {
toggleClass(label, _this8.config.classNames.hidden, false); toggleClass(label, _this9.config.classNames.hidden, false);
toggleClass(label, _this8.config.classNames.tooltip, true); toggleClass(label, _this9.config.classNames.tooltip, true);
}); });
} }
} }
@@ -4374,7 +4432,8 @@ typeof navigator === "object" && (function (global, factory) {
// Clear timer // Clear timer
clearTimeout(_this2.player.timers.controls); clearTimeout(_this2.player.timers.controls);
// Timer to prevent flicker when seeking
// Set new timer to prevent flicker when seeking
_this2.player.timers.controls = setTimeout(function () { _this2.player.timers.controls = setTimeout(function () {
return ui.toggleControls.call(_this2.player, false); return ui.toggleControls.call(_this2.player, false);
}, delay); }, delay);
@@ -4531,124 +4590,104 @@ typeof navigator === "object" && (function (global, factory) {
}); });
} }
// Run default and custom handlers
}, {
key: 'proxy',
value: function proxy(event, defaultHandler, customHandlerKey) {
var customHandler = this.player.config.listeners[customHandlerKey];
var hasCustomHandler = is.function(customHandler);
var returned = true;
// Execute custom handler
if (hasCustomHandler) {
returned = customHandler.call(this.player, event);
}
// Only call default handler if not prevented in custom handler
if (returned && is.function(defaultHandler)) {
defaultHandler.call(this.player, event);
}
}
// Trigger custom and default handlers
}, {
key: 'bind',
value: function bind(element, type, defaultHandler, customHandlerKey) {
var _this4 = this;
var passive = arguments.length > 4 && arguments[4] !== undefined ? arguments[4] : true;
var customHandler = this.player.config.listeners[customHandlerKey];
var hasCustomHandler = is.function(customHandler);
on.call(this.player, element, type, function (event) {
return _this4.proxy(event, defaultHandler, customHandlerKey);
}, passive && !hasCustomHandler);
}
// Listen for control events // Listen for control events
}, { }, {
key: 'controls', key: 'controls',
value: function controls$$1() { value: function controls$$1() {
var _this4 = this; var _this5 = this;
// IE doesn't support input event, so we fallback to change // IE doesn't support input event, so we fallback to change
var inputEvent = browser.isIE ? 'change' : 'input'; var inputEvent = browser.isIE ? 'change' : 'input';
// Run default and custom handlers
var proxy = function proxy(event, defaultHandler, customHandlerKey) {
var customHandler = _this4.player.config.listeners[customHandlerKey];
var hasCustomHandler = is.function(customHandler);
var returned = true;
// Execute custom handler
if (hasCustomHandler) {
returned = customHandler.call(_this4.player, event);
}
// Only call default handler if not prevented in custom handler
if (returned && is.function(defaultHandler)) {
defaultHandler.call(_this4.player, event);
}
};
// Trigger custom and default handlers
var bind = function bind(element, type, defaultHandler, customHandlerKey) {
var passive = arguments.length > 4 && arguments[4] !== undefined ? arguments[4] : true;
var customHandler = _this4.player.config.listeners[customHandlerKey];
var hasCustomHandler = is.function(customHandler);
on.call(_this4.player, element, type, function (event) {
return proxy(event, defaultHandler, customHandlerKey);
}, passive && !hasCustomHandler);
};
// Play/pause toggle // Play/pause toggle
Array.from(this.player.elements.buttons.play).forEach(function (button) { Array.from(this.player.elements.buttons.play).forEach(function (button) {
bind(button, 'click', _this4.player.togglePlay, 'play'); _this5.bind(button, 'click', _this5.player.togglePlay, 'play');
}); });
// Pause // Pause
bind(this.player.elements.buttons.restart, 'click', this.player.restart, 'restart'); this.bind(this.player.elements.buttons.restart, 'click', this.player.restart, 'restart');
// Rewind // Rewind
bind(this.player.elements.buttons.rewind, 'click', this.player.rewind, 'rewind'); this.bind(this.player.elements.buttons.rewind, 'click', this.player.rewind, 'rewind');
// Rewind // Rewind
bind(this.player.elements.buttons.fastForward, 'click', this.player.forward, 'fastForward'); this.bind(this.player.elements.buttons.fastForward, 'click', this.player.forward, 'fastForward');
// Mute toggle // Mute toggle
bind(this.player.elements.buttons.mute, 'click', function () { this.bind(this.player.elements.buttons.mute, 'click', function () {
_this4.player.muted = !_this4.player.muted; _this5.player.muted = !_this5.player.muted;
}, 'mute'); }, 'mute');
// Captions toggle // Captions toggle
bind(this.player.elements.buttons.captions, 'click', function () { this.bind(this.player.elements.buttons.captions, 'click', function () {
return _this4.player.toggleCaptions(); return _this5.player.toggleCaptions();
}); });
// Fullscreen toggle // Fullscreen toggle
bind(this.player.elements.buttons.fullscreen, 'click', function () { this.bind(this.player.elements.buttons.fullscreen, 'click', function () {
_this4.player.fullscreen.toggle(); _this5.player.fullscreen.toggle();
}, 'fullscreen'); }, 'fullscreen');
// Picture-in-Picture // Picture-in-Picture
bind(this.player.elements.buttons.pip, 'click', function () { this.bind(this.player.elements.buttons.pip, 'click', function () {
_this4.player.pip = 'toggle'; _this5.player.pip = 'toggle';
}, 'pip'); }, 'pip');
// Airplay // Airplay
bind(this.player.elements.buttons.airplay, 'click', this.player.airplay, 'airplay'); this.bind(this.player.elements.buttons.airplay, 'click', this.player.airplay, 'airplay');
// Settings menu // Settings menu
bind(this.player.elements.buttons.settings, 'click', function (event) { this.bind(this.player.elements.buttons.settings, 'click', function (event) {
controls.toggleMenu.call(_this4.player, event); controls.toggleMenu.call(_this5.player, event);
});
// Settings menu
bind(this.player.elements.settings.popup, 'click', function (event) {
event.stopPropagation();
// Go back to home tab on click
var showHomeTab = function showHomeTab() {
controls.showMenuPanel.call(_this4.player, 'home');
};
// Settings menu items - use event delegation as items are added/removed
if (matches(event.target, _this4.player.config.selectors.inputs.language)) {
proxy(event, function () {
_this4.player.currentTrack = Number(event.target.value);
showHomeTab();
}, 'language');
} else if (matches(event.target, _this4.player.config.selectors.inputs.quality)) {
proxy(event, function () {
_this4.player.quality = event.target.value;
showHomeTab();
}, 'quality');
} else if (matches(event.target, _this4.player.config.selectors.inputs.speed)) {
proxy(event, function () {
_this4.player.speed = parseFloat(event.target.value);
showHomeTab();
}, 'speed');
}
}); });
// Set range input alternative "value", which matches the tooltip time (#954) // Set range input alternative "value", which matches the tooltip time (#954)
bind(this.player.elements.inputs.seek, 'mousedown mousemove', function (event) { this.bind(this.player.elements.inputs.seek, 'mousedown mousemove', function (event) {
var clientRect = _this4.player.elements.progress.getBoundingClientRect(); var clientRect = _this5.player.elements.progress.getBoundingClientRect();
var percent = 100 / clientRect.width * (event.pageX - clientRect.left); var percent = 100 / clientRect.width * (event.pageX - clientRect.left);
event.currentTarget.setAttribute('seek-value', percent); event.currentTarget.setAttribute('seek-value', percent);
}); });
// Pause while seeking // Pause while seeking
bind(this.player.elements.inputs.seek, 'mousedown mouseup keydown keyup touchstart touchend', function (event) { this.bind(this.player.elements.inputs.seek, 'mousedown mouseup keydown keyup touchstart touchend', function (event) {
var seek = event.currentTarget; var seek = event.currentTarget;
var code = event.keyCode ? event.keyCode : event.which; var code = event.keyCode ? event.keyCode : event.which;
@@ -4666,15 +4705,15 @@ typeof navigator === "object" && (function (global, factory) {
// If we're done seeking and it was playing, resume playback // If we're done seeking and it was playing, resume playback
if (play && done) { if (play && done) {
seek.removeAttribute('play-on-seeked'); seek.removeAttribute('play-on-seeked');
_this4.player.play(); _this5.player.play();
} else if (!done && _this4.player.playing) { } else if (!done && _this5.player.playing) {
seek.setAttribute('play-on-seeked', ''); seek.setAttribute('play-on-seeked', '');
_this4.player.pause(); _this5.player.pause();
} }
}); });
// Seek // Seek
bind(this.player.elements.inputs.seek, inputEvent, function (event) { this.bind(this.player.elements.inputs.seek, inputEvent, function (event) {
var seek = event.currentTarget; var seek = event.currentTarget;
// If it exists, use seek-value instead of "value" for consistency with tooltip time (#954) // If it exists, use seek-value instead of "value" for consistency with tooltip time (#954)
@@ -4686,56 +4725,56 @@ typeof navigator === "object" && (function (global, factory) {
seek.removeAttribute('seek-value'); seek.removeAttribute('seek-value');
_this4.player.currentTime = seekTo / seek.max * _this4.player.duration; _this5.player.currentTime = seekTo / seek.max * _this5.player.duration;
}, 'seek'); }, 'seek');
// Current time invert // Current time invert
// Only if one time element is used for both currentTime and duration // Only if one time element is used for both currentTime and duration
if (this.player.config.toggleInvert && !is.element(this.player.elements.display.duration)) { if (this.player.config.toggleInvert && !is.element(this.player.elements.display.duration)) {
bind(this.player.elements.display.currentTime, 'click', function () { this.bind(this.player.elements.display.currentTime, 'click', function () {
// Do nothing if we're at the start // Do nothing if we're at the start
if (_this4.player.currentTime === 0) { if (_this5.player.currentTime === 0) {
return; return;
} }
_this4.player.config.invertTime = !_this4.player.config.invertTime; _this5.player.config.invertTime = !_this5.player.config.invertTime;
controls.timeUpdate.call(_this4.player); controls.timeUpdate.call(_this5.player);
}); });
} }
// Volume // Volume
bind(this.player.elements.inputs.volume, inputEvent, function (event) { this.bind(this.player.elements.inputs.volume, inputEvent, function (event) {
_this4.player.volume = event.target.value; _this5.player.volume = event.target.value;
}, 'volume'); }, 'volume');
// Polyfill for lower fill in <input type="range"> for webkit // Polyfill for lower fill in <input type="range"> for webkit
if (browser.isWebkit) { if (browser.isWebkit) {
Array.from(getElements.call(this.player, 'input[type="range"]')).forEach(function (element) { Array.from(getElements.call(this.player, 'input[type="range"]')).forEach(function (element) {
bind(element, 'input', function (event) { _this5.bind(element, 'input', function (event) {
return controls.updateRangeFill.call(_this4.player, event.target); return controls.updateRangeFill.call(_this5.player, event.target);
}); });
}); });
} }
// Seek tooltip // Seek tooltip
bind(this.player.elements.progress, 'mouseenter mouseleave mousemove', function (event) { this.bind(this.player.elements.progress, 'mouseenter mouseleave mousemove', function (event) {
return controls.updateSeekTooltip.call(_this4.player, event); return controls.updateSeekTooltip.call(_this5.player, event);
}); });
// Update controls.hover state (used for ui.toggleControls to avoid hiding when interacting) // Update controls.hover state (used for ui.toggleControls to avoid hiding when interacting)
bind(this.player.elements.controls, 'mouseenter mouseleave', function (event) { this.bind(this.player.elements.controls, 'mouseenter mouseleave', function (event) {
_this4.player.elements.controls.hover = !_this4.player.touch && event.type === 'mouseenter'; _this5.player.elements.controls.hover = !_this5.player.touch && event.type === 'mouseenter';
}); });
// Update controls.pressed state (used for ui.toggleControls to avoid hiding when interacting) // Update controls.pressed state (used for ui.toggleControls to avoid hiding when interacting)
bind(this.player.elements.controls, 'mousedown mouseup touchstart touchend touchcancel', function (event) { this.bind(this.player.elements.controls, 'mousedown mouseup touchstart touchend touchcancel', function (event) {
_this4.player.elements.controls.pressed = ['mousedown', 'touchstart'].includes(event.type); _this5.player.elements.controls.pressed = ['mousedown', 'touchstart'].includes(event.type);
}); });
// Focus in/out on controls // Focus in/out on controls
bind(this.player.elements.controls, 'focusin focusout', function (event) { this.bind(this.player.elements.controls, 'focusin focusout', function (event) {
var _player = _this4.player, var _player = _this5.player,
config = _player.config, config = _player.config,
elements = _player.elements, elements = _player.elements,
timers = _player.timers; timers = _player.timers;
@@ -4745,7 +4784,7 @@ typeof navigator === "object" && (function (global, factory) {
toggleClass(elements.controls, config.classNames.noTransition, event.type === 'focusin'); toggleClass(elements.controls, config.classNames.noTransition, event.type === 'focusin');
// Toggle // Toggle
ui.toggleControls.call(_this4.player, event.type === 'focusin'); ui.toggleControls.call(_this5.player, event.type === 'focusin');
// If focusin, hide again after delay // If focusin, hide again after delay
if (event.type === 'focusin') { if (event.type === 'focusin') {
@@ -4755,19 +4794,19 @@ typeof navigator === "object" && (function (global, factory) {
}, 0); }, 0);
// Delay a little more for keyboard users // Delay a little more for keyboard users
var delay = _this4.touch ? 3000 : 4000; var delay = _this5.touch ? 3000 : 4000;
// Clear timer // Clear timer
clearTimeout(timers.controls); clearTimeout(timers.controls);
// Hide // Hide
timers.controls = setTimeout(function () { timers.controls = setTimeout(function () {
return ui.toggleControls.call(_this4.player, false); return ui.toggleControls.call(_this5.player, false);
}, delay); }, delay);
} }
}); });
// Mouse wheel for volume // Mouse wheel for volume
bind(this.player.elements.inputs.volume, 'wheel', function (event) { this.bind(this.player.elements.inputs.volume, 'wheel', function (event) {
// Detect "natural" scroll - suppored on OS X Safari only // Detect "natural" scroll - suppored on OS X Safari only
// Other browsers on OS X will be inverted until support improves // Other browsers on OS X will be inverted until support improves
var inverted = event.webkitDirectionInvertedFromDevice; var inverted = event.webkitDirectionInvertedFromDevice;
@@ -4777,10 +4816,10 @@ typeof navigator === "object" && (function (global, factory) {
// Scroll down (or up on natural) to decrease // Scroll down (or up on natural) to decrease
if (event.deltaY < 0 || event.deltaX > 0) { if (event.deltaY < 0 || event.deltaX > 0) {
if (inverted) { if (inverted) {
_this4.player.decreaseVolume(step); _this5.player.decreaseVolume(step);
direction = -1; direction = -1;
} else { } else {
_this4.player.increaseVolume(step); _this5.player.increaseVolume(step);
direction = 1; direction = 1;
} }
} }
@@ -4788,16 +4827,16 @@ typeof navigator === "object" && (function (global, factory) {
// Scroll up (or down on natural) to increase // Scroll up (or down on natural) to increase
if (event.deltaY > 0 || event.deltaX < 0) { if (event.deltaY > 0 || event.deltaX < 0) {
if (inverted) { if (inverted) {
_this4.player.increaseVolume(step); _this5.player.increaseVolume(step);
direction = 1; direction = 1;
} else { } else {
_this4.player.decreaseVolume(step); _this5.player.decreaseVolume(step);
direction = -1; direction = -1;
} }
} }
// Don't break page scrolling at max and min // Don't break page scrolling at max and min
if (direction === 1 && _this4.player.media.volume < 1 || direction === -1 && _this4.player.media.volume > 0) { if (direction === 1 && _this5.player.media.volume < 1 || direction === -1 && _this5.player.media.volume > 0) {
event.preventDefault(); event.preventDefault();
} }
}, 'volume', false); }, 'volume', false);
+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
+254 -246
View File
@@ -7023,6 +7023,8 @@ typeof navigator === "object" && (function (global, factory) {
// Create a settings menu item // Create a settings menu item
createMenuItem: function createMenuItem(_ref) { createMenuItem: function createMenuItem(_ref) {
var _this = this;
var value = _ref.value, var value = _ref.value,
list = _ref.list, list = _ref.list,
type = _ref.type, type = _ref.type,
@@ -7038,17 +7040,21 @@ typeof navigator === "object" && (function (global, factory) {
type: 'button', type: 'button',
role: 'menuitemradio', role: 'menuitemradio',
class: (this.config.classNames.control + ' ' + (attributes.class ? attributes.class : '')).trim(), class: (this.config.classNames.control + ' ' + (attributes.class ? attributes.class : '')).trim(),
value: value, 'aria-checked': checked,
'aria-checked': checked value: value
})); }));
var flex = createElement('span');
// We have to set as HTML incase of special characters // We have to set as HTML incase of special characters
item.innerHTML = title; flex.innerHTML = title;
if (is$1.element(badge)) { if (is$1.element(badge)) {
item.appendChild(badge); flex.appendChild(badge);
} }
item.appendChild(flex);
Object.defineProperty(item, 'checked', { Object.defineProperty(item, 'checked', {
enumerable: true, enumerable: true,
get: function get() { get: function get() {
@@ -7068,6 +7074,29 @@ typeof navigator === "object" && (function (global, factory) {
} }
}); });
this.listeners.bind(item, 'click', function () {
item.checked = true;
switch (type) {
case 'language':
_this.currentTrack = Number(value);
break;
case 'quality':
_this.quality = value;
break;
case 'speed':
_this.speed = parseFloat(value);
break;
default:
break;
}
controls.showMenuPanel.call(_this, 'home');
}, type);
list.appendChild(item); list.appendChild(item);
}, },
@@ -7141,7 +7170,7 @@ typeof navigator === "object" && (function (global, factory) {
// Update <progress> elements // Update <progress> elements
updateProgress: function updateProgress(event) { updateProgress: function updateProgress(event) {
var _this = this; var _this2 = this;
if (!this.supported.ui || !is$1.event(event)) { if (!this.supported.ui || !is$1.event(event)) {
return; return;
@@ -7151,7 +7180,7 @@ typeof navigator === "object" && (function (global, factory) {
var setProgress = function setProgress(target, input) { var setProgress = function setProgress(target, input) {
var value = is$1.number(input) ? input : 0; var value = is$1.number(input) ? input : 0;
var progress = is$1.element(target) ? target : _this.elements.display.buffer; var progress = is$1.element(target) ? target : _this2.elements.display.buffer;
// Update value and label // Update value and label
if (is$1.element(progress)) { if (is$1.element(progress)) {
@@ -7231,7 +7260,7 @@ typeof navigator === "object" && (function (global, factory) {
// Update hover tooltip for seeking // Update hover tooltip for seeking
updateSeekTooltip: function updateSeekTooltip(event) { updateSeekTooltip: function updateSeekTooltip(event) {
var _this2 = this; var _this3 = this;
// Bail if setting not true // Bail if setting not true
if (!this.config.tooltips.seek || !is$1.element(this.elements.inputs.seek) || !is$1.element(this.elements.display.seekTooltip) || this.duration === 0) { if (!this.config.tooltips.seek || !is$1.element(this.elements.inputs.seek) || !is$1.element(this.elements.display.seekTooltip) || this.duration === 0) {
@@ -7244,7 +7273,7 @@ typeof navigator === "object" && (function (global, factory) {
var visible = this.config.classNames.tooltip + '--visible'; var visible = this.config.classNames.tooltip + '--visible';
var toggle = function toggle(_toggle) { var toggle = function toggle(_toggle) {
toggleClass(_this2.elements.display.seekTooltip, visible, _toggle); toggleClass(_this3.elements.display.seekTooltip, visible, _toggle);
}; };
// Hide on touch // Hide on touch
@@ -7337,99 +7366,6 @@ typeof navigator === "object" && (function (global, factory) {
}, },
// Set the quality menu
setQualityMenu: function setQualityMenu(options) {
var _this3 = this;
// Menu required
if (!is$1.element(this.elements.settings.panels.quality)) {
console.warn('Not an element');
return;
}
var type = 'quality';
var list = this.elements.settings.panels.quality.querySelector('[role="menu"]');
// Set options if passed and filter based on uniqueness and config
if (is$1.array(options)) {
this.options.quality = dedupe(options).filter(function (quality) {
return _this3.config.quality.options.includes(quality);
});
}
// Toggle the pane and tab
console.warn(this.options.quality);
var toggle = !is$1.empty(this.options.quality) && this.options.quality.length > 1;
controls.toggleMenuButton.call(this, type, toggle);
// Check if we need to toggle the parent
controls.checkMenu.call(this);
// If we're hiding, nothing more to do
if (!toggle) {
return;
}
// Empty the menu
emptyElement(list);
// Get the badge HTML for HD, 4K etc
var getBadge = function getBadge(quality) {
var label = i18n.get('qualityBadge.' + quality, _this3.config);
if (!label.length) {
return null;
}
return controls.createBadge.call(_this3, label);
};
// Sort options by the config and then render options
this.options.quality.sort(function (a, b) {
var sorting = _this3.config.quality.options;
return sorting.indexOf(a) > sorting.indexOf(b) ? 1 : -1;
}).forEach(function (quality) {
controls.createMenuItem.call(_this3, {
value: quality,
list: list,
type: type,
title: controls.getLabel.call(_this3, 'quality', quality),
badge: getBadge(quality)
});
});
controls.updateSetting.call(this, type, list);
},
// Translate a value into a nice label
getLabel: function getLabel(setting, value) {
switch (setting) {
case 'speed':
return value === 1 ? i18n.get('normal', this.config) : value + '&times;';
case 'quality':
if (is$1.number(value)) {
var label = i18n.get('qualityLabel.' + value, this.config);
if (!label.length) {
return value + 'p';
}
return label;
}
return toTitleCase(value);
case 'captions':
return captions.getLabel.call(this);
default:
return null;
}
},
// Update the selected setting // Update the selected setting
updateSetting: function updateSetting(setting, container, input) { updateSetting: function updateSetting(setting, container, input) {
var pane = this.elements.settings.panels[setting]; var pane = this.elements.settings.panels[setting];
@@ -7482,6 +7418,97 @@ typeof navigator === "object" && (function (global, factory) {
}, },
// Translate a value into a nice label
getLabel: function getLabel(setting, value) {
switch (setting) {
case 'speed':
return value === 1 ? i18n.get('normal', this.config) : value + '&times;';
case 'quality':
if (is$1.number(value)) {
var label = i18n.get('qualityLabel.' + value, this.config);
if (!label.length) {
return value + 'p';
}
return label;
}
return toTitleCase(value);
case 'captions':
return captions.getLabel.call(this);
default:
return null;
}
},
// Set the quality menu
setQualityMenu: function setQualityMenu(options) {
var _this4 = this;
// Menu required
if (!is$1.element(this.elements.settings.panels.quality)) {
return;
}
var type = 'quality';
var list = this.elements.settings.panels.quality.querySelector('[role="menu"]');
// Set options if passed and filter based on uniqueness and config
if (is$1.array(options)) {
this.options.quality = dedupe(options).filter(function (quality) {
return _this4.config.quality.options.includes(quality);
});
}
// Toggle the pane and tab
var toggle = !is$1.empty(this.options.quality) && this.options.quality.length > 1;
controls.toggleMenuButton.call(this, type, toggle);
// Empty the menu
emptyElement(list);
// Check if we need to toggle the parent
controls.checkMenu.call(this);
// If we're hiding, nothing more to do
if (!toggle) {
return;
}
// Get the badge HTML for HD, 4K etc
var getBadge = function getBadge(quality) {
var label = i18n.get('qualityBadge.' + quality, _this4.config);
if (!label.length) {
return null;
}
return controls.createBadge.call(_this4, label);
};
// Sort options by the config and then render options
this.options.quality.sort(function (a, b) {
var sorting = _this4.config.quality.options;
return sorting.indexOf(a) > sorting.indexOf(b) ? 1 : -1;
}).forEach(function (quality) {
controls.createMenuItem.call(_this4, {
value: quality,
list: list,
type: type,
title: controls.getLabel.call(_this4, 'quality', quality),
badge: getBadge(quality)
});
});
controls.updateSetting.call(this, type, list);
},
// Set the looping options // Set the looping options
/* setLoopMenu() { /* setLoopMenu() {
// Menu required // Menu required
@@ -7523,15 +7550,21 @@ typeof navigator === "object" && (function (global, factory) {
// Set a list of available captions languages // Set a list of available captions languages
setCaptionsMenu: function setCaptionsMenu() { setCaptionsMenu: function setCaptionsMenu() {
var _this4 = this; var _this5 = this;
// Menu required
if (!is$1.element(this.elements.settings.panels.captions)) {
return;
}
// 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.panels.captions.querySelector('[role="menu"]'); var list = this.elements.settings.panels.captions.querySelector('[role="menu"]');
var tracks = captions.getTracks.call(this); var tracks = captions.getTracks.call(this);
var toggle = Boolean(tracks.length);
// Toggle the pane and tab // Toggle the pane and tab
controls.toggleMenuButton.call(this, type, tracks.length); controls.toggleMenuButton.call(this, type, toggle);
// Empty the menu // Empty the menu
emptyElement(list); emptyElement(list);
@@ -7540,7 +7573,7 @@ typeof navigator === "object" && (function (global, factory) {
controls.checkMenu.call(this); controls.checkMenu.call(this);
// If there's no captions, bail // If there's no captions, bail
if (!tracks.length) { if (!toggle) {
return; return;
} }
@@ -7548,9 +7581,9 @@ typeof navigator === "object" && (function (global, factory) {
var options = tracks.map(function (track, value) { var options = tracks.map(function (track, value) {
return { return {
value: value, value: value,
checked: _this4.captions.toggled && _this4.currentTrack === value, checked: _this5.captions.toggled && _this5.currentTrack === value,
title: captions.getLabel.call(_this4, track), title: captions.getLabel.call(_this5, track),
badge: track.language && controls.createBadge.call(_this4, track.language.toUpperCase()), badge: track.language && controls.createBadge.call(_this5, track.language.toUpperCase()),
list: list, list: list,
type: 'language' type: 'language'
}; };
@@ -7574,12 +7607,7 @@ typeof navigator === "object" && (function (global, factory) {
// Set a list of available captions languages // Set a list of available captions languages
setSpeedMenu: function setSpeedMenu(options) { setSpeedMenu: function setSpeedMenu(options) {
var _this5 = this; var _this6 = this;
// Do nothing if not selected
if (!this.config.controls.includes('settings') || !this.config.settings.includes('speed')) {
return;
}
// Menu required // Menu required
if (!is$1.element(this.elements.settings.panels.speed)) { if (!is$1.element(this.elements.settings.panels.speed)) {
@@ -7587,6 +7615,7 @@ typeof navigator === "object" && (function (global, factory) {
} }
var type = 'speed'; var type = 'speed';
var list = this.elements.settings.panels.speed.querySelector('[role="menu"]');
// Set the speed options // Set the speed options
if (is$1.array(options)) { if (is$1.array(options)) {
@@ -7597,13 +7626,16 @@ typeof navigator === "object" && (function (global, factory) {
// Set options if passed and filter based on config // Set options if passed and filter based on config
this.options.speed = this.options.speed.filter(function (speed) { this.options.speed = this.options.speed.filter(function (speed) {
return _this5.config.speed.options.includes(speed); return _this6.config.speed.options.includes(speed);
}); });
// Toggle the pane and tab // Toggle the pane and tab
var toggle = !is$1.empty(this.options.speed) && this.options.speed.length > 1; var toggle = !is$1.empty(this.options.speed) && this.options.speed.length > 1;
controls.toggleMenuButton.call(this, type, toggle); controls.toggleMenuButton.call(this, type, toggle);
// Empty the menu
emptyElement(list);
// Check if we need to toggle the parent // Check if we need to toggle the parent
controls.checkMenu.call(this); controls.checkMenu.call(this);
@@ -7612,19 +7644,13 @@ typeof navigator === "object" && (function (global, factory) {
return; return;
} }
// Get the list to populate
var list = this.elements.settings.panels.speed.querySelector('[role="menu"]');
// Empty the menu
emptyElement(list);
// Create items // Create items
this.options.speed.forEach(function (speed) { this.options.speed.forEach(function (speed) {
controls.createMenuItem.call(_this5, { controls.createMenuItem.call(_this6, {
value: speed, value: speed,
list: list, list: list,
type: type, type: type,
title: controls.getLabel.call(_this5, 'speed', speed) title: controls.getLabel.call(_this6, 'speed', speed)
}); });
}); });
@@ -7718,7 +7744,7 @@ typeof navigator === "object" && (function (global, factory) {
// Show a panel in the menu // Show a panel in the menu
showMenuPanel: function showMenuPanel() { showMenuPanel: function showMenuPanel() {
var _this6 = this; var _this7 = this;
var type = arguments.length > 0 && arguments[0] !== undefined ? arguments[0] : ''; var type = arguments.length > 0 && arguments[0] !== undefined ? arguments[0] : '';
@@ -7756,7 +7782,7 @@ typeof navigator === "object" && (function (global, factory) {
container.style.height = ''; container.style.height = '';
// Only listen once // Only listen once
off.call(_this6, container, transitionEndEvent, restore); off.call(_this7, container, transitionEndEvent, restore);
}; };
// Listen for the transition finishing and restore auto height/width // Listen for the transition finishing and restore auto height/width
@@ -7785,7 +7811,7 @@ typeof navigator === "object" && (function (global, factory) {
// Build the default HTML // Build the default HTML
// TODO: Set order based on order in the config.controls array? // TODO: Set order based on order in the config.controls array?
create: function create(data) { create: function create(data) {
var _this7 = this; var _this8 = this;
// Do nothing if we want no controls // Do nothing if we want no controls
if (is$1.empty(this.config.controls)) { if (is$1.empty(this.config.controls)) {
@@ -7920,17 +7946,18 @@ typeof navigator === "object" && (function (global, factory) {
// Build the menu items // Build the menu items
this.config.settings.forEach(function (type) { this.config.settings.forEach(function (type) {
var menuItem = createElement('button', extend(getAttributesFromSelector(_this7.config.selectors.buttons.settings), { var menuItem = createElement('button', extend(getAttributesFromSelector(_this8.config.selectors.buttons.settings), {
type: 'button', type: 'button',
class: _this7.config.classNames.control + ' ' + _this7.config.classNames.control + '--forward', class: _this8.config.classNames.control + ' ' + _this8.config.classNames.control + '--forward',
role: 'menuitem', role: 'menuitem',
'aria-haspopup': true 'aria-haspopup': true,
hidden: ''
})); }));
var flex = createElement('span', null, i18n.get(type, _this7.config)); var flex = createElement('span', null, i18n.get(type, _this8.config));
var value = createElement('span', { var value = createElement('span', {
class: _this7.config.classNames.menu.value class: _this8.config.classNames.menu.value
}); });
// Speed contains HTML entities // Speed contains HTML entities
@@ -7949,10 +7976,10 @@ typeof navigator === "object" && (function (global, factory) {
// Back button // Back button
var back = createElement('button', { var back = createElement('button', {
type: 'button', type: 'button',
class: _this7.config.classNames.control + ' ' + _this7.config.classNames.control + '--back' class: _this8.config.classNames.control + ' ' + _this8.config.classNames.control + '--back'
}, i18n.get(type, _this7.config)); }, i18n.get(type, _this8.config));
back.addEventListener('click', function () { back.addEventListener('click', function () {
controls.showMenuPanel.call(_this7, 'home'); controls.showMenuPanel.call(_this8, 'home');
}); });
pane.appendChild(back); pane.appendChild(back);
@@ -7964,11 +7991,11 @@ typeof navigator === "object" && (function (global, factory) {
inner.appendChild(pane); inner.appendChild(pane);
menuItem.addEventListener('click', function () { menuItem.addEventListener('click', function () {
controls.showMenuPanel.call(_this7, type); controls.showMenuPanel.call(_this8, type);
}); });
_this7.elements.settings.buttons[type] = menuItem; _this8.elements.settings.buttons[type] = menuItem;
_this7.elements.settings.panels[type] = pane; _this8.elements.settings.panels[type] = pane;
}); });
home.appendChild(menu); home.appendChild(menu);
@@ -8016,7 +8043,7 @@ typeof navigator === "object" && (function (global, factory) {
// Insert controls // Insert controls
inject: function inject() { inject: function inject() {
var _this8 = this; var _this9 = this;
// Sprite // Sprite
if (this.config.loadSprite) { if (this.config.loadSprite) {
@@ -8128,8 +8155,8 @@ typeof navigator === "object" && (function (global, factory) {
var labels = getElements.call(this, selector); var labels = getElements.call(this, selector);
Array.from(labels).forEach(function (label) { Array.from(labels).forEach(function (label) {
toggleClass(label, _this8.config.classNames.hidden, false); toggleClass(label, _this9.config.classNames.hidden, false);
toggleClass(label, _this8.config.classNames.tooltip, true); toggleClass(label, _this9.config.classNames.tooltip, true);
}); });
} }
} }
@@ -9760,7 +9787,8 @@ typeof navigator === "object" && (function (global, factory) {
// Clear timer // Clear timer
clearTimeout(_this2.player.timers.controls); clearTimeout(_this2.player.timers.controls);
// Timer to prevent flicker when seeking
// Set new timer to prevent flicker when seeking
_this2.player.timers.controls = setTimeout(function () { _this2.player.timers.controls = setTimeout(function () {
return ui.toggleControls.call(_this2.player, false); return ui.toggleControls.call(_this2.player, false);
}, delay); }, delay);
@@ -9917,124 +9945,104 @@ typeof navigator === "object" && (function (global, factory) {
}); });
} }
// Run default and custom handlers
}, {
key: 'proxy',
value: function proxy(event, defaultHandler, customHandlerKey) {
var customHandler = this.player.config.listeners[customHandlerKey];
var hasCustomHandler = is$1.function(customHandler);
var returned = true;
// Execute custom handler
if (hasCustomHandler) {
returned = customHandler.call(this.player, event);
}
// Only call default handler if not prevented in custom handler
if (returned && is$1.function(defaultHandler)) {
defaultHandler.call(this.player, event);
}
}
// Trigger custom and default handlers
}, {
key: 'bind',
value: function bind(element, type, defaultHandler, customHandlerKey) {
var _this4 = this;
var passive = arguments.length > 4 && arguments[4] !== undefined ? arguments[4] : true;
var customHandler = this.player.config.listeners[customHandlerKey];
var hasCustomHandler = is$1.function(customHandler);
on.call(this.player, element, type, function (event) {
return _this4.proxy(event, defaultHandler, customHandlerKey);
}, passive && !hasCustomHandler);
}
// Listen for control events // Listen for control events
}, { }, {
key: 'controls', key: 'controls',
value: function controls$$1() { value: function controls$$1() {
var _this4 = this; var _this5 = this;
// IE doesn't support input event, so we fallback to change // IE doesn't support input event, so we fallback to change
var inputEvent = browser.isIE ? 'change' : 'input'; var inputEvent = browser.isIE ? 'change' : 'input';
// Run default and custom handlers
var proxy = function proxy(event, defaultHandler, customHandlerKey) {
var customHandler = _this4.player.config.listeners[customHandlerKey];
var hasCustomHandler = is$1.function(customHandler);
var returned = true;
// Execute custom handler
if (hasCustomHandler) {
returned = customHandler.call(_this4.player, event);
}
// Only call default handler if not prevented in custom handler
if (returned && is$1.function(defaultHandler)) {
defaultHandler.call(_this4.player, event);
}
};
// Trigger custom and default handlers
var bind = function bind(element, type, defaultHandler, customHandlerKey) {
var passive = arguments.length > 4 && arguments[4] !== undefined ? arguments[4] : true;
var customHandler = _this4.player.config.listeners[customHandlerKey];
var hasCustomHandler = is$1.function(customHandler);
on.call(_this4.player, element, type, function (event) {
return proxy(event, defaultHandler, customHandlerKey);
}, passive && !hasCustomHandler);
};
// Play/pause toggle // Play/pause toggle
Array.from(this.player.elements.buttons.play).forEach(function (button) { Array.from(this.player.elements.buttons.play).forEach(function (button) {
bind(button, 'click', _this4.player.togglePlay, 'play'); _this5.bind(button, 'click', _this5.player.togglePlay, 'play');
}); });
// Pause // Pause
bind(this.player.elements.buttons.restart, 'click', this.player.restart, 'restart'); this.bind(this.player.elements.buttons.restart, 'click', this.player.restart, 'restart');
// Rewind // Rewind
bind(this.player.elements.buttons.rewind, 'click', this.player.rewind, 'rewind'); this.bind(this.player.elements.buttons.rewind, 'click', this.player.rewind, 'rewind');
// Rewind // Rewind
bind(this.player.elements.buttons.fastForward, 'click', this.player.forward, 'fastForward'); this.bind(this.player.elements.buttons.fastForward, 'click', this.player.forward, 'fastForward');
// Mute toggle // Mute toggle
bind(this.player.elements.buttons.mute, 'click', function () { this.bind(this.player.elements.buttons.mute, 'click', function () {
_this4.player.muted = !_this4.player.muted; _this5.player.muted = !_this5.player.muted;
}, 'mute'); }, 'mute');
// Captions toggle // Captions toggle
bind(this.player.elements.buttons.captions, 'click', function () { this.bind(this.player.elements.buttons.captions, 'click', function () {
return _this4.player.toggleCaptions(); return _this5.player.toggleCaptions();
}); });
// Fullscreen toggle // Fullscreen toggle
bind(this.player.elements.buttons.fullscreen, 'click', function () { this.bind(this.player.elements.buttons.fullscreen, 'click', function () {
_this4.player.fullscreen.toggle(); _this5.player.fullscreen.toggle();
}, 'fullscreen'); }, 'fullscreen');
// Picture-in-Picture // Picture-in-Picture
bind(this.player.elements.buttons.pip, 'click', function () { this.bind(this.player.elements.buttons.pip, 'click', function () {
_this4.player.pip = 'toggle'; _this5.player.pip = 'toggle';
}, 'pip'); }, 'pip');
// Airplay // Airplay
bind(this.player.elements.buttons.airplay, 'click', this.player.airplay, 'airplay'); this.bind(this.player.elements.buttons.airplay, 'click', this.player.airplay, 'airplay');
// Settings menu // Settings menu
bind(this.player.elements.buttons.settings, 'click', function (event) { this.bind(this.player.elements.buttons.settings, 'click', function (event) {
controls.toggleMenu.call(_this4.player, event); controls.toggleMenu.call(_this5.player, event);
});
// Settings menu
bind(this.player.elements.settings.popup, 'click', function (event) {
event.stopPropagation();
// Go back to home tab on click
var showHomeTab = function showHomeTab() {
controls.showMenuPanel.call(_this4.player, 'home');
};
// Settings menu items - use event delegation as items are added/removed
if (matches(event.target, _this4.player.config.selectors.inputs.language)) {
proxy(event, function () {
_this4.player.currentTrack = Number(event.target.value);
showHomeTab();
}, 'language');
} else if (matches(event.target, _this4.player.config.selectors.inputs.quality)) {
proxy(event, function () {
_this4.player.quality = event.target.value;
showHomeTab();
}, 'quality');
} else if (matches(event.target, _this4.player.config.selectors.inputs.speed)) {
proxy(event, function () {
_this4.player.speed = parseFloat(event.target.value);
showHomeTab();
}, 'speed');
}
}); });
// Set range input alternative "value", which matches the tooltip time (#954) // Set range input alternative "value", which matches the tooltip time (#954)
bind(this.player.elements.inputs.seek, 'mousedown mousemove', function (event) { this.bind(this.player.elements.inputs.seek, 'mousedown mousemove', function (event) {
var clientRect = _this4.player.elements.progress.getBoundingClientRect(); var clientRect = _this5.player.elements.progress.getBoundingClientRect();
var percent = 100 / clientRect.width * (event.pageX - clientRect.left); var percent = 100 / clientRect.width * (event.pageX - clientRect.left);
event.currentTarget.setAttribute('seek-value', percent); event.currentTarget.setAttribute('seek-value', percent);
}); });
// Pause while seeking // Pause while seeking
bind(this.player.elements.inputs.seek, 'mousedown mouseup keydown keyup touchstart touchend', function (event) { this.bind(this.player.elements.inputs.seek, 'mousedown mouseup keydown keyup touchstart touchend', function (event) {
var seek = event.currentTarget; var seek = event.currentTarget;
var code = event.keyCode ? event.keyCode : event.which; var code = event.keyCode ? event.keyCode : event.which;
@@ -10052,15 +10060,15 @@ typeof navigator === "object" && (function (global, factory) {
// If we're done seeking and it was playing, resume playback // If we're done seeking and it was playing, resume playback
if (play && done) { if (play && done) {
seek.removeAttribute('play-on-seeked'); seek.removeAttribute('play-on-seeked');
_this4.player.play(); _this5.player.play();
} else if (!done && _this4.player.playing) { } else if (!done && _this5.player.playing) {
seek.setAttribute('play-on-seeked', ''); seek.setAttribute('play-on-seeked', '');
_this4.player.pause(); _this5.player.pause();
} }
}); });
// Seek // Seek
bind(this.player.elements.inputs.seek, inputEvent, function (event) { this.bind(this.player.elements.inputs.seek, inputEvent, function (event) {
var seek = event.currentTarget; var seek = event.currentTarget;
// If it exists, use seek-value instead of "value" for consistency with tooltip time (#954) // If it exists, use seek-value instead of "value" for consistency with tooltip time (#954)
@@ -10072,56 +10080,56 @@ typeof navigator === "object" && (function (global, factory) {
seek.removeAttribute('seek-value'); seek.removeAttribute('seek-value');
_this4.player.currentTime = seekTo / seek.max * _this4.player.duration; _this5.player.currentTime = seekTo / seek.max * _this5.player.duration;
}, 'seek'); }, 'seek');
// Current time invert // Current time invert
// Only if one time element is used for both currentTime and duration // Only if one time element is used for both currentTime and duration
if (this.player.config.toggleInvert && !is$1.element(this.player.elements.display.duration)) { if (this.player.config.toggleInvert && !is$1.element(this.player.elements.display.duration)) {
bind(this.player.elements.display.currentTime, 'click', function () { this.bind(this.player.elements.display.currentTime, 'click', function () {
// Do nothing if we're at the start // Do nothing if we're at the start
if (_this4.player.currentTime === 0) { if (_this5.player.currentTime === 0) {
return; return;
} }
_this4.player.config.invertTime = !_this4.player.config.invertTime; _this5.player.config.invertTime = !_this5.player.config.invertTime;
controls.timeUpdate.call(_this4.player); controls.timeUpdate.call(_this5.player);
}); });
} }
// Volume // Volume
bind(this.player.elements.inputs.volume, inputEvent, function (event) { this.bind(this.player.elements.inputs.volume, inputEvent, function (event) {
_this4.player.volume = event.target.value; _this5.player.volume = event.target.value;
}, 'volume'); }, 'volume');
// Polyfill for lower fill in <input type="range"> for webkit // Polyfill for lower fill in <input type="range"> for webkit
if (browser.isWebkit) { if (browser.isWebkit) {
Array.from(getElements.call(this.player, 'input[type="range"]')).forEach(function (element) { Array.from(getElements.call(this.player, 'input[type="range"]')).forEach(function (element) {
bind(element, 'input', function (event) { _this5.bind(element, 'input', function (event) {
return controls.updateRangeFill.call(_this4.player, event.target); return controls.updateRangeFill.call(_this5.player, event.target);
}); });
}); });
} }
// Seek tooltip // Seek tooltip
bind(this.player.elements.progress, 'mouseenter mouseleave mousemove', function (event) { this.bind(this.player.elements.progress, 'mouseenter mouseleave mousemove', function (event) {
return controls.updateSeekTooltip.call(_this4.player, event); return controls.updateSeekTooltip.call(_this5.player, event);
}); });
// Update controls.hover state (used for ui.toggleControls to avoid hiding when interacting) // Update controls.hover state (used for ui.toggleControls to avoid hiding when interacting)
bind(this.player.elements.controls, 'mouseenter mouseleave', function (event) { this.bind(this.player.elements.controls, 'mouseenter mouseleave', function (event) {
_this4.player.elements.controls.hover = !_this4.player.touch && event.type === 'mouseenter'; _this5.player.elements.controls.hover = !_this5.player.touch && event.type === 'mouseenter';
}); });
// Update controls.pressed state (used for ui.toggleControls to avoid hiding when interacting) // Update controls.pressed state (used for ui.toggleControls to avoid hiding when interacting)
bind(this.player.elements.controls, 'mousedown mouseup touchstart touchend touchcancel', function (event) { this.bind(this.player.elements.controls, 'mousedown mouseup touchstart touchend touchcancel', function (event) {
_this4.player.elements.controls.pressed = ['mousedown', 'touchstart'].includes(event.type); _this5.player.elements.controls.pressed = ['mousedown', 'touchstart'].includes(event.type);
}); });
// Focus in/out on controls // Focus in/out on controls
bind(this.player.elements.controls, 'focusin focusout', function (event) { this.bind(this.player.elements.controls, 'focusin focusout', function (event) {
var _player = _this4.player, var _player = _this5.player,
config = _player.config, config = _player.config,
elements = _player.elements, elements = _player.elements,
timers = _player.timers; timers = _player.timers;
@@ -10131,7 +10139,7 @@ typeof navigator === "object" && (function (global, factory) {
toggleClass(elements.controls, config.classNames.noTransition, event.type === 'focusin'); toggleClass(elements.controls, config.classNames.noTransition, event.type === 'focusin');
// Toggle // Toggle
ui.toggleControls.call(_this4.player, event.type === 'focusin'); ui.toggleControls.call(_this5.player, event.type === 'focusin');
// If focusin, hide again after delay // If focusin, hide again after delay
if (event.type === 'focusin') { if (event.type === 'focusin') {
@@ -10141,19 +10149,19 @@ typeof navigator === "object" && (function (global, factory) {
}, 0); }, 0);
// Delay a little more for keyboard users // Delay a little more for keyboard users
var delay = _this4.touch ? 3000 : 4000; var delay = _this5.touch ? 3000 : 4000;
// Clear timer // Clear timer
clearTimeout(timers.controls); clearTimeout(timers.controls);
// Hide // Hide
timers.controls = setTimeout(function () { timers.controls = setTimeout(function () {
return ui.toggleControls.call(_this4.player, false); return ui.toggleControls.call(_this5.player, false);
}, delay); }, delay);
} }
}); });
// Mouse wheel for volume // Mouse wheel for volume
bind(this.player.elements.inputs.volume, 'wheel', function (event) { this.bind(this.player.elements.inputs.volume, 'wheel', function (event) {
// Detect "natural" scroll - suppored on OS X Safari only // Detect "natural" scroll - suppored on OS X Safari only
// Other browsers on OS X will be inverted until support improves // Other browsers on OS X will be inverted until support improves
var inverted = event.webkitDirectionInvertedFromDevice; var inverted = event.webkitDirectionInvertedFromDevice;
@@ -10163,10 +10171,10 @@ typeof navigator === "object" && (function (global, factory) {
// Scroll down (or up on natural) to decrease // Scroll down (or up on natural) to decrease
if (event.deltaY < 0 || event.deltaX > 0) { if (event.deltaY < 0 || event.deltaX > 0) {
if (inverted) { if (inverted) {
_this4.player.decreaseVolume(step); _this5.player.decreaseVolume(step);
direction = -1; direction = -1;
} else { } else {
_this4.player.increaseVolume(step); _this5.player.increaseVolume(step);
direction = 1; direction = 1;
} }
} }
@@ -10174,16 +10182,16 @@ typeof navigator === "object" && (function (global, factory) {
// Scroll up (or down on natural) to increase // Scroll up (or down on natural) to increase
if (event.deltaY > 0 || event.deltaX < 0) { if (event.deltaY > 0 || event.deltaX < 0) {
if (inverted) { if (inverted) {
_this4.player.increaseVolume(step); _this5.player.increaseVolume(step);
direction = 1; direction = 1;
} else { } else {
_this4.player.decreaseVolume(step); _this5.player.decreaseVolume(step);
direction = -1; direction = -1;
} }
} }
// Don't break page scrolling at max and min // Don't break page scrolling at max and min
if (direction === 1 && _this4.player.media.volume < 1 || direction === -1 && _this4.player.media.volume > 0) { if (direction === 1 && _this5.player.media.volume < 1 || direction === -1 && _this5.player.media.volume > 0) {
event.preventDefault(); event.preventDefault();
} }
}, 'volume', false); }, 'volume', false);
+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
+136 -107
View File
@@ -370,18 +370,22 @@ const controls = {
type: 'button', type: 'button',
role: 'menuitemradio', role: 'menuitemradio',
class: `${this.config.classNames.control} ${attributes.class ? attributes.class : ''}`.trim(), class: `${this.config.classNames.control} ${attributes.class ? attributes.class : ''}`.trim(),
value,
'aria-checked': checked, 'aria-checked': checked,
}) value,
}),
); );
const flex = createElement('span');
// We have to set as HTML incase of special characters // We have to set as HTML incase of special characters
item.innerHTML = title; flex.innerHTML = title;
if (is.element(badge)) { if (is.element(badge)) {
item.appendChild(badge); flex.appendChild(badge);
} }
item.appendChild(flex);
Object.defineProperty(item, 'checked', { Object.defineProperty(item, 'checked', {
enumerable: true, enumerable: true,
get() { get() {
@@ -399,6 +403,34 @@ const controls = {
}, },
}); });
this.listeners.bind(
item,
'click',
() => {
item.checked = true;
switch (type) {
case 'language':
this.currentTrack = Number(value);
break;
case 'quality':
this.quality = value;
break;
case 'speed':
this.speed = parseFloat(value);
break;
default:
break;
}
controls.showMenuPanel.call(this, 'home');
},
type,
);
list.appendChild(item); list.appendChild(item);
}, },
@@ -657,95 +689,6 @@ const controls = {
toggleHidden(this.elements.settings.buttons[setting], !toggle); toggleHidden(this.elements.settings.buttons[setting], !toggle);
}, },
// Set the quality menu
setQualityMenu(options) {
// Menu required
if (!is.element(this.elements.settings.panels.quality)) {
console.warn('Not an element');
return;
}
const type = 'quality';
const list = this.elements.settings.panels.quality.querySelector('[role="menu"]');
// Set options if passed and filter based on uniqueness and config
if (is.array(options)) {
this.options.quality = dedupe(options).filter(quality => this.config.quality.options.includes(quality));
}
// Toggle the pane and tab
console.warn(this.options.quality);
const toggle = !is.empty(this.options.quality) && this.options.quality.length > 1;
controls.toggleMenuButton.call(this, type, toggle);
// Check if we need to toggle the parent
controls.checkMenu.call(this);
// If we're hiding, nothing more to do
if (!toggle) {
return;
}
// Empty the menu
emptyElement(list);
// Get the badge HTML for HD, 4K etc
const getBadge = quality => {
const label = i18n.get(`qualityBadge.${quality}`, this.config);
if (!label.length) {
return null;
}
return controls.createBadge.call(this, label);
};
// Sort options by the config and then render options
this.options.quality
.sort((a, b) => {
const sorting = this.config.quality.options;
return sorting.indexOf(a) > sorting.indexOf(b) ? 1 : -1;
})
.forEach(quality => {
controls.createMenuItem.call(this, {
value: quality,
list,
type,
title: controls.getLabel.call(this, 'quality', quality),
badge: getBadge(quality),
});
});
controls.updateSetting.call(this, type, list);
},
// Translate a value into a nice label
getLabel(setting, value) {
switch (setting) {
case 'speed':
return value === 1 ? i18n.get('normal', this.config) : `${value}&times;`;
case 'quality':
if (is.number(value)) {
const label = i18n.get(`qualityLabel.${value}`, this.config);
if (!label.length) {
return `${value}p`;
}
return label;
}
return toTitleCase(value);
case 'captions':
return captions.getLabel.call(this);
default:
return null;
}
},
// Update the selected setting // Update the selected setting
updateSetting(setting, container, input) { updateSetting(setting, container, input) {
const pane = this.elements.settings.panels[setting]; const pane = this.elements.settings.panels[setting];
@@ -797,6 +740,93 @@ const controls = {
} }
}, },
// Translate a value into a nice label
getLabel(setting, value) {
switch (setting) {
case 'speed':
return value === 1 ? i18n.get('normal', this.config) : `${value}&times;`;
case 'quality':
if (is.number(value)) {
const label = i18n.get(`qualityLabel.${value}`, this.config);
if (!label.length) {
return `${value}p`;
}
return label;
}
return toTitleCase(value);
case 'captions':
return captions.getLabel.call(this);
default:
return null;
}
},
// Set the quality menu
setQualityMenu(options) {
// Menu required
if (!is.element(this.elements.settings.panels.quality)) {
return;
}
const type = 'quality';
const list = this.elements.settings.panels.quality.querySelector('[role="menu"]');
// Set options if passed and filter based on uniqueness and config
if (is.array(options)) {
this.options.quality = dedupe(options).filter(quality => this.config.quality.options.includes(quality));
}
// Toggle the pane and tab
const toggle = !is.empty(this.options.quality) && this.options.quality.length > 1;
controls.toggleMenuButton.call(this, type, toggle);
// Empty the menu
emptyElement(list);
// Check if we need to toggle the parent
controls.checkMenu.call(this);
// If we're hiding, nothing more to do
if (!toggle) {
return;
}
// Get the badge HTML for HD, 4K etc
const getBadge = quality => {
const label = i18n.get(`qualityBadge.${quality}`, this.config);
if (!label.length) {
return null;
}
return controls.createBadge.call(this, label);
};
// Sort options by the config and then render options
this.options.quality
.sort((a, b) => {
const sorting = this.config.quality.options;
return sorting.indexOf(a) > sorting.indexOf(b) ? 1 : -1;
})
.forEach(quality => {
controls.createMenuItem.call(this, {
value: quality,
list,
type,
title: controls.getLabel.call(this, 'quality', quality),
badge: getBadge(quality),
});
});
controls.updateSetting.call(this, type, list);
},
// Set the looping options // Set the looping options
/* setLoopMenu() { /* setLoopMenu() {
// Menu required // Menu required
@@ -846,13 +876,19 @@ const controls = {
// Set a list of available captions languages // Set a list of available captions languages
setCaptionsMenu() { setCaptionsMenu() {
// Menu required
if (!is.element(this.elements.settings.panels.captions)) {
return;
}
// TODO: Captions or language? Currently it's mixed // TODO: Captions or language? Currently it's mixed
const type = 'captions'; const type = 'captions';
const list = this.elements.settings.panels.captions.querySelector('[role="menu"]'); const list = this.elements.settings.panels.captions.querySelector('[role="menu"]');
const tracks = captions.getTracks.call(this); const tracks = captions.getTracks.call(this);
const toggle = Boolean(tracks.length);
// Toggle the pane and tab // Toggle the pane and tab
controls.toggleMenuButton.call(this, type, tracks.length); controls.toggleMenuButton.call(this, type, toggle);
// Empty the menu // Empty the menu
emptyElement(list); emptyElement(list);
@@ -861,7 +897,7 @@ const controls = {
controls.checkMenu.call(this); controls.checkMenu.call(this);
// If there's no captions, bail // If there's no captions, bail
if (!tracks.length) { if (!toggle) {
return; return;
} }
@@ -892,17 +928,13 @@ const controls = {
// Set a list of available captions languages // Set a list of available captions languages
setSpeedMenu(options) { setSpeedMenu(options) {
// Do nothing if not selected
if (!this.config.controls.includes('settings') || !this.config.settings.includes('speed')) {
return;
}
// Menu required // Menu required
if (!is.element(this.elements.settings.panels.speed)) { if (!is.element(this.elements.settings.panels.speed)) {
return; return;
} }
const type = 'speed'; const type = 'speed';
const list = this.elements.settings.panels.speed.querySelector('[role="menu"]');
// Set the speed options // Set the speed options
if (is.array(options)) { if (is.array(options)) {
@@ -918,6 +950,9 @@ const controls = {
const toggle = !is.empty(this.options.speed) && this.options.speed.length > 1; const toggle = !is.empty(this.options.speed) && this.options.speed.length > 1;
controls.toggleMenuButton.call(this, type, toggle); controls.toggleMenuButton.call(this, type, toggle);
// Empty the menu
emptyElement(list);
// Check if we need to toggle the parent // Check if we need to toggle the parent
controls.checkMenu.call(this); controls.checkMenu.call(this);
@@ -926,12 +961,6 @@ const controls = {
return; return;
} }
// Get the list to populate
const list = this.elements.settings.panels.speed.querySelector('[role="menu"]');
// Empty the menu
emptyElement(list);
// Create items // Create items
this.options.speed.forEach(speed => { this.options.speed.forEach(speed => {
controls.createMenuItem.call(this, { controls.createMenuItem.call(this, {
@@ -1069,7 +1098,6 @@ const controls = {
// Set attributes on current tab // Set attributes on current tab
toggleHidden(current, true); toggleHidden(current, true);
// current.setAttribute('tabindex', -1);
// Set attributes on target // Set attributes on target
toggleHidden(target, false); toggleHidden(target, false);
@@ -1238,6 +1266,7 @@ const controls = {
class: `${this.config.classNames.control} ${this.config.classNames.control}--forward`, class: `${this.config.classNames.control} ${this.config.classNames.control}--forward`,
role: 'menuitem', role: 'menuitem',
'aria-haspopup': true, 'aria-haspopup': true,
hidden: '',
}), }),
); );
+54 -93
View File
@@ -243,7 +243,8 @@ class Listeners {
// Clear timer // Clear timer
clearTimeout(this.player.timers.controls); clearTimeout(this.player.timers.controls);
// Timer to prevent flicker when seeking
// Set new timer to prevent flicker when seeking
this.player.timers.controls = setTimeout(() => ui.toggleControls.call(this.player, false), delay); this.player.timers.controls = setTimeout(() => ui.toggleControls.call(this.player, false), delay);
}, },
); );
@@ -394,58 +395,58 @@ class Listeners {
}); });
} }
// Run default and custom handlers
proxy(event, defaultHandler, customHandlerKey) {
const customHandler = this.player.config.listeners[customHandlerKey];
const hasCustomHandler = is.function(customHandler);
let returned = true;
// Execute custom handler
if (hasCustomHandler) {
returned = customHandler.call(this.player, event);
}
// Only call default handler if not prevented in custom handler
if (returned && is.function(defaultHandler)) {
defaultHandler.call(this.player, event);
}
}
// Trigger custom and default handlers
bind(element, type, defaultHandler, customHandlerKey, passive = true) {
const customHandler = this.player.config.listeners[customHandlerKey];
const hasCustomHandler = is.function(customHandler);
on.call(
this.player,
element,
type,
event => this.proxy(event, defaultHandler, customHandlerKey),
passive && !hasCustomHandler,
);
}
// Listen for control events // Listen for control events
controls() { controls() {
// IE doesn't support input event, so we fallback to change // IE doesn't support input event, so we fallback to change
const inputEvent = browser.isIE ? 'change' : 'input'; const inputEvent = browser.isIE ? 'change' : 'input';
// Run default and custom handlers
const proxy = (event, defaultHandler, customHandlerKey) => {
const customHandler = this.player.config.listeners[customHandlerKey];
const hasCustomHandler = is.function(customHandler);
let returned = true;
// Execute custom handler
if (hasCustomHandler) {
returned = customHandler.call(this.player, event);
}
// Only call default handler if not prevented in custom handler
if (returned && is.function(defaultHandler)) {
defaultHandler.call(this.player, event);
}
};
// Trigger custom and default handlers
const bind = (element, type, defaultHandler, customHandlerKey, passive = true) => {
const customHandler = this.player.config.listeners[customHandlerKey];
const hasCustomHandler = is.function(customHandler);
on.call(
this.player,
element,
type,
event => proxy(event, defaultHandler, customHandlerKey),
passive && !hasCustomHandler,
);
};
// Play/pause toggle // Play/pause toggle
Array.from(this.player.elements.buttons.play).forEach(button => { Array.from(this.player.elements.buttons.play).forEach(button => {
bind(button, 'click', this.player.togglePlay, 'play'); this.bind(button, 'click', this.player.togglePlay, 'play');
}); });
// Pause // Pause
bind(this.player.elements.buttons.restart, 'click', this.player.restart, 'restart'); this.bind(this.player.elements.buttons.restart, 'click', this.player.restart, 'restart');
// Rewind // Rewind
bind(this.player.elements.buttons.rewind, 'click', this.player.rewind, 'rewind'); this.bind(this.player.elements.buttons.rewind, 'click', this.player.rewind, 'rewind');
// Rewind // Rewind
bind(this.player.elements.buttons.fastForward, 'click', this.player.forward, 'fastForward'); this.bind(this.player.elements.buttons.fastForward, 'click', this.player.forward, 'fastForward');
// Mute toggle // Mute toggle
bind( this.bind(
this.player.elements.buttons.mute, this.player.elements.buttons.mute,
'click', 'click',
() => { () => {
@@ -455,10 +456,10 @@ class Listeners {
); );
// Captions toggle // Captions toggle
bind(this.player.elements.buttons.captions, 'click', () => this.player.toggleCaptions()); this.bind(this.player.elements.buttons.captions, 'click', () => this.player.toggleCaptions());
// Fullscreen toggle // Fullscreen toggle
bind( this.bind(
this.player.elements.buttons.fullscreen, this.player.elements.buttons.fullscreen,
'click', 'click',
() => { () => {
@@ -468,7 +469,7 @@ class Listeners {
); );
// Picture-in-Picture // Picture-in-Picture
bind( this.bind(
this.player.elements.buttons.pip, this.player.elements.buttons.pip,
'click', 'click',
() => { () => {
@@ -478,62 +479,22 @@ class Listeners {
); );
// Airplay // Airplay
bind(this.player.elements.buttons.airplay, 'click', this.player.airplay, 'airplay'); this.bind(this.player.elements.buttons.airplay, 'click', this.player.airplay, 'airplay');
// Settings menu // Settings menu
bind(this.player.elements.buttons.settings, 'click', event => { this.bind(this.player.elements.buttons.settings, 'click', event => {
controls.toggleMenu.call(this.player, event); controls.toggleMenu.call(this.player, event);
}); });
// Settings menu
bind(this.player.elements.settings.popup, 'click', event => {
event.stopPropagation();
// Go back to home tab on click
const showHomeTab = () => {
controls.showMenuPanel.call(this.player, 'home');
};
// Settings menu items - use event delegation as items are added/removed
if (matches(event.target, this.player.config.selectors.inputs.language)) {
proxy(
event,
() => {
this.player.currentTrack = Number(event.target.value);
showHomeTab();
},
'language',
);
} else if (matches(event.target, this.player.config.selectors.inputs.quality)) {
proxy(
event,
() => {
this.player.quality = event.target.value;
showHomeTab();
},
'quality',
);
} else if (matches(event.target, this.player.config.selectors.inputs.speed)) {
proxy(
event,
() => {
this.player.speed = parseFloat(event.target.value);
showHomeTab();
},
'speed',
);
}
});
// Set range input alternative "value", which matches the tooltip time (#954) // Set range input alternative "value", which matches the tooltip time (#954)
bind(this.player.elements.inputs.seek, 'mousedown mousemove', event => { this.bind(this.player.elements.inputs.seek, 'mousedown mousemove', event => {
const clientRect = this.player.elements.progress.getBoundingClientRect(); const clientRect = this.player.elements.progress.getBoundingClientRect();
const percent = 100 / clientRect.width * (event.pageX - clientRect.left); const percent = 100 / clientRect.width * (event.pageX - clientRect.left);
event.currentTarget.setAttribute('seek-value', percent); event.currentTarget.setAttribute('seek-value', percent);
}); });
// Pause while seeking // Pause while seeking
bind(this.player.elements.inputs.seek, 'mousedown mouseup keydown keyup touchstart touchend', event => { this.bind(this.player.elements.inputs.seek, 'mousedown mouseup keydown keyup touchstart touchend', event => {
const seek = event.currentTarget; const seek = event.currentTarget;
const code = event.keyCode ? event.keyCode : event.which; const code = event.keyCode ? event.keyCode : event.which;
@@ -559,7 +520,7 @@ class Listeners {
}); });
// Seek // Seek
bind( this.bind(
this.player.elements.inputs.seek, this.player.elements.inputs.seek,
inputEvent, inputEvent,
event => { event => {
@@ -582,7 +543,7 @@ class Listeners {
// Current time invert // Current time invert
// Only if one time element is used for both currentTime and duration // Only if one time element is used for both currentTime and duration
if (this.player.config.toggleInvert && !is.element(this.player.elements.display.duration)) { if (this.player.config.toggleInvert && !is.element(this.player.elements.display.duration)) {
bind(this.player.elements.display.currentTime, 'click', () => { this.bind(this.player.elements.display.currentTime, 'click', () => {
// Do nothing if we're at the start // Do nothing if we're at the start
if (this.player.currentTime === 0) { if (this.player.currentTime === 0) {
return; return;
@@ -595,7 +556,7 @@ class Listeners {
} }
// Volume // Volume
bind( this.bind(
this.player.elements.inputs.volume, this.player.elements.inputs.volume,
inputEvent, inputEvent,
event => { event => {
@@ -607,27 +568,27 @@ class Listeners {
// Polyfill for lower fill in <input type="range"> for webkit // Polyfill for lower fill in <input type="range"> for webkit
if (browser.isWebkit) { if (browser.isWebkit) {
Array.from(getElements.call(this.player, 'input[type="range"]')).forEach(element => { Array.from(getElements.call(this.player, 'input[type="range"]')).forEach(element => {
bind(element, 'input', event => controls.updateRangeFill.call(this.player, event.target)); this.bind(element, 'input', event => controls.updateRangeFill.call(this.player, event.target));
}); });
} }
// Seek tooltip // Seek tooltip
bind(this.player.elements.progress, 'mouseenter mouseleave mousemove', event => this.bind(this.player.elements.progress, 'mouseenter mouseleave mousemove', event =>
controls.updateSeekTooltip.call(this.player, event), controls.updateSeekTooltip.call(this.player, event),
); );
// Update controls.hover state (used for ui.toggleControls to avoid hiding when interacting) // Update controls.hover state (used for ui.toggleControls to avoid hiding when interacting)
bind(this.player.elements.controls, 'mouseenter mouseleave', event => { this.bind(this.player.elements.controls, 'mouseenter mouseleave', event => {
this.player.elements.controls.hover = !this.player.touch && event.type === 'mouseenter'; this.player.elements.controls.hover = !this.player.touch && event.type === 'mouseenter';
}); });
// Update controls.pressed state (used for ui.toggleControls to avoid hiding when interacting) // Update controls.pressed state (used for ui.toggleControls to avoid hiding when interacting)
bind(this.player.elements.controls, 'mousedown mouseup touchstart touchend touchcancel', event => { this.bind(this.player.elements.controls, 'mousedown mouseup touchstart touchend touchcancel', event => {
this.player.elements.controls.pressed = ['mousedown', 'touchstart'].includes(event.type); this.player.elements.controls.pressed = ['mousedown', 'touchstart'].includes(event.type);
}); });
// Focus in/out on controls // Focus in/out on controls
bind(this.player.elements.controls, 'focusin focusout', event => { this.bind(this.player.elements.controls, 'focusin focusout', event => {
const { config, elements, timers } = this.player; const { config, elements, timers } = this.player;
// Skip transition to prevent focus from scrolling the parent element // Skip transition to prevent focus from scrolling the parent element
@@ -654,7 +615,7 @@ class Listeners {
}); });
// Mouse wheel for volume // Mouse wheel for volume
bind( this.bind(
this.player.elements.inputs.volume, this.player.elements.inputs.volume,
'wheel', 'wheel',
event => { event => {
+1 -1
View File
@@ -191,7 +191,7 @@
align-items: center; align-items: center;
display: flex; display: flex;
margin-left: auto; margin-left: auto;
margin-right: -$plyr-control-padding; margin-right: -($plyr-control-padding - 2);
overflow: hidden; overflow: hidden;
padding-left: ceil($plyr-control-padding * 3.5); padding-left: ceil($plyr-control-padding * 3.5);
pointer-events: none; pointer-events: none;
+4
View File
@@ -22,3 +22,7 @@
width: 1px; width: 1px;
} }
} }
.plyr [hidden] {
display: none !important;
}