diff --git a/common/lib/xmodule/xmodule/js/spec/video/video_caption_spec.js b/common/lib/xmodule/xmodule/js/spec/video/video_caption_spec.js index 7ddda1c092..0a0cdd3dbe 100644 --- a/common/lib/xmodule/xmodule/js/spec/video/video_caption_spec.js +++ b/common/lib/xmodule/xmodule/js/spec/video/video_caption_spec.js @@ -986,9 +986,11 @@ videoWrapperHeight = $('.video-wrapper').height(); progressSliderHeight = state.el.find('.slider').height(); controlHeight = state.el.find('.video-controls').height(); - shouldBeHeight = videoWrapperHeight - + shouldBeHeight = parseInt(( + videoWrapperHeight - 0.5 * progressSliderHeight - - controlHeight; + controlHeight + ), 10); expect(realHeight).toBe(shouldBeHeight); }); diff --git a/common/lib/xmodule/xmodule/js/spec/video/video_progress_slider_spec.js b/common/lib/xmodule/xmodule/js/spec/video/video_progress_slider_spec.js index 1f3d5f728d..f5149926f3 100644 --- a/common/lib/xmodule/xmodule/js/spec/video/video_progress_slider_spec.js +++ b/common/lib/xmodule/xmodule/js/spec/video/video_progress_slider_spec.js @@ -44,7 +44,7 @@ expect(timeControl).toHaveAttrs({ 'role': 'slider', - 'aria-label': 'Video position', + 'aria-label': 'Video position. Press space to toggle playback', 'aria-disabled': 'false' }); diff --git a/common/lib/xmodule/xmodule/js/src/video/03_video_player.js b/common/lib/xmodule/xmodule/js/src/video/03_video_player.js index 6eecd3df86..52b2633099 100644 --- a/common/lib/xmodule/xmodule/js/src/video/03_video_player.js +++ b/common/lib/xmodule/xmodule/js/src/video/03_video_player.js @@ -405,6 +405,8 @@ function(HTML5Video, Resizer) { this.videoPlayer.goToStartTime = false; this.videoPlayer.seekTo(time); + this.trigger('videoProgressSlider.focusSlider'); + this.el.trigger('seek', [time, oldTime, type]); } diff --git a/common/lib/xmodule/xmodule/js/src/video/06_video_progress_slider.js b/common/lib/xmodule/xmodule/js/src/video/06_video_progress_slider.js index b79a17fefe..8c87b6b387 100644 --- a/common/lib/xmodule/xmodule/js/src/video/06_video_progress_slider.js +++ b/common/lib/xmodule/xmodule/js/src/video/06_video_progress_slider.js @@ -12,7 +12,9 @@ mind, or whether to act, and in acting, to live." [], function() { var template = [ - '
' + '
' ].join(''); // VideoProgressSlider() function - what this module "exports". @@ -35,6 +37,8 @@ function() { // // Functions which will be accessible via 'state' object. When called, // these functions will get the 'state' object as a context. + + /* eslint-disable no-use-before-define */ function _makeFunctionsPublic(state) { var methodsDict = { destroy: destroy, @@ -45,7 +49,8 @@ function() { updatePlayTime: updatePlayTime, updateStartEndTimeRegion: updateStartEndTimeRegion, notifyThroughHandleEnd: notifyThroughHandleEnd, - getTimeDescription: getTimeDescription + getTimeDescription: getTimeDescription, + focusSlider: focusSlider }; state.bindTo(methodsDict, state.videoProgressSlider, state); @@ -57,6 +62,12 @@ function() { delete this.videoProgressSlider; } + function bindHandlers(state) { + state.videoProgressSlider.el.on('keypress', sliderToggle.bind(state)); + state.el.on('destroy', state.videoProgressSlider.destroy); + } + /* eslint-enable no-use-before-define */ + // function _renderElements(state) // // Create any necessary DOM elements, attach them, and set their @@ -69,6 +80,7 @@ function() { state.el.find('.video-controls').prepend(state.videoProgressSlider.el); state.videoProgressSlider.buildSlider(); _buildHandle(state); + bindHandlers(state); } function _buildHandle(state) { @@ -77,7 +89,10 @@ function() { // ARIA // We just want the knob to be selectable with keyboard - state.videoProgressSlider.el.attr('tabindex', -1); + state.videoProgressSlider.el.attr({ + tabindex: -1 + }); + // Let screen readers know that this div, representing the slider // handle, behaves as a slider named 'video position'. state.videoProgressSlider.handle.attr({ @@ -89,10 +104,8 @@ function() { 'aria-valuemin': '0', 'aria-valuenow': state.videoPlayer.currentTime, 'tabindex': '0', - 'aria-label': gettext('Video position') + 'aria-label': gettext('Video position. Press space to toggle playback') }); - - state.el.on('destroy', state.videoProgressSlider.destroy); } // *************************************************************** @@ -103,8 +116,11 @@ function() { // *************************************************************** function buildSlider() { - this.videoProgressSlider.el - .append('
'); + var sliderContents = edx.HtmlUtils.joinHtml( + edx.HtmlUtils.HTML('
') + ); + + this.videoProgressSlider.el.append(sliderContents.text); this.videoProgressSlider.slider = this.videoProgressSlider.el .slider({ @@ -328,5 +344,21 @@ function() { return i18n(seconds, 'second'); } + + // Shift focus to the progress slider container element. + function focusSlider() { + this.videoProgressSlider.handle.attr( + 'aria-valuetext', getTimeDescription(this.videoPlayer.currentTime) + ); + this.videoProgressSlider.el.trigger('focus'); + } + + // Toggle video playback when the spacebar is pushed. + function sliderToggle(e) { + if (e.which === 32) { + e.preventDefault(); + this.videoCommands.execute('togglePlayback'); + } + } }); }(RequireJS.requirejs, RequireJS.require, RequireJS.define)); diff --git a/common/lib/xmodule/xmodule/js/src/video/07_video_volume_control.js b/common/lib/xmodule/xmodule/js/src/video/07_video_volume_control.js index 9ac4fa3d6b..63d7b7ee35 100644 --- a/common/lib/xmodule/xmodule/js/src/video/07_video_volume_control.js +++ b/common/lib/xmodule/xmodule/js/src/video/07_video_volume_control.js @@ -40,10 +40,10 @@ function(HtmlUtils) { videoVolumeControlHtml: HtmlUtils.interpolateHtml( HtmlUtils.HTML([ '
', - '

', + '

', '{volumeInstructions}', '

', - '', '', '
' - ].join(''), - { - langTitle: gettext('Open language menu') - } - ) - + ].join('')), + { + langTitle: gettext('Open language menu'), + courseId: this.state.id + } ); var subtitlesHtml = HtmlUtils.interpolateHtml( @@ -109,7 +108,7 @@ [ '
', '

', - '
    ', + '
      ', '
      ' ].join('')), {