More work on menus

This commit is contained in:
Sam Potts
2018-06-18 23:13:40 +10:00
parent d64ed4ba5a
commit 7b9ef7d757
11 changed files with 174 additions and 177 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

133
dist/plyr.js vendored
View File

@ -1624,7 +1624,7 @@ typeof navigator === "object" && (function (global, factory) {
var attributes = getAttributesFromSelector(this.config.selectors.display[type]); var attributes = getAttributesFromSelector(this.config.selectors.display[type]);
var container = createElement('div', extend(attributes, { var container = createElement('div', extend(attributes, {
class: 'plyr__time ' + attributes.class, class: (this.config.classNames.display.time + ' ' + (attributes.class ? attributes.class : '')).trim(),
'aria-label': i18n.get(type, this.config) 'aria-label': i18n.get(type, this.config)
}), '00:00'); }), '00:00');
@ -1646,16 +1646,42 @@ typeof navigator === "object" && (function (global, factory) {
_ref$checked = _ref.checked, _ref$checked = _ref.checked,
checked = _ref$checked === undefined ? false : _ref$checked; checked = _ref$checked === undefined ? false : _ref$checked;
var item = createElement('button', extend(getAttributesFromSelector(this.config.selectors.inputs[type]), { var attributes = getAttributesFromSelector(this.config.selectors.inputs[type]);
var item = createElement('button', extend(attributes, {
type: 'button', type: 'button',
role: 'menuitemradio',
class: (this.config.classNames.control + ' ' + (attributes.class ? attributes.class : '')).trim(),
value: value, value: value,
'aria-checked': checked 'aria-checked': checked
}), title); }));
// We have to set as HTML incase of special characters
item.innerHTML = title;
if (is.element(badge)) { if (is.element(badge)) {
item.appendChild(badge); item.appendChild(badge);
} }
Object.defineProperty(item, 'checked', {
enumerable: true,
get: function get$$1() {
return item.getAttribute('aria-checked') === 'true';
},
set: function set$$1(checked) {
// Ensure exclusivity
if (checked) {
Array.from(item.parentNode.children).filter(function (node) {
return matches(node, '[role="menuitemradio"]');
}).forEach(function (node) {
return node.setAttribute('aria-checked', 'false');
});
}
item.setAttribute('aria-checked', checked ? 'true' : 'false');
}
});
list.appendChild(item); list.appendChild(item);
}, },
@ -1930,12 +1956,12 @@ typeof navigator === "object" && (function (global, factory) {
var _this3 = this; var _this3 = this;
// Menu required // Menu required
if (!is.element(this.elements.settings.menus.quality)) { if (!is.element(this.elements.settings.panels.quality)) {
return; return;
} }
var type = 'quality'; var type = 'quality';
var list = this.elements.settings.menus.quality.querySelector('[role="menu"]'); var list = this.elements.settings.panels.quality.querySelector('[role="menu"]');
// Set options if passed and filter based on uniqueness and config // Set options if passed and filter based on uniqueness and config
if (is.array(options)) { if (is.array(options)) {
@ -2018,7 +2044,7 @@ typeof navigator === "object" && (function (global, factory) {
// 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.menus[setting]; var pane = this.elements.settings.panels[setting];
var value = null; var value = null;
var list = container; var list = container;
@ -2060,10 +2086,10 @@ typeof navigator === "object" && (function (global, factory) {
label.innerHTML = controls.getLabel.call(this, setting, value); label.innerHTML = controls.getLabel.call(this, setting, value);
// Find the radio option and check it // Find the radio option and check it
var target = list && list.querySelector('button[value="' + value + '"]'); var target = list && list.querySelector('[value="' + value + '"]');
if (is.element(target)) { if (is.element(target)) {
target.setAttribute('aria-checked', true); target.checked = true;
} }
}, },
@ -2071,14 +2097,14 @@ typeof navigator === "object" && (function (global, factory) {
// Set the looping options // Set the looping options
/* setLoopMenu() { /* setLoopMenu() {
// Menu required // Menu required
if (!is.element(this.elements.settings.menus.loop)) { if (!is.element(this.elements.settings.panels.loop)) {
return; return;
} }
const options = ['start', 'end', 'all', 'reset']; const options = ['start', 'end', 'all', 'reset'];
const list = this.elements.settings.menus.loop.querySelector('[role="menu"]'); const list = this.elements.settings.panels.loop.querySelector('[role="menu"]');
// Show the pane and tab // Show the pane and tab
toggleHidden(this.elements.settings.buttons.loop, false); toggleHidden(this.elements.settings.buttons.loop, false);
toggleHidden(this.elements.settings.menus.loop, false); toggleHidden(this.elements.settings.panels.loop, false);
// Toggle the pane and tab // Toggle the pane and tab
const toggle = !is.empty(this.loop.options); const toggle = !is.empty(this.loop.options);
controls.toggleMenuButton.call(this, 'loop', toggle); controls.toggleMenuButton.call(this, 'loop', toggle);
@ -2113,7 +2139,7 @@ typeof navigator === "object" && (function (global, factory) {
// 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.menus.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);
// Toggle the pane and tab // Toggle the pane and tab
@ -2168,7 +2194,7 @@ typeof navigator === "object" && (function (global, factory) {
} }
// Menu required // Menu required
if (!is.element(this.elements.settings.menus.speed)) { if (!is.element(this.elements.settings.panels.speed)) {
return; return;
} }
@ -2199,7 +2225,7 @@ typeof navigator === "object" && (function (global, factory) {
} }
// Get the list to populate // Get the list to populate
var list = this.elements.settings.menus.speed.querySelector('[role="menu"]'); var list = this.elements.settings.panels.speed.querySelector('[role="menu"]');
// Empty the menu // Empty the menu
emptyElement(list); emptyElement(list);
@ -2278,19 +2304,13 @@ typeof navigator === "object" && (function (global, factory) {
}, },
// Get the natural size of a tab // Get the natural size of a menu panel
getTabSize: function getTabSize(tab) { getMenuSize: function getMenuSize(tab) {
var clone = tab.cloneNode(true); var clone = tab.cloneNode(true);
clone.style.position = 'absolute'; clone.style.position = 'absolute';
clone.style.opacity = 0; clone.style.opacity = 0;
clone.removeAttribute('hidden'); clone.removeAttribute('hidden');
// Prevent input's being unchecked due to the name being identical
/* Array.from(clone.querySelectorAll('input[name]')).forEach(input => {
const name = input.getAttribute('name');
input.setAttribute('name', `${name}-clone`);
}); */
// Append to parent so we get the "real" size // Append to parent so we get the "real" size
tab.parentNode.appendChild(clone); tab.parentNode.appendChild(clone);
@ -2308,38 +2328,24 @@ typeof navigator === "object" && (function (global, factory) {
}, },
// Toggle Menu // Show a panel in the menu
showMenu: function showMenu() { showMenuPanel: function showMenuPanel() {
var _this6 = this; var _this6 = this;
var type = arguments.length > 0 && arguments[0] !== undefined ? arguments[0] : ''; var type = arguments.length > 0 && arguments[0] !== undefined ? arguments[0] : '';
var menu = this.elements.settings.menu;
var pane = document.getElementById('plyr-settings-' + this.id + '-' + type); var target = document.getElementById('plyr-settings-' + this.id + '-' + type);
console.warn('plyr-settings-' + this.id + '-' + type);
// Nothing to show, bail // Nothing to show, bail
if (!is.element(pane)) { if (!is.element(target)) {
console.warn('No pane found');
return; return;
} }
// Are we targeting a tab? If not, bail // Hide all other panels
/* const isTab = pane.getAttribute('role') === 'tabpanel'; var container = target.parentNode;
if (!isTab) { var current = Array.from(container.children).find(function (node) {
return; return !node.hidden;
} */ });
// Hide all other tabs
// Get other tabs
var current = menu.querySelector('[id^=plyr-settings-' + this.id + ']:not([hidden])');
var container = current.parentNode;
// Set other toggles to be expanded false
/* Array.from(menu.querySelectorAll(`[aria-controls="${current.getAttribute('id')}"]`)).forEach(toggle => {
toggle.setAttribute('aria-expanded', false);
}); */
// If we can do fancy animations, we'll animate the height/width // If we can do fancy animations, we'll animate the height/width
if (support.transitions && !support.reducedMotion) { if (support.transitions && !support.reducedMotion) {
@ -2348,12 +2354,12 @@ typeof navigator === "object" && (function (global, factory) {
container.style.height = current.scrollHeight + 'px'; container.style.height = current.scrollHeight + 'px';
// Get potential sizes // Get potential sizes
var size = controls.getTabSize.call(this, pane); var size = controls.getMenuSize.call(this, target);
// Restore auto height/width // Restore auto height/width
var restore = function restore(e) { var restore = function restore(event) {
// We're only bothered about height and width on the container // We're only bothered about height and width on the container
if (e.target !== container || !['width', 'height'].includes(e.propertyName)) { if (event.target !== container || !['width', 'height'].includes(event.propertyName)) {
return; return;
} }
@ -2378,16 +2384,10 @@ typeof navigator === "object" && (function (global, factory) {
// current.setAttribute('tabindex', -1); // current.setAttribute('tabindex', -1);
// Set attributes on target // Set attributes on target
toggleHidden(pane, false); toggleHidden(target, false);
/* const tabs = getElements.call(this, `[aria-controls="${target}"]`);
Array.from(tabs).forEach(tab => {
tab.setAttribute('aria-expanded', true);
});
pane.removeAttribute('tabindex'); */
// Focus the first item // Focus the first item
pane.querySelectorAll('button:not(:disabled), input:not(:disabled), [tabindex]')[0].focus(); target.querySelectorAll('[role^="menuitem"]')[0].focus();
}, },
@ -2532,7 +2532,7 @@ typeof navigator === "object" && (function (global, factory) {
var menuItem = createElement('button', extend(getAttributesFromSelector(_this7.config.selectors.buttons.settings), { var menuItem = createElement('button', extend(getAttributesFromSelector(_this7.config.selectors.buttons.settings), {
type: 'button', type: 'button',
class: _this7.config.classNames.control + ' ' + _this7.config.classNames.control + '--forward', class: _this7.config.classNames.control + ' ' + _this7.config.classNames.control + '--forward',
'role': 'menuitem', role: 'menuitem',
'aria-haspopup': true 'aria-haspopup': true
})); }));
@ -2556,10 +2556,14 @@ typeof navigator === "object" && (function (global, factory) {
}); });
// Back button // Back button
pane.appendChild(createElement('button', { var back = createElement('button', {
type: 'button', type: 'button',
class: _this7.config.classNames.control + ' ' + _this7.config.classNames.control + '--back' class: _this7.config.classNames.control + ' ' + _this7.config.classNames.control + '--back'
}, i18n.get(type, _this7.config))); }, i18n.get(type, _this7.config));
back.addEventListener('click', function () {
controls.showMenuPanel.call(_this7, 'home');
});
pane.appendChild(back);
// Menu // Menu
pane.appendChild(createElement('div', { pane.appendChild(createElement('div', {
@ -2569,11 +2573,11 @@ typeof navigator === "object" && (function (global, factory) {
inner.appendChild(pane); inner.appendChild(pane);
menuItem.addEventListener('click', function () { menuItem.addEventListener('click', function () {
controls.showMenu.call(_this7, type); controls.showMenuPanel.call(_this7, type);
}); });
_this7.elements.settings.buttons[type] = menuItem; _this7.elements.settings.buttons[type] = menuItem;
_this7.elements.settings.menus[type] = pane; _this7.elements.settings.panels[type] = pane;
}); });
home.appendChild(menu); home.appendChild(menu);
@ -3482,6 +3486,9 @@ typeof navigator === "object" && (function (global, factory) {
isTouch: 'plyr--is-touch', isTouch: 'plyr--is-touch',
uiSupported: 'plyr--full-ui', uiSupported: 'plyr--full-ui',
noTransition: 'plyr--no-transition', noTransition: 'plyr--no-transition',
display: {
time: 'plyr__time'
},
menu: { menu: {
value: 'plyr__menu__value', value: 'plyr__menu__value',
badge: 'plyr__badge', badge: 'plyr__badge',
@ -4608,7 +4615,7 @@ typeof navigator === "object" && (function (global, factory) {
// Go back to home tab on click // Go back to home tab on click
var showHomeTab = function showHomeTab() { var showHomeTab = function showHomeTab() {
controls.showMenu.call(_this4.player, 'home'); controls.showMenuPanel.call(_this4.player, 'home');
}; };
// Settings menu items - use event delegation as items are added/removed // Settings menu items - use event delegation as items are added/removed
@ -6942,7 +6949,7 @@ typeof navigator === "object" && (function (global, factory) {
settings: { settings: {
popup: null, popup: null,
menu: null, menu: null,
menus: {}, panels: {},
buttons: {} buttons: {}
} }
}; };

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

@ -354,6 +354,9 @@ const defaults = {
isTouch: 'plyr--is-touch', isTouch: 'plyr--is-touch',
uiSupported: 'plyr--full-ui', uiSupported: 'plyr--full-ui',
noTransition: 'plyr--no-transition', noTransition: 'plyr--no-transition',
display: {
time: 'plyr__time',
},
menu: { menu: {
value: 'plyr__menu__value', value: 'plyr__menu__value',
badge: 'plyr__badge', badge: 'plyr__badge',

146
src/js/controls.js vendored
View File

@ -9,19 +9,7 @@ import support from './support';
import { repaint, transitionEndEvent } from './utils/animation'; import { repaint, transitionEndEvent } from './utils/animation';
import { dedupe } from './utils/arrays'; import { dedupe } from './utils/arrays';
import browser from './utils/browser'; import browser from './utils/browser';
import { import { createElement, emptyElement, getAttributesFromSelector, getElement, getElements, hasClass, matches, removeElement, setAttributes, toggleClass, toggleHidden } from './utils/elements';
createElement,
emptyElement,
getAttributesFromSelector,
getElement,
getElements,
hasClass,
removeElement,
setAttributes,
toggleClass,
toggleHidden,
matches,
} from './utils/elements';
import { off, on } from './utils/events'; import { off, on } from './utils/events';
import is from './utils/is'; import is from './utils/is';
import loadSprite from './utils/loadSprite'; import loadSprite from './utils/loadSprite';
@ -360,7 +348,7 @@ const controls = {
const container = createElement( const container = createElement(
'div', 'div',
extend(attributes, { extend(attributes, {
class: `plyr__time ${attributes.class}`, class: `${this.config.classNames.display.time} ${attributes.class ? attributes.class : ''}`.trim(),
'aria-label': i18n.get(type, this.config), 'aria-label': i18n.get(type, this.config),
}), }),
'00:00', '00:00',
@ -374,20 +362,43 @@ const controls = {
// Create a settings menu item // Create a settings menu item
createMenuItem({ value, list, type, title, badge = null, checked = false }) { createMenuItem({ value, list, type, title, badge = null, checked = false }) {
const attributes = getAttributesFromSelector(this.config.selectors.inputs[type]);
const item = createElement( const item = createElement(
'button', 'button',
extend(getAttributesFromSelector(this.config.selectors.inputs[type]), { extend(attributes, {
type: 'button', type: 'button',
role: 'menuitemradio',
class: `${this.config.classNames.control} ${attributes.class ? attributes.class : ''}`.trim(),
value, value,
'aria-checked': checked, 'aria-checked': checked,
}), })
title,
); );
// We have to set as HTML incase of special characters
item.innerHTML = title;
if (is.element(badge)) { if (is.element(badge)) {
item.appendChild(badge); item.appendChild(badge);
} }
Object.defineProperty(item, 'checked', {
enumerable: true,
get() {
return item.getAttribute('aria-checked') === 'true';
},
set(checked) {
// Ensure exclusivity
if (checked) {
Array.from(item.parentNode.children)
.filter(node => matches(node, '[role="menuitemradio"]'))
.forEach(node => node.setAttribute('aria-checked', 'false'));
}
item.setAttribute('aria-checked', checked ? 'true' : 'false');
},
});
list.appendChild(item); list.appendChild(item);
}, },
@ -649,12 +660,12 @@ const controls = {
// Set the quality menu // Set the quality menu
setQualityMenu(options) { setQualityMenu(options) {
// Menu required // Menu required
if (!is.element(this.elements.settings.menus.quality)) { if (!is.element(this.elements.settings.panels.quality)) {
return; return;
} }
const type = 'quality'; const type = 'quality';
const list = this.elements.settings.menus.quality.querySelector('[role="menu"]'); const list = this.elements.settings.panels.quality.querySelector('[role="menu"]');
// Set options if passed and filter based on uniqueness and config // Set options if passed and filter based on uniqueness and config
if (is.array(options)) { if (is.array(options)) {
@ -735,7 +746,7 @@ const controls = {
// Update the selected setting // Update the selected setting
updateSetting(setting, container, input) { updateSetting(setting, container, input) {
const pane = this.elements.settings.menus[setting]; const pane = this.elements.settings.panels[setting];
let value = null; let value = null;
let list = container; let list = container;
@ -777,26 +788,26 @@ const controls = {
label.innerHTML = controls.getLabel.call(this, setting, value); label.innerHTML = controls.getLabel.call(this, setting, value);
// Find the radio option and check it // Find the radio option and check it
const target = list && list.querySelector(`button[value="${value}"]`); const target = list && list.querySelector(`[value="${value}"]`);
if (is.element(target)) { if (is.element(target)) {
target.setAttribute('aria-checked', true); target.checked = true;
} }
}, },
// Set the looping options // Set the looping options
/* setLoopMenu() { /* setLoopMenu() {
// Menu required // Menu required
if (!is.element(this.elements.settings.menus.loop)) { if (!is.element(this.elements.settings.panels.loop)) {
return; return;
} }
const options = ['start', 'end', 'all', 'reset']; const options = ['start', 'end', 'all', 'reset'];
const list = this.elements.settings.menus.loop.querySelector('[role="menu"]'); const list = this.elements.settings.panels.loop.querySelector('[role="menu"]');
// Show the pane and tab // Show the pane and tab
toggleHidden(this.elements.settings.buttons.loop, false); toggleHidden(this.elements.settings.buttons.loop, false);
toggleHidden(this.elements.settings.menus.loop, false); toggleHidden(this.elements.settings.panels.loop, false);
// Toggle the pane and tab // Toggle the pane and tab
const toggle = !is.empty(this.loop.options); const toggle = !is.empty(this.loop.options);
@ -835,7 +846,7 @@ const controls = {
setCaptionsMenu() { setCaptionsMenu() {
// 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.menus.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);
// Toggle the pane and tab // Toggle the pane and tab
@ -885,7 +896,7 @@ const controls = {
} }
// Menu required // Menu required
if (!is.element(this.elements.settings.menus.speed)) { if (!is.element(this.elements.settings.panels.speed)) {
return; return;
} }
@ -914,7 +925,7 @@ const controls = {
} }
// Get the list to populate // Get the list to populate
const list = this.elements.settings.menus.speed.querySelector('[role="menu"]'); const list = this.elements.settings.panels.speed.querySelector('[role="menu"]');
// Empty the menu // Empty the menu
emptyElement(list); emptyElement(list);
@ -986,19 +997,13 @@ const controls = {
} }
}, },
// Get the natural size of a tab // Get the natural size of a menu panel
getTabSize(tab) { getMenuSize(tab) {
const clone = tab.cloneNode(true); const clone = tab.cloneNode(true);
clone.style.position = 'absolute'; clone.style.position = 'absolute';
clone.style.opacity = 0; clone.style.opacity = 0;
clone.removeAttribute('hidden'); clone.removeAttribute('hidden');
// Prevent input's being unchecked due to the name being identical
/* Array.from(clone.querySelectorAll('input[name]')).forEach(input => {
const name = input.getAttribute('name');
input.setAttribute('name', `${name}-clone`);
}); */
// Append to parent so we get the "real" size // Append to parent so we get the "real" size
tab.parentNode.appendChild(clone); tab.parentNode.appendChild(clone);
@ -1015,34 +1020,18 @@ const controls = {
}; };
}, },
// Toggle Menu // Show a panel in the menu
showMenu(type = '') { showMenuPanel(type = '') {
const { menu } = this.elements.settings; const target = document.getElementById(`plyr-settings-${this.id}-${type}`);
const pane = document.getElementById(`plyr-settings-${this.id}-${type}`);
console.warn(`plyr-settings-${this.id}-${type}`);
// Nothing to show, bail // Nothing to show, bail
if (!is.element(pane)) { if (!is.element(target)) {
console.warn('No pane found');
return; return;
} }
// Are we targeting a tab? If not, bail // Hide all other panels
/* const isTab = pane.getAttribute('role') === 'tabpanel'; const container = target.parentNode;
if (!isTab) { const current = Array.from(container.children).find(node => !node.hidden);
return;
} */
// Hide all other tabs
// Get other tabs
const current = menu.querySelector(`[id^=plyr-settings-${this.id}]:not([hidden])`);
const container = current.parentNode;
// Set other toggles to be expanded false
/* Array.from(menu.querySelectorAll(`[aria-controls="${current.getAttribute('id')}"]`)).forEach(toggle => {
toggle.setAttribute('aria-expanded', false);
}); */
// If we can do fancy animations, we'll animate the height/width // If we can do fancy animations, we'll animate the height/width
if (support.transitions && !support.reducedMotion) { if (support.transitions && !support.reducedMotion) {
@ -1051,12 +1040,12 @@ const controls = {
container.style.height = `${current.scrollHeight}px`; container.style.height = `${current.scrollHeight}px`;
// Get potential sizes // Get potential sizes
const size = controls.getTabSize.call(this, pane); const size = controls.getMenuSize.call(this, target);
// Restore auto height/width // Restore auto height/width
const restore = e => { const restore = event => {
// We're only bothered about height and width on the container // We're only bothered about height and width on the container
if (e.target !== container || !['width', 'height'].includes(e.propertyName)) { if (event.target !== container || !['width', 'height'].includes(event.propertyName)) {
return; return;
} }
@ -1081,16 +1070,10 @@ const controls = {
// current.setAttribute('tabindex', -1); // current.setAttribute('tabindex', -1);
// Set attributes on target // Set attributes on target
toggleHidden(pane, false); toggleHidden(target, false);
/* const tabs = getElements.call(this, `[aria-controls="${target}"]`);
Array.from(tabs).forEach(tab => {
tab.setAttribute('aria-expanded', true);
});
pane.removeAttribute('tabindex'); */
// Focus the first item // Focus the first item
pane.querySelectorAll('button:not(:disabled), input:not(:disabled), [tabindex]')[0].focus(); target.querySelectorAll('[role^="menuitem"]')[0].focus();
}, },
// Build the default HTML // Build the default HTML
@ -1248,12 +1231,12 @@ const controls = {
extend(getAttributesFromSelector(this.config.selectors.buttons.settings), { extend(getAttributesFromSelector(this.config.selectors.buttons.settings), {
type: 'button', type: 'button',
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,
}), }),
); );
const flex = createElement('span', null, i18n.get(type, this.config)) const flex = createElement('span', null, i18n.get(type, this.config));
const value = createElement('span', { const value = createElement('span', {
class: this.config.classNames.menu.value, class: this.config.classNames.menu.value,
@ -1266,7 +1249,6 @@ const controls = {
menuItem.appendChild(flex); menuItem.appendChild(flex);
menu.appendChild(menuItem); menu.appendChild(menuItem);
// Build the panes // Build the panes
const pane = createElement('div', { const pane = createElement('div', {
id: `plyr-settings-${data.id}-${type}`, id: `plyr-settings-${data.id}-${type}`,
@ -1274,28 +1256,34 @@ const controls = {
}); });
// Back button // Back button
pane.appendChild(createElement( const back = createElement(
'button', 'button',
{ {
type: 'button', type: 'button',
class: `${this.config.classNames.control} ${this.config.classNames.control}--back`, class: `${this.config.classNames.control} ${this.config.classNames.control}--back`,
}, },
i18n.get(type, this.config), i18n.get(type, this.config),
)); );
back.addEventListener('click', () => {
controls.showMenuPanel.call(this, 'home');
});
pane.appendChild(back);
// Menu // Menu
pane.appendChild(createElement('div', { pane.appendChild(
createElement('div', {
role: 'menu', role: 'menu',
})); }),
);
inner.appendChild(pane); inner.appendChild(pane);
menuItem.addEventListener('click', () => { menuItem.addEventListener('click', () => {
controls.showMenu.call(this, type); controls.showMenuPanel.call(this, type);
}); });
this.elements.settings.buttons[type] = menuItem; this.elements.settings.buttons[type] = menuItem;
this.elements.settings.menus[type] = pane; this.elements.settings.panels[type] = pane;
}); });
home.appendChild(menu); home.appendChild(menu);

View File

@ -491,7 +491,7 @@ class Listeners {
// Go back to home tab on click // Go back to home tab on click
const showHomeTab = () => { const showHomeTab = () => {
controls.showMenu.call(this.player, 'home'); controls.showMenuPanel.call(this.player, 'home');
}; };
// Settings menu items - use event delegation as items are added/removed // Settings menu items - use event delegation as items are added/removed

View File

@ -83,7 +83,7 @@ class Plyr {
settings: { settings: {
popup: null, popup: null,
menu: null, menu: null,
menus: {}, panels: {},
buttons: {}, buttons: {},
}, },
}; };

View File

@ -139,50 +139,49 @@
} }
} }
label.plyr__control { .plyr__control[role='menuitemradio'] {
padding-left: $plyr-control-padding; padding-left: $plyr-control-padding;
input[type='radio'] + span { &::before,
background: rgba(#000, 0.1); &::after {
border-radius: 100%; border-radius: 100%;
}
&::before {
background: rgba(#000, 0.1);
content: '';
display: block; display: block;
flex-shrink: 0; flex-shrink: 0;
height: 16px; height: 16px;
margin-right: $plyr-control-spacing; margin-right: $plyr-control-spacing;
position: relative;
transition: all 0.3s ease; transition: all 0.3s ease;
width: 16px; width: 16px;
}
&::after { &::after {
background: #fff; background: #fff;
border-radius: 100%; border: 0;
content: '';
height: 6px; height: 6px;
left: 5px; left: 12px;
opacity: 0; opacity: 0;
position: absolute; top: 50%;
top: 5px; transform: translateY(-50%) scale(0);
transform: scale(0);
transition: transform 0.3s ease, opacity 0.3s ease; transition: transform 0.3s ease, opacity 0.3s ease;
width: 6px; width: 6px;
} }
}
input[type='radio']:checked + span { &[aria-checked='true'] {
&::before {
background: $plyr-color-main; background: $plyr-color-main;
}
&::after { &::after {
opacity: 1; opacity: 1;
transform: scale(1); transform: translateY(-50%) scale(1);
} }
} }
input[type='radio']:focus + span { &.plyr__tab-focus::before,
@include plyr-tab-focus(); &:hover::before {
}
&.plyr__tab-focus input[type='radio'] + span,
&:hover input[type='radio'] + span {
background: rgba(#000, 0.1); background: rgba(#000, 0.1);
} }
} }