More work on the menu

This commit is contained in:
Sam Potts 2017-05-22 08:55:45 +10:00
parent 857dfe838c
commit 86c9004183
7 changed files with 134 additions and 94 deletions

2
demo/dist/demo.js vendored

File diff suppressed because one or more lines are too long

View File

@ -1,12 +1,11 @@
// ========================================================================== // ==========================================================================
// Plyr.io demo // Plyr.io demo
// This code is purely for the plyr.io website // This code is purely for the https://plyr.io website
// Please see readme.md in the root or github.com/sampotts/plyr // Please see readme.md in the root or github.com/sampotts/plyr
// ========================================================================== // ==========================================================================
/*global Plyr*/ /*global Plyr*/
// General functions
(function() { (function() {
/*document.body.addEventListener('ready', function(event) { /*document.body.addEventListener('ready', function(event) {
console.log(event); console.log(event);
@ -186,15 +185,16 @@
})(); })();
// Google analytics // Google analytics
// For demo site (http://[www.]plyr.io) only // For demo site (https://plyr.io) only
if (document.domain.indexOf('plyr.io') > -1) { if (window.location.host === 'plyr.io') {
(function(i, s, o, g, r, a, m) { (function(i, s, o, g, r, a, m) {
i.GoogleAnalyticsObject = r; i.GoogleAnalyticsObject = r;
i[r] = i[r] || function() { i[r] = i[r] || function() {
(i[r].q = i[r].q || []).push(arguments) (i[r].q = i[r].q || []).push(arguments)
}, i[r].l = 1 * new Date(); };
a = s.createElement(o), i[r].l = 1 * new Date();
m = s.getElementsByTagName(o)[0]; a = s.createElement(o);
m = s.getElementsByTagName(o)[0];
a.async = 1; a.async = 1;
a.src = g; a.src = g;
m.parentNode.insertBefore(a, m) m.parentNode.insertBefore(a, m)

2
dist/plyr.css vendored

File diff suppressed because one or more lines are too long

4
dist/plyr.js vendored

File diff suppressed because one or more lines are too long

View File

@ -1,20 +1,27 @@
### Todo ### Todo
#### To build #### To finish
[x] Get list of subtitles/captions available (HTML5, Vimeo) [x] Get list of subtitles/captions available (HTML5, Vimeo)
[x] Add preferred quality option into config [x] Add preferred quality option into config
[ ] Update quality options on YouTube play [ ] Update quality options on YouTube play
[ ] Update speed options on YouTube load [ ] Update speed options on YouTube load
[ ] Hide unsupported menu items [ ] Handle quality change for YouTube
[ ] Handle speed change for YouTube
[ ] Set quality when loading YouTube vid
[ ] Set "home" values
[ ] Hide unsupported menu items (+ on source change)
[ ] Test PiP (need MacOS Sierra) [ ] Test PiP (need MacOS Sierra)
[ ] Test AirPlay (need MacOS Sierra) [ ] Test AirPlay (need MacOS Sierra)
[ ] Add controlshidden controlsshown events [ ] Add `controlshidden` and `controlsshown` events
[ ] Test custom controls (with settings support for now) [ ] Test custom controls (with settings support for now)
[ ] Tidy up small UI for iOS inline [ ] Tidy up small UI for iOS inline
[ ] Finish new loop setup and display in seek bar [ ] Finish new loop setup and display in seek bar
[ ] Update docs for removal of setup [ ] Update docs for removal of setup
#### Later #### Later
[ ] Wistia player
[ ] Inlined sprite option
[ ] Start / end options for all players?
[ ] Get quality options for HTML5 somehow (multi source?) [ ] Get quality options for HTML5 somehow (multi source?)
[ ] Download button - grab first <source> or src attribute (or maybe use currentSrc?) for HTML5 and links for embedded players [ ] Download button - grab first <source> or src attribute (or maybe use currentSrc?) for HTML5 and links for embedded players
@ -23,7 +30,7 @@
[ ] Fix events on unsupported devices (iOS, old IE) [ ] Fix events on unsupported devices (iOS, old IE)
[x] Fix YouTube rights blocking (origin perhaps?) [x] Fix YouTube rights blocking (origin perhaps?)
# Notes ### Release notes
- No quality HTML5 support (yet) - No quality HTML5 support (yet)
- No Vimeo quality support - No Vimeo quality support
- No YouTube caption support - No YouTube caption support
@ -39,6 +46,6 @@
- Custom HTML option now `controls` which accepts a string (HTML), a function (your own template engine) or array (use built in controls) - Custom HTML option now `controls` which accepts a string (HTML), a function (your own template engine) or array (use built in controls)
- .setup() is removed in favour of a constructor - .setup() is removed in favour of a constructor
## Added #### Added
- Seek i8n label - Seek i8n label
- Loop related i8n labels - Loop related i8n labels

View File

@ -68,8 +68,8 @@
// Speed up/down // Speed up/down
speed: { speed: {
selected: 1.0, selected: 1,
options: [0.25, 0.5, 0.75, 1.0, 1.25, 1.5, 2.0] options: [0.25, 0.5, 0.75, 1, 1.25, 1.5, 2]
}, },
// Keyboard shortcut settings // Keyboard shortcut settings
@ -204,6 +204,12 @@
'airplay', 'airplay',
'fullscreen' 'fullscreen'
], ],
settings: [
'captions',
'quality',
'speed',
'loop'
],
// Localisation // Localisation
i18n: { i18n: {
@ -1442,13 +1448,9 @@
})); }));
} }
// Add the icon
button.appendChild(createIcon(iconDefault)); button.appendChild(createIcon(iconDefault));
// Add the label
button.appendChild(createLabel(labelKey)); button.appendChild(createLabel(labelKey));
// Set element attributes
utils.setAttributes(button, attributes); utils.setAttributes(button, attributes);
player.elements.buttons[type] = button; player.elements.buttons[type] = button;
@ -1668,13 +1670,16 @@
role: 'tabpanel' role: 'tabpanel'
}); });
// Create the tab list
var tabs = utils.createElement('ul', { var tabs = utils.createElement('ul', {
role: 'tablist' role: 'tablist'
}); });
['captions', 'quality', 'speed', 'loop'].forEach(function(type) { // Build the tabs
config.settings.forEach(function(type) {
var tab = utils.createElement('li', { var tab = utils.createElement('li', {
role: 'tab' role: 'tab',
hidden: ''
}); });
var button = utils.createElement('button', utils.extend(utils.getAttributesFromSelector(config.selectors.buttons.settings), { var button = utils.createElement('button', utils.extend(utils.getAttributesFromSelector(config.selectors.buttons.settings), {
@ -1694,25 +1699,24 @@
value.innerHTML = data[type]; value.innerHTML = data[type];
button.appendChild(value); button.appendChild(value);
tab.appendChild(button); tab.appendChild(button);
tabs.appendChild(tab); tabs.appendChild(tab);
player.elements.settings.tabs[type] = tab; player.elements.settings.tabs[type] = tab;
}); });
home.appendChild(tabs); home.appendChild(tabs);
inner.appendChild(home); inner.appendChild(home);
['captions', 'quality', 'speed', 'loop'].forEach(function(type) { // Build the panes
config.settings.forEach(function(type) {
var pane = utils.createElement('div', { var pane = utils.createElement('div', {
id: 'plyr-settings-' + data.id + '-' + type, id: 'plyr-settings-' + data.id + '-' + type,
'aria-hidden': true, 'aria-hidden': true,
'aria-labelled-by': 'plyr-settings-' + data.id + '-' + type + '-tab', 'aria-labelled-by': 'plyr-settings-' + data.id + '-' + type + '-tab',
role: 'tabpanel', role: 'tabpanel',
tabindex: -1 tabindex: -1,
hidden: ''
}); });
var back = utils.createElement('button', { var back = utils.createElement('button', {
@ -1728,20 +1732,16 @@
var options = utils.createElement('ul'); var options = utils.createElement('ul');
pane.appendChild(options); pane.appendChild(options);
inner.appendChild(pane); inner.appendChild(pane);
player.elements.settings.panes[type] = pane; player.elements.settings.panes[type] = pane;
}); });
form.appendChild(inner); form.appendChild(inner);
menu.appendChild(form); menu.appendChild(form);
controls.appendChild(menu); controls.appendChild(menu);
player.elements.settings.form = form; player.elements.settings.form = form;
player.elements.settings.menu = menu; player.elements.settings.menu = menu;
} }
@ -1774,6 +1774,10 @@
function setQualityMenu(options, current) { function setQualityMenu(options, current) {
var list = player.elements.settings.panes.quality.querySelector('ul'); var list = player.elements.settings.panes.quality.querySelector('ul');
// Show the pane and tab
player.elements.settings.tabs.quality.removeAttribute('hidden');
player.elements.settings.panes.quality.removeAttribute('hidden');
// Empty the menu // Empty the menu
utils.emptyElement(list); utils.emptyElement(list);
@ -1833,19 +1837,17 @@
var item = utils.createElement('li'); var item = utils.createElement('li');
var label = utils.createElement('label', { var label = utils.createElement('label', {
class: config.classes.control, class: config.classes.control
for: 'plyr-quality-' + quality
}); });
var radio = utils.createElement('input', utils.extend(utils.getAttributesFromSelector(config.selectors.inputs.quality), { var radio = utils.createElement('input', utils.extend(utils.getAttributesFromSelector(config.selectors.inputs.quality), {
type: 'radio', type: 'radio',
id: 'plyr-quality-' + quality,
name: 'plyr-quality', name: 'plyr-quality',
value: quality, value: quality,
})); }));
if (quality === config.quality.selected) { if (quality === config.quality.selected) {
radio.setAttribute('checked', ''); radio.checked = true;
} }
label.appendChild(radio); label.appendChild(radio);
@ -1857,7 +1859,6 @@
} }
item.appendChild(label); item.appendChild(label);
list.appendChild(item); list.appendChild(item);
}); });
} }
@ -1868,6 +1869,10 @@
var options = ['start', 'end', 'all', 'reset']; var options = ['start', 'end', 'all', 'reset'];
var list = player.elements.settings.panes.loop.querySelector('ul'); var list = player.elements.settings.panes.loop.querySelector('ul');
// Show the pane and tab
player.elements.settings.tabs.loop.removeAttribute('hidden');
player.elements.settings.panes.loop.removeAttribute('hidden');
// Empty the menu // Empty the menu
utils.emptyElement(list); utils.emptyElement(list);
@ -1881,12 +1886,11 @@
}), config.i18n[option]); }), config.i18n[option]);
if (utils.inArray(['start', 'end'], option)) { if (utils.inArray(['start', 'end'], option)) {
var badge = createBadge('0:00'); var badge = createBadge('00:00');
button.appendChild(badge); button.appendChild(badge);
} }
item.appendChild(button); item.appendChild(button);
list.appendChild(item); list.appendChild(item);
}); });
} }
@ -1895,6 +1899,10 @@
function setCaptionsMenu() { function setCaptionsMenu() {
var list = player.elements.settings.panes.captions.querySelector('ul'); var list = player.elements.settings.panes.captions.querySelector('ul');
// Show the pane and tab
player.elements.settings.tabs.captions.removeAttribute('hidden');
player.elements.settings.panes.captions.removeAttribute('hidden');
// Empty the menu // Empty the menu
utils.emptyElement(list); utils.emptyElement(list);
@ -1923,19 +1931,17 @@
var item = utils.createElement('li'); var item = utils.createElement('li');
var label = utils.createElement('label', { var label = utils.createElement('label', {
class: config.classes.control, class: config.classes.control
for: 'plyr-language-' + track.language
}); });
var radio = utils.createElement('input', utils.extend(utils.getAttributesFromSelector(config.selectors.inputs.language), { var radio = utils.createElement('input', utils.extend(utils.getAttributesFromSelector(config.selectors.inputs.language), {
type: 'radio', type: 'radio',
id: 'plyr-language-' + track.language,
name: 'plyr-language', name: 'plyr-language',
value: track.language, value: track.language,
})); }));
if (track.language === config.captions.language.toLowerCase()) { if (track.language.toLowerCase() === config.captions.language.toLowerCase()) {
radio.setAttribute('checked', ''); radio.checked = true;
} }
label.appendChild(radio); label.appendChild(radio);
@ -1946,7 +1952,6 @@
} }
item.appendChild(label); item.appendChild(label);
list.appendChild(item); list.appendChild(item);
}); });
} }
@ -1955,6 +1960,10 @@
function setSpeedMenu(options) { function setSpeedMenu(options) {
var list = player.elements.settings.panes.speed.querySelector('ul'); var list = player.elements.settings.panes.speed.querySelector('ul');
// Show the pane and tab
player.elements.settings.tabs.speed.removeAttribute('hidden');
player.elements.settings.panes.speed.removeAttribute('hidden');
// Empty the menu // Empty the menu
utils.emptyElement(list); utils.emptyElement(list);
@ -1967,26 +1976,22 @@
var item = utils.createElement('li'); var item = utils.createElement('li');
var label = utils.createElement('label', { var label = utils.createElement('label', {
class: config.classes.control, class: config.classes.control
for: 'plyr-speed-' + speed.toString().replace('.', '-')
}); });
var radio = utils.createElement('input', utils.extend(utils.getAttributesFromSelector(config.selectors.inputs.speed), { var radio = utils.createElement('input', utils.extend(utils.getAttributesFromSelector(config.selectors.inputs.speed), {
type: 'radio', type: 'radio',
id: 'plyr-speed-' + speed.toString().replace('.', '-'),
name: 'plyr-speed', name: 'plyr-speed',
value: speed, value: speed,
})); }));
if (speed === config.speed.selected) { if (speed === config.speed.selected) {
radio.setAttribute('checked', ''); radio.checked = true;
} }
label.appendChild(radio); label.appendChild(radio);
label.insertAdjacentHTML('beforeend', '&times;' + speed); label.insertAdjacentHTML('beforeend', getSpeedLabel(speed));
item.appendChild(label); item.appendChild(label);
list.appendChild(item); list.appendChild(item);
}); });
} }
@ -2259,7 +2264,7 @@
controls = createControls({ controls = createControls({
id: player.id, id: player.id,
seektime: config.seekTime, seektime: config.seekTime,
speed: getSpeed(), speed: getSpeedLabel(),
// TODO: Get current quality // TODO: Get current quality
quality: 'HD', quality: 'HD',
captions: getLanguage(), captions: getLanguage(),
@ -3136,8 +3141,16 @@
} }
// Get the current speed value // Get the current speed value
function getSpeed() { function getSpeedLabel(speed) {
return config.speed.selected.toFixed(1).toString().replace('.0', '') + '&times;' if (!utils.is.number(speed)) {
speed = config.speed.selected;
}
if (speed === 1) {
return 'Normal';
}
return speed + '&times;';
} }
// Rewind // Rewind
@ -3322,20 +3335,25 @@
function toggleMenu(event) { function toggleMenu(event) {
var form = player.elements.settings.form; var form = player.elements.settings.form;
var button = player.elements.buttons.settings; var button = player.elements.buttons.settings;
var show = utils.is.boolean(event) ? event : form.getAttribute('aria-hidden') === 'true';
// If the click was inside the form, do nothing if (utils.is.event(event)) {
if (form.contains(event.target)) { var isMenuItem = form.contains(event.target);
return; var isButton = event.target === player.elements.buttons.settings;
// If the click was inside the form or if the click
// wasn't the button or menu item and we're trying to
// show the menu (a doc click shouldn't show the menu)
if (isMenuItem || (!isMenuItem && !isButton && show)) {
return;
}
// Prevent the toggle being caught by the doc listener
if (isButton) {
event.stopPropagation();
}
} }
// Prevent the toggleMenu being fired twice
if (event.target === player.elements.buttons.settings) {
event.stopPropagation();
}
// Do we need to show it?
var show = form.getAttribute('aria-hidden') === 'true';
// Set form and button attributes // Set form and button attributes
form.setAttribute('aria-hidden', !show); form.setAttribute('aria-hidden', !show);
button.setAttribute('aria-expanded', show); button.setAttribute('aria-expanded', show);
@ -3347,6 +3365,38 @@
} }
} }
// Get the natural size of a tab
function getTabSize(tab) {
var width;
var height;
var clone = tab.cloneNode(true);
clone.style.position = "absolute";
clone.style.opacity = 0;
clone.setAttribute('aria-hidden', false);
// Prevent input's being unchecked due to the name being identical
[].forEach.call(clone.querySelectorAll('input[name]'), function(input) {
var name = input.getAttribute('name');
input.setAttribute('name', name + '-clone');
});
// Append to parent so we get the "real" size
tab.parentNode.appendChild(clone);
// Get the sizes before we remove
width = clone.scrollWidth;
height = clone.scrollHeight;
// Remove from the DOM
utils.removeElement(clone);
return {
width: width,
height: height
};
}
// Toggle Menu // Toggle Menu
function showTab(event) { function showTab(event) {
var menu = player.elements.settings.menu; var menu = player.elements.settings.menu;
@ -3365,14 +3415,10 @@
return; return;
} }
var targetWidth;
var targetHeight;
var container;
// Hide all other tabs // Hide all other tabs
// Get other tabs // Get other tabs
var current = menu.querySelector('[role="tabpanel"][aria-hidden="false"]'); var current = menu.querySelector('[role="tabpanel"][aria-hidden="false"]');
container = current.parentNode; var container = current.parentNode;
// Set other toggles to be expanded false // Set other toggles to be expanded false
[].forEach.call(menu.querySelectorAll('[aria-controls="' + current.getAttribute('id') + '"]'), function(toggle) { [].forEach.call(menu.querySelectorAll('[aria-controls="' + current.getAttribute('id') + '"]'), function(toggle) {
@ -3385,15 +3431,8 @@
container.style.width = current.scrollWidth + 'px'; container.style.width = current.scrollWidth + 'px';
container.style.height = current.scrollHeight + 'px'; container.style.height = current.scrollHeight + 'px';
// Get the natural element size of the target pane // Get potential sizes
var clone = pane.cloneNode(true); var size = getTabSize(pane);
clone.style.position = "absolute";
clone.style.opacity = 0;
clone.setAttribute('aria-hidden', false);
container.appendChild(clone);
targetWidth = clone.scrollWidth;
targetHeight = clone.scrollHeight;
utils.removeElement(clone);
// Restore auto height/width // Restore auto height/width
var restore = function(event) { var restore = function(event) {
@ -3415,8 +3454,8 @@
utils.on(container, utils.transitionEnd, restore); utils.on(container, utils.transitionEnd, restore);
// Set dimensions to target // Set dimensions to target
container.style.width = targetWidth + 'px'; container.style.width = size.width + 'px';
container.style.height = targetHeight + 'px'; container.style.height = size.height + 'px';
} }
// Set attributes on current tab // Set attributes on current tab
@ -4355,7 +4394,7 @@
utils.on(player.elements.buttons.settings, 'click', toggleMenu); utils.on(player.elements.buttons.settings, 'click', toggleMenu);
// Click anywhere closes menu // Click anywhere closes menu
utils.on(document.body, 'click', toggleMenu); utils.on(document.documentElement, 'click', toggleMenu);
// Show tab in menu // Show tab in menu
utils.on(player.elements.settings.form, 'click', showTab); utils.on(player.elements.settings.form, 'click', showTab);

View File

@ -503,7 +503,7 @@
position: absolute; position: absolute;
z-index: 1; z-index: 1;
bottom: 100%; bottom: 100%;
right: -5px; right: -3px;
margin-bottom: 10px; margin-bottom: 10px;
animation: plyr-popup .2s ease; animation: plyr-popup .2s ease;
@ -529,7 +529,7 @@
right: 15px; right: 15px;
height: 0; height: 0;
width: 0; width: 0;
border: 6px solid transparent; border: 4px solid transparent;
border-top-color: @plyr-menu-bg; border-top-color: @plyr-menu-bg;
} }
@ -554,7 +554,7 @@
position: absolute; position: absolute;
top: 50%; top: 50%;
transform: translateY(-50%); transform: translateY(-50%);
border: 5px solid transparent; border: 4px solid transparent;
} }
&--forward { &--forward {
@ -576,7 +576,7 @@
font-weight: 500; font-weight: 500;
&::after { &::after {
left: 5px; left: @plyr-control-padding;
border-right-color: fade(@plyr-menu-color, 80%); border-right-color: fade(@plyr-menu-color, 80%);
} }
&::before { &::before {
@ -617,12 +617,6 @@
font-weight: 600; font-weight: 600;
} }
} }
// When animating between menus
&.is-resizing {
overflow: hidden;
transition: height .35s cubic-bezier(.4,0,.2,1), width .35s cubic-bezier(.4,0,.2,1);
}
} }
} }