Controls fixes

This commit is contained in:
Sam Potts 2018-03-27 23:43:38 +11:00
parent 0cf75eed3f
commit 7b1e4abda7
17 changed files with 219 additions and 128 deletions

2
demo/dist/demo.css vendored

File diff suppressed because one or more lines are too long

2
dist/plyr.css vendored

File diff suppressed because one or more lines are too long

123
dist/plyr.js vendored
View File

@ -170,7 +170,6 @@ var defaults = {
end: 'End', end: 'End',
all: 'All', all: 'All',
reset: 'Reset', reset: 'Reset',
none: 'None',
disabled: 'Disabled', disabled: 'Disabled',
advertisement: 'Ad' advertisement: 'Ad'
}, },
@ -1964,7 +1963,7 @@ var support = {
}(), }(),
// Touch // Touch
// Remember a device can be moust + touch enabled // NOTE: Remember a device can be mouse + touch enabled so we check on first touch event
touch: 'ontouchstart' in document.documentElement, touch: 'ontouchstart' in document.documentElement,
// Detect transitions support // Detect transitions support
@ -2869,6 +2868,7 @@ var ui = {
// Plyr controls // Plyr controls
// ========================================================================== // ==========================================================================
// Sniff out the browser
var browser$2 = utils.getBrowser(); var browser$2 = utils.getBrowser();
var controls = { var controls = {
@ -3206,6 +3206,8 @@ var controls = {
// Update hover tooltip for seeking // Update hover tooltip for seeking
updateSeekTooltip: function updateSeekTooltip(event) { updateSeekTooltip: function updateSeekTooltip(event) {
var _this = this;
// Bail if setting not true // Bail if setting not true
if (!this.config.tooltips.seek || !utils.is.element(this.elements.inputs.seek) || !utils.is.element(this.elements.display.seekTooltip) || this.duration === 0) { if (!this.config.tooltips.seek || !utils.is.element(this.elements.inputs.seek) || !utils.is.element(this.elements.display.seekTooltip) || this.duration === 0) {
return; return;
@ -3216,6 +3218,16 @@ var controls = {
var clientRect = this.elements.inputs.seek.getBoundingClientRect(); var clientRect = this.elements.inputs.seek.getBoundingClientRect();
var visible = this.config.classNames.tooltip + '--visible'; var visible = this.config.classNames.tooltip + '--visible';
var toggle = function toggle(_toggle) {
utils.toggleClass(_this.elements.display.seekTooltip, visible, _toggle);
};
// Hide on touch
if (this.touch) {
toggle(false);
return;
}
// Determine percentage, if already visible // Determine percentage, if already visible
if (utils.is.event(event)) { if (utils.is.event(event)) {
percent = 100 / clientRect.width * (event.pageX - clientRect.left); percent = 100 / clientRect.width * (event.pageX - clientRect.left);
@ -3241,7 +3253,7 @@ var controls = {
// Show/hide the tooltip // Show/hide the tooltip
// If the event is a moues in/out and percentage is inside bounds // If the event is a moues in/out and percentage is inside bounds
if (utils.is.event(event) && ['mouseenter', 'mouseleave'].includes(event.type)) { if (utils.is.event(event) && ['mouseenter', 'mouseleave'].includes(event.type)) {
utils.toggleClass(this.elements.display.seekTooltip, visible, event.type === 'mouseenter'); toggle(event.type === 'mouseenter');
} }
}, },
@ -3259,7 +3271,7 @@ var controls = {
// Set the YouTube quality menu // Set the YouTube quality menu
// TODO: Support for HTML5 // TODO: Support for HTML5
setQualityMenu: function setQualityMenu(options) { setQualityMenu: function setQualityMenu(options) {
var _this = this; var _this2 = this;
// Menu required // Menu required
if (!utils.is.element(this.elements.settings.panes.quality)) { if (!utils.is.element(this.elements.settings.panes.quality)) {
@ -3272,7 +3284,7 @@ var controls = {
// Set options if passed and filter based on config // Set options if passed and filter based on config
if (utils.is.array(options)) { if (utils.is.array(options)) {
this.options.quality = options.filter(function (quality) { this.options.quality = options.filter(function (quality) {
return _this.config.quality.options.includes(quality); return _this2.config.quality.options.includes(quality);
}); });
} else { } else {
this.options.quality = this.config.quality.options; this.options.quality = this.config.quality.options;
@ -3319,11 +3331,11 @@ var controls = {
return null; return null;
} }
return controls.createBadge.call(_this, label); return controls.createBadge.call(_this2, label);
}; };
this.options.quality.forEach(function (quality) { this.options.quality.forEach(function (quality) {
return controls.createMenuItem.call(_this, quality, list, type, controls.getLabel.call(_this, 'quality', quality), getBadge(quality)); return controls.createMenuItem.call(_this2, quality, list, type, controls.getLabel.call(_this2, 'quality', quality), getBadge(quality));
}); });
controls.updateSetting.call(this, type, list); controls.updateSetting.call(this, type, list);
@ -3378,7 +3390,7 @@ var controls = {
switch (setting) { switch (setting) {
case 'captions': case 'captions':
value = this.captions.active ? this.captions.language : ''; value = this.captions.active ? this.captions.language : i18n.get('disabled', this.config);
break; break;
default: default:
@ -3468,11 +3480,7 @@ var controls = {
return null; return null;
} }
if (!support.textTracks || !captions.getTracks.call(this).length) { if (support.textTracks && captions.getTracks.call(this).length && this.captions.active) {
return i18n.get('none', this.config);
}
if (this.captions.active) {
var currentTrack = captions.getCurrentTrack.call(this); var currentTrack = captions.getCurrentTrack.call(this);
if (utils.is.track(currentTrack)) { if (utils.is.track(currentTrack)) {
@ -3486,7 +3494,7 @@ var controls = {
// Set a list of available captions languages // Set a list of available captions languages
setCaptionsMenu: function setCaptionsMenu() { setCaptionsMenu: function setCaptionsMenu() {
var _this2 = this; var _this3 = this;
// TODO: Captions or language? Currently it's mixed // TODO: Captions or language? Currently it's mixed
var type = 'captions'; var type = 'captions';
@ -3512,15 +3520,15 @@ var controls = {
}; };
}); });
// Add the "None" option to turn off captions // Add the "Disabled" option to turn off captions
tracks.unshift({ tracks.unshift({
language: '', language: '',
label: i18n.get('none', this.config) label: i18n.get('disabled', this.config)
}); });
// Generate options // Generate options
tracks.forEach(function (track) { tracks.forEach(function (track) {
controls.createMenuItem.call(_this2, track.language, list, 'language', track.label || track.language, controls.createBadge.call(_this2, track.language.toUpperCase()), track.language.toLowerCase() === _this2.captions.language.toLowerCase()); controls.createMenuItem.call(_this3, track.language, list, 'language', track.label || track.language, controls.createBadge.call(_this3, track.language.toUpperCase()), track.language.toLowerCase() === _this3.captions.language.toLowerCase());
}); });
controls.updateSetting.call(this, type, list); controls.updateSetting.call(this, type, list);
@ -3529,7 +3537,7 @@ var controls = {
// Set a list of available captions languages // Set a list of available captions languages
setSpeedMenu: function setSpeedMenu() { setSpeedMenu: function setSpeedMenu() {
var _this3 = this; var _this4 = this;
// Menu required // Menu required
if (!utils.is.element(this.elements.settings.panes.speed)) { if (!utils.is.element(this.elements.settings.panes.speed)) {
@ -3545,7 +3553,7 @@ var controls = {
// 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 _this3.config.speed.options.includes(speed); return _this4.config.speed.options.includes(speed);
}); });
// Toggle the pane and tab // Toggle the pane and tab
@ -3569,7 +3577,7 @@ var controls = {
// Create items // Create items
this.options.speed.forEach(function (speed) { this.options.speed.forEach(function (speed) {
return controls.createMenuItem.call(_this3, speed, list, type, controls.getLabel.call(_this3, 'speed', speed)); return controls.createMenuItem.call(_this4, speed, list, type, controls.getLabel.call(_this4, 'speed', speed));
}); });
controls.updateSetting.call(this, type, list); controls.updateSetting.call(this, type, list);
@ -3732,7 +3740,7 @@ var controls = {
// 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 _this4 = this; var _this5 = this;
// Do nothing if we want no controls // Do nothing if we want no controls
if (utils.is.empty(this.config.controls)) { if (utils.is.empty(this.config.controls)) {
@ -3881,17 +3889,17 @@ var controls = {
hidden: '' hidden: ''
}); });
var button = utils.createElement('button', utils.extend(utils.getAttributesFromSelector(_this4.config.selectors.buttons.settings), { var button = utils.createElement('button', utils.extend(utils.getAttributesFromSelector(_this5.config.selectors.buttons.settings), {
type: 'button', type: 'button',
class: _this4.config.classNames.control + ' ' + _this4.config.classNames.control + '--forward', class: _this5.config.classNames.control + ' ' + _this5.config.classNames.control + '--forward',
id: 'plyr-settings-' + data.id + '-' + type + '-tab', id: 'plyr-settings-' + data.id + '-' + type + '-tab',
'aria-haspopup': true, 'aria-haspopup': true,
'aria-controls': 'plyr-settings-' + data.id + '-' + type, 'aria-controls': 'plyr-settings-' + data.id + '-' + type,
'aria-expanded': false 'aria-expanded': false
}), i18n.get(type, _this4.config)); }), i18n.get(type, _this5.config));
var value = utils.createElement('span', { var value = utils.createElement('span', {
class: _this4.config.classNames.menu.value class: _this5.config.classNames.menu.value
}); });
// Speed contains HTML entities // Speed contains HTML entities
@ -3901,7 +3909,7 @@ var controls = {
tab.appendChild(button); tab.appendChild(button);
tabs.appendChild(tab); tabs.appendChild(tab);
_this4.elements.settings.tabs[type] = tab; _this5.elements.settings.tabs[type] = tab;
}); });
home.appendChild(tabs); home.appendChild(tabs);
@ -3920,11 +3928,11 @@ var controls = {
var back = utils.createElement('button', { var back = utils.createElement('button', {
type: 'button', type: 'button',
class: _this4.config.classNames.control + ' ' + _this4.config.classNames.control + '--back', class: _this5.config.classNames.control + ' ' + _this5.config.classNames.control + '--back',
'aria-haspopup': true, 'aria-haspopup': true,
'aria-controls': 'plyr-settings-' + data.id + '-home', 'aria-controls': 'plyr-settings-' + data.id + '-home',
'aria-expanded': false 'aria-expanded': false
}, i18n.get(type, _this4.config)); }, i18n.get(type, _this5.config));
pane.appendChild(back); pane.appendChild(back);
@ -3933,7 +3941,7 @@ var controls = {
pane.appendChild(options); pane.appendChild(options);
inner.appendChild(pane); inner.appendChild(pane);
_this4.elements.settings.panes[type] = pane; _this5.elements.settings.panes[type] = pane;
}); });
form.appendChild(inner); form.appendChild(inner);
@ -3976,7 +3984,7 @@ var controls = {
// Insert controls // Insert controls
inject: function inject() { inject: function inject() {
var _this5 = this; var _this6 = this;
// Sprite // Sprite
if (this.config.loadSprite) { if (this.config.loadSprite) {
@ -4054,8 +4062,8 @@ var controls = {
var labels = utils.getElements.call(this, [this.config.selectors.controls.wrapper, ' ', this.config.selectors.labels, ' .', this.config.classNames.hidden].join('')); var labels = utils.getElements.call(this, [this.config.selectors.controls.wrapper, ' ', this.config.selectors.labels, ' .', this.config.classNames.hidden].join(''));
Array.from(labels).forEach(function (label) { Array.from(labels).forEach(function (label) {
utils.toggleClass(label, _this5.config.classNames.hidden, false); utils.toggleClass(label, _this6.config.classNames.hidden, false);
utils.toggleClass(label, _this5.config.classNames.tooltip, true); utils.toggleClass(label, _this6.config.classNames.tooltip, true);
label.setAttribute('role', 'tooltip'); label.setAttribute('role', 'tooltip');
}); });
} }
@ -4077,6 +4085,7 @@ var Listeners = function () {
this.handleKey = this.handleKey.bind(this); this.handleKey = this.handleKey.bind(this);
this.toggleMenu = this.toggleMenu.bind(this); this.toggleMenu = this.toggleMenu.bind(this);
this.firstTouch = this.firstTouch.bind(this);
} }
// Handle key presses // Handle key presses
@ -4232,6 +4241,20 @@ var Listeners = function () {
controls.toggleMenu.call(this.player, event); controls.toggleMenu.call(this.player, event);
} }
// Device is touch enabled
}, {
key: 'firstTouch',
value: function firstTouch() {
this.player.touch = true;
// Add touch class
utils.toggleClass(this.player.elements.container, this.player.config.classNames.isTouch, true);
// Clean up
utils.off(document.body, 'touchstart', this.firstTouch);
}
// Global window & document listeners // Global window & document listeners
}, { }, {
@ -4246,6 +4269,9 @@ var Listeners = function () {
// Click anywhere closes menu // Click anywhere closes menu
utils.toggleListener(document.body, 'click', this.toggleMenu, toggle); utils.toggleListener(document.body, 'click', this.toggleMenu, toggle);
// Detect touch by events
utils.on(document.body, 'touchstart', this.firstTouch);
} }
// Container listeners // Container listeners
@ -4360,7 +4386,7 @@ var Listeners = function () {
// On click play, pause ore restart // On click play, pause ore restart
utils.on(wrapper, 'click', function () { utils.on(wrapper, 'click', function () {
// Touch devices will just show controls (if we're hiding controls) // Touch devices will just show controls (if we're hiding controls)
if (_this3.player.config.hideControls && support.touch && !_this3.player.paused) { if (_this3.player.config.hideControls && _this3.player.touch && !_this3.player.paused) {
return; return;
} }
@ -4486,7 +4512,7 @@ var Listeners = function () {
on(this.player.elements.buttons.rewind, 'click', this.player.rewind, 'rewind'); on(this.player.elements.buttons.rewind, 'click', this.player.rewind, 'rewind');
// Rewind // Rewind
on(this.player.elements.buttons.fastForward, 'click', this.player.fastForward, 'fastForward'); on(this.player.elements.buttons.fastForward, 'click', this.player.forward, 'fastForward');
// Mute toggle // Mute toggle
on(this.player.elements.buttons.mute, 'click', function () { on(this.player.elements.buttons.mute, 'click', function () {
@ -4576,7 +4602,7 @@ var Listeners = function () {
if (this.player.config.hideControls) { if (this.player.config.hideControls) {
// Watch for cursor over controls so they don't hide when trying to interact // Watch for cursor over controls so they don't hide when trying to interact
on(this.player.elements.controls, 'mouseenter mouseleave', function (event) { on(this.player.elements.controls, 'mouseenter mouseleave', function (event) {
_this4.player.elements.controls.hover = event.type === 'mouseenter'; _this4.player.elements.controls.hover = !_this4.player.touch && event.type === 'mouseenter';
}); });
// Watch for cursor over controls so they don't hide when trying to interact // Watch for cursor over controls so they don't hide when trying to interact
@ -6183,7 +6209,7 @@ var media = {
utils.toggleClass(this.elements.container, this.config.classNames.isIos, browser$3.isIos); utils.toggleClass(this.elements.container, this.config.classNames.isIos, browser$3.isIos);
// Add touch class // Add touch class
utils.toggleClass(this.elements.container, this.config.classNames.isTouch, support.touch); utils.toggleClass(this.elements.container, this.config.classNames.isTouch, this.touch);
} }
// Inject the player wrapper // Inject the player wrapper
@ -6390,12 +6416,6 @@ var source = {
// License: The MIT License (MIT) // License: The MIT License (MIT)
// ========================================================================== // ==========================================================================
// Private properties
// TODO: Use a WeakMap for private globals
// const globals = new WeakMap();
// Plyr instance
var Plyr = function () { var Plyr = function () {
function Plyr(target, options) { function Plyr(target, options) {
var _this = this; var _this = this;
@ -6409,6 +6429,9 @@ var Plyr = function () {
this.loading = false; this.loading = false;
this.failed = false; this.failed = false;
// Touch device
this.touch = support.touch;
// Set the media element // Set the media element
this.media = target; this.media = target;
@ -6889,16 +6912,22 @@ var Plyr = function () {
// Is the enter fullscreen event // Is the enter fullscreen event
isEnterFullscreen = toggle.type === 'enterfullscreen'; isEnterFullscreen = toggle.type === 'enterfullscreen';
// Events that show the controls
var showEvents = ['touchstart', 'touchmove', 'mouseenter', 'mousemove', 'focusin'];
// Events that delay hiding
var delayEvents = ['touchmove', 'touchend', 'mousemove'];
// Whether to show controls // Whether to show controls
show = ['mouseenter', 'mousemove', 'touchstart', 'touchmove', 'focusin'].includes(toggle.type); show = showEvents.includes(toggle.type);
// Delay hiding on move events // Delay hiding on move events
if (['mousemove', 'touchmove', 'touchend'].includes(toggle.type)) { if (delayEvents.includes(toggle.type)) {
delay = 2000; delay = 2000;
} }
// Delay a little more for keyboard users // Delay a little more for keyboard users
if (toggle.type === 'focusin') { if (!this.touch && toggle.type === 'focusin') {
delay = 3000; delay = 3000;
utils.toggleClass(this.elements.controls, this.config.classNames.noTransition, true); utils.toggleClass(this.elements.controls, this.config.classNames.noTransition, true);
} }
@ -6926,7 +6955,7 @@ var Plyr = function () {
} }
// Delay for hiding on touch // Delay for hiding on touch
if (support.touch) { if (this.touch) {
delay = 3000; delay = 3000;
} }
} }
@ -6935,6 +6964,8 @@ var Plyr = function () {
// then set the timer to hide the controls // then set the timer to hide the controls
if (!show || this.playing) { if (!show || this.playing) {
this.timers.controls = setTimeout(function () { this.timers.controls = setTimeout(function () {
console.warn(_this3.elements.controls.pressed, _this3.elements.controls.hover, delay);
// If the mouse is over the controls (and not entering fullscreen), bail // If the mouse is over the controls (and not entering fullscreen), bail
if ((_this3.elements.controls.pressed || _this3.elements.controls.hover) && !isEnterFullscreen) { if ((_this3.elements.controls.pressed || _this3.elements.controls.hover) && !isEnterFullscreen) {
return; return;

2
dist/plyr.js.map vendored

File diff suppressed because one or more lines are too long

2
dist/plyr.min.js vendored

File diff suppressed because one or more lines are too long

File diff suppressed because one or more lines are too long

View File

@ -6078,7 +6078,6 @@ var defaults = {
end: 'End', end: 'End',
all: 'All', all: 'All',
reset: 'Reset', reset: 'Reset',
none: 'None',
disabled: 'Disabled', disabled: 'Disabled',
advertisement: 'Ad' advertisement: 'Ad'
}, },
@ -7862,7 +7861,7 @@ var support = {
}(), }(),
// Touch // Touch
// Remember a device can be moust + touch enabled // NOTE: Remember a device can be mouse + touch enabled so we check on first touch event
touch: 'ontouchstart' in document.documentElement, touch: 'ontouchstart' in document.documentElement,
// Detect transitions support // Detect transitions support
@ -8767,6 +8766,7 @@ var ui = {
// Plyr controls // Plyr controls
// ========================================================================== // ==========================================================================
// Sniff out the browser
var browser$2 = utils.getBrowser(); var browser$2 = utils.getBrowser();
var controls = { var controls = {
@ -9104,6 +9104,8 @@ var controls = {
// Update hover tooltip for seeking // Update hover tooltip for seeking
updateSeekTooltip: function updateSeekTooltip(event) { updateSeekTooltip: function updateSeekTooltip(event) {
var _this = this;
// Bail if setting not true // Bail if setting not true
if (!this.config.tooltips.seek || !utils.is.element(this.elements.inputs.seek) || !utils.is.element(this.elements.display.seekTooltip) || this.duration === 0) { if (!this.config.tooltips.seek || !utils.is.element(this.elements.inputs.seek) || !utils.is.element(this.elements.display.seekTooltip) || this.duration === 0) {
return; return;
@ -9114,6 +9116,16 @@ var controls = {
var clientRect = this.elements.inputs.seek.getBoundingClientRect(); var clientRect = this.elements.inputs.seek.getBoundingClientRect();
var visible = this.config.classNames.tooltip + '--visible'; var visible = this.config.classNames.tooltip + '--visible';
var toggle = function toggle(_toggle) {
utils.toggleClass(_this.elements.display.seekTooltip, visible, _toggle);
};
// Hide on touch
if (this.touch) {
toggle(false);
return;
}
// Determine percentage, if already visible // Determine percentage, if already visible
if (utils.is.event(event)) { if (utils.is.event(event)) {
percent = 100 / clientRect.width * (event.pageX - clientRect.left); percent = 100 / clientRect.width * (event.pageX - clientRect.left);
@ -9139,7 +9151,7 @@ var controls = {
// Show/hide the tooltip // Show/hide the tooltip
// If the event is a moues in/out and percentage is inside bounds // If the event is a moues in/out and percentage is inside bounds
if (utils.is.event(event) && ['mouseenter', 'mouseleave'].includes(event.type)) { if (utils.is.event(event) && ['mouseenter', 'mouseleave'].includes(event.type)) {
utils.toggleClass(this.elements.display.seekTooltip, visible, event.type === 'mouseenter'); toggle(event.type === 'mouseenter');
} }
}, },
@ -9157,7 +9169,7 @@ var controls = {
// Set the YouTube quality menu // Set the YouTube quality menu
// TODO: Support for HTML5 // TODO: Support for HTML5
setQualityMenu: function setQualityMenu(options) { setQualityMenu: function setQualityMenu(options) {
var _this = this; var _this2 = this;
// Menu required // Menu required
if (!utils.is.element(this.elements.settings.panes.quality)) { if (!utils.is.element(this.elements.settings.panes.quality)) {
@ -9170,7 +9182,7 @@ var controls = {
// Set options if passed and filter based on config // Set options if passed and filter based on config
if (utils.is.array(options)) { if (utils.is.array(options)) {
this.options.quality = options.filter(function (quality) { this.options.quality = options.filter(function (quality) {
return _this.config.quality.options.includes(quality); return _this2.config.quality.options.includes(quality);
}); });
} else { } else {
this.options.quality = this.config.quality.options; this.options.quality = this.config.quality.options;
@ -9217,11 +9229,11 @@ var controls = {
return null; return null;
} }
return controls.createBadge.call(_this, label); return controls.createBadge.call(_this2, label);
}; };
this.options.quality.forEach(function (quality) { this.options.quality.forEach(function (quality) {
return controls.createMenuItem.call(_this, quality, list, type, controls.getLabel.call(_this, 'quality', quality), getBadge(quality)); return controls.createMenuItem.call(_this2, quality, list, type, controls.getLabel.call(_this2, 'quality', quality), getBadge(quality));
}); });
controls.updateSetting.call(this, type, list); controls.updateSetting.call(this, type, list);
@ -9276,7 +9288,7 @@ var controls = {
switch (setting) { switch (setting) {
case 'captions': case 'captions':
value = this.captions.active ? this.captions.language : ''; value = this.captions.active ? this.captions.language : i18n.get('disabled', this.config);
break; break;
default: default:
@ -9366,11 +9378,7 @@ var controls = {
return null; return null;
} }
if (!support.textTracks || !captions.getTracks.call(this).length) { if (support.textTracks && captions.getTracks.call(this).length && this.captions.active) {
return i18n.get('none', this.config);
}
if (this.captions.active) {
var currentTrack = captions.getCurrentTrack.call(this); var currentTrack = captions.getCurrentTrack.call(this);
if (utils.is.track(currentTrack)) { if (utils.is.track(currentTrack)) {
@ -9384,7 +9392,7 @@ var controls = {
// Set a list of available captions languages // Set a list of available captions languages
setCaptionsMenu: function setCaptionsMenu() { setCaptionsMenu: function setCaptionsMenu() {
var _this2 = this; var _this3 = this;
// TODO: Captions or language? Currently it's mixed // TODO: Captions or language? Currently it's mixed
var type = 'captions'; var type = 'captions';
@ -9410,15 +9418,15 @@ var controls = {
}; };
}); });
// Add the "None" option to turn off captions // Add the "Disabled" option to turn off captions
tracks.unshift({ tracks.unshift({
language: '', language: '',
label: i18n.get('none', this.config) label: i18n.get('disabled', this.config)
}); });
// Generate options // Generate options
tracks.forEach(function (track) { tracks.forEach(function (track) {
controls.createMenuItem.call(_this2, track.language, list, 'language', track.label || track.language, controls.createBadge.call(_this2, track.language.toUpperCase()), track.language.toLowerCase() === _this2.captions.language.toLowerCase()); controls.createMenuItem.call(_this3, track.language, list, 'language', track.label || track.language, controls.createBadge.call(_this3, track.language.toUpperCase()), track.language.toLowerCase() === _this3.captions.language.toLowerCase());
}); });
controls.updateSetting.call(this, type, list); controls.updateSetting.call(this, type, list);
@ -9427,7 +9435,7 @@ var controls = {
// Set a list of available captions languages // Set a list of available captions languages
setSpeedMenu: function setSpeedMenu() { setSpeedMenu: function setSpeedMenu() {
var _this3 = this; var _this4 = this;
// Menu required // Menu required
if (!utils.is.element(this.elements.settings.panes.speed)) { if (!utils.is.element(this.elements.settings.panes.speed)) {
@ -9443,7 +9451,7 @@ var controls = {
// 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 _this3.config.speed.options.includes(speed); return _this4.config.speed.options.includes(speed);
}); });
// Toggle the pane and tab // Toggle the pane and tab
@ -9467,7 +9475,7 @@ var controls = {
// Create items // Create items
this.options.speed.forEach(function (speed) { this.options.speed.forEach(function (speed) {
return controls.createMenuItem.call(_this3, speed, list, type, controls.getLabel.call(_this3, 'speed', speed)); return controls.createMenuItem.call(_this4, speed, list, type, controls.getLabel.call(_this4, 'speed', speed));
}); });
controls.updateSetting.call(this, type, list); controls.updateSetting.call(this, type, list);
@ -9630,7 +9638,7 @@ var controls = {
// 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 _this4 = this; var _this5 = this;
// Do nothing if we want no controls // Do nothing if we want no controls
if (utils.is.empty(this.config.controls)) { if (utils.is.empty(this.config.controls)) {
@ -9779,17 +9787,17 @@ var controls = {
hidden: '' hidden: ''
}); });
var button = utils.createElement('button', utils.extend(utils.getAttributesFromSelector(_this4.config.selectors.buttons.settings), { var button = utils.createElement('button', utils.extend(utils.getAttributesFromSelector(_this5.config.selectors.buttons.settings), {
type: 'button', type: 'button',
class: _this4.config.classNames.control + ' ' + _this4.config.classNames.control + '--forward', class: _this5.config.classNames.control + ' ' + _this5.config.classNames.control + '--forward',
id: 'plyr-settings-' + data.id + '-' + type + '-tab', id: 'plyr-settings-' + data.id + '-' + type + '-tab',
'aria-haspopup': true, 'aria-haspopup': true,
'aria-controls': 'plyr-settings-' + data.id + '-' + type, 'aria-controls': 'plyr-settings-' + data.id + '-' + type,
'aria-expanded': false 'aria-expanded': false
}), i18n.get(type, _this4.config)); }), i18n.get(type, _this5.config));
var value = utils.createElement('span', { var value = utils.createElement('span', {
class: _this4.config.classNames.menu.value class: _this5.config.classNames.menu.value
}); });
// Speed contains HTML entities // Speed contains HTML entities
@ -9799,7 +9807,7 @@ var controls = {
tab.appendChild(button); tab.appendChild(button);
tabs.appendChild(tab); tabs.appendChild(tab);
_this4.elements.settings.tabs[type] = tab; _this5.elements.settings.tabs[type] = tab;
}); });
home.appendChild(tabs); home.appendChild(tabs);
@ -9818,11 +9826,11 @@ var controls = {
var back = utils.createElement('button', { var back = utils.createElement('button', {
type: 'button', type: 'button',
class: _this4.config.classNames.control + ' ' + _this4.config.classNames.control + '--back', class: _this5.config.classNames.control + ' ' + _this5.config.classNames.control + '--back',
'aria-haspopup': true, 'aria-haspopup': true,
'aria-controls': 'plyr-settings-' + data.id + '-home', 'aria-controls': 'plyr-settings-' + data.id + '-home',
'aria-expanded': false 'aria-expanded': false
}, i18n.get(type, _this4.config)); }, i18n.get(type, _this5.config));
pane.appendChild(back); pane.appendChild(back);
@ -9831,7 +9839,7 @@ var controls = {
pane.appendChild(options); pane.appendChild(options);
inner.appendChild(pane); inner.appendChild(pane);
_this4.elements.settings.panes[type] = pane; _this5.elements.settings.panes[type] = pane;
}); });
form.appendChild(inner); form.appendChild(inner);
@ -9874,7 +9882,7 @@ var controls = {
// Insert controls // Insert controls
inject: function inject() { inject: function inject() {
var _this5 = this; var _this6 = this;
// Sprite // Sprite
if (this.config.loadSprite) { if (this.config.loadSprite) {
@ -9952,8 +9960,8 @@ var controls = {
var labels = utils.getElements.call(this, [this.config.selectors.controls.wrapper, ' ', this.config.selectors.labels, ' .', this.config.classNames.hidden].join('')); var labels = utils.getElements.call(this, [this.config.selectors.controls.wrapper, ' ', this.config.selectors.labels, ' .', this.config.classNames.hidden].join(''));
Array.from(labels).forEach(function (label) { Array.from(labels).forEach(function (label) {
utils.toggleClass(label, _this5.config.classNames.hidden, false); utils.toggleClass(label, _this6.config.classNames.hidden, false);
utils.toggleClass(label, _this5.config.classNames.tooltip, true); utils.toggleClass(label, _this6.config.classNames.tooltip, true);
label.setAttribute('role', 'tooltip'); label.setAttribute('role', 'tooltip');
}); });
} }
@ -9975,6 +9983,7 @@ var Listeners = function () {
this.handleKey = this.handleKey.bind(this); this.handleKey = this.handleKey.bind(this);
this.toggleMenu = this.toggleMenu.bind(this); this.toggleMenu = this.toggleMenu.bind(this);
this.firstTouch = this.firstTouch.bind(this);
} }
// Handle key presses // Handle key presses
@ -10130,6 +10139,20 @@ var Listeners = function () {
controls.toggleMenu.call(this.player, event); controls.toggleMenu.call(this.player, event);
} }
// Device is touch enabled
}, {
key: 'firstTouch',
value: function firstTouch() {
this.player.touch = true;
// Add touch class
utils.toggleClass(this.player.elements.container, this.player.config.classNames.isTouch, true);
// Clean up
utils.off(document.body, 'touchstart', this.firstTouch);
}
// Global window & document listeners // Global window & document listeners
}, { }, {
@ -10144,6 +10167,9 @@ var Listeners = function () {
// Click anywhere closes menu // Click anywhere closes menu
utils.toggleListener(document.body, 'click', this.toggleMenu, toggle); utils.toggleListener(document.body, 'click', this.toggleMenu, toggle);
// Detect touch by events
utils.on(document.body, 'touchstart', this.firstTouch);
} }
// Container listeners // Container listeners
@ -10258,7 +10284,7 @@ var Listeners = function () {
// On click play, pause ore restart // On click play, pause ore restart
utils.on(wrapper, 'click', function () { utils.on(wrapper, 'click', function () {
// Touch devices will just show controls (if we're hiding controls) // Touch devices will just show controls (if we're hiding controls)
if (_this3.player.config.hideControls && support.touch && !_this3.player.paused) { if (_this3.player.config.hideControls && _this3.player.touch && !_this3.player.paused) {
return; return;
} }
@ -10384,7 +10410,7 @@ var Listeners = function () {
on(this.player.elements.buttons.rewind, 'click', this.player.rewind, 'rewind'); on(this.player.elements.buttons.rewind, 'click', this.player.rewind, 'rewind');
// Rewind // Rewind
on(this.player.elements.buttons.fastForward, 'click', this.player.fastForward, 'fastForward'); on(this.player.elements.buttons.fastForward, 'click', this.player.forward, 'fastForward');
// Mute toggle // Mute toggle
on(this.player.elements.buttons.mute, 'click', function () { on(this.player.elements.buttons.mute, 'click', function () {
@ -10474,7 +10500,7 @@ var Listeners = function () {
if (this.player.config.hideControls) { if (this.player.config.hideControls) {
// Watch for cursor over controls so they don't hide when trying to interact // Watch for cursor over controls so they don't hide when trying to interact
on(this.player.elements.controls, 'mouseenter mouseleave', function (event) { on(this.player.elements.controls, 'mouseenter mouseleave', function (event) {
_this4.player.elements.controls.hover = event.type === 'mouseenter'; _this4.player.elements.controls.hover = !_this4.player.touch && event.type === 'mouseenter';
}); });
// Watch for cursor over controls so they don't hide when trying to interact // Watch for cursor over controls so they don't hide when trying to interact
@ -12081,7 +12107,7 @@ var media = {
utils.toggleClass(this.elements.container, this.config.classNames.isIos, browser$3.isIos); utils.toggleClass(this.elements.container, this.config.classNames.isIos, browser$3.isIos);
// Add touch class // Add touch class
utils.toggleClass(this.elements.container, this.config.classNames.isTouch, support.touch); utils.toggleClass(this.elements.container, this.config.classNames.isTouch, this.touch);
} }
// Inject the player wrapper // Inject the player wrapper
@ -12288,12 +12314,6 @@ var source = {
// License: The MIT License (MIT) // License: The MIT License (MIT)
// ========================================================================== // ==========================================================================
// Private properties
// TODO: Use a WeakMap for private globals
// const globals = new WeakMap();
// Plyr instance
var Plyr$1 = function () { var Plyr$1 = function () {
function Plyr(target, options) { function Plyr(target, options) {
var _this = this; var _this = this;
@ -12307,6 +12327,9 @@ var Plyr$1 = function () {
this.loading = false; this.loading = false;
this.failed = false; this.failed = false;
// Touch device
this.touch = support.touch;
// Set the media element // Set the media element
this.media = target; this.media = target;
@ -12787,16 +12810,22 @@ var Plyr$1 = function () {
// Is the enter fullscreen event // Is the enter fullscreen event
isEnterFullscreen = toggle.type === 'enterfullscreen'; isEnterFullscreen = toggle.type === 'enterfullscreen';
// Events that show the controls
var showEvents = ['touchstart', 'touchmove', 'mouseenter', 'mousemove', 'focusin'];
// Events that delay hiding
var delayEvents = ['touchmove', 'touchend', 'mousemove'];
// Whether to show controls // Whether to show controls
show = ['mouseenter', 'mousemove', 'touchstart', 'touchmove', 'focusin'].includes(toggle.type); show = showEvents.includes(toggle.type);
// Delay hiding on move events // Delay hiding on move events
if (['mousemove', 'touchmove', 'touchend'].includes(toggle.type)) { if (delayEvents.includes(toggle.type)) {
delay = 2000; delay = 2000;
} }
// Delay a little more for keyboard users // Delay a little more for keyboard users
if (toggle.type === 'focusin') { if (!this.touch && toggle.type === 'focusin') {
delay = 3000; delay = 3000;
utils.toggleClass(this.elements.controls, this.config.classNames.noTransition, true); utils.toggleClass(this.elements.controls, this.config.classNames.noTransition, true);
} }
@ -12824,7 +12853,7 @@ var Plyr$1 = function () {
} }
// Delay for hiding on touch // Delay for hiding on touch
if (support.touch) { if (this.touch) {
delay = 3000; delay = 3000;
} }
} }
@ -12833,6 +12862,8 @@ var Plyr$1 = function () {
// then set the timer to hide the controls // then set the timer to hide the controls
if (!show || this.playing) { if (!show || this.playing) {
this.timers.controls = setTimeout(function () { this.timers.controls = setTimeout(function () {
console.warn(_this3.elements.controls.pressed, _this3.elements.controls.hover, delay);
// If the mouse is over the controls (and not entering fullscreen), bail // If the mouse is over the controls (and not entering fullscreen), bail
if ((_this3.elements.controls.pressed || _this3.elements.controls.hover) && !isEnterFullscreen) { if ((_this3.elements.controls.pressed || _this3.elements.controls.hover) && !isEnterFullscreen) {
return; return;

File diff suppressed because one or more lines are too long

File diff suppressed because one or more lines are too long

File diff suppressed because one or more lines are too long

24
src/js/controls.js vendored
View File

@ -384,6 +384,16 @@ const controls = {
const clientRect = this.elements.inputs.seek.getBoundingClientRect(); const clientRect = this.elements.inputs.seek.getBoundingClientRect();
const visible = `${this.config.classNames.tooltip}--visible`; const visible = `${this.config.classNames.tooltip}--visible`;
const toggle = toggle => {
utils.toggleClass(this.elements.display.seekTooltip, visible, toggle);
};
// Hide on touch
if (this.touch) {
toggle(false);
return;
}
// Determine percentage, if already visible // Determine percentage, if already visible
if (utils.is.event(event)) { if (utils.is.event(event)) {
percent = 100 / clientRect.width * (event.pageX - clientRect.left); percent = 100 / clientRect.width * (event.pageX - clientRect.left);
@ -412,7 +422,7 @@ const controls = {
'mouseenter', 'mouseenter',
'mouseleave', 'mouseleave',
].includes(event.type)) { ].includes(event.type)) {
utils.toggleClass(this.elements.display.seekTooltip, visible, event.type === 'mouseenter'); toggle(event.type === 'mouseenter');
} }
}, },
@ -541,7 +551,7 @@ const controls = {
switch (setting) { switch (setting) {
case 'captions': case 'captions':
value = this.captions.active ? this.captions.language : ''; value = this.captions.active ? this.captions.language : i18n.get('disabled', this.config);
break; break;
default: default:
@ -638,11 +648,7 @@ const controls = {
return null; return null;
} }
if (!support.textTracks || !captions.getTracks.call(this).length) { if (support.textTracks && captions.getTracks.call(this).length && this.captions.active) {
return i18n.get('none', this.config);
}
if (this.captions.active) {
const currentTrack = captions.getCurrentTrack.call(this); const currentTrack = captions.getCurrentTrack.call(this);
if (utils.is.track(currentTrack)) { if (utils.is.track(currentTrack)) {
@ -677,10 +683,10 @@ const controls = {
label: !utils.is.empty(track.label) ? track.label : track.language.toUpperCase(), label: !utils.is.empty(track.label) ? track.label : track.language.toUpperCase(),
})); }));
// Add the "None" option to turn off captions // Add the "Disabled" option to turn off captions
tracks.unshift({ tracks.unshift({
language: '', language: '',
label: i18n.get('none', this.config), label: i18n.get('disabled', this.config),
}); });
// Generate options // Generate options

View File

@ -181,7 +181,6 @@ const defaults = {
end: 'End', end: 'End',
all: 'All', all: 'All',
reset: 'Reset', reset: 'Reset',
none: 'None',
disabled: 'Disabled', disabled: 'Disabled',
advertisement: 'Ad', advertisement: 'Ad',
}, },

View File

@ -17,6 +17,7 @@ class Listeners {
this.handleKey = this.handleKey.bind(this); this.handleKey = this.handleKey.bind(this);
this.toggleMenu = this.toggleMenu.bind(this); this.toggleMenu = this.toggleMenu.bind(this);
this.firstTouch = this.firstTouch.bind(this);
} }
// Handle key presses // Handle key presses
@ -187,6 +188,17 @@ class Listeners {
controls.toggleMenu.call(this.player, event); controls.toggleMenu.call(this.player, event);
} }
// Device is touch enabled
firstTouch() {
this.player.touch = true;
// Add touch class
utils.toggleClass(this.player.elements.container, this.player.config.classNames.isTouch, true);
// Clean up
utils.off(document.body, 'touchstart', this.firstTouch);
}
// Global window & document listeners // Global window & document listeners
global(toggle = true) { global(toggle = true) {
// Keyboard shortcuts // Keyboard shortcuts
@ -196,6 +208,9 @@ class Listeners {
// Click anywhere closes menu // Click anywhere closes menu
utils.toggleListener(document.body, 'click', this.toggleMenu, toggle); utils.toggleListener(document.body, 'click', this.toggleMenu, toggle);
// Detect touch by events
utils.on(document.body, 'touchstart', this.firstTouch);
} }
// Container listeners // Container listeners
@ -288,7 +303,7 @@ class Listeners {
// On click play, pause ore restart // On click play, pause ore restart
utils.on(wrapper, 'click', () => { utils.on(wrapper, 'click', () => {
// Touch devices will just show controls (if we're hiding controls) // Touch devices will just show controls (if we're hiding controls)
if (this.player.config.hideControls && support.touch && !this.player.paused) { if (this.player.config.hideControls && this.player.touch && !this.player.paused) {
return; return;
} }
@ -538,7 +553,7 @@ class Listeners {
if (this.player.config.hideControls) { if (this.player.config.hideControls) {
// Watch for cursor over controls so they don't hide when trying to interact // Watch for cursor over controls so they don't hide when trying to interact
on(this.player.elements.controls, 'mouseenter mouseleave', event => { on(this.player.elements.controls, 'mouseenter mouseleave', event => {
this.player.elements.controls.hover = event.type === 'mouseenter'; this.player.elements.controls.hover = !this.player.touch && event.type === 'mouseenter';
}); });
// Watch for cursor over controls so they don't hide when trying to interact // Watch for cursor over controls so they don't hide when trying to interact

View File

@ -46,7 +46,7 @@ const media = {
utils.toggleClass(this.elements.container, this.config.classNames.isIos, browser.isIos); utils.toggleClass(this.elements.container, this.config.classNames.isIos, browser.isIos);
// Add touch class // Add touch class
utils.toggleClass(this.elements.container, this.config.classNames.isTouch, support.touch); utils.toggleClass(this.elements.container, this.config.classNames.isTouch, this.touch);
} }
// Inject the player wrapper // Inject the player wrapper

View File

@ -36,6 +36,9 @@ class Plyr {
this.loading = false; this.loading = false;
this.failed = false; this.failed = false;
// Touch device
this.touch = support.touch;
// Set the media element // Set the media element
this.media = target; this.media = target;
@ -954,26 +957,32 @@ class Plyr {
// Is the enter fullscreen event // Is the enter fullscreen event
isEnterFullscreen = toggle.type === 'enterfullscreen'; isEnterFullscreen = toggle.type === 'enterfullscreen';
// Whether to show controls // Events that show the controls
show = [ const showEvents = [
'mouseenter',
'mousemove',
'touchstart', 'touchstart',
'touchmove', 'touchmove',
'focusin', 'mouseenter',
].includes(toggle.type);
// Delay hiding on move events
if ([
'mousemove', 'mousemove',
'focusin',
];
// Events that delay hiding
const delayEvents = [
'touchmove', 'touchmove',
'touchend', 'touchend',
].includes(toggle.type)) { 'mousemove',
];
// Whether to show controls
show = showEvents.includes(toggle.type);
// Delay hiding on move events
if (delayEvents.includes(toggle.type)) {
delay = 2000; delay = 2000;
} }
// Delay a little more for keyboard users // Delay a little more for keyboard users
if (toggle.type === 'focusin') { if (!this.touch && toggle.type === 'focusin') {
delay = 3000; delay = 3000;
utils.toggleClass(this.elements.controls, this.config.classNames.noTransition, true); utils.toggleClass(this.elements.controls, this.config.classNames.noTransition, true);
} }
@ -1001,7 +1010,7 @@ class Plyr {
} }
// Delay for hiding on touch // Delay for hiding on touch
if (support.touch) { if (this.touch) {
delay = 3000; delay = 3000;
} }
} }
@ -1010,6 +1019,8 @@ class Plyr {
// then set the timer to hide the controls // then set the timer to hide the controls
if (!show || this.playing) { if (!show || this.playing) {
this.timers.controls = setTimeout(() => { this.timers.controls = setTimeout(() => {
console.warn(this.elements.controls.pressed, this.elements.controls.hover, delay);
// If the mouse is over the controls (and not entering fullscreen), bail // If the mouse is over the controls (and not entering fullscreen), bail
if ((this.elements.controls.pressed || this.elements.controls.hover) && !isEnterFullscreen) { if ((this.elements.controls.pressed || this.elements.controls.hover) && !isEnterFullscreen) {
return; return;

View File

@ -143,7 +143,7 @@ const support = {
})(), })(),
// Touch // Touch
// Remember a device can be moust + touch enabled // NOTE: Remember a device can be mouse + touch enabled so we check on first touch event
touch: 'ontouchstart' in document.documentElement, touch: 'ontouchstart' in document.documentElement,
// Detect transitions support // Detect transitions support

View File

@ -84,7 +84,6 @@
position: absolute; position: absolute;
top: 50%; top: 50%;
transform: translateY(-50%); transform: translateY(-50%);
transition: border-color 0.2s ease;
} }
&--forward { &--forward {
@ -108,7 +107,6 @@
margin-bottom: floor($plyr-control-padding / 2); margin-bottom: floor($plyr-control-padding / 2);
padding-left: ceil($plyr-control-padding * 4); padding-left: ceil($plyr-control-padding * 4);
position: relative; position: relative;
width: calc(100% - #{$horizontal-padding}); width: calc(100% - #{$horizontal-padding});
&::after { &::after {