From 9efdc88120b1301fc0c279e03959657c47de9613 Mon Sep 17 00:00:00 2001 From: Cameron Vargas Date: Tue, 15 Dec 2020 17:57:10 +0300 Subject: [PATCH 1/5] init dev commit --- library.json | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/library.json b/library.json index 1fab7cfa4..c94d41368 100644 --- a/library.json +++ b/library.json @@ -1,12 +1,12 @@ { - "title": "Interactive Video", + "title": "Interactive Video Dev", "description": "Put texts, tasks and other medias on top of your video.", "license": "MIT", "contentType": "Media", "majorVersion": 1, "minorVersion": 22, "patchVersion": 4, - "machineName": "H5P.InteractiveVideo", + "machineName": "H5P.InteractiveVideoDev", "author": "Joubel", "embedTypes": [ "iframe" From 4f9bc5f08e2e246c890402dae5176a733c047de5 Mon Sep 17 00:00:00 2001 From: Cameron Vargas Date: Thu, 24 Dec 2020 22:05:23 +0300 Subject: [PATCH 2/5] Added volume control slider for mute button --- library.json | 6 +- src/scripts/interactive-video.js | 119 +++++++++++++++++++++++++++++-- src/styles/interactive-video.css | 57 +++++++++++++++ 3 files changed, 175 insertions(+), 7 deletions(-) diff --git a/library.json b/library.json index c94d41368..6e7671916 100644 --- a/library.json +++ b/library.json @@ -1,12 +1,12 @@ { - "title": "Interactive Video Dev", + "title": "Interactive Video", "description": "Put texts, tasks and other medias on top of your video.", "license": "MIT", "contentType": "Media", "majorVersion": 1, "minorVersion": 22, - "patchVersion": 4, - "machineName": "H5P.InteractiveVideoDev", + "patchVersion": 5, + "machineName": "H5P.InteractiveVideo", "author": "Joubel", "embedTypes": [ "iframe" diff --git a/src/scripts/interactive-video.js b/src/scripts/interactive-video.js index bb32b347a..590db5ae1 100644 --- a/src/scripts/interactive-video.js +++ b/src/scripts/interactive-video.js @@ -524,6 +524,8 @@ function InteractiveVideo(params, id, contentData) { */ self.toggleMute = (refocus = true) => { const $muteButton = self.controls.$volume; + const $volumeSlider = self.controls.$volumeSlider; + const defaultVol = 15; if (!self.deactivateSound) { if ($muteButton.hasClass('h5p-muted')) { @@ -532,13 +534,25 @@ function InteractiveVideo(params, id, contentData) { .attr('aria-label', self.l10n.mute); self.video.unMute(); + + // Set slider to a low volume if video was muted by dragging the slider down to 0 + if (self.video.getVolume() < 1) { + self.video.setVolume(defaultVol); + $volumeSlider.slider('value', defaultVol); + } + // Otherwise reset to the previous volume level + else { + $volumeSlider.slider('value', self.video.getVolume()); + } } else { $muteButton - .addClass('h5p-muted') - .attr('aria-label', self.l10n.unmute); - + .addClass('h5p-muted') + .attr('aria-label', self.l10n.unmute); + self.video.mute(); + // Set slider to 0 (but do not adjust volume) + $volumeSlider.slider('value', 0); } if (refocus) { @@ -2065,9 +2079,106 @@ InteractiveVideo.prototype.attachControls = function ($wrapper) { self.controls.$playbackRateChooser.insertAfter(self.controls.$playbackRateButton); + // * Volume Control (wrapper, mute, slider) * + // Add volume control wrapper + if (!isAndroid() && !isIpad()) { + self.controls.$volumeWrapper = $('
', { + tabindex: 0, + class: 'h5p-control ' + 'h5p-' + 'volume-wrapper', + on: { + mouseenter: function (event) { + self.controls.$volumeSliderWrapper.addClass('h5p-show'); + }, + mouseleave: function (event) { + self.controls.$volumeSliderWrapper.removeClass('h5p-show'); + } + }, + appendTo: $right + }); + } + + // TODO: Maintain slider focus when mouse is moved outside of wrapper + // Add volume slider + if (!isAndroid() && !isIpad()) { + self.controls.$volumeSliderWrapper = $('
', { + class: 'h5p-volume-slider', + appendTo: self.controls.$volumeWrapper + }); + + self.controls.$volumeSlider = $('
', { + appendTo: self.controls.$volumeSliderWrapper + }).slider({ + value: self.video.getVolume(), + step: 1, + orientation: 'vertical', + range: 'min', + max: 100, + create: function (event) { + const $handle = $(event.target).find('.ui-slider-handle'); + const volumeNow = self.video.getVolume(); + // Prepend rail + $(event.target).prepend('
') + + $handle + .attr('role', 'slider') + .attr('aria-valuemin', '0') + .attr('aria-valuemax', '100') + .attr('aria-valuetext', volumeNow) // TODO: l10n + .attr('aria-valuenow', volumeNow); + + if (self.deactivateSound) { + // TODO: self.setDisabled($handle).attr('aria-hidden', 'true'); + } + }, + slide: function (event, ui) { + const $handle = $(event.target).find('.ui-slider-handle'); + let volume = Math.floor(ui.value); + self.controls.$volumeSliderWrapper.addClass('h5p-active'); + + // When the slider is dragged to 0, toggle the mute button + if (volume < 1 && !self.video.isMuted()) { + self.toggleMute.call(this); + } + if (volume > 0 && self.video.isMuted()) { + self.toggleMute.call(this); + } + + // Update volume + self.video.setVolume(volume); + $handle + .attr('aria-valuetext', volume) // TODO: l10n + .attr('aria-valuenow', volume); + }, + stop: function (event, ui) { + self.controls.$volumeSliderWrapper.removeClass('h5p-active'); + } + // TODO: on: keydown adjust volume + }); + } + // Add volume button control (toggle mute) if (!isAndroid() && !isIpad()) { - self.controls.$volume = self.createButton('mute', 'h5p-control', $right, self.toggleMute); + var options = { + role: 'button', + tabindex: 0, + class: 'h5p-control h5p-mute', + on: { + click: function () { + self.toggleMute.call(this); + }, + keydown: function (event) { + if (isSpaceOrEnterKey(event)) { + self.toggleMute.call(this); + event.preventDefault(); + event.stopPropagation(); + } + }, + }, + appendTo: self.controls.$volumeWrapper + }; + options['aria-label'] = self.l10n['mute']; + self.controls.$volume = $('
', options); + if (self.deactivateSound) { self.controls.$volume .addClass('h5p-muted') diff --git a/src/styles/interactive-video.css b/src/styles/interactive-video.css index b6b4dbb6a..6dac137b9 100644 --- a/src/styles/interactive-video.css +++ b/src/styles/interactive-video.css @@ -1875,3 +1875,60 @@ .h5p-interactive-video .h5p-control:not(.h5p-no-tooltip):hover > .h5p-interactive-video-tooltip { visibility: visible; } +/* * Volume Slider * */ +.h5p-interactive-video .h5p-control.h5p-volume-wrapper .h5p-volume-slider { + position: absolute; + bottom: 35px; + width: 36px; + height: 66px; + padding: 20px 0 15px; + z-index: 10; + opacity: 0; + visibility: hidden; + transition: opacity 0.3s ease, visibility 0.3s ease; +} +.h5p-interactive-video .h5p-control.h5p-volume-wrapper .h5p-volume-slider.h5p-show, +.h5p-interactive-video .h5p-control.h5p-volume-wrapper .h5p-volume-slider.h5p-active { + opacity: 1; + visibility: visible; +} +.h5p-interactive-video .h5p-control.h5p-volume-wrapper .h5p-volume-slider .ui-slider { + background: none; + height: 66px; + border: 0; + border-radius: 0; + cursor: pointer; + -ms-touch-action: manipulation; + touch-action: manipulation; + z-index: 1; +} +.h5p-interactive-video .h5p-control.h5p-volume-wrapper .h5p-volume-slider .ui-slider.ui-slider-vertical { + width: 36px; +} +.h5p-interactive-video .h5p-control.h5p-volume-wrapper .h5p-volume-slider .ui-slider .ui-slider-handle { + margin-left: auto; + margin-right: auto; + left: 0px; + right: 0px; + width: 12px; + height: 12px; + border-radius: 50px; +} +.h5p-interactive-video .h5p-volume-slider .ui-slider-range { + margin-left: auto; + margin-right: auto; + left: 0px; + right: 0px; + width: 4px; + border: 0; + border-radius: 0; + color: #e2e2e2; +} +.h5p-interactive-video .h5p-volume-slider .ui-slider-range.h5p-volume-rail { + height: 100%; + background: #7a7a7a; +} + +.h5p-volume-slider .ui-slider .ui-slider-handle.ui-state-active { + box-shadow: 0px 0px 0px 6px rgba(255, 255, 255, .2); +} \ No newline at end of file From 7287ceb0cacd243202199be9f5d8f7ebfbf93c5d Mon Sep 17 00:00:00 2001 From: Cameron Vargas Date: Sat, 26 Dec 2020 00:07:45 +0300 Subject: [PATCH 3/5] Added slider focus outside of element --- src/scripts/interactive-video.js | 35 ++++++++++++++++++-------------- src/styles/interactive-video.css | 12 +++++------ 2 files changed, 26 insertions(+), 21 deletions(-) diff --git a/src/scripts/interactive-video.js b/src/scripts/interactive-video.js index 590db5ae1..63d81d5f1 100644 --- a/src/scripts/interactive-video.js +++ b/src/scripts/interactive-video.js @@ -547,9 +547,9 @@ function InteractiveVideo(params, id, contentData) { } else { $muteButton - .addClass('h5p-muted') - .attr('aria-label', self.l10n.unmute); - + .addClass('h5p-muted') + .attr('aria-label', self.l10n.unmute); + self.video.mute(); // Set slider to 0 (but do not adjust volume) $volumeSlider.slider('value', 0); @@ -2084,7 +2084,7 @@ InteractiveVideo.prototype.attachControls = function ($wrapper) { if (!isAndroid() && !isIpad()) { self.controls.$volumeWrapper = $('
', { tabindex: 0, - class: 'h5p-control ' + 'h5p-' + 'volume-wrapper', + class: 'h5p-control h5p-volume-wrapper', on: { mouseenter: function (event) { self.controls.$volumeSliderWrapper.addClass('h5p-show'); @@ -2097,7 +2097,6 @@ InteractiveVideo.prototype.attachControls = function ($wrapper) { }); } - // TODO: Maintain slider focus when mouse is moved outside of wrapper // Add volume slider if (!isAndroid() && !isIpad()) { self.controls.$volumeSliderWrapper = $('
', { @@ -2116,18 +2115,18 @@ InteractiveVideo.prototype.attachControls = function ($wrapper) { create: function (event) { const $handle = $(event.target).find('.ui-slider-handle'); const volumeNow = self.video.getVolume(); - // Prepend rail + // Prepend slider rail $(event.target).prepend('
') $handle .attr('role', 'slider') .attr('aria-valuemin', '0') .attr('aria-valuemax', '100') - .attr('aria-valuetext', volumeNow) // TODO: l10n + .attr('aria-valuetext', volumeNow) // TODO: l10n, eg. "Volume 30% .attr('aria-valuenow', volumeNow); if (self.deactivateSound) { - // TODO: self.setDisabled($handle).attr('aria-hidden', 'true'); + self.setDisabled($handle).attr('aria-hidden', 'true'); } }, slide: function (event, ui) { @@ -2135,7 +2134,7 @@ InteractiveVideo.prototype.attachControls = function ($wrapper) { let volume = Math.floor(ui.value); self.controls.$volumeSliderWrapper.addClass('h5p-active'); - // When the slider is dragged to 0, toggle the mute button + // When the slider is dragged to/from 0, toggle the mute button if (volume < 1 && !self.video.isMuted()) { self.toggleMute.call(this); } @@ -2146,19 +2145,25 @@ InteractiveVideo.prototype.attachControls = function ($wrapper) { // Update volume self.video.setVolume(volume); $handle - .attr('aria-valuetext', volume) // TODO: l10n + .attr('aria-valuetext', volume) // TODO: l10n, eg. "Volume 30%" .attr('aria-valuenow', volume); + + // Make overlay visible to catch mouseup/move events. + self.$overlay.addClass('h5p-visible'); }, stop: function (event, ui) { self.controls.$volumeSliderWrapper.removeClass('h5p-active'); + + // Done catching mouse events + self.$overlay.removeClass('h5p-visible'); } - // TODO: on: keydown adjust volume + // TODO: on: keydown adjust volume ? }); } // Add volume button control (toggle mute) if (!isAndroid() && !isIpad()) { - var options = { + self.controls.$volume = $('
', { role: 'button', tabindex: 0, class: 'h5p-control h5p-mute', @@ -2175,9 +2180,9 @@ InteractiveVideo.prototype.attachControls = function ($wrapper) { }, }, appendTo: self.controls.$volumeWrapper - }; - options['aria-label'] = self.l10n['mute']; - self.controls.$volume = $('
', options); + }); + self.controls.$volume + .attr('aria-label', self.l10n.mute); if (self.deactivateSound) { self.controls.$volume diff --git a/src/styles/interactive-video.css b/src/styles/interactive-video.css index 6dac137b9..f98e0307d 100644 --- a/src/styles/interactive-video.css +++ b/src/styles/interactive-video.css @@ -1875,13 +1875,12 @@ .h5p-interactive-video .h5p-control:not(.h5p-no-tooltip):hover > .h5p-interactive-video-tooltip { visibility: visible; } -/* * Volume Slider * */ .h5p-interactive-video .h5p-control.h5p-volume-wrapper .h5p-volume-slider { position: absolute; bottom: 35px; width: 36px; height: 66px; - padding: 20px 0 15px; + padding: 20px 0 18px; z-index: 10; opacity: 0; visibility: hidden; @@ -1893,14 +1892,14 @@ visibility: visible; } .h5p-interactive-video .h5p-control.h5p-volume-wrapper .h5p-volume-slider .ui-slider { - background: none; height: 66px; border: 0; border-radius: 0; + z-index: 1; + background: none; cursor: pointer; -ms-touch-action: manipulation; touch-action: manipulation; - z-index: 1; } .h5p-interactive-video .h5p-control.h5p-volume-wrapper .h5p-volume-slider .ui-slider.ui-slider-vertical { width: 36px; @@ -1913,6 +1912,8 @@ width: 12px; height: 12px; border-radius: 50px; + border-color: rgb(102, 102, 102); + transition: box-shadow 0.1s ease; } .h5p-interactive-video .h5p-volume-slider .ui-slider-range { margin-left: auto; @@ -1928,7 +1929,6 @@ height: 100%; background: #7a7a7a; } - .h5p-volume-slider .ui-slider .ui-slider-handle.ui-state-active { - box-shadow: 0px 0px 0px 6px rgba(255, 255, 255, .2); + box-shadow: 0px 0px 6px rgba(0, 0, 0, .4), 0px 0px 0px 6px rgba(255, 255, 255, .2); } \ No newline at end of file From 93f793bdc7f1c4bcfb8fe7dc899a3c682359e4b7 Mon Sep 17 00:00:00 2001 From: Cameron Vargas Date: Sun, 27 Dec 2020 17:49:18 +0300 Subject: [PATCH 4/5] Adjusting comments --- src/scripts/interactive-video.js | 25 ++++++++++++------------- 1 file changed, 12 insertions(+), 13 deletions(-) diff --git a/src/scripts/interactive-video.js b/src/scripts/interactive-video.js index 63d81d5f1..d16515d8d 100644 --- a/src/scripts/interactive-video.js +++ b/src/scripts/interactive-video.js @@ -535,7 +535,7 @@ function InteractiveVideo(params, id, contentData) { self.video.unMute(); - // Set slider to a low volume if video was muted by dragging the slider down to 0 + // Set slider to a default low volume if video was muted by dragging the slider down to 0 if (self.video.getVolume() < 1) { self.video.setVolume(defaultVol); $volumeSlider.slider('value', defaultVol); @@ -551,7 +551,7 @@ function InteractiveVideo(params, id, contentData) { .attr('aria-label', self.l10n.unmute); self.video.mute(); - // Set slider to 0 (but do not adjust volume) + // Set slider to 0 (but do not adjust volume), getVolume() will persist our previous volume level $volumeSlider.slider('value', 0); } @@ -2079,7 +2079,6 @@ InteractiveVideo.prototype.attachControls = function ($wrapper) { self.controls.$playbackRateChooser.insertAfter(self.controls.$playbackRateButton); - // * Volume Control (wrapper, mute, slider) * // Add volume control wrapper if (!isAndroid() && !isIpad()) { self.controls.$volumeWrapper = $('
', { @@ -2087,10 +2086,10 @@ InteractiveVideo.prototype.attachControls = function ($wrapper) { class: 'h5p-control h5p-volume-wrapper', on: { mouseenter: function (event) { - self.controls.$volumeSliderWrapper.addClass('h5p-show'); + self.controls.$volumeSliderOverlay.addClass('h5p-show'); }, mouseleave: function (event) { - self.controls.$volumeSliderWrapper.removeClass('h5p-show'); + self.controls.$volumeSliderOverlay.removeClass('h5p-show'); } }, appendTo: $right @@ -2099,13 +2098,13 @@ InteractiveVideo.prototype.attachControls = function ($wrapper) { // Add volume slider if (!isAndroid() && !isIpad()) { - self.controls.$volumeSliderWrapper = $('
', { + self.controls.$volumeSliderOverlay = $('
', { class: 'h5p-volume-slider', appendTo: self.controls.$volumeWrapper }); self.controls.$volumeSlider = $('
', { - appendTo: self.controls.$volumeSliderWrapper + appendTo: self.controls.$volumeSliderOverlay }).slider({ value: self.video.getVolume(), step: 1, @@ -2115,14 +2114,14 @@ InteractiveVideo.prototype.attachControls = function ($wrapper) { create: function (event) { const $handle = $(event.target).find('.ui-slider-handle'); const volumeNow = self.video.getVolume(); - // Prepend slider rail + // Slider style are wide to capture events, add another slider rail $(event.target).prepend('
') $handle .attr('role', 'slider') .attr('aria-valuemin', '0') .attr('aria-valuemax', '100') - .attr('aria-valuetext', volumeNow) // TODO: l10n, eg. "Volume 30% + .attr('aria-valuetext', volumeNow) // TODO: l10n, eg. "Volume 30%" ? .attr('aria-valuenow', volumeNow); if (self.deactivateSound) { @@ -2132,7 +2131,7 @@ InteractiveVideo.prototype.attachControls = function ($wrapper) { slide: function (event, ui) { const $handle = $(event.target).find('.ui-slider-handle'); let volume = Math.floor(ui.value); - self.controls.$volumeSliderWrapper.addClass('h5p-active'); + self.controls.$volumeSliderOverlay.addClass('h5p-active'); // When the slider is dragged to/from 0, toggle the mute button if (volume < 1 && !self.video.isMuted()) { @@ -2145,19 +2144,19 @@ InteractiveVideo.prototype.attachControls = function ($wrapper) { // Update volume self.video.setVolume(volume); $handle - .attr('aria-valuetext', volume) // TODO: l10n, eg. "Volume 30%" + .attr('aria-valuetext', volume) // TODO: l10n, eg. "Volume 30%" ? .attr('aria-valuenow', volume); // Make overlay visible to catch mouseup/move events. self.$overlay.addClass('h5p-visible'); }, stop: function (event, ui) { - self.controls.$volumeSliderWrapper.removeClass('h5p-active'); + self.controls.$volumeSliderOverlay.removeClass('h5p-active'); // Done catching mouse events self.$overlay.removeClass('h5p-visible'); } - // TODO: on: keydown adjust volume ? + // TODO: add event on: keydown -> adjust volume ? }); } From d11cce9255442b3c0c04792c420da06c760f4030 Mon Sep 17 00:00:00 2001 From: Cameron Vargas Date: Mon, 28 Dec 2020 21:55:36 +0300 Subject: [PATCH 5/5] Added style change, reversion --- library.json | 2 +- src/scripts/interactive-video.js | 22 +--------------------- src/styles/interactive-video.css | 1 + 3 files changed, 3 insertions(+), 22 deletions(-) diff --git a/library.json b/library.json index 6e7671916..1fab7cfa4 100644 --- a/library.json +++ b/library.json @@ -5,7 +5,7 @@ "contentType": "Media", "majorVersion": 1, "minorVersion": 22, - "patchVersion": 5, + "patchVersion": 4, "machineName": "H5P.InteractiveVideo", "author": "Joubel", "embedTypes": [ diff --git a/src/scripts/interactive-video.js b/src/scripts/interactive-video.js index d16515d8d..3f35fdc21 100644 --- a/src/scripts/interactive-video.js +++ b/src/scripts/interactive-video.js @@ -2162,27 +2162,7 @@ InteractiveVideo.prototype.attachControls = function ($wrapper) { // Add volume button control (toggle mute) if (!isAndroid() && !isIpad()) { - self.controls.$volume = $('
', { - role: 'button', - tabindex: 0, - class: 'h5p-control h5p-mute', - on: { - click: function () { - self.toggleMute.call(this); - }, - keydown: function (event) { - if (isSpaceOrEnterKey(event)) { - self.toggleMute.call(this); - event.preventDefault(); - event.stopPropagation(); - } - }, - }, - appendTo: self.controls.$volumeWrapper - }); - self.controls.$volume - .attr('aria-label', self.l10n.mute); - + self.controls.$volume = self.createButton('mute', 'h5p-control', self.controls.$volumeWrapper, self.toggleMute); if (self.deactivateSound) { self.controls.$volume .addClass('h5p-muted') diff --git a/src/styles/interactive-video.css b/src/styles/interactive-video.css index f98e0307d..b8d9211d0 100644 --- a/src/styles/interactive-video.css +++ b/src/styles/interactive-video.css @@ -1928,6 +1928,7 @@ .h5p-interactive-video .h5p-volume-slider .ui-slider-range.h5p-volume-rail { height: 100%; background: #7a7a7a; + box-shadow: 0 0 6px rgba(0, 0, 0, .4); } .h5p-volume-slider .ui-slider .ui-slider-handle.ui-state-active { box-shadow: 0px 0px 6px rgba(0, 0, 0, .4), 0px 0px 0px 6px rgba(255, 255, 255, .2);