From dcabccc1c59d42b3469439f24d8082c8ebfebcd0 Mon Sep 17 00:00:00 2001 From: jmclaus Date: Tue, 10 Sep 2013 21:15:07 -0400 Subject: [PATCH 01/11] Tabbing through captions works except for persistence of outline after mouse click --- .../xmodule/js/src/video/09_video_caption.js | 79 ++++++++++++++++++- 1 file changed, 76 insertions(+), 3 deletions(-) diff --git a/common/lib/xmodule/xmodule/js/src/video/09_video_caption.js b/common/lib/xmodule/xmodule/js/src/video/09_video_caption.js index 2ebb73c692..be45fd95b9 100644 --- a/common/lib/xmodule/xmodule/js/src/video/09_video_caption.js +++ b/common/lib/xmodule/xmodule/js/src/video/09_video_caption.js @@ -62,6 +62,13 @@ function () { state.videoCaption.bindHandlers = _.bind(bindHandlers, state); state.videoCaption.fetchCaption = _.bind(fetchCaption, state); state.videoCaption.captionURL = _.bind(captionURL, state); + state.videoCaption.captionMouseEnter = _.bind(captionMouseEnter, state); + state.videoCaption.captionMouseLeave = _.bind(captionMouseLeave, state); + state.videoCaption.captionMouseDown = _.bind(captionMouseDown, state); + state.videoCaption.captionMouseUp = _.bind(captionMouseUp, state); + state.videoCaption.captionFocus = _.bind(captionFocus, state); + state.videoCaption.captionBlur = _.bind(captionBlur, state); + state.videoCaption.captionPressEnter = _.bind(captionPressEnter, state); } // *************************************************************** @@ -309,7 +316,8 @@ function () { liEl.attr({ 'data-index': index, - 'data-start': _this.videoCaption.start[index] + 'data-start': _this.videoCaption.start[index], + 'tabindex': 0 }); container.append(liEl); @@ -317,7 +325,16 @@ function () { this.videoCaption.subtitlesEl.html(container.html()); - this.videoCaption.subtitlesEl.find('li[data-index]').on('click', this.videoCaption.seekPlayer); + this.videoCaption.subtitlesEl.find('li[data-index]').on('mouseenter', this.videoCaption.captionMouseEnter); + this.videoCaption.subtitlesEl.find('li[data-index]').on('mouseleave', this.videoCaption.captionMouseLeave); + this.videoCaption.subtitlesEl.find('li[data-index]').on('mousedown', this.videoCaption.captionMouseDown); + this.videoCaption.subtitlesEl.find('li[data-index]').on('mouseup', this.videoCaption.captionMouseUp); + this.videoCaption.subtitlesEl.find('li[data-index]').on('click', this.videoCaption.captionMouseUp); + this.videoCaption.subtitlesEl.find('li[data-index]').on('focus', this.videoCaption.captionFocus); + this.videoCaption.subtitlesEl.find('li[data-index]').on('blur', this.videoCaption.captionBlur); + this.videoCaption.subtitlesEl.find('li[data-index]').on('keydown', this.videoCaption.captionPressEnter); + this.videoCaption.tabbing = false; + this.videoCaption.tabIndex = 0; this.videoCaption.subtitlesEl.prepend($('
  • ').height(this.videoCaption.topSpacingHeight())); this.videoCaption.subtitlesEl.append($('
  • ').height(this.videoCaption.bottomSpacingHeight())); @@ -325,10 +342,66 @@ function () { this.videoCaption.rendered = true; } + function captionMouseEnter(event) { + var target = $(event.target); + var targetIndex = parseInt(target.attr('data-index'), 10); + if (targetIndex === this.tabIndex) { + target.css('outlineWidth', '0px'); + } + } + + function captionMouseLeave(event) { + var target = $(event.target); + var targetIndex = parseInt(target.attr('data-index'), 10); + if (targetIndex === this.tabIndex) { + target.css('outlineWidth', '1px'); + } + } + + function captionMouseDown(event) { + var target = $(event.target); + target.css('outlineWidth', '0px'); + this.videoCaption.tabbing = false; + } + + function captionMouseUp(event) { + this.videoCaption.seekPlayer(event); + } + + function captionFocus(event) { + var target = $(event.target); + var targetIndex = parseInt(target.attr('data-index'), 10); + this.tabIndex = targetIndex; + target.css('outlineWidth', '1px'); + target.css('outlineStyle', 'dotted'); + if (targetIndex === 0 || + targetIndex === 1 || + targetIndex === this.videoCaption.captions.length-2 || + targetIndex === this.videoCaption.captions.length-1) { + this.videoCaption.tabbing = true; + } + } + + function captionBlur(event) { + var target = $(event.target); + targetIndex = parseInt(target.attr('data-index'), 10); + target.css('outlineWidth', '0px'); + target.css('outlineStyle', 'none'); + if (targetIndex === 0 || targetIndex === this.videoCaption.captions.length-1) { + this.videoCaption.tabbing = false; + } + } + + function captionPressEnter(event) { + if (event.which === 13) { //Enter key + this.videoCaption.seekPlayer(event); + } + } + function scrollCaption() { var el = this.videoCaption.subtitlesEl.find('.current:first'); - if (!this.videoCaption.frozen && el.length) { + if (!this.videoCaption.frozen && el.length && !this.videoCaption.tabbing) { this.videoCaption.subtitlesEl.scrollTo( el, { From b2ff98f044e711f626c7e3a3b83c1521fce132fb Mon Sep 17 00:00:00 2001 From: jmclaus Date: Wed, 11 Sep 2013 13:24:12 -0400 Subject: [PATCH 02/11] Tabbing through captions is completely functional. --- .../xmodule/js/src/video/09_video_caption.js | 90 ++++++++++++------- 1 file changed, 57 insertions(+), 33 deletions(-) diff --git a/common/lib/xmodule/xmodule/js/src/video/09_video_caption.js b/common/lib/xmodule/xmodule/js/src/video/09_video_caption.js index be45fd95b9..54a5118532 100644 --- a/common/lib/xmodule/xmodule/js/src/video/09_video_caption.js +++ b/common/lib/xmodule/xmodule/js/src/video/09_video_caption.js @@ -68,7 +68,7 @@ function () { state.videoCaption.captionMouseUp = _.bind(captionMouseUp, state); state.videoCaption.captionFocus = _.bind(captionFocus, state); state.videoCaption.captionBlur = _.bind(captionBlur, state); - state.videoCaption.captionPressEnter = _.bind(captionPressEnter, state); + state.videoCaption.captionKeyDown = _.bind(captionKeyDown, state); } // *************************************************************** @@ -332,9 +332,10 @@ function () { this.videoCaption.subtitlesEl.find('li[data-index]').on('click', this.videoCaption.captionMouseUp); this.videoCaption.subtitlesEl.find('li[data-index]').on('focus', this.videoCaption.captionFocus); this.videoCaption.subtitlesEl.find('li[data-index]').on('blur', this.videoCaption.captionBlur); - this.videoCaption.subtitlesEl.find('li[data-index]').on('keydown', this.videoCaption.captionPressEnter); - this.videoCaption.tabbing = false; - this.videoCaption.tabIndex = 0; + this.videoCaption.subtitlesEl.find('li[data-index]').on('keydown', this.videoCaption.captionKeyDown); + this.videoCaption.automaticScroll = true; + this.videoCaption.currentCaptionIndex = 0; + this.videoCaption.isMouseFocus = false; this.videoCaption.subtitlesEl.prepend($('
  • ').height(this.videoCaption.topSpacingHeight())); this.videoCaption.subtitlesEl.append($('
  • ').height(this.videoCaption.bottomSpacingHeight())); @@ -342,26 +343,29 @@ function () { this.videoCaption.rendered = true; } + // On mouseEnter, hide the outline of a caption that has been tabbed to. function captionMouseEnter(event) { - var target = $(event.target); - var targetIndex = parseInt(target.attr('data-index'), 10); - if (targetIndex === this.tabIndex) { - target.css('outlineWidth', '0px'); + var caption = $(event.target); + var captionIndex = parseInt(caption.attr('data-index'), 10); + if (captionIndex === this.videoCaption.currentCaptionIndex) { + caption.css('outlineWidth', '0px'); } } + // On mouseLeave, show the outline of a caption that has been tabbed to. function captionMouseLeave(event) { - var target = $(event.target); - var targetIndex = parseInt(target.attr('data-index'), 10); - if (targetIndex === this.tabIndex) { - target.css('outlineWidth', '1px'); + var caption = $(event.target), + captionIndex = parseInt(caption.attr('data-index'), 10); + if (captionIndex === this.videoCaption.currentCaptionIndex) { + caption.css('outlineWidth', '1px'); } } function captionMouseDown(event) { - var target = $(event.target); - target.css('outlineWidth', '0px'); - this.videoCaption.tabbing = false; + var caption = $(event.target); + this.videoCaption.isMouseFocus = true; + caption.css('outlineWidth', '0px'); + this.videoCaption.automaticScroll = true; } function captionMouseUp(event) { @@ -369,30 +373,50 @@ function () { } function captionFocus(event) { - var target = $(event.target); - var targetIndex = parseInt(target.attr('data-index'), 10); - this.tabIndex = targetIndex; - target.css('outlineWidth', '1px'); - target.css('outlineStyle', 'dotted'); - if (targetIndex === 0 || - targetIndex === 1 || - targetIndex === this.videoCaption.captions.length-2 || - targetIndex === this.videoCaption.captions.length-1) { - this.videoCaption.tabbing = true; + var caption = $(event.target), + captionIndex = parseInt(caption.attr('data-index'), 10); + // If the focus comes from a mouse click, hide the outline and turn on + // automatic scrolling. + if (this.videoCaption.isMouseFocus) { + this.videoCaption.automaticScroll = true; + caption.css('outlineWidth', '0px'); + caption.css('outlineStyle', 'none'); + } + // If the focus comes from tabbing, show the outline and turn off + // automatic scrolling. + else { + this.videoCaption.currentCaptionIndex = captionIndex; + caption.css('outlineWidth', '1px'); + caption.css('outlineStyle', 'dotted'); + // The second and second to last elements turn automatic scrolling + // off again as it may have been enabled in captionBlur. + if (captionIndex === 0 || + captionIndex === 1 || + captionIndex === this.videoCaption.captions.length-2 || + captionIndex === this.videoCaption.captions.length-1) { + this.videoCaption.automaticScroll = false; + } } } function captionBlur(event) { - var target = $(event.target); - targetIndex = parseInt(target.attr('data-index'), 10); - target.css('outlineWidth', '0px'); - target.css('outlineStyle', 'none'); - if (targetIndex === 0 || targetIndex === this.videoCaption.captions.length-1) { - this.videoCaption.tabbing = false; + var caption = $(event.target), + captionIndex = parseInt(caption.attr('data-index'), 10); + caption.css('outlineWidth', '0px'); + caption.css('outlineStyle', 'none'); + // If we are on first or last index, we have to turn automatic scroll on + // again when losing focus. There is no way to know in what direction we + // are tabbing. So we could be on the first element and tabbing back out + // of the captions or on the last element and tabbing forward out of the + // captions. + if (captionIndex === 0 || + captionIndex === this.videoCaption.captions.length-1) { + this.videoCaption.automaticScroll = true; } } - function captionPressEnter(event) { + function captionKeyDown(event) { + this.videoCaption.isMouseFocus = false; if (event.which === 13) { //Enter key this.videoCaption.seekPlayer(event); } @@ -401,7 +425,7 @@ function () { function scrollCaption() { var el = this.videoCaption.subtitlesEl.find('.current:first'); - if (!this.videoCaption.frozen && el.length && !this.videoCaption.tabbing) { + if (!this.videoCaption.frozen && el.length && this.videoCaption.automaticScroll) { this.videoCaption.subtitlesEl.scrollTo( el, { From cf69e35f11740c345eb847470e5eb30a5e426e2d Mon Sep 17 00:00:00 2001 From: jmclaus Date: Wed, 11 Sep 2013 14:53:36 -0400 Subject: [PATCH 03/11] Adressed pull request comments --- .../xmodule/js/src/video/09_video_caption.js | 118 +++++++++--------- 1 file changed, 58 insertions(+), 60 deletions(-) diff --git a/common/lib/xmodule/xmodule/js/src/video/09_video_caption.js b/common/lib/xmodule/xmodule/js/src/video/09_video_caption.js index 54a5118532..a814d1a030 100644 --- a/common/lib/xmodule/xmodule/js/src/video/09_video_caption.js +++ b/common/lib/xmodule/xmodule/js/src/video/09_video_caption.js @@ -37,38 +37,37 @@ function () { // Functions which will be accessible via 'state' object. When called, these functions will // get the 'state' object as a context. function _makeFunctionsPublic(state) { - state.videoCaption.autoShowCaptions = _.bind(autoShowCaptions, state); - state.videoCaption.autoHideCaptions = _.bind(autoHideCaptions, state); - state.videoCaption.resize = _.bind(resize, state); - state.videoCaption.toggle = _.bind(toggle, state); - state.videoCaption.onMouseEnter = _.bind(onMouseEnter, state); - state.videoCaption.onMouseLeave = _.bind(onMouseLeave, state); - state.videoCaption.onMovement = _.bind(onMovement, state); - state.videoCaption.renderCaption = _.bind(renderCaption, state); - state.videoCaption.captionHeight = _.bind(captionHeight, state); - state.videoCaption.topSpacingHeight = _.bind(topSpacingHeight, state); - state.videoCaption.bottomSpacingHeight = _.bind(bottomSpacingHeight, state); - state.videoCaption.scrollCaption = _.bind(scrollCaption, state); - state.videoCaption.search = _.bind(search, state); - state.videoCaption.play = _.bind(play, state); - state.videoCaption.pause = _.bind(pause, state); - state.videoCaption.seekPlayer = _.bind(seekPlayer, state); - state.videoCaption.hideCaptions = _.bind(hideCaptions, state); - state.videoCaption.calculateOffset = _.bind(calculateOffset, state); - state.videoCaption.updatePlayTime = _.bind(updatePlayTime, state); - state.videoCaption.setSubtitlesHeight = _.bind(setSubtitlesHeight, state); + state.videoCaption.autoShowCaptions = _.bind(autoShowCaptions, state); + state.videoCaption.autoHideCaptions = _.bind(autoHideCaptions, state); + state.videoCaption.resize = _.bind(resize, state); + state.videoCaption.toggle = _.bind(toggle, state); + state.videoCaption.onMouseEnter = _.bind(onMouseEnter, state); + state.videoCaption.onMouseLeave = _.bind(onMouseLeave, state); + state.videoCaption.onMovement = _.bind(onMovement, state); + state.videoCaption.renderCaption = _.bind(renderCaption, state); + state.videoCaption.captionHeight = _.bind(captionHeight, state); + state.videoCaption.topSpacingHeight = _.bind(topSpacingHeight, state); + state.videoCaption.bottomSpacingHeight = _.bind(bottomSpacingHeight, state); + state.videoCaption.scrollCaption = _.bind(scrollCaption, state); + state.videoCaption.search = _.bind(search, state); + state.videoCaption.play = _.bind(play, state); + state.videoCaption.pause = _.bind(pause, state); + state.videoCaption.seekPlayer = _.bind(seekPlayer, state); + state.videoCaption.hideCaptions = _.bind(hideCaptions, state); + state.videoCaption.calculateOffset = _.bind(calculateOffset, state); + state.videoCaption.updatePlayTime = _.bind(updatePlayTime, state); + state.videoCaption.setSubtitlesHeight = _.bind(setSubtitlesHeight, state); - state.videoCaption.renderElements = _.bind(renderElements, state); - state.videoCaption.bindHandlers = _.bind(bindHandlers, state); - state.videoCaption.fetchCaption = _.bind(fetchCaption, state); - state.videoCaption.captionURL = _.bind(captionURL, state); - state.videoCaption.captionMouseEnter = _.bind(captionMouseEnter, state); - state.videoCaption.captionMouseLeave = _.bind(captionMouseLeave, state); - state.videoCaption.captionMouseDown = _.bind(captionMouseDown, state); - state.videoCaption.captionMouseUp = _.bind(captionMouseUp, state); - state.videoCaption.captionFocus = _.bind(captionFocus, state); - state.videoCaption.captionBlur = _.bind(captionBlur, state); - state.videoCaption.captionKeyDown = _.bind(captionKeyDown, state); + state.videoCaption.renderElements = _.bind(renderElements, state); + state.videoCaption.bindHandlers = _.bind(bindHandlers, state); + state.videoCaption.fetchCaption = _.bind(fetchCaption, state); + state.videoCaption.captionURL = _.bind(captionURL, state); + state.videoCaption.captionMouseEnterLeave = _.bind(captionMouseEnterLeave, state); + state.videoCaption.captionMouseDown = _.bind(captionMouseDown, state); + state.videoCaption.captionMouseUp = _.bind(captionMouseUp, state); + state.videoCaption.captionFocus = _.bind(captionFocus, state); + state.videoCaption.captionBlur = _.bind(captionBlur, state); + state.videoCaption.captionKeyDown = _.bind(captionKeyDown, state); } // *************************************************************** @@ -325,14 +324,17 @@ function () { this.videoCaption.subtitlesEl.html(container.html()); - this.videoCaption.subtitlesEl.find('li[data-index]').on('mouseenter', this.videoCaption.captionMouseEnter); - this.videoCaption.subtitlesEl.find('li[data-index]').on('mouseleave', this.videoCaption.captionMouseLeave); - this.videoCaption.subtitlesEl.find('li[data-index]').on('mousedown', this.videoCaption.captionMouseDown); - this.videoCaption.subtitlesEl.find('li[data-index]').on('mouseup', this.videoCaption.captionMouseUp); - this.videoCaption.subtitlesEl.find('li[data-index]').on('click', this.videoCaption.captionMouseUp); - this.videoCaption.subtitlesEl.find('li[data-index]').on('focus', this.videoCaption.captionFocus); - this.videoCaption.subtitlesEl.find('li[data-index]').on('blur', this.videoCaption.captionBlur); - this.videoCaption.subtitlesEl.find('li[data-index]').on('keydown', this.videoCaption.captionKeyDown); + this.videoCaption.subtitlesEl.find('li[data-index]').on({ + mouseenter: this.videoCaption.captionMouseEnterLeave, + mouseleave: this.videoCaption.captionMouseEnterLeave, + mousedown: this.videoCaption.captionMouseDown, + mouseup: this.videoCaption.captionMouseUp, + click: this.videoCaption.captionMouseUp, + focus: this.videoCaption.captionFocus, + blur: this.videoCaption.captionBlur, + keydown: this.videoCaption.captionKeyDown + }); + this.videoCaption.automaticScroll = true; this.videoCaption.currentCaptionIndex = 0; this.videoCaption.isMouseFocus = false; @@ -344,21 +346,14 @@ function () { } // On mouseEnter, hide the outline of a caption that has been tabbed to. - function captionMouseEnter(event) { - var caption = $(event.target); - var captionIndex = parseInt(caption.attr('data-index'), 10); - if (captionIndex === this.videoCaption.currentCaptionIndex) { - caption.css('outlineWidth', '0px'); - } - } - // On mouseLeave, show the outline of a caption that has been tabbed to. - function captionMouseLeave(event) { + function captionMouseEnterLeave(event) { var caption = $(event.target), + outlineWidth = (event.type === 'mouseleave') ? 1 : 0, captionIndex = parseInt(caption.attr('data-index'), 10); if (captionIndex === this.videoCaption.currentCaptionIndex) { - caption.css('outlineWidth', '1px'); - } + caption.css('outlineWidth', outlineWidth + 'px'); + } } function captionMouseDown(event) { @@ -379,21 +374,22 @@ function () { // automatic scrolling. if (this.videoCaption.isMouseFocus) { this.videoCaption.automaticScroll = true; - caption.css('outlineWidth', '0px'); - caption.css('outlineStyle', 'none'); + caption.css({ + 'outlineWidth': '0px', + 'outlineStyle': 'none' + }); } // If the focus comes from tabbing, show the outline and turn off // automatic scrolling. else { this.videoCaption.currentCaptionIndex = captionIndex; - caption.css('outlineWidth', '1px'); - caption.css('outlineStyle', 'dotted'); + caption.css({ + 'outlineWidth': '1px', + 'outlineStyle': 'dotted' + }); // The second and second to last elements turn automatic scrolling // off again as it may have been enabled in captionBlur. - if (captionIndex === 0 || - captionIndex === 1 || - captionIndex === this.videoCaption.captions.length-2 || - captionIndex === this.videoCaption.captions.length-1) { + if (captionIndex <= 1 || captionIndex >= this.videoCaption.captions.length-2) { this.videoCaption.automaticScroll = false; } } @@ -402,8 +398,10 @@ function () { function captionBlur(event) { var caption = $(event.target), captionIndex = parseInt(caption.attr('data-index'), 10); - caption.css('outlineWidth', '0px'); - caption.css('outlineStyle', 'none'); + caption.css({ + 'outlineWidth': '0px', + 'outlineStyle': 'none' + }); // If we are on first or last index, we have to turn automatic scroll on // again when losing focus. There is no way to know in what direction we // are tabbing. So we could be on the first element and tabbing back out From 165a1227667e672eeedc223bd8a1ff311630b490 Mon Sep 17 00:00:00 2001 From: jmclaus Date: Thu, 12 Sep 2013 15:45:23 -0400 Subject: [PATCH 04/11] Removed unnecessary event handler --- .../lib/xmodule/xmodule/js/src/video/09_video_caption.js | 7 +++---- 1 file changed, 3 insertions(+), 4 deletions(-) diff --git a/common/lib/xmodule/xmodule/js/src/video/09_video_caption.js b/common/lib/xmodule/xmodule/js/src/video/09_video_caption.js index a814d1a030..e810f8a4c4 100644 --- a/common/lib/xmodule/xmodule/js/src/video/09_video_caption.js +++ b/common/lib/xmodule/xmodule/js/src/video/09_video_caption.js @@ -64,7 +64,7 @@ function () { state.videoCaption.captionURL = _.bind(captionURL, state); state.videoCaption.captionMouseEnterLeave = _.bind(captionMouseEnterLeave, state); state.videoCaption.captionMouseDown = _.bind(captionMouseDown, state); - state.videoCaption.captionMouseUp = _.bind(captionMouseUp, state); + state.videoCaption.captionClick = _.bind(captionClick, state); state.videoCaption.captionFocus = _.bind(captionFocus, state); state.videoCaption.captionBlur = _.bind(captionBlur, state); state.videoCaption.captionKeyDown = _.bind(captionKeyDown, state); @@ -328,8 +328,7 @@ function () { mouseenter: this.videoCaption.captionMouseEnterLeave, mouseleave: this.videoCaption.captionMouseEnterLeave, mousedown: this.videoCaption.captionMouseDown, - mouseup: this.videoCaption.captionMouseUp, - click: this.videoCaption.captionMouseUp, + click: this.videoCaption.captionClick, focus: this.videoCaption.captionFocus, blur: this.videoCaption.captionBlur, keydown: this.videoCaption.captionKeyDown @@ -363,7 +362,7 @@ function () { this.videoCaption.automaticScroll = true; } - function captionMouseUp(event) { + function captionClick(event) { this.videoCaption.seekPlayer(event); } From c541fb7bf4ff29609196aea7da51b6f1e94df8df Mon Sep 17 00:00:00 2001 From: jmclaus Date: Fri, 13 Sep 2013 17:25:07 -0400 Subject: [PATCH 05/11] Added comments --- .../xmodule/js/src/video/09_video_caption.js | 28 +++++++++++++++---- 1 file changed, 22 insertions(+), 6 deletions(-) diff --git a/common/lib/xmodule/xmodule/js/src/video/09_video_caption.js b/common/lib/xmodule/xmodule/js/src/video/09_video_caption.js index e810f8a4c4..69d9c65346 100644 --- a/common/lib/xmodule/xmodule/js/src/video/09_video_caption.js +++ b/common/lib/xmodule/xmodule/js/src/video/09_video_caption.js @@ -334,8 +334,22 @@ function () { keydown: this.videoCaption.captionKeyDown }); - this.videoCaption.automaticScroll = true; + // Enables or disables automatic scrolling of the captions when the + // video is playing. This feature has to be disabled when tabbing + // through them as it interferes with that action. Initially, have this + // flag enabled as we assume mouse use. Then, if the first caption + // (through forward tabbing) or the last caption (through backwards + // tabbing) gets the focus, disable that feature. Renable it if tabbing + // then cycles out of the the captions. + this.videoCaption.autoScrolling = true; + // Keeps track of where the focus is situated in the array of captions. + // Used to implement the automatic scrolling behavior and decide if the + // outline around a caption has to be hidden or shown on a mouseenter or + // mouseleave. this.videoCaption.currentCaptionIndex = 0; + // Used to track if the focus is coming from a click or tabbing. This + // has to be known to decide if, when a caption gets the focus, an + // outline has to be drawn (tabbing) or not (mouse click). this.videoCaption.isMouseFocus = false; this.videoCaption.subtitlesEl.prepend($('
  • ').height(this.videoCaption.topSpacingHeight())); @@ -359,7 +373,7 @@ function () { var caption = $(event.target); this.videoCaption.isMouseFocus = true; caption.css('outlineWidth', '0px'); - this.videoCaption.automaticScroll = true; + this.videoCaption.autoScrolling = true; } function captionClick(event) { @@ -372,7 +386,7 @@ function () { // If the focus comes from a mouse click, hide the outline and turn on // automatic scrolling. if (this.videoCaption.isMouseFocus) { - this.videoCaption.automaticScroll = true; + this.videoCaption.autoScrolling = true; caption.css({ 'outlineWidth': '0px', 'outlineStyle': 'none' @@ -389,7 +403,7 @@ function () { // The second and second to last elements turn automatic scrolling // off again as it may have been enabled in captionBlur. if (captionIndex <= 1 || captionIndex >= this.videoCaption.captions.length-2) { - this.videoCaption.automaticScroll = false; + this.videoCaption.autoScrolling = false; } } } @@ -408,7 +422,7 @@ function () { // captions. if (captionIndex === 0 || captionIndex === this.videoCaption.captions.length-1) { - this.videoCaption.automaticScroll = true; + this.videoCaption.autoScrolling = true; } } @@ -422,7 +436,9 @@ function () { function scrollCaption() { var el = this.videoCaption.subtitlesEl.find('.current:first'); - if (!this.videoCaption.frozen && el.length && this.videoCaption.automaticScroll) { + // Automatic scrolling gets disabled if one of the captions has received + // focus through tabbing. + if (!this.videoCaption.frozen && el.length && this.videoCaption.autoScrolling) { this.videoCaption.subtitlesEl.scrollTo( el, { From 5ccf717db296b6f1d30d1e3e29d602fa25f5f624 Mon Sep 17 00:00:00 2001 From: jmclaus Date: Mon, 16 Sep 2013 15:02:16 -0400 Subject: [PATCH 06/11] Moved css from js file to relevant scss file. --- .../xmodule/xmodule/css/video/display.scss | 10 ++++++ .../xmodule/js/src/video/09_video_caption.js | 31 +++++++++---------- 2 files changed, 24 insertions(+), 17 deletions(-) diff --git a/common/lib/xmodule/xmodule/css/video/display.scss b/common/lib/xmodule/xmodule/css/video/display.scss index d133426fb5..7e67207fb0 100644 --- a/common/lib/xmodule/xmodule/css/video/display.scss +++ b/common/lib/xmodule/xmodule/css/video/display.scss @@ -531,6 +531,16 @@ div.video { font-weight: 700; } + &.unfocused { + outline-width: 0px; + outline-style: none; + } + + &.focused { + outline-width: 1px; + outline-style: dotted; + } + &:hover { color: $blue; } diff --git a/common/lib/xmodule/xmodule/js/src/video/09_video_caption.js b/common/lib/xmodule/xmodule/js/src/video/09_video_caption.js index 69d9c65346..b3c42c0772 100644 --- a/common/lib/xmodule/xmodule/js/src/video/09_video_caption.js +++ b/common/lib/xmodule/xmodule/js/src/video/09_video_caption.js @@ -362,17 +362,21 @@ function () { // On mouseLeave, show the outline of a caption that has been tabbed to. function captionMouseEnterLeave(event) { var caption = $(event.target), - outlineWidth = (event.type === 'mouseleave') ? 1 : 0, captionIndex = parseInt(caption.attr('data-index'), 10); if (captionIndex === this.videoCaption.currentCaptionIndex) { - caption.css('outlineWidth', outlineWidth + 'px'); + if (event.type === 'mouseenter') { + caption.removeClass('focused').addClass('unfocused'); + } + else { // mouseleave + caption.removeClass('unfocused').addClass('focused'); + } } } function captionMouseDown(event) { var caption = $(event.target); this.videoCaption.isMouseFocus = true; - caption.css('outlineWidth', '0px'); + caption.removeClass('focused').addClass('unfocused'); this.videoCaption.autoScrolling = true; } @@ -383,23 +387,19 @@ function () { function captionFocus(event) { var caption = $(event.target), captionIndex = parseInt(caption.attr('data-index'), 10); - // If the focus comes from a mouse click, hide the outline and turn on - // automatic scrolling. + // If the focus comes from a mouse click, hide the outline, turn on + // automatic scrolling and set currentCaptionIndex to point outside of + // caption list (ie -1) to disable mouseenter, mouseleave behavior. if (this.videoCaption.isMouseFocus) { this.videoCaption.autoScrolling = true; - caption.css({ - 'outlineWidth': '0px', - 'outlineStyle': 'none' - }); + caption.removeClass('focused').addClass('unfocused'); + this.videoCaption.currentCaptionIndex = -1; } // If the focus comes from tabbing, show the outline and turn off // automatic scrolling. else { this.videoCaption.currentCaptionIndex = captionIndex; - caption.css({ - 'outlineWidth': '1px', - 'outlineStyle': 'dotted' - }); + caption.removeClass('unfocused').addClass('focused'); // The second and second to last elements turn automatic scrolling // off again as it may have been enabled in captionBlur. if (captionIndex <= 1 || captionIndex >= this.videoCaption.captions.length-2) { @@ -411,10 +411,7 @@ function () { function captionBlur(event) { var caption = $(event.target), captionIndex = parseInt(caption.attr('data-index'), 10); - caption.css({ - 'outlineWidth': '0px', - 'outlineStyle': 'none' - }); + caption.removeClass('focused').addClass('unfocused'); // If we are on first or last index, we have to turn automatic scroll on // again when losing focus. There is no way to know in what direction we // are tabbing. So we could be on the first element and tabbing back out From 2fb6c02ba18891af011c3d7b5fc25483d164579b Mon Sep 17 00:00:00 2001 From: jmclaus Date: Wed, 18 Sep 2013 10:14:04 +0200 Subject: [PATCH 07/11] Added tests for tabbing through captions --- .../js/spec/video/video_caption_spec.js | 110 +++++++++++++++++- 1 file changed, 108 insertions(+), 2 deletions(-) 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 7751b80e51..3b0e4b6a7d 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 @@ -93,6 +93,7 @@ $('.subtitles li[data-index]').each(function(index, link) { expect($(link)).toHaveData('index', index); expect($(link)).toHaveData('start', captionsData.start[index]); + expect($(link)).toHaveData('tabindex', 0); expect($(link)).toHaveText(captionsData.text[index]); }); }); @@ -104,7 +105,13 @@ it('bind all the caption link', function() { $('.subtitles li[data-index]').each(function(index, link) { - expect($(link)).toHandleWith('click', videoCaption.seekPlayer); + expect($(link)).toHandleWith('mouseenter', videoCaption.captionMouseEnterLeave); + expect($(link)).toHandleWith('mouseleave', videoCaption.captionMouseEnterLeave); + expect($(link)).toHandleWith('mousedown', videoCaption.captionMouseDown); + expect($(link)).toHandleWith('click', videoCaption.captionClick); + expect($(link)).toHandleWith('focus', videoCaption.captionFocus); + expect($(link)).toHandleWith('blur', videoCaption.captionBlur); + expect($(link)).toHandleWith('keydown', videoCaption.captionKeyDown); }); }); @@ -278,6 +285,7 @@ $('.subtitles li[data-index]').each(function(index, link) { expect($(link)).toHaveData('index', index); expect($(link)).toHaveData('start', captionsData.start[index]); + expect($(link)).toHaveData('tabindex', 0); expect($(link)).toHaveText(captionsData.text[index]); }); }); @@ -289,7 +297,13 @@ it('bind all the caption link', function() { $('.subtitles li[data-index]').each(function(index, link) { - expect($(link)).toHandleWith('click', videoCaption.seekPlayer); + expect($(link)).toHandleWith('mouseenter', videoCaption.captionMouseEnterLeave); + expect($(link)).toHandleWith('mouseleave', videoCaption.captionMouseEnterLeave); + expect($(link)).toHandleWith('mousedown', videoCaption.captionMouseDown); + expect($(link)).toHandleWith('click', videoCaption.captionClick); + expect($(link)).toHandleWith('focus', videoCaption.captionFocus); + expect($(link)).toHandleWith('blur', videoCaption.captionBlur); + expect($(link)).toHandleWith('keydown', videoCaption.captionKeyDown); }); }); @@ -558,6 +572,98 @@ }); }); }); + + describe('caption accessibility', function() { + beforeEach(function() { + initialize(); + }); + + describe('when getting focus through TAB key', function() { + beforeEach(function() { + $('.subtitles li:first').trigger(jQuery.Event('focus'); + }); + + it('shows an outline around the caption', function() { + expect($('.subtitles li:first')).not.toHaveClass('unfocused'); + expect($('.subtitles li:first')).toHaveClass('focused'); + }); + + it('has automatic scrolling disabled', function() { + expect(videoCaption.autoScrolling).toBe(false)); + }); + }); + + describe('when loosing focus through TAB key', function() { + beforeEach(function() { + $('.subtitles li:first').trigger(jQuery.Event('blur'); + }); + + it('does not show an outline around the caption', function() { + expect($('.subtitles li:first')).not.toHaveClass('focused'); + expect($('.subtitles li:first')).toHaveClass('unfocused'); + }); + + it('has automatic scrolling enabled', function() { + expect(videoCaption.autoScrolling).toBe(true)); + }); + }); + + describe('when same caption gets the focus through mouse after having + focus through TAB key', function() { + beforeEach(function() { + $('.subtitles li:first').trigger(jQuery.Event('focus'); + $('.subtitles li:first').trigger(jQuery.Event('mouseclick'); + }); + + it('does not show an outline around it', function() { + expect($('.subtitles li:first')).not.toHaveClass('focused'); + expect($('.subtitles li:first')).toHaveClass('unfocused'); + }); + + it('has automatic scrolling enabled', function() { + expect(videoCaption.autoScrolling).toBe(true)); + }); + }); + + describe('when a second caption gets focus through mouse after first had + focus through TAB key', function() { + beforeEach(function() { + $('.subtitles li:first').trigger(jQuery.Event('focus'); + $('.subtitles li:last').trigger(jQuery.Event('mouseclick'); + }); + + it('does not show an outline around the first', function() { + expect($('.subtitles li:first')).not.toHaveClass('focused'); + expect($('.subtitles li:first')).toHaveClass('unfocused'); + }); + + it('shows an outline around the second', function() { + expect($('.subtitles li:last')).not.toHaveClass('unfocused'); + expect($('.subtitles li:last')).toHaveClass('focused'); + }); + + it('has automatic scrolling enabled', function() { + expect(videoCaption.autoScrolling).toBe(true)); + }); + }); + + describe('when enter key is pressed on a caption', function() { + beforeEach(function() { + var e = $.Event('keypress'); + e.which = 13; // ENTER key + $('.subtitles li:first').trigger(e); + }); + + it('shows an outline around it', function() { + expect($('.subtitles li:first')).not.toHaveClass('unfocused'); + expect($('.subtitles li:first')).toHaveClass('focused'); + }); + + it('calls seekPlayer', function() { + expect(videoCaption.seekPlayer).toHaveBeenCalled(); + }); + }); + }); }); }).call(this); From 27d006735cc57ad9cbb58cd7df026bfbe4fd75e0 Mon Sep 17 00:00:00 2001 From: jmclaus Date: Wed, 18 Sep 2013 13:39:44 +0200 Subject: [PATCH 08/11] Bug fixes, mainly in tests --- .../js/spec/video/video_caption_spec.js | 63 ++++++++++--------- .../xmodule/js/src/video/09_video_caption.js | 3 +- 2 files changed, 34 insertions(+), 32 deletions(-) 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 3b0e4b6a7d..7e39e6c807 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 @@ -93,7 +93,7 @@ $('.subtitles li[data-index]').each(function(index, link) { expect($(link)).toHaveData('index', index); expect($(link)).toHaveData('start', captionsData.start[index]); - expect($(link)).toHaveData('tabindex', 0); + expect($(link)).toHaveAttr('tabindex', 0); expect($(link)).toHaveText(captionsData.text[index]); }); }); @@ -285,7 +285,7 @@ $('.subtitles li[data-index]').each(function(index, link) { expect($(link)).toHaveData('index', index); expect($(link)).toHaveData('start', captionsData.start[index]); - expect($(link)).toHaveData('tabindex', 0); + expect($(link)).toHaveAttr('tabindex', 0); expect($(link)).toHaveText(captionsData.text[index]); }); }); @@ -580,83 +580,84 @@ describe('when getting focus through TAB key', function() { beforeEach(function() { - $('.subtitles li:first').trigger(jQuery.Event('focus'); + videoCaption.isMouseFocus = false; + $('.subtitles li[data-index=0]').trigger(jQuery.Event('focus')); }); it('shows an outline around the caption', function() { - expect($('.subtitles li:first')).not.toHaveClass('unfocused'); - expect($('.subtitles li:first')).toHaveClass('focused'); + expect($('.subtitles li[data-index=0]')).toHaveClass('focused'); }); it('has automatic scrolling disabled', function() { - expect(videoCaption.autoScrolling).toBe(false)); + expect(videoCaption.autoScrolling).toBe(false); }); }); describe('when loosing focus through TAB key', function() { beforeEach(function() { - $('.subtitles li:first').trigger(jQuery.Event('blur'); + $('.subtitles li[data-index=0]').trigger(jQuery.Event('blur')); }); it('does not show an outline around the caption', function() { - expect($('.subtitles li:first')).not.toHaveClass('focused'); - expect($('.subtitles li:first')).toHaveClass('unfocused'); + expect($('.subtitles li[data-index=0]')).not.toHaveClass('focused'); }); it('has automatic scrolling enabled', function() { - expect(videoCaption.autoScrolling).toBe(true)); + expect(videoCaption.autoScrolling).toBe(true); }); }); - describe('when same caption gets the focus through mouse after having - focus through TAB key', function() { + describe('when same caption gets the focus through mouse after having focus through TAB key', function() { beforeEach(function() { - $('.subtitles li:first').trigger(jQuery.Event('focus'); - $('.subtitles li:first').trigger(jQuery.Event('mouseclick'); + videoCaption.isMouseFocus = false; + $('.subtitles li[data-index=0]').trigger(jQuery.Event('focus')); + $('.subtitles li[data-index=0]').trigger(jQuery.Event('mousedown')); }); it('does not show an outline around it', function() { - expect($('.subtitles li:first')).not.toHaveClass('focused'); - expect($('.subtitles li:first')).toHaveClass('unfocused'); + expect($('.subtitles li[data-index=0]')).not.toHaveClass('focused'); }); it('has automatic scrolling enabled', function() { - expect(videoCaption.autoScrolling).toBe(true)); + expect(videoCaption.autoScrolling).toBe(true); }); }); - describe('when a second caption gets focus through mouse after first had - focus through TAB key', function() { + describe('when a second caption gets focus through mouse after first had focus through TAB key', function() { beforeEach(function() { - $('.subtitles li:first').trigger(jQuery.Event('focus'); - $('.subtitles li:last').trigger(jQuery.Event('mouseclick'); + videoCaption.isMouseFocus = false; + $('.subtitles li[data-index=0]').trigger(jQuery.Event('focus')); + $('.subtitles li[data-index=0]').trigger(jQuery.Event('blur')); + videoCaption.isMouseFocus = true; + $('.subtitles li[data-index=1]').trigger(jQuery.Event('mousedown')); }); it('does not show an outline around the first', function() { - expect($('.subtitles li:first')).not.toHaveClass('focused'); - expect($('.subtitles li:first')).toHaveClass('unfocused'); + expect($('.subtitles li[data-index=0]')).not.toHaveClass('focused'); }); - it('shows an outline around the second', function() { - expect($('.subtitles li:last')).not.toHaveClass('unfocused'); - expect($('.subtitles li:last')).toHaveClass('focused'); + it('does not show an outline around the second', function() { + expect($('.subtitles li[data-index=1]')).not.toHaveClass('focused'); }); it('has automatic scrolling enabled', function() { - expect(videoCaption.autoScrolling).toBe(true)); + expect(videoCaption.autoScrolling).toBe(true); }); }); describe('when enter key is pressed on a caption', function() { beforeEach(function() { - var e = $.Event('keypress'); + var e; + spyOn(videoCaption, 'seekPlayer').andCallThrough(); + videoCaption.isMouseFocus = false; + $('.subtitles li[data-index=0]').trigger(jQuery.Event('focus')); + e = jQuery.Event('keydown'); e.which = 13; // ENTER key - $('.subtitles li:first').trigger(e); + $('.subtitles li[data-index=0]').trigger(e); }); it('shows an outline around it', function() { - expect($('.subtitles li:first')).not.toHaveClass('unfocused'); - expect($('.subtitles li:first')).toHaveClass('focused'); + expect($('.subtitles li[data-index=0]')).toHaveClass('focused'); }); it('calls seekPlayer', function() { diff --git a/common/lib/xmodule/xmodule/js/src/video/09_video_caption.js b/common/lib/xmodule/xmodule/js/src/video/09_video_caption.js index b3c42c0772..ffd845cb13 100644 --- a/common/lib/xmodule/xmodule/js/src/video/09_video_caption.js +++ b/common/lib/xmodule/xmodule/js/src/video/09_video_caption.js @@ -376,8 +376,9 @@ function () { function captionMouseDown(event) { var caption = $(event.target); this.videoCaption.isMouseFocus = true; - caption.removeClass('focused').addClass('unfocused'); this.videoCaption.autoScrolling = true; + caption.removeClass('focused').addClass('unfocused'); + this.videoCaption.currentCaptionIndex = -1; } function captionClick(event) { From 497f324d8a8fe964d75067d61d2616a06cca662e Mon Sep 17 00:00:00 2001 From: jmclaus Date: Wed, 18 Sep 2013 15:58:07 +0200 Subject: [PATCH 09/11] Replaced mouseenter and mouseleave event handlers by mouseover and mouseout. The former were failing Jasmine tests. Since the captions are li elements without descendants, they are identical. --- .../xmodule/js/spec/video/video_caption_spec.js | 8 ++++---- .../xmodule/js/src/video/09_video_caption.js | 16 ++++++++-------- 2 files changed, 12 insertions(+), 12 deletions(-) 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 7e39e6c807..2273e4be71 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 @@ -105,8 +105,8 @@ it('bind all the caption link', function() { $('.subtitles li[data-index]').each(function(index, link) { - expect($(link)).toHandleWith('mouseenter', videoCaption.captionMouseEnterLeave); - expect($(link)).toHandleWith('mouseleave', videoCaption.captionMouseEnterLeave); + expect($(link)).toHandleWith('mouseover', videoCaption.captionMouseOverOut); + expect($(link)).toHandleWith('mouseout', videoCaption.captionMouseOverOut); expect($(link)).toHandleWith('mousedown', videoCaption.captionMouseDown); expect($(link)).toHandleWith('click', videoCaption.captionClick); expect($(link)).toHandleWith('focus', videoCaption.captionFocus); @@ -297,8 +297,8 @@ it('bind all the caption link', function() { $('.subtitles li[data-index]').each(function(index, link) { - expect($(link)).toHandleWith('mouseenter', videoCaption.captionMouseEnterLeave); - expect($(link)).toHandleWith('mouseleave', videoCaption.captionMouseEnterLeave); + expect($(link)).toHandleWith('mouseover', videoCaption.captionMouseOverOut); + expect($(link)).toHandleWith('mouseout', videoCaption.captionMouseOverOut); expect($(link)).toHandleWith('mousedown', videoCaption.captionMouseDown); expect($(link)).toHandleWith('click', videoCaption.captionClick); expect($(link)).toHandleWith('focus', videoCaption.captionFocus); diff --git a/common/lib/xmodule/xmodule/js/src/video/09_video_caption.js b/common/lib/xmodule/xmodule/js/src/video/09_video_caption.js index ffd845cb13..c9499fe44b 100644 --- a/common/lib/xmodule/xmodule/js/src/video/09_video_caption.js +++ b/common/lib/xmodule/xmodule/js/src/video/09_video_caption.js @@ -62,7 +62,7 @@ function () { state.videoCaption.bindHandlers = _.bind(bindHandlers, state); state.videoCaption.fetchCaption = _.bind(fetchCaption, state); state.videoCaption.captionURL = _.bind(captionURL, state); - state.videoCaption.captionMouseEnterLeave = _.bind(captionMouseEnterLeave, state); + state.videoCaption.captionMouseOverOut = _.bind(captionMouseOverOut, state); state.videoCaption.captionMouseDown = _.bind(captionMouseDown, state); state.videoCaption.captionClick = _.bind(captionClick, state); state.videoCaption.captionFocus = _.bind(captionFocus, state); @@ -325,8 +325,8 @@ function () { this.videoCaption.subtitlesEl.html(container.html()); this.videoCaption.subtitlesEl.find('li[data-index]').on({ - mouseenter: this.videoCaption.captionMouseEnterLeave, - mouseleave: this.videoCaption.captionMouseEnterLeave, + mouseover: this.videoCaption.captionMouseOverOut, + mouseout: this.videoCaption.captionMouseOverOut, mousedown: this.videoCaption.captionMouseDown, click: this.videoCaption.captionClick, focus: this.videoCaption.captionFocus, @@ -358,16 +358,16 @@ function () { this.videoCaption.rendered = true; } - // On mouseEnter, hide the outline of a caption that has been tabbed to. - // On mouseLeave, show the outline of a caption that has been tabbed to. - function captionMouseEnterLeave(event) { + // On mouseOver, hide the outline of a caption that has been tabbed to. + // On mouseOut, show the outline of a caption that has been tabbed to. + function captionMouseOverOut(event) { var caption = $(event.target), captionIndex = parseInt(caption.attr('data-index'), 10); if (captionIndex === this.videoCaption.currentCaptionIndex) { - if (event.type === 'mouseenter') { + if (event.type === 'mouseover') { caption.removeClass('focused').addClass('unfocused'); } - else { // mouseleave + else { // mouseout caption.removeClass('unfocused').addClass('focused'); } } From 752e1d8b4f2da8b638f3a197c534c5f2f3668649 Mon Sep 17 00:00:00 2001 From: jmclaus Date: Wed, 18 Sep 2013 17:11:59 +0200 Subject: [PATCH 10/11] Caption have unfocused class as default --- common/lib/xmodule/xmodule/js/src/video/09_video_caption.js | 2 ++ 1 file changed, 2 insertions(+) diff --git a/common/lib/xmodule/xmodule/js/src/video/09_video_caption.js b/common/lib/xmodule/xmodule/js/src/video/09_video_caption.js index c9499fe44b..1855b990af 100644 --- a/common/lib/xmodule/xmodule/js/src/video/09_video_caption.js +++ b/common/lib/xmodule/xmodule/js/src/video/09_video_caption.js @@ -319,6 +319,8 @@ function () { 'tabindex': 0 }); + liEl.addClass('unfocused'); + container.append(liEl); }); From 7659c5b13030f5433bfdb4c0a5d7b6dd207b4d09 Mon Sep 17 00:00:00 2001 From: jmclaus Date: Wed, 18 Sep 2013 17:33:56 +0200 Subject: [PATCH 11/11] Removed unfocused class and set the captions default values of outline-width and outline-style to it. --- common/lib/xmodule/xmodule/css/video/display.scss | 7 ++----- .../xmodule/js/src/video/09_video_caption.js | 14 ++++++-------- 2 files changed, 8 insertions(+), 13 deletions(-) diff --git a/common/lib/xmodule/xmodule/css/video/display.scss b/common/lib/xmodule/xmodule/css/video/display.scss index 7e67207fb0..2dce290a96 100644 --- a/common/lib/xmodule/xmodule/css/video/display.scss +++ b/common/lib/xmodule/xmodule/css/video/display.scss @@ -525,17 +525,14 @@ div.video { margin-bottom: 8px; padding: 0; line-height: lh(); + outline-width: 0px; + outline-style: none; &.current { color: #333; font-weight: 700; } - &.unfocused { - outline-width: 0px; - outline-style: none; - } - &.focused { outline-width: 1px; outline-style: dotted; diff --git a/common/lib/xmodule/xmodule/js/src/video/09_video_caption.js b/common/lib/xmodule/xmodule/js/src/video/09_video_caption.js index 1855b990af..3dc675b4c2 100644 --- a/common/lib/xmodule/xmodule/js/src/video/09_video_caption.js +++ b/common/lib/xmodule/xmodule/js/src/video/09_video_caption.js @@ -319,8 +319,6 @@ function () { 'tabindex': 0 }); - liEl.addClass('unfocused'); - container.append(liEl); }); @@ -367,10 +365,10 @@ function () { captionIndex = parseInt(caption.attr('data-index'), 10); if (captionIndex === this.videoCaption.currentCaptionIndex) { if (event.type === 'mouseover') { - caption.removeClass('focused').addClass('unfocused'); + caption.removeClass('focused'); } else { // mouseout - caption.removeClass('unfocused').addClass('focused'); + caption.addClass('focused'); } } } @@ -379,7 +377,7 @@ function () { var caption = $(event.target); this.videoCaption.isMouseFocus = true; this.videoCaption.autoScrolling = true; - caption.removeClass('focused').addClass('unfocused'); + caption.removeClass('focused'); this.videoCaption.currentCaptionIndex = -1; } @@ -395,14 +393,14 @@ function () { // caption list (ie -1) to disable mouseenter, mouseleave behavior. if (this.videoCaption.isMouseFocus) { this.videoCaption.autoScrolling = true; - caption.removeClass('focused').addClass('unfocused'); + caption.removeClass('focused'); this.videoCaption.currentCaptionIndex = -1; } // If the focus comes from tabbing, show the outline and turn off // automatic scrolling. else { this.videoCaption.currentCaptionIndex = captionIndex; - caption.removeClass('unfocused').addClass('focused'); + caption.addClass('focused'); // The second and second to last elements turn automatic scrolling // off again as it may have been enabled in captionBlur. if (captionIndex <= 1 || captionIndex >= this.videoCaption.captions.length-2) { @@ -414,7 +412,7 @@ function () { function captionBlur(event) { var caption = $(event.target), captionIndex = parseInt(caption.attr('data-index'), 10); - caption.removeClass('focused').addClass('unfocused'); + caption.removeClass('focused'); // If we are on first or last index, we have to turn automatic scroll on // again when losing focus. There is no way to know in what direction we // are tabbing. So we could be on the first element and tabbing back out