From a41208578552dca987ccd5c5ee166f3b0dcc84c5 Mon Sep 17 00:00:00 2001 From: Amo Wu Date: Wed, 31 Aug 2016 15:11:29 +0800 Subject: feat: add playback speed button --- src/js/plyr.js | 74 +++++++++++++++++++++++++++++++++++++++++++++++++++++++--- 1 file changed, 71 insertions(+), 3 deletions(-) (limited to 'src') diff --git a/src/js/plyr.js b/src/js/plyr.js index 9af0ad05..f880ee4f 100644 --- a/src/js/plyr.js +++ b/src/js/plyr.js @@ -39,6 +39,14 @@ volumeMin: 0, volumeMax: 10, volumeStep: 1, + defaultSpeed: 1.0, + currentSpeed: 1.0, + speeds: [ + 1.0, + 1.5, + 2.0, + 0.5 + ], duration: null, displayDuration: true, loadSprite: true, @@ -75,7 +83,8 @@ forward: '[data-plyr="fast-forward"]', mute: '[data-plyr="mute"]', captions: '[data-plyr="captions"]', - fullscreen: '[data-plyr="fullscreen"]' + fullscreen: '[data-plyr="fullscreen"]', + speedup: '[data-plyr="speed-up"]' }, volume: { input: '[data-plyr="volume"]', @@ -143,7 +152,8 @@ toggleMute: 'Toggle Mute', toggleCaptions: 'Toggle Captions', toggleFullscreen: 'Toggle Fullscreen', - frameTitle: 'Player for {title}' + frameTitle: 'Player for {title}', + speedup: 'Speed x{speed}' }, types: { embed: ['youtube', 'vimeo', 'soundcloud'], @@ -172,7 +182,8 @@ mute: null, volume: null, captions: null, - fullscreen: null + fullscreen: null, + speedup: null }, // Events to watch on HTML5 media elements events: ['ready', 'ended', 'progress', 'stalled', 'playing', 'waiting', 'canplay', 'canplaythrough', 'loadstart', 'loadeddata', 'loadedmetadata', 'timeupdate', 'volumechange', 'play', 'pause', 'error', 'seeking', 'emptied'], @@ -802,6 +813,16 @@ ); } + // Speed-up button + if (_inArray(config.controls, 'speed-up')) { + html.push( + '' + ); + } + // Progress if (_inArray(config.controls, 'progress')) { // Create progress @@ -1270,6 +1291,9 @@ // Replace seek time instances html = _replaceAll(html, '{seektime}', config.seekTime); + // Replace seek time instances + html = _replaceAll(html, '{speed}', config.currentSpeed); + // Replace all id references with random numbers html = _replaceAll(html, '{id}', Math.floor(Math.random() * (10000))); @@ -1316,6 +1340,7 @@ plyr.buttons.rewind = _getElement(config.selectors.buttons.rewind); plyr.buttons.forward = _getElement(config.selectors.buttons.forward); plyr.buttons.fullscreen = _getElement(config.selectors.buttons.fullscreen); + plyr.buttons.speedup = _getElement(config.selectors.buttons.speedup); // Inputs plyr.buttons.mute = _getElement(config.selectors.buttons.mute); @@ -1956,6 +1981,28 @@ _seek(plyr.media.currentTime + seekTime); } + // Speed-up + function _speedup(speed) { + if (!_is.number(speed)) { + var index = config.speeds.indexOf(config.currentSpeed); + if (index !== -1) { + var nextIndex = index + 1; + if (nextIndex >= config.speeds.length) { + nextIndex = 0; + } + speed = config.speeds[nextIndex]; + } else { + speed = config.defaultSpeed; + } + } + + config.currentSpeed = speed; + + plyr.media.playbackRate = speed; + + _updateSpeedupTooltip(speed); + } + // Seek to time // The input parameter can be an event or a number function _seek(input) { @@ -2523,6 +2570,24 @@ } } + // Update hover tooltip for playback speed changed + function _updateSpeedupTooltip(speed) { + if (!isNaN(speed)) { + speed = config.currentSpeed; + } + + var button = plyr.buttons.speedup; + var template = config.i18n.speedup; + + var elements= button.getElementsByClassName(config.classes.tooltip); + if (elements.length === 0){ + return; + } + + var tooltip = elements[0]; + tooltip.innerHTML = _replaceAll(template, '{speed}', speed); + } + // Show the player controls in fullscreen mode function _toggleControls(toggle) { // Don't hide if config says not to, it's audio, or not ready or loading @@ -2985,6 +3050,9 @@ // Fast forward _proxyListener(plyr.buttons.forward, 'click', config.listeners.forward, _forward); + // Speed-up + _proxyListener(plyr.buttons.speedup, 'click', config.listeners.speedup, _speedup); + // Seek _proxyListener(plyr.buttons.seek, inputEvent, config.listeners.seek, _seek); -- cgit v1.2.3 From f0ac542a7f313c472a869ea522ff3fbcc133ca70 Mon Sep 17 00:00:00 2001 From: Amo Wu Date: Wed, 31 Aug 2016 15:34:44 +0800 Subject: refactor: add localStorage supporting --- src/js/plyr.js | 16 ++++++++++++++++ 1 file changed, 16 insertions(+) (limited to 'src') diff --git a/src/js/plyr.js b/src/js/plyr.js index f880ee4f..eb7b9f2d 100644 --- a/src/js/plyr.js +++ b/src/js/plyr.js @@ -2001,6 +2001,9 @@ plyr.media.playbackRate = speed; _updateSpeedupTooltip(speed); + + // Save speed to localStorage + _updateStorage({speed: speed}); } // Seek to time @@ -2570,6 +2573,16 @@ } } + // Set playback speed + function _setSpeedup(speed) { + // Load speed from storage or default value + if (_is.undefined(speed)) { + speed = plyr.storage.speed || config.defaultSpeed; + } + + _speedup(speed); + } + // Update hover tooltip for playback speed changed function _updateSpeedupTooltip(speed) { if (!isNaN(speed)) { @@ -3438,6 +3451,9 @@ _setVolume(); _updateVolume(); + // Set playback speed + _setSpeedup(); + // Reset time display _timeUpdate(); -- cgit v1.2.3 From c291e8c5d90710cf7c1afd6f6e50f41333dd67b4 Mon Sep 17 00:00:00 2001 From: Amo Wu Date: Wed, 31 Aug 2016 15:42:01 +0800 Subject: refactor: check config.speeds format --- src/js/plyr.js | 4 ++++ 1 file changed, 4 insertions(+) (limited to 'src') diff --git a/src/js/plyr.js b/src/js/plyr.js index eb7b9f2d..a676f635 100644 --- a/src/js/plyr.js +++ b/src/js/plyr.js @@ -1983,6 +1983,10 @@ // Speed-up function _speedup(speed) { + if (!_is.array(config.speeds)) { + _warn('Invalid speeds format'); + return; + } if (!_is.number(speed)) { var index = config.speeds.indexOf(config.currentSpeed); if (index !== -1) { -- cgit v1.2.3 From 78ec5b3322e082b609b5f038350d84d7027b2e92 Mon Sep 17 00:00:00 2001 From: Amo Wu Date: Mon, 5 Sep 2016 22:56:19 +0800 Subject: refactor: sorting speed --- src/js/plyr.js | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) (limited to 'src') diff --git a/src/js/plyr.js b/src/js/plyr.js index a676f635..9a437383 100644 --- a/src/js/plyr.js +++ b/src/js/plyr.js @@ -42,10 +42,10 @@ defaultSpeed: 1.0, currentSpeed: 1.0, speeds: [ + 0.5, 1.0, 1.5, - 2.0, - 0.5 + 2.0 ], duration: null, displayDuration: true, -- cgit v1.2.3 From 37840c384414401a914eb43aa7a93eb0e17ee68e Mon Sep 17 00:00:00 2001 From: Sam Date: Tue, 6 Sep 2016 23:48:09 +1000 Subject: Working on settings menu --- src/js/plyr.js | 153 +++++++++++++++++++++---------------------- src/less/plyr.less | 109 ++++++++++++++++++++++++++++-- src/less/variables.less | 10 +-- src/sprite/plyr-settings.svg | 12 ++++ 4 files changed, 193 insertions(+), 91 deletions(-) create mode 100644 src/sprite/plyr-settings.svg (limited to 'src') diff --git a/src/js/plyr.js b/src/js/plyr.js index 9a437383..53af4cda 100644 --- a/src/js/plyr.js +++ b/src/js/plyr.js @@ -41,12 +41,7 @@ volumeStep: 1, defaultSpeed: 1.0, currentSpeed: 1.0, - speeds: [ - 0.5, - 1.0, - 1.5, - 2.0 - ], + speeds: [ 0.5, 1.0, 1.5, 2.0 ], duration: null, displayDuration: true, loadSprite: true, @@ -84,7 +79,7 @@ mute: '[data-plyr="mute"]', captions: '[data-plyr="captions"]', fullscreen: '[data-plyr="fullscreen"]', - speedup: '[data-plyr="speed-up"]' + settings: '[data-plyr="settings"]' }, volume: { input: '[data-plyr="volume"]', @@ -137,7 +132,7 @@ enabled: true, key: 'plyr' }, - controls: ['play-large', 'play', 'progress', 'current-time', 'mute', 'volume', 'captions', 'fullscreen'], + controls: ['play-large', 'play', 'progress', 'current-time', 'mute', 'volume', 'settings', 'fullscreen'], i18n: { restart: 'Restart', rewind: 'Rewind {seektime} secs', @@ -153,7 +148,9 @@ toggleCaptions: 'Toggle Captions', toggleFullscreen: 'Toggle Fullscreen', frameTitle: 'Player for {title}', - speedup: 'Speed x{speed}' + captions: 'Captions', + settings: 'Settings', + speed: 'Speed' }, types: { embed: ['youtube', 'vimeo', 'soundcloud'], @@ -183,7 +180,7 @@ volume: null, captions: null, fullscreen: null, - speedup: null + speed: null }, // Events to watch on HTML5 media elements events: ['ready', 'ended', 'progress', 'stalled', 'playing', 'waiting', 'canplay', 'canplaythrough', 'loadstart', 'loadeddata', 'loadedmetadata', 'timeupdate', 'volumechange', 'play', 'pause', 'error', 'seeking', 'emptied'], @@ -354,21 +351,6 @@ } } - // Unwrap an element - // http://plainjs.com/javascript/manipulation/unwrap-a-dom-element-35/ - /*function _unwrap(wrapper) { - // Get the element's parent node - var parent = wrapper.parentNode; - - // Move all children out of the element - while (wrapper.firstChild) { - parent.insertBefore(wrapper.firstChild, wrapper); - } - - // Remove the empty element - parent.removeChild(wrapper); - }*/ - // Remove an element function _remove(element) { if (!element) { @@ -452,7 +434,7 @@ } // Toggle event listener - function _toggleListener(element, events, callback, toggle, useCapture) { + function _toggleListener(elements, events, callback, toggle, useCapture) { var eventList = events.split(' '); // Whether the listener is a capturing listener or not @@ -462,10 +444,10 @@ } // If a nodelist is passed, call itself on each node - if (element instanceof NodeList) { - for (var x = 0; x < element.length; x++) { - if (element[x] instanceof Node) { - _toggleListener(element[x], arguments[1], arguments[2], arguments[3]); + if (elements instanceof NodeList) { + for (var x = 0; x < elements.length; x++) { + if (elements[x] instanceof Node) { + _toggleListener(elements[x], arguments[1], arguments[2], arguments[3]); } } return; @@ -473,7 +455,7 @@ // If a single node is passed, bind the event listener for (var i = 0; i < eventList.length; i++) { - element[toggle ? 'addEventListener' : 'removeEventListener'](eventList[i], callback, useCapture); + elements[toggle ? 'addEventListener' : 'removeEventListener'](eventList[i], callback, useCapture); } } @@ -484,13 +466,6 @@ } } - // Unbind event - /*function _off(element, events, callback, useCapture) { - if (element) { - _toggleListener(element, events, callback, false, useCapture); - } - }*/ - // Trigger event function _event(element, type, bubbles, properties) { // Bail if no element @@ -604,6 +579,9 @@ }, undefined: function(input) { return input !== null && typeof input === 'undefined'; + }, + empty: function(input) { + return input === null || this.undefined(input) || ((this.string(input) || this.array(input) || this.nodeList(input)) && input.length === 0) || (this.object(input) && Object.keys(input).length === 0); } }; @@ -813,22 +791,12 @@ ); } - // Speed-up button - if (_inArray(config.controls, 'speed-up')) { - html.push( - '' - ); - } - // Progress if (_inArray(config.controls, 'progress')) { // Create progress html.push('', - '', - '', + '', + '', '', '', '0% ' + config.i18n.buffered, @@ -878,8 +846,8 @@ if (_inArray(config.controls, 'volume')) { html.push( '', - '', - '', + '', + '', '', '' ); @@ -896,6 +864,34 @@ ); } + // Settings button + if (_inArray(config.controls, 'settings')) { + + + html.push( + '
', + '', + '', + '
' + ); + } + // Toggle fullscreen button if (_inArray(config.controls, 'fullscreen')) { html.push( @@ -1292,7 +1288,10 @@ html = _replaceAll(html, '{seektime}', config.seekTime); // Replace seek time instances - html = _replaceAll(html, '{speed}', config.currentSpeed); + html = _replaceAll(html, '{speed}', config.currentSpeed === 1 ? 'Normal' : config.currentSpeed.toFixed(1) + 'x'); + + // Replace current captions language + html = _replaceAll(html, '{lang}', 'English'); // Replace all id references with random numbers html = _replaceAll(html, '{id}', Math.floor(Math.random() * (10000))); @@ -1340,7 +1339,7 @@ plyr.buttons.rewind = _getElement(config.selectors.buttons.rewind); plyr.buttons.forward = _getElement(config.selectors.buttons.forward); plyr.buttons.fullscreen = _getElement(config.selectors.buttons.fullscreen); - plyr.buttons.speedup = _getElement(config.selectors.buttons.speedup); + plyr.buttons.settings = _getElement(config.selectors.buttons.settings); // Inputs plyr.buttons.mute = _getElement(config.selectors.buttons.mute); @@ -1982,13 +1981,14 @@ } // Speed-up - function _speedup(speed) { + function _speed(speed) { if (!_is.array(config.speeds)) { _warn('Invalid speeds format'); return; } if (!_is.number(speed)) { var index = config.speeds.indexOf(config.currentSpeed); + if (index !== -1) { var nextIndex = index + 1; if (nextIndex >= config.speeds.length) { @@ -2000,12 +2000,12 @@ } } + // Store current speed config.currentSpeed = speed; + // Set HTML5 speed plyr.media.playbackRate = speed; - _updateSpeedupTooltip(speed); - // Save speed to localStorage _updateStorage({speed: speed}); } @@ -2578,31 +2578,13 @@ } // Set playback speed - function _setSpeedup(speed) { + function _setSpeed(speed) { // Load speed from storage or default value if (_is.undefined(speed)) { speed = plyr.storage.speed || config.defaultSpeed; } - _speedup(speed); - } - - // Update hover tooltip for playback speed changed - function _updateSpeedupTooltip(speed) { - if (!isNaN(speed)) { - speed = config.currentSpeed; - } - - var button = plyr.buttons.speedup; - var template = config.i18n.speedup; - - var elements= button.getElementsByClassName(config.classes.tooltip); - if (elements.length === 0){ - return; - } - - var tooltip = elements[0]; - tooltip.innerHTML = _replaceAll(template, '{speed}', speed); + _speed(speed); } // Show the player controls in fullscreen mode @@ -3068,7 +3050,7 @@ _proxyListener(plyr.buttons.forward, 'click', config.listeners.forward, _forward); // Speed-up - _proxyListener(plyr.buttons.speedup, 'click', config.listeners.speedup, _speedup); + _proxyListener(plyr.buttons.speed, 'click', config.listeners.speed, _speed); // Seek _proxyListener(plyr.buttons.seek, inputEvent, config.listeners.seek, _seek); @@ -3092,6 +3074,18 @@ // Captions _on(plyr.buttons.captions, 'click', _toggleCaptions); + // Menus + _on(plyr.controls.querySelectorAll('[aria-haspopup="true"]'), 'click', function() { + var toggle = this, + target = document.querySelector('#' + toggle.getAttribute('aria-controls')), + show = (toggle.getAttribute('aria-expanded') === 'false'); + + console.log(target, toggle); + + toggle.setAttribute('aria-expanded', show); + target.setAttribute('aria-hidden', !show); + }); + // Seek tooltip _on(plyr.progress.container, 'mouseenter mouseleave mousemove', _updateSeekTooltip); @@ -3456,7 +3450,7 @@ _updateVolume(); // Set playback speed - _setSpeedup(); + _setSpeed(); // Reset time display _timeUpdate(); @@ -3488,6 +3482,7 @@ source: _source, poster: _updatePoster, setVolume: _setVolume, + setSpeed: _setSpeed, togglePlay: _togglePlay, toggleMute: _toggleMute, toggleCaptions: _toggleCaptions, diff --git a/src/less/plyr.less b/src/less/plyr.less index f70d135c..a3dd8e83 100644 --- a/src/less/plyr.less +++ b/src/less/plyr.less @@ -11,6 +11,16 @@ @keyframes plyr-progress { to { background-position: @plyr-progress-loading-size 0; } } +@keyframes plyr-popup { + from { + transform: translateY(10px); + opacity: .5; + } + to { + transform: translateY(0); + opacity: 1; + } +} // Styles // ------------------------------- @@ -40,6 +50,11 @@ } } + // ARIA + [aria-hidden='true'] { + display: none; + } + // Focus &:focus { outline: 0; @@ -268,7 +283,8 @@ // Spacing > button, .plyr__progress, - .plyr__time { + .plyr__time, + .plyr__menu { margin-left: (@plyr-control-spacing / 2); &:first-child { @@ -320,9 +336,16 @@ @media (min-width: @plyr-bp-screen-sm) { > button, .plyr__progress, - .plyr__time { + .plyr__time, + .plyr__menu { margin-left: @plyr-control-spacing; } + + > button + button, + .plyr__menu + button, + > button + .plyr__menu { + margin-left: (@plyr-control-spacing / 2); + } } } // Hide controls @@ -338,7 +361,7 @@ right: 0; bottom: 0; padding: (@plyr-control-spacing * 5) @plyr-control-spacing @plyr-control-spacing; - background: linear-gradient(fade(@plyr-video-controls-bg, 0%), fade(@plyr-video-controls-bg, 50%)); + background: linear-gradient(fade(@plyr-video-controls-bg, 0%), fade(@plyr-video-controls-bg, 70%)); border-bottom-left-radius: inherit; border-bottom-right-radius: inherit; color: @plyr-video-control-color; @@ -442,6 +465,78 @@ display: inline-block; } +// Menus +// -------------------------------------------------------------- +.plyr__menu { + position: relative; + + // Hide tooltip + button[aria-expanded='true'] .plyr__tooltip { + display: none; + } + + // The actual menu container + &__container { + position: absolute; + bottom: 100%; + right: -5px; + margin-bottom: 10px; + animation: plyr-popup .2s ease; + background: fade(@plyr-video-controls-bg, 90%); + box-shadow: 0 1px 0 fade(#000, 20%); + border-radius: 4px; + white-space: nowrap; + text-align: left; + color: @plyr-video-control-color; + font-size: @plyr-font-size-small; + + ul { + margin: 0; + padding: 5px; + list-style: none; + } + + button { + display: flex; + width: 100%; + padding: 10px 30px 10px 12px; + color: @plyr-video-control-color; + font-weight: 600; + + // Arrow + &::after { + content: ""; + position: absolute; + top: 50%; + transform: translateY(-50%); + right: 5px; + border: 5px solid transparent; + border-left-color: fade(@plyr-video-control-color, 80%); + } + } + + // Option value + .plyr__menu__value { + margin-left: auto; + padding-left: 25px; + font-weight: 400; + color: fade(@plyr-video-control-color, 80%); + } + + // Arrow + &::after { + content: ""; + position: absolute; + top: 100%; + right: 15px; + height: 0; + width: 0; + border: 6px solid transparent; + border-top-color: fade(@plyr-video-controls-bg, 90%); + } + } +} + // Tooltips // -------------------------------------------------------------- .plyr__tooltip { @@ -492,7 +587,7 @@ } // First tooltip -.plyr__controls button:first-child .plyr__tooltip { +.plyr__controls > button:first-child .plyr__tooltip { left: 0; transform: translate(0, 10px) scale(.8); transform-origin: 0 100%; @@ -503,7 +598,7 @@ } // Last tooltip -.plyr__controls button:last-child .plyr__tooltip { +.plyr__controls > button:last-child .plyr__tooltip { right: 0; transform: translate(0, 10px) scale(.8); transform-origin: 100% 100%; @@ -515,8 +610,8 @@ } } -.plyr__controls button:first-child, -.plyr__controls button:last-child { +.plyr__controls > button:first-child, +.plyr__controls > button:last-child { &:hover .plyr__tooltip, &.tab-focus:focus .plyr__tooltip, .plyr__tooltip--visible { diff --git a/src/less/variables.less b/src/less/variables.less index fc9e895a..8a601571 100644 --- a/src/less/variables.less +++ b/src/less/variables.less @@ -17,7 +17,7 @@ @plyr-font-size-base: 16px; // Captions -@plyr-captions-bg: fade(#000, 70%); +@plyr-captions-bg: fade(#343f4a, 85%); @plyr-captions-color: #fff; @plyr-font-size-captions-base: @plyr-font-size-base; @plyr-font-size-captions-medium: ceil(@plyr-font-size-base * 1.5); @@ -27,7 +27,7 @@ @plyr-control-icon-size: 18px; @plyr-control-spacing: 10px; @plyr-control-padding: (@plyr-control-spacing * .7); -@plyr-video-controls-bg: #000; +@plyr-video-controls-bg: #343f4a; @plyr-video-control-color: #fff; @plyr-video-control-color-hover: #fff; @plyr-video-control-bg-hover: @plyr-color-main; @@ -38,7 +38,7 @@ @plyr-audio-control-bg-hover: @plyr-color-main; // Tooltips -@plyr-tooltip-bg: fade(#000, 70%); +@plyr-tooltip-bg: fade(#343f4a, 85%); @plyr-tooltip-color: #fff; @plyr-tooltip-padding: (@plyr-control-spacing / 2); @plyr-tooltip-arrow-size: 4px; @@ -46,7 +46,7 @@ // Progress @plyr-progress-loading-size: 25px; -@plyr-progress-loading-bg: fade(#000, 15%); +@plyr-progress-loading-bg: fade(#343f4a, 20%); @plyr-video-progress-bg: fade(#fff, 25%); @plyr-video-progress-buffered-bg: @plyr-video-progress-bg; @plyr-audio-progress-bg: fade(#C6D6DB, 66%); @@ -58,7 +58,7 @@ @plyr-range-thumb-width: floor(@plyr-range-track-height * 2); @plyr-range-thumb-bg: #fff; @plyr-range-thumb-border: 2px solid transparent; -@plyr-range-thumb-shadow: 0 1px 1px fade(@plyr-video-controls-bg, 15%), 0 0 0 1px fade(#000, 15%); +@plyr-range-thumb-shadow: 0 1px 1px fade(@plyr-video-controls-bg, 15%), 0 0 0 1px fade(#343f4a, 20%); @plyr-range-thumb-active-border-color: #fff; @plyr-range-thumb-active-bg: @plyr-video-control-bg-hover; @plyr-range-thumb-active-scale: 1.25; diff --git a/src/sprite/plyr-settings.svg b/src/sprite/plyr-settings.svg new file mode 100644 index 00000000..e6fd0f75 --- /dev/null +++ b/src/sprite/plyr-settings.svg @@ -0,0 +1,12 @@ + + + + -- cgit v1.2.3 From 42a2642d402b0c04dd133a894c1c8461abbfbf2a Mon Sep 17 00:00:00 2001 From: Sam Date: Tue, 6 Sep 2016 23:50:59 +1000 Subject: Icon fix --- src/sprite/plyr-settings.svg | 18 ++++++------------ 1 file changed, 6 insertions(+), 12 deletions(-) (limited to 'src') diff --git a/src/sprite/plyr-settings.svg b/src/sprite/plyr-settings.svg index e6fd0f75..fbf8ecd1 100644 --- a/src/sprite/plyr-settings.svg +++ b/src/sprite/plyr-settings.svg @@ -1,12 +1,6 @@ - - - - + + + + + + \ No newline at end of file -- cgit v1.2.3 From 46f82a4af375164355315f08b5724a25961aa39b Mon Sep 17 00:00:00 2001 From: Sam Potts Date: Wed, 7 Sep 2016 22:18:05 +1000 Subject: Added quality in menu --- src/js/plyr.js | 8 +++++++- src/less/plyr.less | 12 ++++++------ src/less/variables.less | 7 ++++++- 3 files changed, 19 insertions(+), 8 deletions(-) (limited to 'src') diff --git a/src/js/plyr.js b/src/js/plyr.js index 53af4cda..d113882c 100644 --- a/src/js/plyr.js +++ b/src/js/plyr.js @@ -150,7 +150,8 @@ frameTitle: 'Player for {title}', captions: 'Captions', settings: 'Settings', - speed: 'Speed' + speed: 'Speed', + quality: 'Quality' }, types: { embed: ['youtube', 'vimeo', 'soundcloud'], @@ -886,6 +887,11 @@ config.i18n.speed + ' {speed}', '', '', + '
  • ', + '', + '
  • ', '', '', '' diff --git a/src/less/plyr.less b/src/less/plyr.less index a3dd8e83..20550b80 100644 --- a/src/less/plyr.less +++ b/src/less/plyr.less @@ -482,12 +482,12 @@ right: -5px; margin-bottom: 10px; animation: plyr-popup .2s ease; - background: fade(@plyr-video-controls-bg, 90%); + background: @plyr-menu-bg; box-shadow: 0 1px 0 fade(#000, 20%); border-radius: 4px; white-space: nowrap; text-align: left; - color: @plyr-video-control-color; + color: @plyr-menu-color; font-size: @plyr-font-size-small; ul { @@ -500,7 +500,7 @@ display: flex; width: 100%; padding: 10px 30px 10px 12px; - color: @plyr-video-control-color; + color: @plyr-menu-color; font-weight: 600; // Arrow @@ -511,7 +511,7 @@ transform: translateY(-50%); right: 5px; border: 5px solid transparent; - border-left-color: fade(@plyr-video-control-color, 80%); + border-left-color: fade(@plyr-menu-color, 80%); } } @@ -520,7 +520,7 @@ margin-left: auto; padding-left: 25px; font-weight: 400; - color: fade(@plyr-video-control-color, 80%); + color: fade(@plyr-menu-color, 80%); } // Arrow @@ -532,7 +532,7 @@ height: 0; width: 0; border: 6px solid transparent; - border-top-color: fade(@plyr-video-controls-bg, 90%); + border-top-color: @plyr-menu-bg; } } } diff --git a/src/less/variables.less b/src/less/variables.less index 8a601571..c7eab243 100644 --- a/src/less/variables.less +++ b/src/less/variables.less @@ -38,12 +38,17 @@ @plyr-audio-control-bg-hover: @plyr-color-main; // Tooltips -@plyr-tooltip-bg: fade(#343f4a, 85%); +@plyr-tooltip-bg: fade(#343f4a, 90%); @plyr-tooltip-color: #fff; @plyr-tooltip-padding: (@plyr-control-spacing / 2); @plyr-tooltip-arrow-size: 4px; @plyr-tooltip-radius: 3px; +// Menus +@plyr-menu-bg: @plyr-tooltip-bg; +@plyr-menu-color: @plyr-tooltip-color; +@plyr-menu-arrow-size: 6px; + // Progress @plyr-progress-loading-size: 25px; @plyr-progress-loading-bg: fade(#343f4a, 20%); -- cgit v1.2.3 From d638cdcdd346b964ef0e782e4111adbe7877f05e Mon Sep 17 00:00:00 2001 From: Sam Date: Tue, 13 Sep 2016 00:16:27 +1000 Subject: Started on PIP support --- src/js/plyr.js | 221 +++++++++++++++++++++++++++-------------------------- src/less/plyr.less | 5 +- 2 files changed, 117 insertions(+), 109 deletions(-) (limited to 'src') diff --git a/src/js/plyr.js b/src/js/plyr.js index d113882c..317e3b1b 100644 --- a/src/js/plyr.js +++ b/src/js/plyr.js @@ -9,7 +9,7 @@ ;(function(root, factory) { 'use strict'; - /*global define,module*/ + /* global define,module */ if (typeof module === 'object' && typeof module.exports === 'object') { // Node, CommonJS-like @@ -25,8 +25,7 @@ 'use strict'; // Globals - var fullscreen, - scroll = { x: 0, y: 0 }, + var scroll = { x: 0, y: 0 }, // Default config defaults = { @@ -118,6 +117,10 @@ enabled: 'plyr--fullscreen-enabled', active: 'plyr--fullscreen-active' }, + pip: { + enabled: 'plyr--pip-enabled', + active: 'plyr--pip-active' + }, tabFocus: 'tab-focus' }, captions: { @@ -191,7 +194,7 @@ // Credits: http://paypal.github.io/accessible-html5-video-player/ // Unfortunately, due to mixed support, UA sniffing is required - function _browserSniff() { + function _getBrowser() { var ua = navigator.userAgent, name = navigator.appName, fullVersion = '' + parseFloat(navigator.appVersion), @@ -270,32 +273,6 @@ }; } - // Check for mime type support against a player instance - // Credits: http://diveintohtml5.info/everything.html - // Related: http://www.leanbackplyr.com/test/h5mt.html - function _supportMime(plyr, mimeType) { - var media = plyr.media; - - if (plyr.type === 'video') { - // Check type - switch (mimeType) { - case 'video/webm': return !!(media.canPlayType && media.canPlayType('video/webm; codecs="vp8, vorbis"').replace(/no/, '')); - case 'video/mp4': return !!(media.canPlayType && media.canPlayType('video/mp4; codecs="avc1.42E01E, mp4a.40.2"').replace(/no/, '')); - case 'video/ogg': return !!(media.canPlayType && media.canPlayType('video/ogg; codecs="theora"').replace(/no/, '')); - } - } else if (plyr.type === 'audio') { - // Check type - switch (mimeType) { - case 'audio/mpeg': return !!(media.canPlayType && media.canPlayType('audio/mpeg;').replace(/no/, '')); - case 'audio/ogg': return !!(media.canPlayType && media.canPlayType('audio/ogg; codecs="vorbis"').replace(/no/, '')); - case 'audio/wav': return !!(media.canPlayType && media.canPlayType('audio/wav; codecs="1"').replace(/no/, '')); - } - } - - // If we got this far, we're stuffed - return false; - } - // Inject a script function _injectScript(source) { if (document.querySelectorAll('script[src="' + source + '"]').length) { @@ -587,45 +564,38 @@ }; // Fullscreen API - function _fullscreen() { - var fullscreen = { - supportsFullScreen: false, - isFullScreen: function() { return false; }, - requestFullScreen: function() {}, - cancelFullScreen: function() {}, - fullScreenEventName: '', - element: null, - prefix: '' - }, - browserPrefixes = 'webkit o moz ms khtml'.split(' '); - - // Check for native support - if (!_is.undefined(document.cancelFullScreen)) { - fullscreen.supportsFullScreen = true; - } else { - // Check for fullscreen support by vendor prefix - for (var i = 0, il = browserPrefixes.length; i < il; i++ ) { - fullscreen.prefix = browserPrefixes[i]; - - if (!_is.undefined(document[fullscreen.prefix + 'CancelFullScreen'])) { - fullscreen.supportsFullScreen = true; - break; - } else if (!_is.undefined(document.msExitFullscreen) && document.msFullscreenEnabled) { - // Special case for MS (when isn't it?) - fullscreen.prefix = 'ms'; - fullscreen.supportsFullScreen = true; - break; - } + var _fullscreen; + (function() { + // Determine the prefix + var prefix = (function() { + if (!_is.undefined(document.cancelFullScreen)) { + return ''; + } else { + // Check for fullscreen support by vendor prefix + ['webkit', 'o', 'moz', 'ms', 'khtml'].forEach(function(prefix) { + if (!_is.undefined(document[prefix + 'CancelFullScreen'])) { + return prefix; + } else if (!_is.undefined(document.msExitFullscreen) && document.msFullscreenEnabled) { + // Special case for MS (when isn't it?) + return 'ms'; + } + }); } - } - // Update methods to do something useful - if (fullscreen.supportsFullScreen) { + // If we got this far, there's no support + return false; + })(); + + _fullscreen = { // Yet again Microsoft awesomeness, // Sometimes the prefix is 'ms', sometimes 'MS' to keep you on your toes - fullscreen.fullScreenEventName = (fullscreen.prefix === 'ms' ? 'MSFullscreenChange' : fullscreen.prefix + 'fullscreenchange'); + eventType: (prefix === 'ms' ? 'MSFullscreenChange' : prefix + 'fullscreenchange'), - fullscreen.isFullScreen = function(element) { + // Is an element fullscreen + isFullScreen: function(element) { + if (!_support.fullscreen) { + return false; + } if (_is.undefined(element)) { element = document.body; } @@ -635,29 +605,40 @@ case 'moz': return document.mozFullScreenElement === element; default: - return document[this.prefix + 'FullscreenElement'] === element; + return document[prefix + 'FullscreenElement'] === element; + } + }, + requestFullScreen: function(element) { + if (!_support.fullscreen) { + return false; } - }; - fullscreen.requestFullScreen = function(element) { if (_is.undefined(element)) { element = document.body; } - return (this.prefix === '') ? element.requestFullScreen() : element[this.prefix + (this.prefix === 'ms' ? 'RequestFullscreen' : 'RequestFullScreen')](); - }; - fullscreen.cancelFullScreen = function() { - return (this.prefix === '') ? document.cancelFullScreen() : document[this.prefix + (this.prefix === 'ms' ? 'ExitFullscreen' : 'CancelFullScreen')](); - }; - fullscreen.element = function() { - return (this.prefix === '') ? document.fullscreenElement : document[this.prefix + 'FullscreenElement']; - }; - } - - return fullscreen; - } + return (prefix === '') ? element.requestFullScreen() : element[prefix + (prefix === 'ms' ? 'RequestFullscreen' : 'RequestFullScreen')](); + }, + cancelFullScreen: function() { + if (!_support.fullscreen) { + return false; + } + return (prefix === '') ? document.cancelFullScreen() : document[prefix + (prefix === 'ms' ? 'ExitFullscreen' : 'CancelFullScreen')](); + }, + element: function() { + if (!_support.fullscreen) { + return null; + } + return (prefix === '') ? document.fullscreenElement : document[prefix + 'FullscreenElement']; + } + }; + })(); - // Local storage - var _storage = { - supported: (function() { + // Check for support + var _support = { + // Fullscreen support and set prefix + fullscreen: _fullscreen.prefix !== false, + // Local storage mode + // We can't assume if local storage is present that we can use it + storage: (function() { if (!('localStorage' in window)) { return false; } @@ -682,7 +663,37 @@ } return false; - })() + })(), + // Picture-in-picture support + // Safari only currently + pip: function(plyr) { + return _is.function(plyr.media.webkitSetPresentationMode); + }, + // Check for mime type support against a player instance + // Credits: http://diveintohtml5.info/everything.html + // Related: http://www.leanbackplyr.com/test/h5mt.html + mime: function(plyr, type) { + var media = plyr.media; + + if (plyr.type === 'video') { + // Check type + switch (type) { + case 'video/webm': return !!(media.canPlayType && media.canPlayType('video/webm; codecs="vp8, vorbis"').replace(/no/, '')); + case 'video/mp4': return !!(media.canPlayType && media.canPlayType('video/mp4; codecs="avc1.42E01E, mp4a.40.2"').replace(/no/, '')); + case 'video/ogg': return !!(media.canPlayType && media.canPlayType('video/ogg; codecs="theora"').replace(/no/, '')); + } + } else if (plyr.type === 'audio') { + // Check type + switch (type) { + case 'audio/mpeg': return !!(media.canPlayType && media.canPlayType('audio/mpeg;').replace(/no/, '')); + case 'audio/ogg': return !!(media.canPlayType && media.canPlayType('audio/ogg; codecs="vorbis"').replace(/no/, '')); + case 'audio/wav': return !!(media.canPlayType && media.canPlayType('audio/wav; codecs="1"').replace(/no/, '')); + } + } + + // If we got this far, we're stuffed + return false; + } }; // Player instance @@ -867,8 +878,6 @@ // Settings button if (_inArray(config.controls, 'settings')) { - - html.push( '
    ', '', '', '
  • ', - '', '
  • ', @@ -923,7 +932,7 @@ if ((plyr.type !== 'audio' || config.fullscreen.allowAudio) && config.fullscreen.enabled) { // Check for native support - var nativeSupport = fullscreen.supportsFullScreen; + var nativeSupport = _support.fullscreen; if (nativeSupport || (config.fullscreen.fallback && !_inFrame())) { _log((nativeSupport ? 'Native' : 'Fallback') + ' fullscreen enabled'); @@ -1435,7 +1444,7 @@ plyr.storage = {}; // Bail if we don't have localStorage support or it's disabled - if (!_storage.supported || !config.storage.enabled) { + if (!_support.storage || !config.storage.enabled) { return; } @@ -1463,7 +1472,7 @@ // Save a value back to local storage function _updateStorage(value) { // Bail if we don't have localStorage support or it's disabled - if (!_storage.supported || !config.storage.enabled) { + if (!_support.storage || !config.storage.enabled) { return; } @@ -1492,6 +1501,9 @@ _toggleClass(plyr.container, config.classes.type.replace('{0}', 'video'), true); } + // Check for picture-in-picture support + _toggleClass(plyr.container, config.classes.pip.enabled, _support.pip(plyr)); + // If there's no autoplay attribute, assume the video is stopped and add state class _toggleClass(plyr.container, config.classes.stopped, config.autoplay); @@ -2126,27 +2138,27 @@ // Toggle fullscreen function _toggleFullscreen(event) { // Check for native support - var nativeSupport = fullscreen.supportsFullScreen; + var nativeSupport = _support.fullscreen; if (nativeSupport) { // If it's a fullscreen change event, update the UI - if (event && event.type === fullscreen.fullScreenEventName) { - plyr.isFullscreen = fullscreen.isFullScreen(plyr.container); + if (event && event.type === _fullscreen.eventType) { + plyr.isFullscreen = _fullscreen.isFullScreen(plyr.container); } else { // Else it's a user request to enter or exit - if (!fullscreen.isFullScreen(plyr.container)) { + if (!_fullscreen.isFullScreen(plyr.container)) { // Save scroll position _saveScrollPosition(); // Request full screen - fullscreen.requestFullScreen(plyr.container); + _fullscreen.requestFullScreen(plyr.container); } else { // Bail from fullscreen - fullscreen.cancelFullScreen(); + _fullscreen.cancelFullScreen(); } // Check if we're actually full screen (it could fail) - plyr.isFullscreen = fullscreen.isFullScreen(plyr.container); + plyr.isFullscreen = _fullscreen.isFullScreen(plyr.container); return; } @@ -3009,7 +3021,7 @@ // Escape is handle natively when in full screen // So we only need to worry about non native - if (!fullscreen.supportsFullScreen && plyr.isFullscreen && code === 27) { + if (!_support.fullscreen && plyr.isFullscreen && code === 27) { _toggleFullscreen(); } @@ -3073,8 +3085,8 @@ _proxyListener(plyr.buttons.fullscreen, 'click', config.listeners.fullscreen, _toggleFullscreen); // Handle user exiting fullscreen by escaping etc - if (fullscreen.supportsFullScreen) { - _on(document, fullscreen.fullScreenEventName, _toggleFullscreen); + if (_support.fullscreen) { + _on(document, _fullscreen.eventType, _toggleFullscreen); } // Captions @@ -3086,8 +3098,6 @@ target = document.querySelector('#' + toggle.getAttribute('aria-controls')), show = (toggle.getAttribute('aria-expanded') === 'false'); - console.log(target, toggle); - toggle.setAttribute('aria-expanded', show); target.setAttribute('aria-hidden', !show); }); @@ -3332,11 +3342,8 @@ return null; } - // Setup the fullscreen api - fullscreen = _fullscreen(); - // Sniff out the browser - plyr.browser = _browserSniff(); + plyr.browser = _getBrowser(); // Bail if nothing to setup if (!_is.htmlElement(plyr.media)) { @@ -3495,7 +3502,7 @@ toggleFullscreen: _toggleFullscreen, toggleControls: _toggleControls, isFullscreen: function() { return plyr.isFullscreen || false; }, - support: function(mimeType) { return _supportMime(plyr, mimeType); }, + support: function(mimeType) { return _support.mime(plyr, mimeType); }, destroy: _destroy }; @@ -3566,7 +3573,7 @@ // Check for support function supported(type) { - var browser = _browserSniff(), + var browser = _getBrowser(), isOldIE = (browser.isIE && browser.version <= 9), isIos = browser.isIos, isIphone = /iPhone|iPod/i.test(navigator.userAgent), diff --git a/src/less/plyr.less b/src/less/plyr.less index 20550b80..cf48274d 100644 --- a/src/less/plyr.less +++ b/src/less/plyr.less @@ -30,6 +30,7 @@ max-width: 100%; min-width: 200px; font-family: @plyr-font-family; + font-weight: 500; direction: ltr; & when (@plyr-border-box = true) { @@ -239,7 +240,6 @@ color: @plyr-captions-color; font-size: @plyr-font-size-captions-base; text-align: center; - font-weight: 400; span { border-radius: 2px; @@ -519,7 +519,7 @@ .plyr__menu__value { margin-left: auto; padding-left: 25px; - font-weight: 400; + font-weight: 500; color: fade(@plyr-menu-color, 80%); } @@ -553,6 +553,7 @@ color: @plyr-tooltip-color; font-size: @plyr-font-size-small; + font-weight: 500; line-height: 1.3; transform: translate(-50%, 10px) scale(.8); -- cgit v1.2.3 From c8b9c9bcaaf7fcf8c6386047cd8729b05159585f Mon Sep 17 00:00:00 2001 From: Sam Potts Date: Tue, 13 Sep 2016 23:52:25 +1000 Subject: Expanded --- src/js/plyr.js | 2 -- src/less/plyr.less | 6 ++++-- 2 files changed, 4 insertions(+), 4 deletions(-) (limited to 'src') diff --git a/src/js/plyr.js b/src/js/plyr.js index d113882c..e6bdd055 100644 --- a/src/js/plyr.js +++ b/src/js/plyr.js @@ -3086,8 +3086,6 @@ target = document.querySelector('#' + toggle.getAttribute('aria-controls')), show = (toggle.getAttribute('aria-expanded') === 'false'); - console.log(target, toggle); - toggle.setAttribute('aria-expanded', show); target.setAttribute('aria-hidden', !show); }); diff --git a/src/less/plyr.less b/src/less/plyr.less index 20550b80..78b967a5 100644 --- a/src/less/plyr.less +++ b/src/less/plyr.less @@ -370,7 +370,8 @@ button { // Hover and tab focus &.tab-focus:focus, - &:hover { + &:hover, + &[aria-expanded='true'] { background: @plyr-video-control-bg-hover; color: @plyr-video-control-color-hover; } @@ -388,7 +389,8 @@ button { // Hover and tab focus &.tab-focus:focus, - &:hover { + &:hover, + &[aria-expanded='true'] { background: @plyr-audio-control-bg-hover; color: @plyr-audio-control-color-hover; } -- cgit v1.2.3 From d3bbf09d124344fd065e17707f008e4c2282e038 Mon Sep 17 00:00:00 2001 From: Sam Potts Date: Sun, 25 Sep 2016 20:01:58 +1000 Subject: More menu work --- src/js/plyr.js | 142 ++++++++++++++++++++++++++++++++++++++++++----------- src/less/plyr.less | 99 ++++++++++++++++++++++++++++--------- 2 files changed, 189 insertions(+), 52 deletions(-) (limited to 'src') diff --git a/src/js/plyr.js b/src/js/plyr.js index 317e3b1b..bd79df0e 100644 --- a/src/js/plyr.js +++ b/src/js/plyr.js @@ -532,10 +532,10 @@ // Check variable types var _is = { object: function(input) { - return input !== null && typeof(input) === 'object'; + return input !== null && typeof(input) === 'object' && input.constructor === Object; }, array: function(input) { - return input !== null && (typeof(input) === 'object' && input.constructor === Array); + return input !== null && typeof(input) === 'object' && input.constructor === Array; }, number: function(input) { return input !== null && (typeof(input) === 'number' && !isNaN(input - 0) || (typeof input === 'object' && input.constructor === Number)); @@ -555,6 +555,9 @@ function: function(input) { return input !== null && typeof input === 'function'; }, + event: function(input) { + return input !== null && typeof input === 'object' && (input.constructor === Event || input.constructor === CustomEvent); + }, undefined: function(input) { return input !== null && typeof input === 'undefined'; }, @@ -876,32 +879,91 @@ ); } - // Settings button + // Settings button / menu if (_inArray(config.controls, 'settings')) { html.push( - '
    ', - '', - '' ); @@ -1303,7 +1365,7 @@ html = _replaceAll(html, '{seektime}', config.seekTime); // Replace seek time instances - html = _replaceAll(html, '{speed}', config.currentSpeed === 1 ? 'Normal' : config.currentSpeed.toFixed(1) + 'x'); + html = _replaceAll(html, '{speed}', config.currentSpeed.toFixed(1).toString().replace('.0', '') + '×'); // Replace current captions language html = _replaceAll(html, '{lang}', 'English'); @@ -2037,7 +2099,7 @@ if (_is.number(input)) { targetTime = input; - } else if (_is.object(input) && _inArray(['input', 'change'], input.type)) { + } else if (_is.event(input) && _inArray(['input', 'change'], input.type)) { // It's the seek slider // Seek to the selected time targetTime = ((input.target.value / input.target.max) * duration); @@ -3092,15 +3154,35 @@ // Captions _on(plyr.buttons.captions, 'click', _toggleCaptions); - // Menus - _on(plyr.controls.querySelectorAll('[aria-haspopup="true"]'), 'click', function() { - var toggle = this, - target = document.querySelector('#' + toggle.getAttribute('aria-controls')), + // Settings + /*_on(plyr.buttons.settings, 'click', function(event) { + var menu = this, + toggle = event.target, + target = document.getElementById(toggle.getAttribute('aria-controls')), + tabs = menu.querySelectorAll('[role="tabpanel"]'), show = (toggle.getAttribute('aria-expanded') === 'false'); + // Nothing to show, bail + if (!_is.htmlElement(target)) { + return; + } + + // Hide all other tabs + if (target.getAttribute('role') === 'tabpanel') { + [].forEach.call(tabs, function(tab) { + tab.setAttribute('aria-hidden', true); + tab.setAttribute('tabindex', -1); + + [].forEach.call(menu.querySelectorAll('[aria-controls="' + tab.getAttribute('id') + '"]'), function(toggle) { + toggle.setAttribute('aria-expanded', false); + }); + }); + } + toggle.setAttribute('aria-expanded', show); target.setAttribute('aria-hidden', !show); - }); + target.setAttribute('tabindex', 0); + });*/ // Seek tooltip _on(plyr.progress.container, 'mouseenter mouseleave mousemove', _updateSeekTooltip); diff --git a/src/less/plyr.less b/src/less/plyr.less index ae9fae0e..26c92b2d 100644 --- a/src/less/plyr.less +++ b/src/less/plyr.less @@ -473,8 +473,16 @@ position: relative; // Hide tooltip - button[aria-expanded='true'] .plyr__tooltip { - display: none; + button svg { + transition: transform .3s ease; + } + button[aria-expanded='true'] { + svg { + transform: rotate(45deg); + } + .plyr__tooltip { + display: none; + } } // The actual menu container @@ -492,49 +500,96 @@ color: @plyr-menu-color; font-size: @plyr-font-size-small; + // Arrow + &::after { + content: ""; + position: absolute; + top: 100%; + right: 15px; + height: 0; + width: 0; + border: 6px solid transparent; + border-top-color: @plyr-menu-bg; + } + ul { margin: 0; padding: 5px; list-style: none; } - button { display: flex; width: 100%; - padding: 10px 30px 10px 12px; + padding: @plyr-control-padding (@plyr-control-padding * 2); color: @plyr-menu-color; font-weight: 600; + user-select: none; + } + + // Buttons + .plyr__menu__btn::after { + content: ""; + position: absolute; + top: 50%; + transform: translateY(-50%); + border: 5px solid transparent; + } + .plyr__menu__btn--forward { + padding-right: ceil(@plyr-control-padding * 4); - // Arrow &::after { - content: ""; - position: absolute; - top: 50%; - transform: translateY(-50%); right: 5px; - border: 5px solid transparent; border-left-color: fade(@plyr-menu-color, 80%); } } + .plyr__menu__btn--back { + position: relative; + padding-top: floor(@plyr-control-padding * .7); + padding-bottom: floor(@plyr-control-padding * .7); + padding-left: ceil(@plyr-control-padding * 4); + margin-bottom: ceil(@plyr-control-padding * 1.3); + font-weight: 500; + + &::after { + left: 5px; + border-right-color: fade(@plyr-menu-color, 80%); + } + &::before { + content: ""; + position: absolute; + top: 100%; + left: 0; + right: 0; + height: 1px; + overflow: hidden; + margin-top: ceil(@plyr-control-padding / 2); + background: fade(#000, 15%); + box-shadow: 0 1px 0 fade(#fff, 10%); + } + } // Option value - .plyr__menu__value { + .plyr__menu__btn__value, + .plyr__menu__btn__badge { + display: inherit; margin-left: auto; - padding-left: 25px; + padding-left: ceil(@plyr-control-padding * 3.5); + pointer-events: none; + } + + // Option value + .plyr__menu__btn__value { font-weight: 500; color: fade(@plyr-menu-color, 80%); } - // Arrow - &::after { - content: ""; - position: absolute; - top: 100%; - right: 15px; - height: 0; - width: 0; - border: 6px solid transparent; - border-top-color: @plyr-menu-bg; + // Option value + .plyr__menu__btn__badge span { + padding: 2px 4px; + border-radius: 2px; + background: @plyr-menu-color; + color: @plyr-menu-bg; + font-size: 10px; } } } -- cgit v1.2.3 From ca37b4c9ac24b840a9e8e5930012c33da9a44682 Mon Sep 17 00:00:00 2001 From: Sam Date: Sun, 25 Sep 2016 23:54:49 +1000 Subject: Menu --- src/js/plyr.js | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) (limited to 'src') diff --git a/src/js/plyr.js b/src/js/plyr.js index bd79df0e..f6c98caa 100644 --- a/src/js/plyr.js +++ b/src/js/plyr.js @@ -3155,7 +3155,7 @@ _on(plyr.buttons.captions, 'click', _toggleCaptions); // Settings - /*_on(plyr.buttons.settings, 'click', function(event) { + _on(plyr.buttons.settings, 'click', function(event) { var menu = this, toggle = event.target, target = document.getElementById(toggle.getAttribute('aria-controls')), @@ -3182,7 +3182,7 @@ toggle.setAttribute('aria-expanded', show); target.setAttribute('aria-hidden', !show); target.setAttribute('tabindex', 0); - });*/ + }); // Seek tooltip _on(plyr.progress.container, 'mouseenter mouseleave mousemove', _updateSeekTooltip); -- cgit v1.2.3 From 1ad103c29fd5c92fc05c6a6d85c9d74e61b0fb54 Mon Sep 17 00:00:00 2001 From: Sam Date: Mon, 26 Sep 2016 23:21:57 +1000 Subject: Menu animation --- src/js/plyr.js | 200 +++++++++++++++++++++++++++++++---------------------- src/less/plyr.less | 19 +++++ 2 files changed, 135 insertions(+), 84 deletions(-) (limited to 'src') diff --git a/src/js/plyr.js b/src/js/plyr.js index f6c98caa..e24f258b 100644 --- a/src/js/plyr.js +++ b/src/js/plyr.js @@ -888,81 +888,83 @@ '' + config.i18n.settings + '', '', '' @@ -3159,7 +3161,6 @@ var menu = this, toggle = event.target, target = document.getElementById(toggle.getAttribute('aria-controls')), - tabs = menu.querySelectorAll('[role="tabpanel"]'), show = (toggle.getAttribute('aria-expanded') === 'false'); // Nothing to show, bail @@ -3167,21 +3168,52 @@ return; } + // Are we targetting a tab? + var isTab = target.getAttribute('role') === 'tabpanel', + targetWidth, + targetHeight, + container; + // Hide all other tabs - if (target.getAttribute('role') === 'tabpanel') { - [].forEach.call(tabs, function(tab) { - tab.setAttribute('aria-hidden', true); - tab.setAttribute('tabindex', -1); + if (isTab) { + // Get other tabs + var current = menu.querySelector('[role="tabpanel"][aria-hidden="false"]'); + container = current.parentNode; - [].forEach.call(menu.querySelectorAll('[aria-controls="' + tab.getAttribute('id') + '"]'), function(toggle) { - toggle.setAttribute('aria-expanded', false); - }); + [].forEach.call(menu.querySelectorAll('[aria-controls="' + current.getAttribute('id') + '"]'), function(toggle) { + toggle.setAttribute('aria-expanded', false); }); - } - toggle.setAttribute('aria-expanded', show); + container.style.width = current.scrollWidth + 'px'; + container.style.height = current.scrollHeight + 'px'; + + current.setAttribute('aria-hidden', true); + current.setAttribute('tabindex', -1); + + // Get the natural element size + var clone = target.cloneNode(true); + clone.style.position = "absolute"; + clone.style.opacity = 0; + clone.setAttribute('aria-hidden', false); + container.appendChild(clone); + targetWidth = clone.scrollWidth; + targetHeight = clone.scrollHeight; + _remove(clone); + } + target.setAttribute('aria-hidden', !show); + toggle.setAttribute('aria-expanded', show); target.setAttribute('tabindex', 0); + + if (isTab) { + container.style.width = targetWidth + 'px'; + container.style.height = targetHeight + 'px'; + + window.setTimeout(function() { + container.style.width = ''; + container.style.height = ''; + }, 300); + } }); // Seek tooltip diff --git a/src/less/plyr.less b/src/less/plyr.less index 26c92b2d..5ba916cd 100644 --- a/src/less/plyr.less +++ b/src/less/plyr.less @@ -492,14 +492,21 @@ right: -5px; margin-bottom: 10px; animation: plyr-popup .2s ease; + background: @plyr-menu-bg; box-shadow: 0 1px 0 fade(#000, 20%); border-radius: 4px; + white-space: nowrap; text-align: left; color: @plyr-menu-color; font-size: @plyr-font-size-small; + > div { + overflow: hidden; + transition: height .35s cubic-bezier(.4,0,.2,1), width .35s cubic-bezier(.4,0,.2,1); + } + // Arrow &::after { content: ""; @@ -516,6 +523,7 @@ margin: 0; padding: 5px; list-style: none; + overflow: hidden; } button { display: flex; @@ -575,6 +583,7 @@ margin-left: auto; padding-left: ceil(@plyr-control-padding * 3.5); pointer-events: none; + overflow: hidden; } // Option value @@ -591,6 +600,16 @@ color: @plyr-menu-bg; font-size: 10px; } + + // 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); + + ul { + //opacity: 0; + } + } } } -- cgit v1.2.3 From eba083153845a472629d3010bc8e348e34ecc4c9 Mon Sep 17 00:00:00 2001 From: Sam Date: Sat, 1 Oct 2016 22:07:01 +1000 Subject: Manually merged #385 --- src/js/plyr.js | 81 +++++++++++++++++++++++++++++++++++++++++++++------------- 1 file changed, 63 insertions(+), 18 deletions(-) (limited to 'src') diff --git a/src/js/plyr.js b/src/js/plyr.js index e24f258b..36e446f0 100644 --- a/src/js/plyr.js +++ b/src/js/plyr.js @@ -124,7 +124,8 @@ tabFocus: 'tab-focus' }, captions: { - defaultActive: false + defaultActive: false, + selectedIndex: 0 }, fullscreen: { enabled: true, @@ -437,13 +438,20 @@ } } - // Bind event + // Bind event handler function _on(element, events, callback, useCapture) { - if (element) { + if (_is.htmlElement(element)) { _toggleListener(element, events, callback, true, useCapture); } } + // Unbind event handler + function _off(element, events, callback, useCapture) { + if (_is.htmlElement(element)) { + _toggleListener(element, events, callback, false, useCapture); + } + } + // Trigger event function _event(element, type, bubbles, properties) { // Bail if no element @@ -1017,6 +1025,25 @@ } } + // Caption cue change helper event + /*function _captionCueChange() { + _setActiveCueForTrack(this); + }*/ + + // Display active caption if it contains text + function _setActiveCueForTrack(track) { + if (_is.event(track)) { + track = track.target; + } + + // Display a cue, if there is one + if (track.activeCues[0] && 'text' in track.activeCues[0]) { + _setCaption(track.activeCues[0].getCueAsHTML()); + } else { + _setCaption(); + } + } + // Setup captions function _setupCaptions() { // Bail if not HTML5 video @@ -1036,7 +1063,8 @@ } // Get URL of caption file if exists - var captionSrc = '', + var captionSources = [], + captionSrc = '', kind, children = plyr.media.childNodes; @@ -1044,17 +1072,21 @@ if (children[i].nodeName.toLowerCase() === 'track') { kind = children[i].kind; if (kind === 'captions' || kind === 'subtitles') { - captionSrc = children[i].getAttribute('src'); + captionSources.push(children[i].getAttribute('src')); } } } // Record if caption file exists or not plyr.captionExists = true; - if (captionSrc === '') { + if (captionSources.length === 0) { plyr.captionExists = false; _log('No caption track found'); + } else if ((config.captions.selectedIndex + 1) > captionSources.length) { + plyr.captionExists = false; + _log('Caption index out of bound'); } else { + captionSrc = captionSources[config.captions.selectedIndex]; _log('Caption track found; URI: ' + captionSrc); } @@ -1066,6 +1098,8 @@ // This doesn't seem to work in Safari 7+, so the elements are removed from the dom below var tracks = plyr.media.textTracks; for (var x = 0; x < tracks.length; x++) { + // Remove the listener to prevent event overlapping + _off(tracks[x], 'cuechange', _setActiveCueForTrack); tracks[x].mode = 'hidden'; } @@ -1089,20 +1123,16 @@ if (plyr.usingTextTracks) { _log('TextTracks supported'); - for (var y = 0; y < tracks.length; y++) { - var track = tracks[y]; + var track = tracks[config.captions.selectedIndex]; - if (track.kind === 'captions' || track.kind === 'subtitles') { - _on(track, 'cuechange', function() { - // Display a cue, if there is one - if (this.activeCues[0] && 'text' in this.activeCues[0]) { - _setCaption(this.activeCues[0].getCueAsHTML()); - } else { - _setCaption(); - } - }); + if (track.kind === 'captions' || track.kind === 'subtitles') { + _on(track, 'cuechange', _setActiveCueForTrack); + + // if we change the active track while a cue is already displayed we need to update it + if (track.activeCues && track.activeCues.length > 0) { + _setActiveCueForTrack(track); } - } + } } else { // Caption tracks not natively supported _log('TextTracks not supported so rendering captions manually'); @@ -2425,6 +2455,20 @@ _updateStorage({captionsEnabled: plyr.captionsEnabled}); } + // Select active caption + function _setCaptionIndex(index){ + + //save active caption + config.captions.selectedIndex = index; + + // clear caption + _setCaption(); + + // re-run setup + _setupCaptions(); + + } + // Check if media is loading function _checkLoading(event) { var loading = (event.type === 'waiting'); @@ -3615,6 +3659,7 @@ toggleCaptions: _toggleCaptions, toggleFullscreen: _toggleFullscreen, toggleControls: _toggleControls, + setCaptionIndex: _setCaptionIndex, isFullscreen: function() { return plyr.isFullscreen || false; }, support: function(mimeType) { return _support.mime(plyr, mimeType); }, destroy: _destroy -- cgit v1.2.3 From 8743c6a08d68ef0648ad0a4a59b3dc2b4dcf2e7c Mon Sep 17 00:00:00 2001 From: Sam Date: Sat, 1 Oct 2016 22:18:01 +1000 Subject: Code style --- src/js/plyr.js | 12 +++++------- 1 file changed, 5 insertions(+), 7 deletions(-) (limited to 'src') diff --git a/src/js/plyr.js b/src/js/plyr.js index 36e446f0..cdd23927 100644 --- a/src/js/plyr.js +++ b/src/js/plyr.js @@ -1132,7 +1132,7 @@ if (track.activeCues && track.activeCues.length > 0) { _setActiveCueForTrack(track); } - } + } } else { // Caption tracks not natively supported _log('TextTracks not supported so rendering captions manually'); @@ -2456,17 +2456,15 @@ } // Select active caption - function _setCaptionIndex(index){ - - //save active caption + function _setCaptionIndex(index) { + // Save active caption config.captions.selectedIndex = index; - // clear caption + // Clear caption _setCaption(); - // re-run setup + // Re-run setup _setupCaptions(); - } // Check if media is loading -- cgit v1.2.3 From 21a30f1b6fd3f95550ea37fc610b94ea9e688899 Mon Sep 17 00:00:00 2001 From: Sam Potts Date: Mon, 3 Oct 2016 17:16:05 +1100 Subject: Fixed for array passed to _on and _off --- src/js/plyr.js | 37 ++++++++++++++++++------------------- src/less/variables.less | 2 +- 2 files changed, 19 insertions(+), 20 deletions(-) (limited to 'src') diff --git a/src/js/plyr.js b/src/js/plyr.js index 2ce6cd3b..f42e7641 100644 --- a/src/js/plyr.js +++ b/src/js/plyr.js @@ -440,14 +440,14 @@ // Bind event handler function _on(element, events, callback, useCapture) { - if (_is.htmlElement(element)) { + if (!_is.undefined(element)) { _toggleListener(element, events, callback, true, useCapture); } } // Unbind event handler function _off(element, events, callback, useCapture) { - if (_is.htmlElement(element)) { + if (!_is.undefined(element)) { _toggleListener(element, events, callback, false, useCapture); } } @@ -1025,13 +1025,9 @@ } } - // Caption cue change helper event - /*function _captionCueChange() { - _setActiveCueForTrack(this); - }*/ - // Display active caption if it contains text - function _setActiveCueForTrack(track) { + function _setActiveCue(track) { + // Get the track from the event if needed if (_is.event(track)) { track = track.target; } @@ -1094,14 +1090,17 @@ if (!plyr.captionExists) { _toggleClass(plyr.container, config.classes.captions.enabled); } else { + var tracks = plyr.media.textTracks; + // Turn off native caption rendering to avoid double captions // This doesn't seem to work in Safari 7+, so the elements are removed from the dom below - var tracks = plyr.media.textTracks; - for (var x = 0; x < tracks.length; x++) { + [].forEach.call(tracks, function(track) { // Remove the listener to prevent event overlapping - _off(tracks[x], 'cuechange', _setActiveCueForTrack); - tracks[x].mode = 'hidden'; - } + _off(track, 'cuechange', _setActiveCue); + + // Hide captions + track.mode = 'hidden'; + }); // Enable UI _showCaptions(plyr); @@ -1126,11 +1125,11 @@ var track = tracks[config.captions.selectedIndex]; if (track.kind === 'captions' || track.kind === 'subtitles') { - _on(track, 'cuechange', _setActiveCueForTrack); + _on(track, 'cuechange', _setActiveCue); - // if we change the active track while a cue is already displayed we need to update it + // If we change the active track while a cue is already displayed we need to update it if (track.activeCues && track.activeCues.length > 0) { - _setActiveCueForTrack(track); + _setActiveCue(track); } } } else { @@ -1155,15 +1154,15 @@ //According to webvtt spec, line terminator consists of one of the following // CRLF (U+000D U+000A), LF (U+000A) or CR (U+000D) var lineSeparator = '\r\n'; - if(req.indexOf(lineSeparator+lineSeparator) === -1) { - if(req.indexOf('\r\r') !== -1){ + if (req.indexOf(lineSeparator + lineSeparator) === -1) { + if (req.indexOf('\r\r') !== -1) { lineSeparator = '\r'; } else { lineSeparator = '\n'; } } - captions = req.split(lineSeparator+lineSeparator); + captions = req.split(lineSeparator + lineSeparator); for (var r = 0; r < captions.length; r++) { caption = captions[r]; diff --git a/src/less/variables.less b/src/less/variables.less index c7eab243..bea9a0f7 100644 --- a/src/less/variables.less +++ b/src/less/variables.less @@ -17,7 +17,7 @@ @plyr-font-size-base: 16px; // Captions -@plyr-captions-bg: fade(#343f4a, 85%); +@plyr-captions-bg: fade(#000, 85%); @plyr-captions-color: #fff; @plyr-font-size-captions-base: @plyr-font-size-base; @plyr-font-size-captions-medium: ceil(@plyr-font-size-base * 1.5); -- cgit v1.2.3 From 90338d96000dcebd89fcb7f10d09afe0522cd1c0 Mon Sep 17 00:00:00 2001 From: Sam Date: Sun, 23 Oct 2016 21:15:19 +1100 Subject: Tweaks --- src/js/plyr.js | 25 +++++++++++-------------- 1 file changed, 11 insertions(+), 14 deletions(-) (limited to 'src') diff --git a/src/js/plyr.js b/src/js/plyr.js index 2ce6cd3b..711c4555 100644 --- a/src/js/plyr.js +++ b/src/js/plyr.js @@ -1064,18 +1064,15 @@ // Get URL of caption file if exists var captionSources = [], - captionSrc = '', - kind, - children = plyr.media.childNodes; - - for (var i = 0; i < children.length; i++) { - if (children[i].nodeName.toLowerCase() === 'track') { - kind = children[i].kind; - if (kind === 'captions' || kind === 'subtitles') { - captionSources.push(children[i].getAttribute('src')); + captionSrc = ''; + + plyr.media.childNodes.forEach(function(child) { + if (child.nodeName.toLowerCase() === 'track') { + if (child.kind === 'captions' || child.kind === 'subtitles') { + captionSources.push(child.getAttribute('src')); } } - } + }); // Record if caption file exists or not plyr.captionExists = true; @@ -1152,18 +1149,18 @@ caption, req = xhr.responseText; - //According to webvtt spec, line terminator consists of one of the following + // According to webvtt spec, line terminator consists of one of the following // CRLF (U+000D U+000A), LF (U+000A) or CR (U+000D) var lineSeparator = '\r\n'; - if(req.indexOf(lineSeparator+lineSeparator) === -1) { - if(req.indexOf('\r\r') !== -1){ + if (req.indexOf(lineSeparator + lineSeparator) === -1) { + if (req.indexOf('\r\r') !== -1){ lineSeparator = '\r'; } else { lineSeparator = '\n'; } } - captions = req.split(lineSeparator+lineSeparator); + captions = req.split(lineSeparator + lineSeparator); for (var r = 0; r < captions.length; r++) { caption = captions[r]; -- cgit v1.2.3 From 801ed63be5e415e76d989ee96cf18e95a86ef82f Mon Sep 17 00:00:00 2001 From: Sam Potts Date: Sun, 23 Oct 2016 21:21:42 +1100 Subject: Work on PiP --- src/js/plyr.js | 109 +++++++++++++++++++++++++++++++------------- src/sprite/plyr-airplay.svg | 7 +++ src/sprite/plyr-pip.svg | 7 +++ 3 files changed, 91 insertions(+), 32 deletions(-) create mode 100644 src/sprite/plyr-airplay.svg create mode 100644 src/sprite/plyr-pip.svg (limited to 'src') diff --git a/src/js/plyr.js b/src/js/plyr.js index 7eb72067..48ee8e63 100644 --- a/src/js/plyr.js +++ b/src/js/plyr.js @@ -78,7 +78,9 @@ mute: '[data-plyr="mute"]', captions: '[data-plyr="captions"]', fullscreen: '[data-plyr="fullscreen"]', - settings: '[data-plyr="settings"]' + settings: '[data-plyr="settings"]', + pip: '[data-plyr="pip"]', + airplay: '[data-plyr="airplay"]' }, volume: { input: '[data-plyr="volume"]', @@ -136,7 +138,7 @@ enabled: true, key: 'plyr' }, - controls: ['play-large', 'play', 'progress', 'current-time', 'mute', 'volume', 'settings', 'fullscreen'], + controls: ['play-large', 'play', 'progress', 'current-time', 'mute', 'volume', 'settings', 'pip', 'airplay', 'fullscreen'], i18n: { restart: 'Restart', rewind: 'Rewind {seektime} secs', @@ -677,9 +679,15 @@ })(), // Picture-in-picture support // Safari only currently - pip: function(plyr) { - return _is.function(plyr.media.webkitSetPresentationMode); - }, + pip: (function() { + var video = document.createElement('video'); + return _is.function(video.webkitSetPresentationMode); + })(), + // Airplay support + // Safari only currently + airplay: (function() { + return _is.function(window.WebKitPlaybackTargetAvailabilityEvent); + })(), // Check for mime type support against a player instance // Credits: http://diveintohtml5.info/everything.html // Related: http://www.leanbackplyr.com/test/h5mt.html @@ -979,6 +987,27 @@ ); } + // Picture in picture button + console.log(_support.pip); + if (_inArray(config.controls, 'pip') && _support.pip) { + html.push( + '' + ); + } + + // Airplay button + if (_inArray(config.controls, 'airplay') && _support.airplay) { + html.push( + '' + ); + } + // Toggle fullscreen button if (_inArray(config.controls, 'fullscreen')) { html.push( @@ -1447,52 +1476,61 @@ // Find the UI controls and store references function _findElements() { try { - plyr.controls = _getElement(config.selectors.controls.wrapper); + plyr.controls = _getElement(config.selectors.controls.wrapper); // Buttons - plyr.buttons = {}; - plyr.buttons.seek = _getElement(config.selectors.buttons.seek); - plyr.buttons.play = _getElements(config.selectors.buttons.play); - plyr.buttons.pause = _getElement(config.selectors.buttons.pause); - plyr.buttons.restart = _getElement(config.selectors.buttons.restart); - plyr.buttons.rewind = _getElement(config.selectors.buttons.rewind); - plyr.buttons.forward = _getElement(config.selectors.buttons.forward); - plyr.buttons.fullscreen = _getElement(config.selectors.buttons.fullscreen); - plyr.buttons.settings = _getElement(config.selectors.buttons.settings); + plyr.buttons = { + seek: _getElement(config.selectors.buttons.seek), + play: _getElements(config.selectors.buttons.play), + pause: _getElement(config.selectors.buttons.pause), + restart: _getElement(config.selectors.buttons.restart), + rewind: _getElement(config.selectors.buttons.rewind), + forward: _getElement(config.selectors.buttons.forward), + fullscreen: _getElement(config.selectors.buttons.fullscreen), + settings: _getElement(config.selectors.buttons.settings), + pip: _getElement(config.selectors.buttons.pip) + }; // Inputs - plyr.buttons.mute = _getElement(config.selectors.buttons.mute); - plyr.buttons.captions = _getElement(config.selectors.buttons.captions); + plyr.buttons.mute = _getElement(config.selectors.buttons.mute); + plyr.buttons.captions = _getElement(config.selectors.buttons.captions); // Progress - plyr.progress = {}; - plyr.progress.container = _getElement(config.selectors.progress.container); + plyr.progress = { + container: _getElement(config.selectors.progress.container) + }; // Progress - Buffering - plyr.progress.buffer = {}; - plyr.progress.buffer.bar = _getElement(config.selectors.progress.buffer); - plyr.progress.buffer.text = plyr.progress.buffer.bar && plyr.progress.buffer.bar.getElementsByTagName('span')[0]; + plyr.progress.buffer = (function() { + var bar = _getElement(config.selectors.progress.buffer); + + return { + bar: bar, + text: _is.htmlElement(bar) && bar.getElementsByTagName('span')[0] + }; + })(); // Progress - Played - plyr.progress.played = _getElement(config.selectors.progress.played); + plyr.progress.played = _getElement(config.selectors.progress.played); // Seek tooltip - plyr.progress.tooltip = plyr.progress.container && plyr.progress.container.querySelector('.' + config.classes.tooltip); + plyr.progress.tooltip = plyr.progress.container && plyr.progress.container.querySelector('.' + config.classes.tooltip); // Volume - plyr.volume = {}; - plyr.volume.input = _getElement(config.selectors.volume.input); - plyr.volume.display = _getElement(config.selectors.volume.display); + plyr.volume = { + input: _getElement(config.selectors.volume.input), + display: _getElement(config.selectors.volume.display) + }; // Timing - plyr.duration = _getElement(config.selectors.duration); - plyr.currentTime = _getElement(config.selectors.currentTime); - plyr.seekTime = _getElements(config.selectors.seekTime); + plyr.duration = _getElement(config.selectors.duration); + plyr.currentTime = _getElement(config.selectors.currentTime); + plyr.seekTime = _getElements(config.selectors.seekTime); return true; } catch(e) { - _warn('It looks like there is a problem with your controls HTML'); + _warn('It looks like there is a problem with your controls HTML', e); // Restore native video controls _toggleNativeControls(true); @@ -1606,7 +1644,7 @@ } // Check for picture-in-picture support - _toggleClass(plyr.container, config.classes.pip.enabled, _support.pip(plyr)); + _toggleClass(plyr.container, config.classes.pip.enabled, _support.pip); // If there's no autoplay attribute, assume the video is stopped and add state class _toggleClass(plyr.container, config.classes.stopped, config.autoplay); @@ -3276,6 +3314,13 @@ } }); + // Picture in picture + _on(plyr.buttons.pip, 'click', function() { + //if () + + plyr.media.webkitSetPresentationMode(plyr.media.webkitPresentationMode === 'optimized' ? 'inline' : 'optimized'); + }); + // Seek tooltip _on(plyr.progress.container, 'mouseenter mouseleave mousemove', _updateSeekTooltip); diff --git a/src/sprite/plyr-airplay.svg b/src/sprite/plyr-airplay.svg new file mode 100644 index 00000000..45c55414 --- /dev/null +++ b/src/sprite/plyr-airplay.svg @@ -0,0 +1,7 @@ + + + + + + + \ No newline at end of file diff --git a/src/sprite/plyr-pip.svg b/src/sprite/plyr-pip.svg new file mode 100644 index 00000000..d841fce5 --- /dev/null +++ b/src/sprite/plyr-pip.svg @@ -0,0 +1,7 @@ + + + + + + + \ No newline at end of file -- cgit v1.2.3 From c7310c21fbc3634c375c5dab72de55d12fc64df9 Mon Sep 17 00:00:00 2001 From: Sam Date: Mon, 24 Oct 2016 00:11:47 +1100 Subject: Fullscreen fix, styling --- src/js/plyr.js | 29 +++++++++++++++++------------ src/less/plyr.less | 6 +++--- src/scss/plyr.scss | 6 +++--- 3 files changed, 23 insertions(+), 18 deletions(-) (limited to 'src') diff --git a/src/js/plyr.js b/src/js/plyr.js index 36b99fd2..e21c5ab7 100644 --- a/src/js/plyr.js +++ b/src/js/plyr.js @@ -581,22 +581,25 @@ (function() { // Determine the prefix var prefix = (function() { - if (!_is.undefined(document.cancelFullScreen)) { - return ''; + var value = false; + + if (_is.function(document.cancelFullScreen)) { + value = ''; } else { // Check for fullscreen support by vendor prefix - ['webkit', 'o', 'moz', 'ms', 'khtml'].forEach(function(prefix) { - if (!_is.undefined(document[prefix + 'CancelFullScreen'])) { - return prefix; - } else if (!_is.undefined(document.msExitFullscreen) && document.msFullscreenEnabled) { + ['webkit', 'o', 'moz', 'ms', 'khtml'].some(function(prefix) { + if (_is.function(document[prefix + 'CancelFullScreen'])) { + value = prefix; + return true; + } else if (_is.function(document.msExitFullscreen) && document.msFullscreenEnabled) { // Special case for MS (when isn't it?) - return 'ms'; + value = 'ms'; + return true; } }); } - // If we got this far, there's no support - return false; + return value; })(); _fullscreen = { @@ -625,9 +628,12 @@ if (!_support.fullscreen) { return false; } - if (_is.undefined(element)) { + if (!_is.htmlElement(element)) { element = document.body; } + + console.log(prefix); + return (prefix === '') ? element.requestFullScreen() : element[prefix + (prefix === 'ms' ? 'RequestFullscreen' : 'RequestFullScreen')](); }, cancelFullScreen: function() { @@ -988,7 +994,6 @@ } // Picture in picture button - console.log(_support.pip); if (_inArray(config.controls, 'pip') && _support.pip) { html.push( '' @@ -816,7 +816,7 @@ // Rewind button if (_inArray(config.controls, 'rewind')) { html.push( - '' @@ -827,11 +827,11 @@ // TODO: This should be a toggle button really? if (_inArray(config.controls, 'play')) { html.push( - '', - '' @@ -841,7 +841,7 @@ // Fast forward button if (_inArray(config.controls, 'fast-forward')) { html.push( - '' @@ -891,7 +891,7 @@ // Toggle mute button if (_inArray(config.controls, 'mute')) { html.push( - '', @@ -934,18 +934,18 @@ '
    ', '
      ', '
    • ', - '', '
    • ', '
    • ', - '', '
    • ', '
    • ', - '', '
    • ', '
    ', @@ -953,59 +953,95 @@ '', '', '', '
    ', '
    ', @@ -1016,7 +1052,7 @@ // Picture in picture button if (_inArray(config.controls, 'pip') && _support.pip) { html.push( - '' @@ -1026,7 +1062,7 @@ // Airplay button if (_inArray(config.controls, 'airplay') && _support.airplay) { html.push( - '' @@ -1036,7 +1072,7 @@ // Toggle fullscreen button if (_inArray(config.controls, 'fullscreen')) { html.push( - '' ); + /* beautify ignore:end */ } html.push('
    '); // Restart button if (_inArray(config.controls, 'restart')) { + /* beautify ignore:start */ html.push( '' ); + /* beautify ignore:end */ } // Rewind button if (_inArray(config.controls, 'rewind')) { + /* beautify ignore:start */ html.push( '' ); + /* beautify ignore:end */ } // Play Pause button // TODO: This should be a toggle button really? if (_inArray(config.controls, 'play')) { + /* beautify ignore:start */ html.push( '' ); + /* beautify ignore:end */ } // Fast forward button if (_inArray(config.controls, 'fast-forward')) { + /* beautify ignore:start */ html.push( '' ); + /* beautify ignore:end */ } // Progress if (_inArray(config.controls, 'progress')) { // Create progress - html.push('', - '', - '', - '', - '', + /* beautify ignore:start */ + html.push( + '', + '', + '', + '', + '', '0% ' + config.i18n.buffered, - ''); + '' + ); + /* beautify ignore:end */ // Seek tooltip if (config.tooltips.seek) { @@ -871,26 +904,31 @@ // Media current time display if (_inArray(config.controls, 'current-time')) { + /* beautify ignore:start */ html.push( '', '' + config.i18n.currentTime + '', '00:00', '' ); + /* beautify ignore:end */ } // Media duration display if (_inArray(config.controls, 'duration')) { + /* beautify ignore:start */ html.push( '', '' + config.i18n.duration + '', '00:00', '' ); + /* beautify ignore:end */ } // Toggle mute button if (_inArray(config.controls, 'mute')) { + /* beautify ignore:start */ html.push( '' ); + /* beautify ignore:end */ } // Volume range control if (_inArray(config.controls, 'volume')) { + /* beautify ignore:start */ html.push( '', '', @@ -909,21 +949,25 @@ '', '' ); + /* beautify ignore:end */ } // Toggle captions button if (_inArray(config.controls, 'captions')) { + /* beautify ignore:start */ html.push( '' ); + /* beautify ignore:end */ } // Settings button / menu if (_inArray(config.controls, 'settings')) { + /* beautify ignore:start */ html.push( '
    ', '', '', '
  • ', '', '
  • ', '
  • ', '', '
  • ', '', @@ -964,7 +1011,7 @@ '
  • ', '', '
  • ', - '', + '', '
    ', '', '', '
    ' ); + /* beautify ignore:end */ } // Picture in picture button if (_inArray(config.controls, 'pip') && _support.pip) { + /* beautify ignore:start */ html.push( '' ); + /* beautify ignore:end */ } // Airplay button if (_inArray(config.controls, 'airplay') && _support.airplay) { + /* beautify ignore:start */ html.push( '' ); + /* beautify ignore:end */ } // Toggle fullscreen button if (_inArray(config.controls, 'fullscreen')) { + /* beautify ignore:start */ html.push( '' ); + /* beautify ignore:end */ } // Close everything @@ -1238,7 +1292,7 @@ var captions = [], caption, req = xhr.responseText; - + // According to webvtt spec, line terminator consists of one of the following // CRLF (U+000D U+000A), LF (U+000A) or CR (U+000D) var lineSeparator = '\r\n'; @@ -1249,11 +1303,11 @@ lineSeparator = '\n'; } } - + captions = req.split(lineSeparator + lineSeparator); var numOfAvailableCaptions = 0; - + for (var r = 0; r < captions.length; r++) { caption = captions[r]; @@ -1264,7 +1318,7 @@ // Incase caption numbers are added if (parts[index].indexOf(":") !== -1) { plyr.captions[numOfAvailableCaptions] = [parts[index], parts[index + 1]]; - numOfAvailableCaptions ++; + numOfAvailableCaptions++; } } @@ -1318,19 +1372,22 @@ function _timecodeCommon(tc, pos) { var tcpair = []; tcpair = tc.split(' --> '); - for(var i = 0; i < tcpair.length; i++) { + for (var i = 0; i < tcpair.length; i++) { // WebVTT allows for extra meta data after the timestamp line // So get rid of this if it exists tcpair[i] = tcpair[i].replace(/(\d+:\d+:\d+\.\d+).*/, "$1"); } return _subTcSecs(tcpair[pos]); } + function _timecodeMin(tc) { return _timecodeCommon(tc, 0); } + function _timecodeMax(tc) { return _timecodeCommon(tc, 1); } + function _subTcSecs(tc) { if (tc === null || tc === undefined) { return 0; @@ -1342,9 +1399,9 @@ tc2 = tc1[0].split(':'); for (var i = 0, len = tc2.length; i < len; i++) { - seconds += Math.floor(tc2[i]*(Math.pow(60, len-(i+1)))); + seconds += Math.floor(tc2[i] * (Math.pow(60, len - (i + 1)))); } - + return seconds; } } @@ -1378,7 +1435,7 @@ // Check if the next caption is in the current time range if (plyr.media.currentTime.toFixed(1) >= _timecodeMin(plyr.captions[plyr.subcount][0]) && plyr.media.currentTime.toFixed(1) <= _timecodeMax(plyr.captions[plyr.subcount][0])) { - plyr.currentCaption = plyr.captions[plyr.subcount][1]; + plyr.currentCaption = plyr.captions[plyr.subcount][1]; // Render the caption _setCaption(plyr.currentCaption); @@ -1424,17 +1481,16 @@ function _inFrame() { try { return window.self !== window.top; - } - catch (e) { + } catch (e) { return true; } } // Trap focus inside container function _focusTrap() { - var tabbables = _getElements('input:not([disabled]), button:not([disabled])'), - first = tabbables[0], - last = tabbables[tabbables.length - 1]; + var tabbables = _getElements('input:not([disabled]), button:not([disabled])'), + first = tabbables[0], + last = tabbables[tabbables.length - 1]; function _checkFocus(event) { // If it is TAB @@ -1458,7 +1514,9 @@ // Add elements to HTML5 media (source, tracks, etc) function _insertChildElements(type, attributes) { if (_is.string(attributes)) { - _insertElement(type, plyr.media, { src: attributes }); + _insertElement(type, plyr.media, { + src: attributes + }); } else if (attributes.constructor === Array) { for (var i = attributes.length - 1; i >= 0; i--) { _insertElement(type, plyr.media, attributes[i]); @@ -1536,28 +1594,28 @@ // Find the UI controls and store references function _findElements() { try { - plyr.controls = _getElement(config.selectors.controls.wrapper); + plyr.controls = _getElement(config.selectors.controls.wrapper); // Buttons plyr.buttons = { - seek: _getElement(config.selectors.buttons.seek), - play: _getElements(config.selectors.buttons.play), - pause: _getElement(config.selectors.buttons.pause), - restart: _getElement(config.selectors.buttons.restart), - rewind: _getElement(config.selectors.buttons.rewind), - forward: _getElement(config.selectors.buttons.forward), - fullscreen: _getElement(config.selectors.buttons.fullscreen), - settings: _getElement(config.selectors.buttons.settings), - pip: _getElement(config.selectors.buttons.pip) + seek: _getElement(config.selectors.buttons.seek), + play: _getElements(config.selectors.buttons.play), + pause: _getElement(config.selectors.buttons.pause), + restart: _getElement(config.selectors.buttons.restart), + rewind: _getElement(config.selectors.buttons.rewind), + forward: _getElement(config.selectors.buttons.forward), + fullscreen: _getElement(config.selectors.buttons.fullscreen), + settings: _getElement(config.selectors.buttons.settings), + pip: _getElement(config.selectors.buttons.pip) }; // Inputs - plyr.buttons.mute = _getElement(config.selectors.buttons.mute); - plyr.buttons.captions = _getElement(config.selectors.buttons.captions); + plyr.buttons.mute = _getElement(config.selectors.buttons.mute); + plyr.buttons.captions = _getElement(config.selectors.buttons.captions); // Progress plyr.progress = { - container: _getElement(config.selectors.progress.container) + container: _getElement(config.selectors.progress.container) }; // Progress - Buffering @@ -1565,31 +1623,30 @@ var bar = _getElement(config.selectors.progress.buffer); return { - bar: bar, - text: _is.htmlElement(bar) && bar.getElementsByTagName('span')[0] + bar: bar, + text: _is.htmlElement(bar) && bar.getElementsByTagName('span')[0] }; })(); // Progress - Played - plyr.progress.played = _getElement(config.selectors.progress.played); + plyr.progress.played = _getElement(config.selectors.progress.played); // Seek tooltip - plyr.progress.tooltip = plyr.progress.container && plyr.progress.container.querySelector('.' + config.classes.tooltip); + plyr.progress.tooltip = plyr.progress.container && plyr.progress.container.querySelector('.' + config.classes.tooltip); // Volume plyr.volume = { - input: _getElement(config.selectors.volume.input), - display: _getElement(config.selectors.volume.display) + input: _getElement(config.selectors.volume.input), + display: _getElement(config.selectors.volume.display) }; // Timing - plyr.duration = _getElement(config.selectors.duration); - plyr.currentTime = _getElement(config.selectors.currentTime); - plyr.seekTime = _getElements(config.selectors.seekTime); + plyr.duration = _getElement(config.selectors.duration); + plyr.currentTime = _getElement(config.selectors.currentTime); + plyr.seekTime = _getElements(config.selectors.seekTime); return true; - } - catch(e) { + } catch (e) { _warn('It looks like there is a problem with your controls HTML', e); // Restore native video controls @@ -1664,7 +1721,9 @@ // If value is a number, it's probably volume from an older // version of plyr. See: https://github.com/Selz/plyr/pull/313 // Update the key to be JSON - _updateStorage({volume: parseFloat(value)}); + _updateStorage({ + volume: parseFloat(value) + }); } else { // Assume it's JSON from this or a later version of plyr plyr.storage = JSON.parse(value); @@ -1710,7 +1769,7 @@ _toggleClass(plyr.container, config.classes.stopped, config.autoplay); // Add iOS class - _toggleClass(plyr.ontainer, config.classes.isIos, plyr.browser.isIos); + _toggleClass(plyr.container, config.classes.isIos, plyr.browser.isIos); // Add touch class _toggleClass(plyr.container, config.classes.isTouch, plyr.browser.isTouch); @@ -1751,7 +1810,7 @@ mediaId = _parseVimeoId(plyr.embedId); break; - default: + default: mediaId = plyr.embedId; } @@ -1783,11 +1842,15 @@ window.onYouTubeReadyCallbacks = window.onYouTubeReadyCallbacks || []; // Add to queue - window.onYouTubeReadyCallbacks.push(function() { _youTubeReady(mediaId, container); }); + window.onYouTubeReadyCallbacks.push(function() { + _youTubeReady(mediaId, container); + }); // Set callback to process queue - window.onYouTubeIframeAPIReady = function () { - window.onYouTubeReadyCallbacks.forEach(function(callback) { callback(); }); + window.onYouTubeIframeAPIReady = function() { + window.onYouTubeReadyCallbacks.forEach(function(callback) { + callback(); + }); }; } } else if (plyr.type === 'vimeo') { @@ -1822,11 +1885,13 @@ // Watch for iframe load soundCloud.loaded = false; - _on(soundCloud, 'load', function() { soundCloud.loaded = true; }); + _on(soundCloud, 'load', function() { + soundCloud.loaded = true; + }); _setAttributes(soundCloud, { - 'src': 'https://w.soundcloud.com/player/?url=https://api.soundcloud.com/tracks/' + mediaId, - 'id': id + 'src': 'https://w.soundcloud.com/player/?url=https://api.soundcloud.com/tracks/' + mediaId, + 'id': id }); container.appendChild(soundCloud); @@ -1866,23 +1931,23 @@ plyr.embed = new window.YT.Player(container.id, { videoId: videoId, playerVars: { - autoplay: (config.autoplay ? 1 : 0), - controls: (plyr.supported.full ? 0 : 1), - rel: 0, - showinfo: 0, + autoplay: (config.autoplay ? 1 : 0), + controls: (plyr.supported.full ? 0 : 1), + rel: 0, + showinfo: 0, iv_load_policy: 3, cc_load_policy: (config.captions.defaultActive ? 1 : 0), - cc_lang_pref: 'en', - wmode: 'transparent', + cc_lang_pref: 'en', + wmode: 'transparent', modestbranding: 1, - disablekb: 1, - origin: '*' // https://code.google.com/p/gdata-issues/issues/detail?id=5788#c45 + disablekb: 1, + origin: '*' // https://code.google.com/p/gdata-issues/issues/detail?id=5788#c45 }, events: { 'onError': function(event) { _triggerEvent(plyr.container, 'error', true, { - code: event.data, - embed: event.target + code: event.data, + embed: event.target }); }, 'onPlaybackQualityChange': function(event) { @@ -1890,7 +1955,7 @@ var instance = event.target; var quality = instance.getPlaybackQuality(); - + // var set = instance.setPlaybackQuality(); console.warn(quality); }, @@ -2038,12 +2103,12 @@ // Setup instance // https://github.com/vimeo/player.js plyr.embed = new window.Vimeo.Player(container, { - id: parseInt(mediaId), - loop: config.loop, - autoplay: config.autoplay, - byline: false, - portrait: false, - title: false + id: parseInt(mediaId), + loop: config.loop, + autoplay: config.autoplay, + byline: false, + portrait: false, + title: false }); // Create a faux HTML5 API using the Vimeo API @@ -2059,7 +2124,7 @@ plyr.embed.stop(); plyr.media.paused = true; }; - + plyr.media.paused = true; plyr.media.currentTime = 0; @@ -2075,7 +2140,7 @@ plyr.embed.getDuration().then(function(value) { plyr.media.duration = value; - + // Trigger timeupdate _triggerEvent(plyr.media, 'durationchange'); }); @@ -2138,7 +2203,7 @@ plyr.embed = window.SC.Widget(this); // Setup on ready - plyr.embed.bind(window.SC.Widget.Events.READY, function() { + plyr.embed.bind(window.SC.Widget.Events.READY, function() { // Create a faux HTML5 API using the Soundcloud API plyr.media.play = function() { plyr.embed.play(); @@ -2158,7 +2223,7 @@ plyr.media.currentTime = 0; plyr.embed.getDuration(function(value) { - plyr.media.duration = value/1000; + plyr.media.duration = value / 1000; // Update UI _embedReady(); @@ -2184,7 +2249,7 @@ plyr.embed.bind(window.SC.Widget.Events.PLAY_PROGRESS, function(data) { plyr.media.seeking = false; - plyr.media.currentTime = data.currentPosition/1000; + plyr.media.currentTime = data.currentPosition / 1000; _triggerEvent(plyr.media, 'timeupdate'); }); @@ -2280,15 +2345,17 @@ plyr.media.playbackRate = speed; // Save speed to localStorage - _updateStorage({speed: speed}); + _updateStorage({ + speed: speed + }); } // Seek to time // The input parameter can be an event or a number function _seek(input) { - var targetTime = 0, - paused = plyr.media.paused, - duration = _getDuration(); + var targetTime = 0, + paused = plyr.media.paused, + duration = _getDuration(); if (_is.number(input)) { targetTime = input; @@ -2305,19 +2372,18 @@ targetTime = duration; } - // Update seek range and progress + // Update seek range and progress _updateSeekDisplay(targetTime); // Set the current time // Try/catch incase the media isn't set and we're calling seek() from source() and IE moans try { plyr.media.currentTime = targetTime.toFixed(4); - } - catch(e) {} + } catch (e) {} // Embeds if (_inArray(config.types.embed, plyr.type)) { - switch(plyr.type) { + switch (plyr.type) { case 'youtube': plyr.embed.seekTo(targetTime); break; @@ -2358,8 +2424,8 @@ // It should be a number, but parse it just incase var duration = parseInt(config.duration), - // True duration - mediaDuration = 0; + // True duration + mediaDuration = 0; // Only if duration available if (plyr.media.duration !== null && !isNaN(plyr.media.duration)) { @@ -2396,7 +2462,7 @@ function _toggleFullscreen(event) { // Check for native support var nativeSupport = _support.fullscreen; - + if (nativeSupport) { // If it's a fullscreen change event, update the UI if (event && event.type === _fullscreen.eventType) { @@ -2468,7 +2534,7 @@ // Embeds if (_inArray(config.types.embed, plyr.type)) { // YouTube - switch(plyr.type) { + switch (plyr.type) { case 'youtube': plyr.embed[plyr.media.muted ? 'mute' : 'unMute'](); break; @@ -2518,7 +2584,7 @@ // Embeds if (_inArray(config.types.embed, plyr.type)) { - switch(plyr.type) { + switch (plyr.type) { case 'youtube': plyr.embed.setVolume(plyr.media.volume * 100); break; @@ -2579,7 +2645,9 @@ } // Update the volume in storage - _updateStorage({volume: volume}); + _updateStorage({ + volume: volume + }); // Toggle class if muted _toggleClass(plyr.container, config.classes.muted, (volume === 0)); @@ -2615,7 +2683,9 @@ _triggerEvent(plyr.container, plyr.captionsEnabled ? 'captionsenabled' : 'captionsdisabled', true); // Save captions state to localStorage - _updateStorage({captionsEnabled: plyr.captionsEnabled}); + _updateStorage({ + captionsEnabled: plyr.captionsEnabled + }); } // Select active caption @@ -2653,9 +2723,9 @@ return; } - var progress = plyr.progress.played, - value = 0, - duration = _getDuration(); + var progress = plyr.progress.played, + value = 0, + duration = _getDuration(); if (event) { switch (event.type) { @@ -2675,11 +2745,11 @@ break; - // Check buffer status + // Check buffer status case 'playing': case 'progress': - progress = plyr.progress.buffer; - value = (function() { + progress = plyr.progress.buffer; + value = (function() { var buffered = plyr.media.buffered; if (buffered && buffered.length) { @@ -2706,7 +2776,7 @@ if (!plyr.supported.full) { return; } - + // Default to 0 if (_is.undefined(value)) { value = 0; @@ -2798,17 +2868,17 @@ _updateProgress(event); } - // Update seek range and progress + // Update seek range and progress function _updateSeekDisplay(time) { // Default to 0 if (!_is.number(time)) { time = 0; } - var duration = _getDuration(), - value = _getPercentage(time, duration); + var duration = _getDuration(), + value = _getPercentage(time, duration); - // Update progress + // Update progress if (plyr.progress && plyr.progress.played) { plyr.progress.played.value = value; } @@ -2829,9 +2899,9 @@ } // Calculate percentage - var clientRect = plyr.progress.container.getBoundingClientRect(), - percent = 0, - visible = config.classes.tooltip + '--visible'; + var clientRect = plyr.progress.container.getBoundingClientRect(), + percent = 0, + visible = config.classes.tooltip + '--visible'; // Determine percentage, if already visible if (!event) { @@ -2927,15 +2997,15 @@ } } - // If toggle is false or if we're playing (regardless of toggle), - // then set the timer to hide the controls + // If toggle is false or if we're playing (regardless of toggle), + // then set the timer to hide the controls if (!show || !plyr.media.paused) { timers.hover = window.setTimeout(function() { // If the mouse is over the controls (and not entering fullscreen), bail if ((plyr.controls.pressed || plyr.controls.hover) && !isEnterFullscreen) { return; } - + _toggleClass(plyr.container, config.classes.hideControls, true); }, delay); } @@ -2951,13 +3021,13 @@ // Return the current source var url; - switch(plyr.type) { + switch (plyr.type) { case 'youtube': url = plyr.embed.getVideoUrl(); break; case 'vimeo': - plyr.embed.getVideoUrl.then(function (value) { + plyr.embed.getVideoUrl.then(function(value) { url = value; }); break; @@ -3012,7 +3082,7 @@ _remove(plyr.videoContainer); } - // Reset class name + // Reset class name if (plyr.container) { plyr.container.removeAttribute('class'); } @@ -3035,7 +3105,7 @@ plyr.supported = supported(plyr.type); // Create new markup - switch(plyr.type) { + switch (plyr.type) { case 'video': plyr.media = document.createElement('video'); break; @@ -3202,12 +3272,12 @@ if (config.keyboardShorcuts.global) { _on(window, 'keydown keyup', function(event) { var code = getKeyCode(event), - focused = getFocusElement(), - allowed = [48,49,50,51,52,53,54,56,57,75,77,70,67], - count = get().length; + focused = getFocusElement(), + allowed = [48, 49, 50, 51, 52, 53, 54, 56, 57, 75, 77, 70, 67], + count = get().length; // Only handle global key press if there's only one player - // and the key is in the allowed keys + // and the key is in the allowed keys // and if the focused element is not editable (e.g. text input) // and any that accept key input http://webaim.org/techniques/keyboard/ if (count === 1 && _inArray(allowed, code) && (!_is.htmlElement(focused) || !_matches(focused, config.selectors.editable))) { @@ -3241,7 +3311,7 @@ return; } - // Divide the max duration into 10th's and times by the number value + // Divide the max duration into 10th's and times by the number value _seek((duration / 10) * (code - 48)); } @@ -3249,8 +3319,8 @@ // Reset on keyup if (pressed) { // Which keycodes should we prevent default - var preventDefault = [48,49,50,51,52,53,54,56,57,32,75,38,40,77,39,37,70,67]; - var checkFocus = [38,40]; + var preventDefault = [48, 49, 50, 51, 52, 53, 54, 56, 57, 32, 75, 38, 40, 77, 39, 37, 70, 67]; + var checkFocus = [38, 40]; if (_inArray(checkFocus, code)) { var focused = getFocusElement(); @@ -3266,38 +3336,64 @@ event.stopPropagation(); } - switch(code) { + switch (code) { // 0-9 - case 48: - case 49: - case 50: - case 51: - case 52: - case 53: - case 54: - case 55: + case 48: + case 49: + case 50: + case 51: + case 52: + case 53: + case 54: + case 55: case 56: - case 57: if (!held) { seekByKey(); } break; - // Space and K key - case 32: - case 75: if (!held) { _togglePlay(); } break; - // Arrow up - case 38: _increaseVolume(); break; - // Arrow down - case 40: _decreaseVolume(); break; - // M key - case 77: if (!held) { _toggleMute() } break; - // Arrow forward - case 39: _forward(); break; - // Arrow back - case 37: _rewind(); break; - // F key - case 70: _toggleFullscreen(); break; - // C key - case 67: if (!held) { _toggleCaptions(); } break; + case 57: + if (!held) { + seekByKey(); + } + break; + // Space and K key + case 32: + case 75: + if (!held) { + _togglePlay(); + } + break; + // Arrow up + case 38: + _increaseVolume(); + break; + // Arrow down + case 40: + _decreaseVolume(); + break; + // M key + case 77: + if (!held) { + _toggleMute() + } + break; + // Arrow forward + case 39: + _forward(); + break; + // Arrow back + case 37: + _rewind(); + break; + // F key + case 70: + _toggleFullscreen(); + break; + // C key + case 67: + if (!held) { + _toggleCaptions(); + } + break; } - // Escape is handle natively when in full screen + // Escape is handle natively when in full screen // So we only need to worry about non native if (!_support.fullscreen && plyr.isFullscreen && code === 27) { _toggleFullscreen(); @@ -3371,7 +3467,7 @@ _on(plyr.buttons.captions, 'click', _toggleCaptions); // Settings - _on(plyr.buttons.settings, 'click', function(event) { + _on(plyr.buttons.settings, 'click', function(event) { var menu = this, toggle = event.target, target = document.getElementById(toggle.getAttribute('aria-controls')), @@ -3384,22 +3480,22 @@ // Are we targetting a tab? var isTab = target.getAttribute('role') === 'tabpanel', - targetWidth, + targetWidth, targetHeight, container; // Hide all other tabs if (isTab) { // Get other tabs - var current = menu.querySelector('[role="tabpanel"][aria-hidden="false"]'); + var current = menu.querySelector('[role="tabpanel"][aria-hidden="false"]'); container = current.parentNode; [].forEach.call(menu.querySelectorAll('[aria-controls="' + current.getAttribute('id') + '"]'), function(toggle) { toggle.setAttribute('aria-expanded', false); }); - container.style.width = current.scrollWidth + 'px'; - container.style.height = current.scrollHeight + 'px'; + container.style.width = current.scrollWidth + 'px'; + container.style.height = current.scrollHeight + 'px'; current.setAttribute('aria-hidden', true); current.setAttribute('tabindex', -1); @@ -3412,9 +3508,9 @@ container.appendChild(clone); targetWidth = clone.scrollWidth; targetHeight = clone.scrollHeight; - _remove(clone); + _remove(clone); } - + target.setAttribute('aria-hidden', !show); toggle.setAttribute('aria-expanded', show); target.setAttribute('tabindex', 0); @@ -3431,7 +3527,7 @@ }); // Picture in picture - _on(plyr.buttons.pip, 'click', function() { + _on(plyr.buttons.pip, 'click', function() { //if () plyr.media.webkitSetPresentationMode(plyr.media.webkitPresentationMode === 'picture-in-picture' ? 'inline' : 'picture-in-picture'); @@ -3446,12 +3542,12 @@ _on(plyr.container, 'mouseenter mouseleave mousemove touchstart touchend touchcancel touchmove enterfullscreen', _toggleControls); // Watch for cursor over controls so they don't hide when trying to interact - _on(plyr.controls, 'mouseenter mouseleave', function(event) { + _on(plyr.controls, 'mouseenter mouseleave', function(event) { plyr.controls.hover = event.type === 'mouseenter'; }); - // Watch for cursor over controls so they don't hide when trying to interact - _on(plyr.controls, 'mousedown mouseup touchstart touchend touchcancel', function(event) { + // Watch for cursor over controls so they don't hide when trying to interact + _on(plyr.controls, 'mousedown mouseup touchstart touchend touchcancel', function(event) { plyr.controls.pressed = _inArray(['mousedown', 'touchstart'], event.type); }); @@ -3507,7 +3603,7 @@ if (plyr.type === 'video') { _setCaption(); } - + // Restart _seek(); @@ -3561,7 +3657,9 @@ // Disable right click if (config.disableContextMenu) { - _on(plyr.media, 'contextmenu', function(event) { event.preventDefault(); }); + _on(plyr.media, 'contextmenu', function(event) { + event.preventDefault(); + }); } // Proxy events to container @@ -3609,7 +3707,7 @@ // Type specific stuff switch (plyr.type) { - case 'youtube': + case 'youtube': // Clear timers window.clearInterval(timers.buffering); window.clearInterval(timers.playing); @@ -3619,11 +3717,11 @@ // Clean up cleanUp(); - + break; case 'vimeo': - // Destroy Vimeo API + // Destroy Vimeo API // then clean up (wait, to prevent postmessage errors) plyr.embed.unload().then(cleanUp); @@ -3695,17 +3793,17 @@ // Supported: video, audio, vimeo, youtube var tagName = media.tagName.toLowerCase(); if (tagName === 'div') { - plyr.type = media.getAttribute('data-type'); - plyr.embedId = media.getAttribute('data-video-id'); + plyr.type = media.getAttribute('data-type'); + plyr.embedId = media.getAttribute('data-video-id'); // Clean up media.removeAttribute('data-type'); media.removeAttribute('data-video-id'); } else { - plyr.type = tagName; - config.crossorigin = (media.getAttribute('crossorigin') !== null); - config.autoplay = (config.autoplay || (media.getAttribute('autoplay') !== null)); - config.loop = (config.loop || (media.getAttribute('loop') !== null)); + plyr.type = tagName; + config.crossorigin = (media.getAttribute('crossorigin') !== null); + config.autoplay = (config.autoplay || (media.getAttribute('autoplay') !== null)); + config.loop = (config.loop || (media.getAttribute('loop') !== null)); } // Check for support @@ -3811,45 +3909,77 @@ } api = { - getOriginal: function() { return original; }, - getContainer: function() { return plyr.container }, - getEmbed: function() { return plyr.embed; }, - getMedia: function() { return plyr.media; }, - getType: function() { return plyr.type; }, - getDuration: _getDuration, - getCurrentTime: function() { return plyr.media.currentTime; }, - getVolume: function() { return plyr.media.volume; }, - isMuted: function() { return plyr.media.muted; }, - isReady: function() { return _hasClass(plyr.container, config.classes.ready); }, - isLoading: function() { return _hasClass(plyr.container, config.classes.loading); }, - isPaused: function() { return plyr.media.paused; }, - on: function(event, callback) { _on(plyr.container, event, callback); return this; }, - play: _play, - pause: _pause, - stop: function() { _pause(); _seek(); }, - restart: _seek, - rewind: _rewind, - forward: _forward, - seek: _seek, - source: _source, - poster: _updatePoster, - setVolume: _setVolume, - setSpeed: _setSpeed, - togglePlay: _togglePlay, - toggleMute: _toggleMute, - toggleCaptions: _toggleCaptions, - toggleFullscreen: _toggleFullscreen, - toggleControls: _toggleControls, - setCaptionIndex: _setCaptionIndex, - isFullscreen: function() { return plyr.isFullscreen || false; }, - support: function(mimeType) { return _support.mime(plyr, mimeType); }, - destroy: _destroy + getOriginal: function() { + return original; + }, + getContainer: function() { + return plyr.container + }, + getEmbed: function() { + return plyr.embed; + }, + getMedia: function() { + return plyr.media; + }, + getType: function() { + return plyr.type; + }, + getDuration: _getDuration, + getCurrentTime: function() { + return plyr.media.currentTime; + }, + getVolume: function() { + return plyr.media.volume; + }, + isMuted: function() { + return plyr.media.muted; + }, + isReady: function() { + return _hasClass(plyr.container, config.classes.ready); + }, + isLoading: function() { + return _hasClass(plyr.container, config.classes.loading); + }, + isPaused: function() { + return plyr.media.paused; + }, + on: function(event, callback) { + _on(plyr.container, event, callback); + return this; + }, + play: _play, + pause: _pause, + stop: function() { + _pause(); + _seek(); + }, + restart: _seek, + rewind: _rewind, + forward: _forward, + seek: _seek, + source: _source, + poster: _updatePoster, + setVolume: _setVolume, + setSpeed: _setSpeed, + togglePlay: _togglePlay, + toggleMute: _toggleMute, + toggleCaptions: _toggleCaptions, + toggleFullscreen: _toggleFullscreen, + toggleControls: _toggleControls, + setCaptionIndex: _setCaptionIndex, + isFullscreen: function() { + return plyr.isFullscreen || false; + }, + support: function(mimeType) { + return _support.mime(plyr, mimeType); + }, + destroy: _destroy }; // Everything done function _ready() { // Ready event at end of execution stack - window.setTimeout(function() { + window.setTimeout(function() { _triggerEvent(plyr.media, 'ready'); }, 0); @@ -3913,58 +4043,58 @@ // Check for support function supported(type) { - var browser = _getBrowser(), - isOldIE = (browser.isIE && browser.version <= 9), - isIos = browser.isIos, - isIphone = /iPhone|iPod/i.test(navigator.userAgent), - audio = !!document.createElement('audio').canPlayType, - video = !!document.createElement('video').canPlayType, + var browser = _getBrowser(), + isOldIE = (browser.isIE && browser.version <= 9), + isIos = browser.isIos, + isIphone = /iPhone|iPod/i.test(navigator.userAgent), + audio = !!document.createElement('audio').canPlayType, + video = !!document.createElement('video').canPlayType, basic, full; switch (type) { case 'video': basic = video; - full = (basic && (!isOldIE && !isIphone)); + full = (basic && (!isOldIE && !isIphone)); break; case 'audio': basic = audio; - full = (basic && !isOldIE); + full = (basic && !isOldIE); break; case 'vimeo': case 'youtube': case 'soundcloud': basic = true; - full = (!isOldIE && !isIos); + full = (!isOldIE && !isIos); break; default: basic = (audio && video); - full = (basic && !isOldIE); + full = (basic && !isOldIE); } return { - basic: basic, - full: full + basic: basic, + full: full }; } // Setup function function setup(targets, options) { // Get the players - var players = [], - instances = [], - selector = [defaults.selectors.html5, defaults.selectors.embed].join(','); + var players = [], + instances = [], + selector = [defaults.selectors.html5, defaults.selectors.embed].join(','); // Select the elements if (_is.string(targets)) { // String selector passed targets = document.querySelectorAll(targets); - } else if (_is.htmlElement(targets)) { + } else if (_is.htmlElement(targets)) { // Single HTMLElement passed targets = [targets]; - } else if (!_is.nodeList(targets) && !_is.array(targets) && !_is.string(targets)) { + } else if (!_is.nodeList(targets) && !_is.array(targets) && !_is.string(targets)) { // No selector passed, possibly options as first argument // If options are the first argument if (_is.undefined(options) && _is.object(targets)) { @@ -3993,9 +4123,9 @@ // Always wrap in a
    for styling //container: _wrap(media, document.createElement('div')), // Could be a container or the media itself - target: target, + target: target, // This should be the
    ' @@ -1278,6 +1331,35 @@ } } + // Setup Loop + function setupLoop() { + if (!plyr.supported.full) { + return; + } + + if ((plyr.type !== 'audio' || config.fullscreen.allowAudio) && config.fullscreen.enabled) { + // Check for native support + var nativeSupport = support.fullscreen; + + if (nativeSupport || (config.fullscreen.fallback && !inFrame())) { + log((nativeSupport ? 'Native' : 'Fallback') + ' fullscreen enabled'); + + // Add styling hook + toggleClass(plyr.container, config.classes.fullscreen.enabled, true); + } else { + log('Fullscreen not supported and fallback disabled'); + } + + // Toggle state + if (plyr.buttons && plyr.buttons.fullscreen) { + toggleState(plyr.buttons.fullscreen, false); + } + + // Setup focus trap + focusTrap(); + } + } + // Display active caption if it contains text function setActiveCue(track) { // Get the track from the event if needed @@ -1715,7 +1797,11 @@ fullscreen: getElement(config.selectors.buttons.fullscreen), settings: getElement(config.selectors.buttons.settings), pip: getElement(config.selectors.buttons.pip), - speed: document.querySelectorAll(config.selectors.buttons.speed) + speed: document.querySelectorAll(config.selectors.buttons.speed), + loopin: document.querySelectorAll(config.selectors.buttons.loopin), + loopout: document.querySelectorAll(config.selectors.buttons.loopout), + loopall: document.querySelectorAll(config.selectors.buttons.loopall), + loopclear: document.querySelectorAll(config.selectors.buttons.loopclear) }; // Inputs @@ -2410,6 +2496,50 @@ return toggle; } + // Toggle loop + function toggleLoop(toggle) { + if (['loopin', 'loopout', 'loopall'].indexOf(toggle) === -1) { + toggle = 'loopclear'; + } + + var currentTime = Number(plyr.media.currentTime); + + switch(toggle) { + case 'loopin': + if (config.loopout && config.loopout <= currentTime) { + config.loopout = null; + } + config.loopin = currentTime; + break; + case 'loopout': + if (config.loopin >= currentTime) { + return; + } + config.loopout = currentTime; + break; + case 'loopall': + config.loopin = 0; + config.loopout = plyr.media.duration - 2; + break; + default: + config.loopin = 0; + config.loopout = null; + break; + } + + //check if can loop + config.loop = is.number(config.loopin) && is.number(config.loopout); + + var loopin = updateTimeDisplay(config.loopin, document.querySelector('[data-loop__value="loopin"]')); + var loopout = is.number(config.loopout) ? updateTimeDisplay(config.loopout, document.querySelector('[data-loop__value="loopout"]')) : null; + if (config.loop) { + document.querySelector('[data-menu="loop"]').innerHTML = loopin + ' - ' + loopout; + } else { + document.querySelector('[data-menu="loop"]').innerHTML = config.i18n.loopclear; + } + + } + // Speed-up function setSpeed(speed) { // Load speed from storage or default value @@ -2776,6 +2906,36 @@ } } + + // Update volume UI and storage + function updateLoop() { + // Get the current volume + var volume = plyr.media.muted ? 0 : (plyr.media.volume * config.volumeMax); + + // Update the if present + if (plyr.supported.full) { + if (plyr.volume.input) { + plyr.volume.input.value = volume; + } + if (plyr.volume.display) { + plyr.volume.display.value = volume; + } + } + + // Update the volume in storage + updateStorage({ + volume: volume + }); + + // Toggle class if muted + toggleClass(plyr.container, config.classes.muted, (volume === 0)); + + // Update checkbox for mute state + if (plyr.supported.full && plyr.buttons.mute) { + toggleState(plyr.buttons.mute, (volume === 0)); + } + } + // Toggle captions function toggleCaptions(show) { // If there's no full support, or there's no caption toggle @@ -2885,7 +3045,10 @@ } } - // Set values + if (is.number(config.loopin) && is.number(config.loopout) && plyr.media.currentTime >= config.loopout) { + seek(config.loopin); + } + setProgress(progress, value); } @@ -2945,8 +3108,10 @@ plyr.secs = ('0' + plyr.secs).slice(-2); plyr.mins = ('0' + plyr.mins).slice(-2); + var txt = (displayHours ? plyr.hours + ':' : '') + plyr.mins + ':' + plyr.secs; // Render - element.innerHTML = (displayHours ? plyr.hours + ':' : '') + plyr.mins + ':' + plyr.secs; + element.innerHTML = txt; + return txt; } // Show the duration on metadataloaded @@ -3577,6 +3742,20 @@ // Fullscreen proxy(plyr.buttons.fullscreen, 'click', config.listeners.fullscreen, toggleFullscreen); + // Loop + proxy(plyr.buttons.loopall, 'click', config.listeners.loopall, function () { + toggleLoop('loopall'); + }); + proxy(plyr.buttons.loopin, 'click', config.listeners.loopin, function(){ + toggleLoop('loopin'); + }); + proxy(plyr.buttons.loopout, 'click', config.listeners.loopout, function () { + toggleLoop('loopout'); + }); + proxy(plyr.buttons.loopclear, 'click', config.listeners.loopclear, function () { + toggleLoop('loopclear'); + }); + // Handle user exiting fullscreen by escaping etc if (support.fullscreen) { on(document, fullscreen.eventType, toggleFullscreen); @@ -4019,6 +4198,10 @@ // Set playback speed setSpeed(); + + // Set loop + toggleLoop(); + // Reset time display timeUpdate(); @@ -4061,12 +4244,16 @@ isPaused: function() { return plyr.media.paused; }, + isLooping: function() { + return config.loopin && config.loopout; + }, on: function(event, callback) { on(plyr.container, event, callback); return this; }, play: play, pause: pause, + loop: toggleLoop, stop: function() { pause(); seek(); -- cgit v1.2.3 From 1bcdbe4c005968954813783af44dc6240e06e0ed Mon Sep 17 00:00:00 2001 From: Chrysa Papadopoulou Date: Thu, 2 Feb 2017 11:38:08 +0200 Subject: Refactored loop event buttons + on 'No Loop' cleared displayed timing --- src/js/plyr.js | 42 +++++++++++++----------------------------- 1 file changed, 13 insertions(+), 29 deletions(-) (limited to 'src') diff --git a/src/js/plyr.js b/src/js/plyr.js index 3b849d4f..903fa88f 100644 --- a/src/js/plyr.js +++ b/src/js/plyr.js @@ -89,10 +89,7 @@ pip: '[data-plyr="pip"]', airplay: '[data-plyr="airplay"]', speed: '[data-plyr="speed"]', - loopin: '[data-plyr="loopin"]', - loopout: '[data-plyr="loopout"]', - loopall: '[data-plyr="loopall"]', - loopclear: '[data-plyr="loopclear"]', + loop: '[data-plyr="loop"]' }, volume: { input: '[data-plyr="volume"]', @@ -205,10 +202,7 @@ captions: null, fullscreen: null, speed: null, - loopin: null, - loopout: null, - loopall: null, - loopclear: null + loop: null }, // Events to watch on HTML5 media elements events: ['ready', 'ended', 'progress', 'stalled', 'playing', 'waiting', 'canplay', 'canplaythrough', 'loadstart', 'loadeddata', 'loadedmetadata', 'timeupdate', 'volumechange', 'play', 'pause', 'error', 'seeking', 'seeked', 'emptied'], @@ -1133,25 +1127,25 @@ '', '', '
  • ', - '', '
  • ', '
  • ', - '', '
  • ', '
  • ', - '', '
  • ', '
  • ', - '', '
  • ', @@ -1798,10 +1792,7 @@ settings: getElement(config.selectors.buttons.settings), pip: getElement(config.selectors.buttons.pip), speed: document.querySelectorAll(config.selectors.buttons.speed), - loopin: document.querySelectorAll(config.selectors.buttons.loopin), - loopout: document.querySelectorAll(config.selectors.buttons.loopout), - loopall: document.querySelectorAll(config.selectors.buttons.loopall), - loopclear: document.querySelectorAll(config.selectors.buttons.loopclear) + loop: document.querySelectorAll(config.selectors.buttons.loop) }; // Inputs @@ -2529,9 +2520,8 @@ //check if can loop config.loop = is.number(config.loopin) && is.number(config.loopout); - var loopin = updateTimeDisplay(config.loopin, document.querySelector('[data-loop__value="loopin"]')); - var loopout = is.number(config.loopout) ? updateTimeDisplay(config.loopout, document.querySelector('[data-loop__value="loopout"]')) : null; + var loopout = is.number(config.loopout) ? updateTimeDisplay(config.loopout + 2, document.querySelector('[data-loop__value="loopout"]')) : document.querySelector('[data-loop__value="loopout"]').innerHTML = ''; if (config.loop) { document.querySelector('[data-menu="loop"]').innerHTML = loopin + ' - ' + loopout; } else { @@ -3743,17 +3733,11 @@ proxy(plyr.buttons.fullscreen, 'click', config.listeners.fullscreen, toggleFullscreen); // Loop - proxy(plyr.buttons.loopall, 'click', config.listeners.loopall, function () { - toggleLoop('loopall'); - }); - proxy(plyr.buttons.loopin, 'click', config.listeners.loopin, function(){ - toggleLoop('loopin'); - }); - proxy(plyr.buttons.loopout, 'click', config.listeners.loopout, function () { - toggleLoop('loopout'); - }); - proxy(plyr.buttons.loopclear, 'click', config.listeners.loopclear, function () { - toggleLoop('loopclear'); + proxy(plyr.buttons.loop, 'click', config.listeners.loop, function (event) { + var loopValue = event.target.getAttribute('data-loop__value') || event.target.getAttribute('data-loop__type'); + if (['loopin', 'loopout', 'loopall', 'loopclear'].indexOf(loopValue) > -1) { + toggleLoop(loopValue); + } }); // Handle user exiting fullscreen by escaping etc -- cgit v1.2.3 From afcdf17a72ffe8dc8f431765d867b97e0f57cbb1 Mon Sep 17 00:00:00 2001 From: Chrysa Papadopoulou Date: Fri, 3 Feb 2017 14:52:38 +0200 Subject: Removed not needed functions + reverted demo.js to previous --- src/js/plyr.js | 61 +--------------------------------------------------------- 1 file changed, 1 insertion(+), 60 deletions(-) (limited to 'src') diff --git a/src/js/plyr.js b/src/js/plyr.js index 903fa88f..88fcd548 100644 --- a/src/js/plyr.js +++ b/src/js/plyr.js @@ -46,7 +46,7 @@ volumeMax: 10, volumeStep: 1, defaultSpeed: 1.0, - currentSpeed: 1.0, + currentSpeed: 1, speeds: [0.5, 1.0, 1.5, 2.0], duration: null, displayDuration: true, @@ -1325,35 +1325,6 @@ } } - // Setup Loop - function setupLoop() { - if (!plyr.supported.full) { - return; - } - - if ((plyr.type !== 'audio' || config.fullscreen.allowAudio) && config.fullscreen.enabled) { - // Check for native support - var nativeSupport = support.fullscreen; - - if (nativeSupport || (config.fullscreen.fallback && !inFrame())) { - log((nativeSupport ? 'Native' : 'Fallback') + ' fullscreen enabled'); - - // Add styling hook - toggleClass(plyr.container, config.classes.fullscreen.enabled, true); - } else { - log('Fullscreen not supported and fallback disabled'); - } - - // Toggle state - if (plyr.buttons && plyr.buttons.fullscreen) { - toggleState(plyr.buttons.fullscreen, false); - } - - // Setup focus trap - focusTrap(); - } - } - // Display active caption if it contains text function setActiveCue(track) { // Get the track from the event if needed @@ -2896,36 +2867,6 @@ } } - - // Update volume UI and storage - function updateLoop() { - // Get the current volume - var volume = plyr.media.muted ? 0 : (plyr.media.volume * config.volumeMax); - - // Update the if present - if (plyr.supported.full) { - if (plyr.volume.input) { - plyr.volume.input.value = volume; - } - if (plyr.volume.display) { - plyr.volume.display.value = volume; - } - } - - // Update the volume in storage - updateStorage({ - volume: volume - }); - - // Toggle class if muted - toggleClass(plyr.container, config.classes.muted, (volume === 0)); - - // Update checkbox for mute state - if (plyr.supported.full && plyr.buttons.mute) { - toggleState(plyr.buttons.mute, (volume === 0)); - } - } - // Toggle captions function toggleCaptions(show) { // If there's no full support, or there's no caption toggle -- cgit v1.2.3 From cbef45841cbd677a62052e8464151704c55f9966 Mon Sep 17 00:00:00 2001 From: Sam Potts Date: Sun, 5 Feb 2017 11:34:33 +1100 Subject: Menu work --- src/js/plyr.js | 19 +++++++++++-------- src/less/plyr.less | 50 ++++++++++++++++++++++++-------------------------- 2 files changed, 35 insertions(+), 34 deletions(-) (limited to 'src') diff --git a/src/js/plyr.js b/src/js/plyr.js index c2000234..7a4f19e0 100644 --- a/src/js/plyr.js +++ b/src/js/plyr.js @@ -98,7 +98,10 @@ }, captions: '.plyr__captions', currentTime: '.plyr__time--current', - duration: '.plyr__time--duration' + duration: '.plyr__time--duration', + menu: { + quality: '.js-plyr__menu__list--quality' + } }, classes: { setup: 'plyr--setup', @@ -976,7 +979,7 @@ '', '