Commit 7fca5e8b by brianhw

Merge pull request #1360 from edx/valera/carry_over_of_add_option_transcripts_remove_onhover_2

Valera/carry over of add option transcripts remove onhover 2
parents 5c883993 4b371d47
...@@ -2,15 +2,18 @@ ...@@ -2,15 +2,18 @@
Feature: CMS.Video Component Feature: CMS.Video Component
As a course author, I want to be able to view my created videos in Studio. As a course author, I want to be able to view my created videos in Studio.
# 1
# Video Alpha Features will work in Firefox only when Firefox is the active window # Video Alpha Features will work in Firefox only when Firefox is the active window
Scenario: Autoplay is disabled in Studio Scenario: Autoplay is disabled in Studio
Given I have created a Video component Given I have created a Video component
Then when I view the video it does not have autoplay enabled Then when I view the video it does not have autoplay enabled
# 2
Scenario: Creating a video takes a single click Scenario: Creating a video takes a single click
Given I have clicked the new unit button Given I have clicked the new unit button
Then creating a video takes a single click Then creating a video takes a single click
# 3
# Sauce Labs cannot delete cookies # Sauce Labs cannot delete cookies
@skip_sauce @skip_sauce
Scenario: Captions are hidden correctly Scenario: Captions are hidden correctly
...@@ -18,12 +21,14 @@ Feature: CMS.Video Component ...@@ -18,12 +21,14 @@ Feature: CMS.Video Component
And I have hidden captions And I have hidden captions
Then when I view the video it does not show the captions Then when I view the video it does not show the captions
# 4
# Sauce Labs cannot delete cookies # Sauce Labs cannot delete cookies
@skip_sauce @skip_sauce
Scenario: Captions are shown correctly Scenario: Captions are shown correctly
Given I have created a Video component with subtitles Given I have created a Video component with subtitles
Then when I view the video it does show the captions Then when I view the video it does show the captions
# 5
# Sauce Labs cannot delete cookies # Sauce Labs cannot delete cookies
@skip_sauce @skip_sauce
Scenario: Captions are toggled correctly Scenario: Captions are toggled correctly
...@@ -31,6 +36,35 @@ Feature: CMS.Video Component ...@@ -31,6 +36,35 @@ Feature: CMS.Video Component
And I have toggled captions And I have toggled captions
Then when I view the video it does show the captions Then when I view the video it does show the captions
# 6
Scenario: Video data is shown correctly Scenario: Video data is shown correctly
Given I have created a video with only XML data Given I have created a video with only XML data
Then the correct Youtube video is shown Then the correct Youtube video is shown
# 7
Scenario: Closed captions become visible when the mouse hovers over CC button
Given I have created a Video component with subtitles
And Make sure captions are closed
Then Captions become "invisible" after 3 seconds
And I hover over button "CC"
Then Captions become "visible"
And I hover over button "volume"
Then Captions become "invisible" after 3 seconds
# 8
Scenario: Open captions never become invisible
Given I have created a Video component with subtitles
And Make sure captions are open
Then Captions are "visible"
And I hover over button "CC"
Then Captions are "visible"
And I hover over button "volume"
Then Captions are "visible"
# 9
Scenario: Closed captions are invisible when mouse doesn't hover on CC button
Given I have created a Video component with subtitles
And Make sure captions are closed
Then Captions become "invisible" after 3 seconds
And I hover over button "volume"
Then Captions are "invisible"
...@@ -5,6 +5,11 @@ from terrain.steps import reload_the_page ...@@ -5,6 +5,11 @@ from terrain.steps import reload_the_page
from xmodule.modulestore import Location from xmodule.modulestore import Location
from contentstore.utils import get_modulestore from contentstore.utils import get_modulestore
BUTTONS = {
'CC': '.hide-subtitles',
'volume': '.volume',
}
@step('I have created a Video component$') @step('I have created a Video component$')
def i_created_a_video_component(step): def i_created_a_video_component(step):
...@@ -17,8 +22,13 @@ def i_created_a_video_component(step): ...@@ -17,8 +22,13 @@ def i_created_a_video_component(step):
@step('I have created a Video component with subtitles$') @step('I have created a Video component with subtitles$')
def i_created_a_video_component_subtitles(step): def i_created_a_video_with_subs(_step):
step.given('I have created a Video component') _step.given('I have created a Video component with subtitles "OEoXaMPEzfM"')
@step('I have created a Video component with subtitles "([^"]*)"$')
def i_created_a_video_with_subs_with_name(_step, sub_id):
_step.given('I have created a Video component')
# Store the current URL so we can return here # Store the current URL so we can return here
video_url = world.browser.url video_url = world.browser.url
...@@ -108,3 +118,37 @@ def the_youtube_video_is_shown(_step): ...@@ -108,3 +118,37 @@ def the_youtube_video_is_shown(_step):
ele = world.css_find('.video').first ele = world.css_find('.video').first
assert ele['data-streams'].split(':')[1] == world.scenario_dict['YOUTUBE_ID'] assert ele['data-streams'].split(':')[1] == world.scenario_dict['YOUTUBE_ID']
@step('Make sure captions are (.+)$')
def set_captions_visibility_state(_step, captions_state):
if captions_state == 'closed':
if world.css_visible('.subtitles'):
world.browser.find_by_css('.hide-subtitles').click()
else:
if not world.css_visible('.subtitles'):
world.browser.find_by_css('.hide-subtitles').click()
@step('I hover over button "([^"]*)"$')
def hover_over_button(_step, button):
world.css_find(BUTTONS[button.strip()]).mouse_over()
@step('Captions (?:are|become) "([^"]*)"$')
def are_captions_visibile(_step, visibility_state):
_step.given('Captions become "{0}" after 0 seconds'.format(visibility_state))
@step('Captions (?:are|become) "([^"]*)" after (.+) seconds$')
def check_captions_visibility_state(_step, visibility_state, timeout):
timeout = int(timeout.strip())
# Captions become invisible by fading out. We must wait by a specified
# time.
world.wait(timeout)
if visibility_state == 'visible':
assert world.css_visible('.subtitles')
else:
assert not world.css_visible('.subtitles')
...@@ -610,6 +610,8 @@ div.video { ...@@ -610,6 +610,8 @@ div.video {
ol.subtitles { ol.subtitles {
width: 0; width: 0;
height: 0; height: 0;
visibility: hidden;
} }
ol.subtitles.html5 { ol.subtitles.html5 {
...@@ -643,6 +645,8 @@ div.video { ...@@ -643,6 +645,8 @@ div.video {
ol.subtitles { ol.subtitles {
right: -(flex-grid(4)); right: -(flex-grid(4));
width: auto; width: auto;
visibility: hidden;
} }
} }
......
...@@ -12,6 +12,7 @@ ...@@ -12,6 +12,7 @@
data-autoplay="False" data-autoplay="False"
data-yt-test-timeout="1500" data-yt-test-timeout="1500"
data-yt-test-url="https://gdata.youtube.com/feeds/api/videos/" data-yt-test-url="https://gdata.youtube.com/feeds/api/videos/"
data-autohide-html5="True"
> >
<div class="focus_grabber first"></div> <div class="focus_grabber first"></div>
......
...@@ -15,6 +15,7 @@ ...@@ -15,6 +15,7 @@
data-autoplay="False" data-autoplay="False"
data-yt-test-timeout="1500" data-yt-test-timeout="1500"
data-yt-test-url="https://gdata.youtube.com/feeds/api/videos/" data-yt-test-url="https://gdata.youtube.com/feeds/api/videos/"
data-autohide-html5="True"
> >
<div class="focus_grabber first"></div> <div class="focus_grabber first"></div>
......
...@@ -15,6 +15,7 @@ ...@@ -15,6 +15,7 @@
data-autoplay="False" data-autoplay="False"
data-yt-test-timeout="1500" data-yt-test-timeout="1500"
data-yt-test-url="https://gdata.youtube.com/feeds/api/videos/" data-yt-test-url="https://gdata.youtube.com/feeds/api/videos/"
data-autohide-html5="True"
> >
<div class="focus_grabber first"></div> <div class="focus_grabber first"></div>
......
...@@ -12,6 +12,7 @@ ...@@ -12,6 +12,7 @@
data-autoplay="False" data-autoplay="False"
data-yt-test-timeout="1500" data-yt-test-timeout="1500"
data-yt-test-url="https://gdata.youtube.com/feeds/api/videos/" data-yt-test-url="https://gdata.youtube.com/feeds/api/videos/"
data-autohide-html5="True"
> >
<div class="focus_grabber first"></div> <div class="focus_grabber first"></div>
......
...@@ -12,6 +12,7 @@ ...@@ -12,6 +12,7 @@
data-autoplay="False" data-autoplay="False"
data-yt-test-timeout="1500" data-yt-test-timeout="1500"
data-yt-test-url="https://gdata.youtube.com/feeds/api/videos/" data-yt-test-url="https://gdata.youtube.com/feeds/api/videos/"
data-autohide-html5="True"
> >
<div class="focus_grabber first"></div> <div class="focus_grabber first"></div>
...@@ -73,6 +74,8 @@ ...@@ -73,6 +74,8 @@
data-autoplay="False" data-autoplay="False"
data-yt-test-timeout="1500" data-yt-test-timeout="1500"
data-yt-test-url="https://gdata.youtube.com/feeds/api/videos/" data-yt-test-url="https://gdata.youtube.com/feeds/api/videos/"
data-autohide-html5="True"
> >
<div class="tc-wrapper"> <div class="tc-wrapper">
<article class="video-wrapper"> <article class="video-wrapper">
...@@ -130,6 +133,8 @@ ...@@ -130,6 +133,8 @@
data-autoplay="False" data-autoplay="False"
data-yt-test-timeout="1500" data-yt-test-timeout="1500"
data-yt-test-url="https://gdata.youtube.com/feeds/api/videos/" data-yt-test-url="https://gdata.youtube.com/feeds/api/videos/"
data-autohide-html5="True"
> >
<div class="tc-wrapper"> <div class="tc-wrapper">
<article class="video-wrapper"> <article class="video-wrapper">
......
(function() { (function () {
describe('VideoCaption', function() { describe('VideoCaption', function () {
var state, videoPlayer, videoCaption, videoSpeedControl, oldOTBD; var state, videoPlayer, videoCaption, videoSpeedControl, oldOTBD;
function initialize() { function initialize() {
...@@ -11,36 +11,37 @@ ...@@ -11,36 +11,37 @@
videoControl = state.videoControl; videoControl = state.videoControl;
} }
beforeEach(function() { beforeEach(function () {
oldOTBD = window.onTouchBasedDevice; oldOTBD = window.onTouchBasedDevice;
window.onTouchBasedDevice = jasmine.createSpy('onTouchBasedDevice').andReturn(false); window.onTouchBasedDevice = jasmine.createSpy('onTouchBasedDevice')
.andReturn(false);
initialize(); initialize();
}); });
afterEach(function() { afterEach(function () {
YT.Player = void 0; YT.Player = undefined;
$.fn.scrollTo.reset(); $.fn.scrollTo.reset();
$('.subtitles').remove(); $('.subtitles').remove();
$('source').remove(); $('source').remove();
window.onTouchBasedDevice = oldOTBD; window.onTouchBasedDevice = oldOTBD;
}); });
describe('constructor', function() { describe('constructor', function () {
describe('always', function() { describe('always', function () {
beforeEach(function() { beforeEach(function () {
spyOn($, 'ajaxWithPrefix').andCallThrough(); spyOn($, 'ajaxWithPrefix').andCallThrough();
initialize(); initialize();
}); });
it('create the caption element', function() { it('create the caption element', function () {
expect($('.video')).toContain('ol.subtitles'); expect($('.video')).toContain('ol.subtitles');
}); });
it('add caption control to video player', function() { it('add caption control to video player', function () {
expect($('.video')).toContain('a.hide-subtitles'); expect($('.video')).toContain('a.hide-subtitles');
}); });
it('fetch the caption', function() { it('fetch the caption', function () {
waitsFor(function () { waitsFor(function () {
if (videoCaption.loaded === true) { if (videoCaption.loaded === true) {
return true; return true;
...@@ -54,83 +55,124 @@ ...@@ -54,83 +55,124 @@
url: videoCaption.captionURL(), url: videoCaption.captionURL(),
notifyOnError: false, notifyOnError: false,
success: jasmine.any(Function), success: jasmine.any(Function),
error: jasmine.any(Function), error: jasmine.any(Function)
}); });
}); });
}); });
it('bind window resize event', function() { it('bind window resize event', function () {
expect($(window)).toHandleWith('resize', videoCaption.resize); expect($(window)).toHandleWith(
'resize', videoCaption.resize
);
}); });
it('bind the hide caption button', function() { it('bind the hide caption button', function () {
expect($('.hide-subtitles')).toHandleWith('click', videoCaption.toggle); expect($('.hide-subtitles')).toHandleWith(
'click', videoCaption.toggle
);
}); });
it('bind the mouse movement', function() { it('bind the mouse movement', function () {
expect($('.subtitles')).toHandleWith('mouseover', videoCaption.onMouseEnter); expect($('.subtitles')).toHandleWith(
expect($('.subtitles')).toHandleWith('mouseout', videoCaption.onMouseLeave); 'mouseover', videoCaption.onMouseEnter
expect($('.subtitles')).toHandleWith('mousemove', videoCaption.onMovement); );
expect($('.subtitles')).toHandleWith('mousewheel', videoCaption.onMovement); expect($('.subtitles')).toHandleWith(
expect($('.subtitles')).toHandleWith('DOMMouseScroll', videoCaption.onMovement); 'mouseout', videoCaption.onMouseLeave
);
expect($('.subtitles')).toHandleWith(
'mousemove', videoCaption.onMovement
);
expect($('.subtitles')).toHandleWith(
'mousewheel', videoCaption.onMovement
);
expect($('.subtitles')).toHandleWith(
'DOMMouseScroll', videoCaption.onMovement
);
}); });
it('bind the scroll', function() { it('bind the scroll', function () {
expect($('.subtitles')).toHandleWith('scroll', videoCaption.autoShowCaptions); expect($('.subtitles'))
expect($('.subtitles')).toHandleWith('scroll', videoControl.showControls); .toHandleWith('scroll', videoCaption.autoShowCaptions);
expect($('.subtitles'))
.toHandleWith('scroll', videoControl.showControls);
}); });
}); });
describe('when on a non touch-based device', function() { describe('when on a non touch-based device', function () {
beforeEach(function() { beforeEach(function () {
initialize(); initialize();
}); });
it('render the caption', function() { it('render the caption', function () {
var captionsData; var captionsData;
captionsData = jasmine.stubbedCaption; captionsData = jasmine.stubbedCaption;
$('.subtitles li[data-index]').each(function(index, link) { $('.subtitles li[data-index]').each(
function (index, link) {
expect($(link)).toHaveData('index', index); expect($(link)).toHaveData('index', index);
expect($(link)).toHaveData('start', captionsData.start[index]); expect($(link)).toHaveData(
'start', captionsData.start[index]
);
expect($(link)).toHaveAttr('tabindex', 0); expect($(link)).toHaveAttr('tabindex', 0);
expect($(link)).toHaveText(captionsData.text[index]); expect($(link)).toHaveText(captionsData.text[index]);
}); });
}); });
it('add a padding element to caption', function() { it('add a padding element to caption', function () {
expect($('.subtitles li:first').hasClass('spacing')).toBe(true); expect($('.subtitles li:first').hasClass('spacing'))
expect($('.subtitles li:last').hasClass('spacing')).toBe(true); .toBe(true);
expect($('.subtitles li:last').hasClass('spacing'))
.toBe(true);
}); });
it('bind all the caption link', function() { it('bind all the caption link', function () {
$('.subtitles li[data-index]').each(function(index, link) { $('.subtitles li[data-index]').each(
expect($(link)).toHandleWith('mouseover', videoCaption.captionMouseOverOut); function (index, link) {
expect($(link)).toHandleWith('mouseout', videoCaption.captionMouseOverOut);
expect($(link)).toHandleWith('mousedown', videoCaption.captionMouseDown); expect($(link)).toHandleWith(
expect($(link)).toHandleWith('click', videoCaption.captionClick); 'mouseover', videoCaption.captionMouseOverOut
expect($(link)).toHandleWith('focus', videoCaption.captionFocus); );
expect($(link)).toHandleWith('blur', videoCaption.captionBlur); expect($(link)).toHandleWith(
expect($(link)).toHandleWith('keydown', videoCaption.captionKeyDown); 'mouseout', videoCaption.captionMouseOverOut
);
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
);
}); });
}); });
it('set rendered to true', function() { it('set rendered to true', function () {
expect(videoCaption.rendered).toBeTruthy(); expect(videoCaption.rendered).toBeTruthy();
}); });
}); });
describe('when on a touch-based device', function() { describe('when on a touch-based device', function () {
beforeEach(function() { beforeEach(function () {
window.onTouchBasedDevice.andReturn(true); window.onTouchBasedDevice.andReturn(true);
initialize(); initialize();
}); });
it('show explaination message', function() { it('show explaination message', function () {
expect($('.subtitles li')).toHaveHtml("Caption will be displayed when you start playing the video."); expect($('.subtitles li')).toHaveHtml(
'Caption will be displayed when you start playing ' +
'the video.'
);
}); });
it('does not set rendered to true', function() { it('does not set rendered to true', function () {
expect(videoCaption.rendered).toBeFalsy(); expect(videoCaption.rendered).toBeFalsy();
}); });
}); });
...@@ -152,115 +194,123 @@ ...@@ -152,115 +194,123 @@
}); });
}); });
describe('mouse movement', function() { describe('mouse movement', function () {
// We will store default window.setTimeout() function here. // We will store default window.setTimeout() function here.
var oldSetTimeout = null; var oldSetTimeout = null;
beforeEach(function() { beforeEach(function () {
// Store original window.setTimeout() function. If we do not do this, then // Store original window.setTimeout() function. If we do not do
// all other tests that rely on code which uses window.setTimeout() // this, then all other tests that rely on code which uses
// function might (and probably will) fail. // window.setTimeout() function might (and probably will) fail.
oldSetTimeout = window.setTimeout; oldSetTimeout = window.setTimeout;
// Redefine window.setTimeout() function as a spy. // Redefine window.setTimeout() function as a spy.
window.setTimeout = jasmine.createSpy().andCallFake(function(callback, timeout) { return 5; }) window.setTimeout = jasmine.createSpy().andCallFake(
function (callback, timeout) {
return 5;
}
);
window.setTimeout.andReturn(100); window.setTimeout.andReturn(100);
spyOn(window, 'clearTimeout'); spyOn(window, 'clearTimeout');
}); });
afterEach(function () { afterEach(function () {
// Reset the default window.setTimeout() function. If we do not do this, // Reset the default window.setTimeout() function. If we do not
// then all other tests that rely on code which uses window.setTimeout() // do this, then all other tests that rely on code which uses
// function might (and probably will) fail. // window.setTimeout() function might (and probably will) fail.
window.setTimeout = oldSetTimeout; window.setTimeout = oldSetTimeout;
}); });
describe('when cursor is outside of the caption box', function() { describe('when cursor is outside of the caption box', function () {
beforeEach(function() { beforeEach(function () {
$(window).trigger(jQuery.Event('mousemove')); $(window).trigger(jQuery.Event('mousemove'));
}); });
it('does not set freezing timeout', function() { it('does not set freezing timeout', function () {
expect(videoCaption.frozen).toBeFalsy(); expect(videoCaption.frozen).toBeFalsy();
}); });
}); });
describe('when cursor is in the caption box', function() { describe('when cursor is in the caption box', function () {
beforeEach(function() { beforeEach(function () {
$('.subtitles').trigger(jQuery.Event('mouseenter')); $('.subtitles').trigger(jQuery.Event('mouseenter'));
}); });
it('set the freezing timeout', function() { it('set the freezing timeout', function () {
expect(videoCaption.frozen).toEqual(100); expect(videoCaption.frozen).toEqual(100);
}); });
describe('when the cursor is moving', function() { describe('when the cursor is moving', function () {
beforeEach(function() { beforeEach(function () {
$('.subtitles').trigger(jQuery.Event('mousemove')); $('.subtitles').trigger(jQuery.Event('mousemove'));
}); });
it('reset the freezing timeout', function() { it('reset the freezing timeout', function () {
expect(window.clearTimeout).toHaveBeenCalledWith(100); expect(window.clearTimeout).toHaveBeenCalledWith(100);
}); });
}); });
describe('when the mouse is scrolling', function() { describe('when the mouse is scrolling', function () {
beforeEach(function() { beforeEach(function () {
$('.subtitles').trigger(jQuery.Event('mousewheel')); $('.subtitles').trigger(jQuery.Event('mousewheel'));
}); });
it('reset the freezing timeout', function() { it('reset the freezing timeout', function () {
expect(window.clearTimeout).toHaveBeenCalledWith(100); expect(window.clearTimeout).toHaveBeenCalledWith(100);
}); });
}); });
}); });
describe('when cursor is moving out of the caption box', function() { describe(
beforeEach(function() { 'when cursor is moving out of the caption box',
function () {
beforeEach(function () {
videoCaption.frozen = 100; videoCaption.frozen = 100;
$.fn.scrollTo.reset(); $.fn.scrollTo.reset();
}); });
describe('always', function() { describe('always', function () {
beforeEach(function() { beforeEach(function () {
$('.subtitles').trigger(jQuery.Event('mouseout')); $('.subtitles').trigger(jQuery.Event('mouseout'));
}); });
it('reset the freezing timeout', function() { it('reset the freezing timeout', function () {
expect(window.clearTimeout).toHaveBeenCalledWith(100); expect(window.clearTimeout).toHaveBeenCalledWith(100);
}); });
it('unfreeze the caption', function() { it('unfreeze the caption', function () {
expect(videoCaption.frozen).toBeNull(); expect(videoCaption.frozen).toBeNull();
}); });
}); });
describe('when the player is playing', function() { describe('when the player is playing', function () {
beforeEach(function() { beforeEach(function () {
videoCaption.playing = true; videoCaption.playing = true;
$('.subtitles li[data-index]:first').addClass('current'); $('.subtitles li[data-index]:first')
.addClass('current');
$('.subtitles').trigger(jQuery.Event('mouseout')); $('.subtitles').trigger(jQuery.Event('mouseout'));
}); });
it('scroll the caption', function() { it('scroll the caption', function () {
expect($.fn.scrollTo).toHaveBeenCalled(); expect($.fn.scrollTo).toHaveBeenCalled();
}); });
}); });
describe('when the player is not playing', function() { describe('when the player is not playing', function () {
beforeEach(function() { beforeEach(function () {
videoCaption.playing = false; videoCaption.playing = false;
$('.subtitles').trigger(jQuery.Event('mouseout')); $('.subtitles').trigger(jQuery.Event('mouseout'));
}); });
it('does not scroll the caption', function() { it('does not scroll the caption', function () {
expect($.fn.scrollTo).not.toHaveBeenCalled(); expect($.fn.scrollTo).not.toHaveBeenCalled();
}); });
}); });
}); });
}); });
describe('search', function() { describe('search', function () {
it('return a correct caption index', function() { it('return a correct caption index', function () {
expect(videoCaption.search(0)).toEqual(-1); expect(videoCaption.search(0)).toEqual(-1);
expect(videoCaption.search(3120)).toEqual(1); expect(videoCaption.search(3120)).toEqual(1);
expect(videoCaption.search(6270)).toEqual(2); expect(videoCaption.search(6270)).toEqual(2);
...@@ -270,151 +320,178 @@ ...@@ -270,151 +320,178 @@
}); });
}); });
describe('play', function() { describe('play', function () {
describe('when the caption was not rendered', function() { describe('when the caption was not rendered', function () {
beforeEach(function() { beforeEach(function () {
window.onTouchBasedDevice.andReturn(true); window.onTouchBasedDevice.andReturn(true);
initialize(); initialize();
videoCaption.play(); videoCaption.play();
}); });
it('render the caption', function() { it('render the caption', function () {
var captionsData; var captionsData;
captionsData = jasmine.stubbedCaption; captionsData = jasmine.stubbedCaption;
$('.subtitles li[data-index]').each(function(index, link) { $('.subtitles li[data-index]').each(
function (index, link) {
expect($(link)).toHaveData('index', index); expect($(link)).toHaveData('index', index);
expect($(link)).toHaveData('start', captionsData.start[index]); expect($(link)).toHaveData(
'start', captionsData.start[index]
);
expect($(link)).toHaveAttr('tabindex', 0); expect($(link)).toHaveAttr('tabindex', 0);
expect($(link)).toHaveText(captionsData.text[index]); expect($(link)).toHaveText(captionsData.text[index]);
}); });
}); });
it('add a padding element to caption', function() { it('add a padding element to caption', function () {
expect($('.subtitles li:first')).toBe('.spacing'); expect($('.subtitles li:first')).toBe('.spacing');
expect($('.subtitles li:last')).toBe('.spacing'); expect($('.subtitles li:last')).toBe('.spacing');
}); });
it('bind all the caption link', function() { it('bind all the caption link', function () {
$('.subtitles li[data-index]').each(function(index, link) { $('.subtitles li[data-index]').each(
expect($(link)).toHandleWith('mouseover', videoCaption.captionMouseOverOut); function (index, link) {
expect($(link)).toHandleWith('mouseout', videoCaption.captionMouseOverOut);
expect($(link)).toHandleWith('mousedown', videoCaption.captionMouseDown); expect($(link)).toHandleWith(
expect($(link)).toHandleWith('click', videoCaption.captionClick); 'mouseover', videoCaption.captionMouseOverOut
expect($(link)).toHandleWith('focus', videoCaption.captionFocus); );
expect($(link)).toHandleWith('blur', videoCaption.captionBlur); expect($(link)).toHandleWith(
expect($(link)).toHandleWith('keydown', videoCaption.captionKeyDown); 'mouseout', videoCaption.captionMouseOverOut
}); );
}); expect($(link)).toHandleWith(
'mousedown', videoCaption.captionMouseDown
it('set rendered to true', function() { );
expect($(link)).toHandleWith(
'click', videoCaption.captionClick
);
expect($(link)).toHandleWith(
'focus', videoCaption.captionFocus
);
expect($(link)).toHandleWith(
'blur', videoCaption.captionBlur
);
expect($(link)).toHandleWith(
'keydown', videoCaption.captionKeyDown
);
});
});
it('set rendered to true', function () {
expect(videoCaption.rendered).toBeTruthy(); expect(videoCaption.rendered).toBeTruthy();
}); });
it('set playing to true', function() { it('set playing to true', function () {
expect(videoCaption.playing).toBeTruthy(); expect(videoCaption.playing).toBeTruthy();
}); });
}); });
}); });
describe('pause', function() { describe('pause', function () {
beforeEach(function() { beforeEach(function () {
videoCaption.playing = true; videoCaption.playing = true;
videoCaption.pause(); videoCaption.pause();
}); });
it('set playing to false', function() { it('set playing to false', function () {
expect(videoCaption.playing).toBeFalsy(); expect(videoCaption.playing).toBeFalsy();
}); });
}); });
describe('updatePlayTime', function() { describe('updatePlayTime', function () {
describe('when the video speed is 1.0x', function() { describe('when the video speed is 1.0x', function () {
beforeEach(function() { beforeEach(function () {
videoSpeedControl.currentSpeed = '1.0'; videoSpeedControl.currentSpeed = '1.0';
videoCaption.updatePlayTime(25.000); videoCaption.updatePlayTime(25.000);
}); });
it('search the caption based on time', function() { it('search the caption based on time', function () {
expect(videoCaption.currentIndex).toEqual(5); expect(videoCaption.currentIndex).toEqual(5);
}); });
}); });
describe('when the video speed is not 1.0x', function() { describe('when the video speed is not 1.0x', function () {
beforeEach(function() { beforeEach(function () {
videoSpeedControl.currentSpeed = '0.75'; videoSpeedControl.currentSpeed = '0.75';
videoCaption.updatePlayTime(25.000); videoCaption.updatePlayTime(25.000);
}); });
it('search the caption based on 1.0x speed', function() { it('search the caption based on 1.0x speed', function () {
expect(videoCaption.currentIndex).toEqual(5); expect(videoCaption.currentIndex).toEqual(5);
}); });
}); });
describe('when the index is not the same', function() { describe('when the index is not the same', function () {
beforeEach(function() { beforeEach(function () {
videoCaption.currentIndex = 1; videoCaption.currentIndex = 1;
$('.subtitles li[data-index=5]').addClass('current'); $('.subtitles li[data-index=5]').addClass('current');
videoCaption.updatePlayTime(25.000); videoCaption.updatePlayTime(25.000);
}); });
it('deactivate the previous caption', function() { it('deactivate the previous caption', function () {
expect($('.subtitles li[data-index=1]')).not.toHaveClass('current'); expect($('.subtitles li[data-index=1]'))
.not.toHaveClass('current');
}); });
it('activate new caption', function() { it('activate new caption', function () {
expect($('.subtitles li[data-index=5]')).toHaveClass('current'); expect($('.subtitles li[data-index=5]'))
.toHaveClass('current');
}); });
it('save new index', function() { it('save new index', function () {
expect(videoCaption.currentIndex).toEqual(5); expect(videoCaption.currentIndex).toEqual(5);
}); });
it('scroll caption to new position', function() { it('scroll caption to new position', function () {
expect($.fn.scrollTo).toHaveBeenCalled(); expect($.fn.scrollTo).toHaveBeenCalled();
}); });
}); });
describe('when the index is the same', function() { describe('when the index is the same', function () {
beforeEach(function() { beforeEach(function () {
videoCaption.currentIndex = 1; videoCaption.currentIndex = 1;
$('.subtitles li[data-index=3]').addClass('current'); $('.subtitles li[data-index=3]').addClass('current');
videoCaption.updatePlayTime(15.000); videoCaption.updatePlayTime(15.000);
}); });
it('does not change current subtitle', function() { it('does not change current subtitle', function () {
expect($('.subtitles li[data-index=3]')).toHaveClass('current'); expect($('.subtitles li[data-index=3]'))
.toHaveClass('current');
}); });
}); });
}); });
describe('resize', function() { describe('resize', function () {
beforeEach(function() { beforeEach(function () {
initialize(); initialize();
$('.subtitles li[data-index=1]').addClass('current'); $('.subtitles li[data-index=1]').addClass('current');
videoCaption.resize(); videoCaption.resize();
}); });
describe('set the height of caption container', function(){ describe('set the height of caption container', function () {
// Temporarily disabled due to intermittent failures // Temporarily disabled due to intermittent failures
// with error "Expected 745 to be close to 805, 2." in Firefox // with error "Expected 745 to be close to 805, 2." in Firefox
xit('when CC button is enabled', function() { xit('when CC button is enabled', function () {
var realHeight = parseInt($('.subtitles').css('maxHeight'), 10), var realHeight = parseInt(
$('.subtitles').css('maxHeight'), 10
),
shouldBeHeight = $('.video-wrapper').height(); shouldBeHeight = $('.video-wrapper').height();
// Because of some problems with rounding on different enviroments: // Because of some problems with rounding on different
// Linux * Mac * FF * Chrome // environments: Linux * Mac * FF * Chrome
expect(realHeight).toBeCloseTo(shouldBeHeight, 2); expect(realHeight).toBeCloseTo(shouldBeHeight, 2);
}); });
it('when CC button is disabled ', function() { it('when CC button is disabled ', function () {
var realHeight, videoWrapperHeight, progressSliderHeight, var realHeight, videoWrapperHeight, progressSliderHeight,
controlHeight, shouldBeHeight; controlHeight, shouldBeHeight;
state.captionsHidden = true; state.captionsHidden = true;
videoCaption.setSubtitlesHeight(); videoCaption.setSubtitlesHeight();
realHeight = parseInt($('.subtitles').css('maxHeight'), 10); realHeight = parseInt(
$('.subtitles').css('maxHeight'), 10
);
videoWrapperHeight = $('.video-wrapper').height(); videoWrapperHeight = $('.video-wrapper').height();
progressSliderHeight = videoControl.sliderEl.height(); progressSliderHeight = videoControl.sliderEl.height();
controlHeight = videoControl.el.height(); controlHeight = videoControl.el.height();
...@@ -426,67 +503,75 @@ ...@@ -426,67 +503,75 @@
}); });
}); });
it('set the height of caption spacing', function() { it('set the height of caption spacing', function () {
var firstSpacing, lastSpacing; var firstSpacing, lastSpacing;
firstSpacing = Math.abs(parseInt($('.subtitles .spacing:first').css('height'), 10));
lastSpacing = Math.abs(parseInt($('.subtitles .spacing:last').css('height'), 10)); firstSpacing = Math.abs(parseInt(
expect(firstSpacing - videoCaption.topSpacingHeight()).toBeLessThan(1); $('.subtitles .spacing:first').css('height'), 10
expect(lastSpacing - videoCaption.bottomSpacingHeight()).toBeLessThan(1); ));
lastSpacing = Math.abs(parseInt(
$('.subtitles .spacing:last').css('height'), 10
));
expect(firstSpacing - videoCaption.topSpacingHeight())
.toBeLessThan(1);
expect(lastSpacing - videoCaption.bottomSpacingHeight())
.toBeLessThan(1);
}); });
it('scroll caption to new position', function() { it('scroll caption to new position', function () {
expect($.fn.scrollTo).toHaveBeenCalled(); expect($.fn.scrollTo).toHaveBeenCalled();
}); });
}); });
describe('scrollCaption', function() { describe('scrollCaption', function () {
beforeEach(function() { beforeEach(function () {
initialize(); initialize();
}); });
describe('when frozen', function() { describe('when frozen', function () {
beforeEach(function() { beforeEach(function () {
videoCaption.frozen = true; videoCaption.frozen = true;
$('.subtitles li[data-index=1]').addClass('current'); $('.subtitles li[data-index=1]').addClass('current');
videoCaption.scrollCaption(); videoCaption.scrollCaption();
}); });
it('does not scroll the caption', function() { it('does not scroll the caption', function () {
expect($.fn.scrollTo).not.toHaveBeenCalled(); expect($.fn.scrollTo).not.toHaveBeenCalled();
}); });
}); });
describe('when not frozen', function() { describe('when not frozen', function () {
beforeEach(function() { beforeEach(function () {
videoCaption.frozen = false; videoCaption.frozen = false;
}); });
describe('when there is no current caption', function() { describe('when there is no current caption', function () {
beforeEach(function() { beforeEach(function () {
videoCaption.scrollCaption(); videoCaption.scrollCaption();
}); });
it('does not scroll the caption', function() { it('does not scroll the caption', function () {
expect($.fn.scrollTo).not.toHaveBeenCalled(); expect($.fn.scrollTo).not.toHaveBeenCalled();
}); });
}); });
describe('when there is a current caption', function() { describe('when there is a current caption', function () {
beforeEach(function() { beforeEach(function () {
$('.subtitles li[data-index=1]').addClass('current'); $('.subtitles li[data-index=1]').addClass('current');
videoCaption.scrollCaption(); videoCaption.scrollCaption();
}); });
it('scroll to current caption', function() { it('scroll to current caption', function () {
expect($.fn.scrollTo).toHaveBeenCalled(); expect($.fn.scrollTo).toHaveBeenCalled();
}); });
}); });
}); });
}); });
describe('seekPlayer', function() { describe('seekPlayer', function () {
describe('when the video speed is 1.0x', function() { describe('when the video speed is 1.0x', function () {
beforeEach(function() { beforeEach(function () {
videoSpeedControl.currentSpeed = '1.0'; videoSpeedControl.currentSpeed = '1.0';
$('.subtitles li[data-start="14910"]').trigger('click'); $('.subtitles li[data-start="14910"]').trigger('click');
}); });
...@@ -496,24 +581,26 @@ ...@@ -496,24 +581,26 @@
// use an object that is not, or is no longer, usable // use an object that is not, or is no longer, usable
// Expected 0 to equal 14.91." // Expected 0 to equal 14.91."
// on Firefox // on Firefox
xit('trigger seek event with the correct time', function() { xit('trigger seek event with the correct time', function () {
expect(videoPlayer.currentTime).toEqual(14.91); expect(videoPlayer.currentTime).toEqual(14.91);
}); });
}); });
describe('when the video speed is not 1.0x', function() { describe('when the video speed is not 1.0x', function () {
beforeEach(function() { beforeEach(function () {
initialize(); initialize();
videoSpeedControl.currentSpeed = '0.75'; videoSpeedControl.currentSpeed = '0.75';
$('.subtitles li[data-start="14910"]').trigger('click'); $('.subtitles li[data-start="14910"]').trigger('click');
}); });
it('trigger seek event with the correct time', function() { it('trigger seek event with the correct time', function () {
expect(videoPlayer.currentTime).toEqual(14.91); expect(videoPlayer.currentTime).toEqual(14.91);
}); });
}); });
describe('when the player type is Flash at speed 0.75x', function () { describe('when the player type is Flash at speed 0.75x',
function () {
beforeEach(function () { beforeEach(function () {
initialize(); initialize();
videoSpeedControl.currentSpeed = '0.75'; videoSpeedControl.currentSpeed = '0.75';
...@@ -527,143 +614,181 @@ ...@@ -527,143 +614,181 @@
}); });
}); });
describe('toggle', function() { describe('toggle', function () {
beforeEach(function() { beforeEach(function () {
initialize(); initialize();
spyOn(videoPlayer, 'log'); spyOn(videoPlayer, 'log');
$('.subtitles li[data-index=1]').addClass('current'); $('.subtitles li[data-index=1]').addClass('current');
}); });
describe('when the caption is visible', function() { describe('when the caption is visible', function () {
beforeEach(function() { beforeEach(function () {
state.el.removeClass('closed'); state.el.removeClass('closed');
videoCaption.toggle(jQuery.Event('click')); videoCaption.toggle(jQuery.Event('click'));
}); });
it('log the hide_transcript event', function() { it('log the hide_transcript event', function () {
expect(videoPlayer.log).toHaveBeenCalledWith('hide_transcript', { expect(videoPlayer.log).toHaveBeenCalledWith(
'hide_transcript',
{
currentTime: videoPlayer.currentTime currentTime: videoPlayer.currentTime
}); }
);
}); });
it('hide the caption', function() { it('hide the caption', function () {
expect(state.el).toHaveClass('closed'); expect(state.el).toHaveClass('closed');
}); });
}); });
describe('when the caption is hidden', function() { describe('when the caption is hidden', function () {
beforeEach(function() { beforeEach(function () {
state.el.addClass('closed'); state.el.addClass('closed');
videoCaption.toggle(jQuery.Event('click')); videoCaption.toggle(jQuery.Event('click'));
}); });
it('log the show_transcript event', function() { it('log the show_transcript event', function () {
expect(videoPlayer.log).toHaveBeenCalledWith('show_transcript', { expect(videoPlayer.log).toHaveBeenCalledWith(
'show_transcript',
{
currentTime: videoPlayer.currentTime currentTime: videoPlayer.currentTime
}); }
);
}); });
it('show the caption', function() { it('show the caption', function () {
expect(state.el).not.toHaveClass('closed'); expect(state.el).not.toHaveClass('closed');
}); });
it('scroll the caption', function() { it('scroll the caption', function () {
expect($.fn.scrollTo).toHaveBeenCalled(); expect($.fn.scrollTo).toHaveBeenCalled();
}); });
}); });
}); });
describe('caption accessibility', function() { describe('caption accessibility', function () {
beforeEach(function() { beforeEach(function () {
initialize(); initialize();
}); });
describe('when getting focus through TAB key', function() { describe('when getting focus through TAB key', function () {
beforeEach(function() { beforeEach(function () {
videoCaption.isMouseFocus = false; videoCaption.isMouseFocus = false;
$('.subtitles li[data-index=0]').trigger(jQuery.Event('focus')); $('.subtitles li[data-index=0]').trigger(
jQuery.Event('focus')
);
}); });
it('shows an outline around the caption', function() { it('shows an outline around the caption', function () {
expect($('.subtitles li[data-index=0]')).toHaveClass('focused'); expect($('.subtitles li[data-index=0]'))
.toHaveClass('focused');
}); });
it('has automatic scrolling disabled', function() { it('has automatic scrolling disabled', function () {
expect(videoCaption.autoScrolling).toBe(false); expect(videoCaption.autoScrolling).toBe(false);
}); });
}); });
describe('when loosing focus through TAB key', function() { describe('when loosing focus through TAB key', function () {
beforeEach(function() { beforeEach(function () {
$('.subtitles li[data-index=0]').trigger(jQuery.Event('blur')); $('.subtitles li[data-index=0]').trigger(
jQuery.Event('blur')
);
}); });
it('does not show an outline around the caption', function() { it('does not show an outline around the caption', function () {
expect($('.subtitles li[data-index=0]')).not.toHaveClass('focused'); expect($('.subtitles li[data-index=0]'))
.not.toHaveClass('focused');
}); });
it('has automatic scrolling enabled', function() { 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(
beforeEach(function() { 'when same caption gets the focus through mouse after ' +
'having focus through TAB key',
function () {
beforeEach(function () {
videoCaption.isMouseFocus = false; videoCaption.isMouseFocus = false;
$('.subtitles li[data-index=0]').trigger(jQuery.Event('focus')); $('.subtitles li[data-index=0]')
$('.subtitles li[data-index=0]').trigger(jQuery.Event('mousedown')); .trigger(jQuery.Event('focus'));
$('.subtitles li[data-index=0]')
.trigger(jQuery.Event('mousedown'));
}); });
it('does not show an outline around it', function() { it('does not show an outline around it', function () {
expect($('.subtitles li[data-index=0]')).not.toHaveClass('focused'); expect($('.subtitles li[data-index=0]'))
.not.toHaveClass('focused');
}); });
it('has automatic scrolling enabled', function() { 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(
beforeEach(function() { 'when a second caption gets focus through mouse after ' +
'first had focus through TAB key',
function () {
var subDataLiIdx__0, subDataLiIdx__1;
beforeEach(function () {
subDataLiIdx__0 = $('.subtitles li[data-index=0]');
subDataLiIdx__1 = $('.subtitles li[data-index=1]');
videoCaption.isMouseFocus = false; videoCaption.isMouseFocus = false;
$('.subtitles li[data-index=0]').trigger(jQuery.Event('focus'));
$('.subtitles li[data-index=0]').trigger(jQuery.Event('blur')); subDataLiIdx__0.trigger(jQuery.Event('focus'));
subDataLiIdx__0.trigger(jQuery.Event('blur'));
videoCaption.isMouseFocus = true; videoCaption.isMouseFocus = true;
$('.subtitles li[data-index=1]').trigger(jQuery.Event('mousedown'));
subDataLiIdx__1.trigger(jQuery.Event('mousedown'));
}); });
it('does not show an outline around the first', function() { it('does not show an outline around the first', function () {
expect($('.subtitles li[data-index=0]')).not.toHaveClass('focused'); expect(subDataLiIdx__0).not.toHaveClass('focused');
}); });
it('does not show an outline around the second', function() { it('does not show an outline around the second', function () {
expect($('.subtitles li[data-index=1]')).not.toHaveClass('focused'); expect(subDataLiIdx__1).not.toHaveClass('focused');
}); });
it('has automatic scrolling enabled', function() { it('has automatic scrolling enabled', function () {
expect(videoCaption.autoScrolling).toBe(true); expect(videoCaption.autoScrolling).toBe(true);
}); });
}); });
xdescribe('when enter key is pressed on a caption', function() { xdescribe('when enter key is pressed on a caption', function () {
beforeEach(function() { var subDataLiIdx__0;
beforeEach(function () {
var e; var e;
subDataLiIdx__0 = $('.subtitles li[data-index=0]');
spyOn(videoCaption, 'seekPlayer').andCallThrough(); spyOn(videoCaption, 'seekPlayer').andCallThrough();
videoCaption.isMouseFocus = false; videoCaption.isMouseFocus = false;
$('.subtitles li[data-index=0]').trigger(jQuery.Event('focus')); subDataLiIdx__0.trigger(jQuery.Event('focus'));
e = jQuery.Event('keydown'); e = jQuery.Event('keydown');
e.which = 13; // ENTER key e.which = 13; // ENTER key
$('.subtitles li[data-index=0]').trigger(e); subDataLiIdx__0.trigger(e);
}); });
// Temporarily disabled due to intermittent failures // Temporarily disabled due to intermittent failures.
// Fails with error: "InvalidStateError: InvalidStateError: An attempt //
// was made to use an object that is not, or is no longer, usable" // Fails with error: "InvalidStateError: InvalidStateError: An
xit('shows an outline around it', function() { // attempt was made to use an object that is not, or is no
expect($('.subtitles li[data-index=0]')).toHaveClass('focused'); // longer, usable".
xit('shows an outline around it', function () {
expect(subDataLiIdx__0).toHaveClass('focused');
}); });
xit('calls seekPlayer', function() { xit('calls seekPlayer', function () {
expect(videoCaption.seekPlayer).toHaveBeenCalled(); expect(videoCaption.seekPlayer).toHaveBeenCalled();
}); });
}); });
......
...@@ -264,15 +264,21 @@ function (VideoPlayer) { ...@@ -264,15 +264,21 @@ function (VideoPlayer) {
// The function set initial configuration and preparation. // The function set initial configuration and preparation.
function initialize(element) { function initialize(element) {
var _this = this, tempYtTestTimeout; var _this = this,
regExp = /^true$/i,
data, tempYtTestTimeout;
// This is used in places where we instead would have to check if an // This is used in places where we instead would have to check if an
// element has a CSS class 'fullscreen'. // element has a CSS class 'fullscreen'.
this.isFullScreen = false; this.isFullScreen = false;
// The parent element of the video, and the ID. // The parent element of the video, and the ID.
this.el = $(element).find('.video'); this.el = $(element).find('.video');
this.elVideoWrapper = this.el.find('.video-wrapper');
this.id = this.el.attr('id').replace(/video_/, ''); this.id = this.el.attr('id').replace(/video_/, '');
// jQuery .data() return object with keys in lower camelCase format.
data = this.el.data();
console.log( console.log(
'[Video info]: Initializing video with id "' + this.id + '".' '[Video info]: Initializing video with id "' + this.id + '".'
); );
...@@ -283,32 +289,26 @@ function (VideoPlayer) { ...@@ -283,32 +289,26 @@ function (VideoPlayer) {
this.config = { this.config = {
element: element, element: element,
start: this.el.data('start'), start: data['start'],
end: this.el.data('end'), end: data['end'],
caption_data_dir: data['captionDataDir'],
caption_data_dir: this.el.data('caption-data-dir'), caption_asset_path: data['captionAssetPath'],
caption_asset_path: this.el.data('caption-asset-path'), show_captions: regExp.test(data['showCaptions'].toString()),
show_captions: ( youtubeStreams: data['streams'],
this.el.data('show-captions') autohideHtml5: regExp.test(data['autohideHtml5'].toString()),
.toString().toLowerCase() === 'true' sub: data['sub'],
), mp4Source: data['mp4Source'],
youtubeStreams: this.el.data('streams'), webmSource: data['webmSource'],
oggSource: data['oggSource'],
sub: this.el.data('sub'), ytTestUrl: data['ytTestUrl'],
mp4Source: this.el.data('mp4-source'),
webmSource: this.el.data('webm-source'),
oggSource: this.el.data('ogg-source'),
ytTestUrl: this.el.data('yt-test-url'),
fadeOutTimeout: 1400, fadeOutTimeout: 1400,
captionsFreezeTime: 10000,
availableQualities: ['hd720', 'hd1080', 'highres'] availableQualities: ['hd720', 'hd1080', 'highres']
}; };
// Check if the YT test timeout has been set. If not, or it is in // Check if the YT test timeout has been set. If not, or it is in
// improper format, then set to default value. // improper format, then set to default value.
tempYtTestTimeout = parseInt(this.el.data('yt-test-timeout'), 10); tempYtTestTimeout = parseInt(data['ytTestTimeout'], 10);
if (!isFinite(tempYtTestTimeout)) { if (!isFinite(tempYtTestTimeout)) {
tempYtTestTimeout = 1500; tempYtTestTimeout = 1500;
} }
......
...@@ -57,7 +57,7 @@ function () { ...@@ -57,7 +57,7 @@ function () {
state.videoControl.play(); state.videoControl.play();
} }
if (state.videoType === 'html5') { if ((state.videoType === 'html5') && (state.config.autohideHtml5)) {
state.videoControl.fadeOutTimeout = state.config.fadeOutTimeout; state.videoControl.fadeOutTimeout = state.config.fadeOutTimeout;
state.videoControl.el.addClass('html5'); state.videoControl.el.addClass('html5');
...@@ -81,7 +81,7 @@ function () { ...@@ -81,7 +81,7 @@ function () {
state.videoControl.fullScreenEl.on('click', state.videoControl.toggleFullScreen); state.videoControl.fullScreenEl.on('click', state.videoControl.toggleFullScreen);
$(document).on('keyup', state.videoControl.exitFullScreen); $(document).on('keyup', state.videoControl.exitFullScreen);
if (state.videoType === 'html5') { if ((state.videoType === 'html5') && (state.config.autohideHtml5)) {
state.el.on('mousemove', state.videoControl.showControls); state.el.on('mousemove', state.videoControl.showControls);
state.el.on('keydown', state.videoControl.showControls); state.el.on('keydown', state.videoControl.showControls);
} }
......
...@@ -34,11 +34,15 @@ function () { ...@@ -34,11 +34,15 @@ function () {
// function _makeFunctionsPublic(state) // function _makeFunctionsPublic(state)
// //
// Functions which will be accessible via 'state' object. When called, these functions will // Functions which will be accessible via 'state' object. When called,
// get the 'state' object as a context. // these functions will get the 'state' object as a context.
function _makeFunctionsPublic(state) { function _makeFunctionsPublic(state) {
state.videoCaption.autoShowCaptions = _.bind(autoShowCaptions, state); state.videoCaption.autoShowCaptions = _.bind(
state.videoCaption.autoHideCaptions = _.bind(autoHideCaptions, state); autoShowCaptions, state
);
state.videoCaption.autoHideCaptions = _.bind(
autoHideCaptions, state
);
state.videoCaption.resize = _.bind(resize, state); state.videoCaption.resize = _.bind(resize, state);
state.videoCaption.toggle = _.bind(toggle, state); state.videoCaption.toggle = _.bind(toggle, state);
state.videoCaption.onMouseEnter = _.bind(onMouseEnter, state); state.videoCaption.onMouseEnter = _.bind(onMouseEnter, state);
...@@ -46,24 +50,36 @@ function () { ...@@ -46,24 +50,36 @@ function () {
state.videoCaption.onMovement = _.bind(onMovement, state); state.videoCaption.onMovement = _.bind(onMovement, state);
state.videoCaption.renderCaption = _.bind(renderCaption, state); state.videoCaption.renderCaption = _.bind(renderCaption, state);
state.videoCaption.captionHeight = _.bind(captionHeight, state); state.videoCaption.captionHeight = _.bind(captionHeight, state);
state.videoCaption.topSpacingHeight = _.bind(topSpacingHeight, state); state.videoCaption.topSpacingHeight = _.bind(
state.videoCaption.bottomSpacingHeight = _.bind(bottomSpacingHeight, state); topSpacingHeight, state
);
state.videoCaption.bottomSpacingHeight = _.bind(
bottomSpacingHeight, state
);
state.videoCaption.scrollCaption = _.bind(scrollCaption, state); state.videoCaption.scrollCaption = _.bind(scrollCaption, state);
state.videoCaption.search = _.bind(search, state); state.videoCaption.search = _.bind(search, state);
state.videoCaption.play = _.bind(play, state); state.videoCaption.play = _.bind(play, state);
state.videoCaption.pause = _.bind(pause, state); state.videoCaption.pause = _.bind(pause, state);
state.videoCaption.seekPlayer = _.bind(seekPlayer, state); state.videoCaption.seekPlayer = _.bind(seekPlayer, state);
state.videoCaption.hideCaptions = _.bind(hideCaptions, state); state.videoCaption.hideCaptions = _.bind(hideCaptions, state);
state.videoCaption.calculateOffset = _.bind(calculateOffset, state); state.videoCaption.calculateOffset = _.bind(
calculateOffset, state
);
state.videoCaption.updatePlayTime = _.bind(updatePlayTime, state); state.videoCaption.updatePlayTime = _.bind(updatePlayTime, state);
state.videoCaption.setSubtitlesHeight = _.bind(setSubtitlesHeight, state); state.videoCaption.setSubtitlesHeight = _.bind(
setSubtitlesHeight, state
);
state.videoCaption.renderElements = _.bind(renderElements, state); state.videoCaption.renderElements = _.bind(renderElements, state);
state.videoCaption.bindHandlers = _.bind(bindHandlers, state); state.videoCaption.bindHandlers = _.bind(bindHandlers, state);
state.videoCaption.fetchCaption = _.bind(fetchCaption, state); state.videoCaption.fetchCaption = _.bind(fetchCaption, state);
state.videoCaption.captionURL = _.bind(captionURL, state); state.videoCaption.captionURL = _.bind(captionURL, state);
state.videoCaption.captionMouseOverOut = _.bind(captionMouseOverOut, state); state.videoCaption.captionMouseOverOut = _.bind(
state.videoCaption.captionMouseDown = _.bind(captionMouseDown, state); captionMouseOverOut, state
);
state.videoCaption.captionMouseDown = _.bind(
captionMouseDown, state
);
state.videoCaption.captionClick = _.bind(captionClick, state); state.videoCaption.captionClick = _.bind(captionClick, state);
state.videoCaption.captionFocus = _.bind(captionFocus, state); state.videoCaption.captionFocus = _.bind(captionFocus, state);
state.videoCaption.captionBlur = _.bind(captionBlur, state); state.videoCaption.captionBlur = _.bind(captionBlur, state);
...@@ -72,8 +88,9 @@ function () { ...@@ -72,8 +88,9 @@ function () {
// *************************************************************** // ***************************************************************
// Public functions start here. // Public functions start here.
// These are available via the 'state' object. Their context ('this' keyword) is the 'state' object. // These are available via the 'state' object. Their context ('this'
// The magic private function that makes them available and sets up their context is makeFunctionsPublic(). // keyword) is the 'state' object. The magic private function that makes
// them available and sets up their context is makeFunctionsPublic().
// *************************************************************** // ***************************************************************
/** /**
...@@ -109,10 +126,13 @@ function () { ...@@ -109,10 +126,13 @@ function () {
// function bindHandlers() // function bindHandlers()
// //
// Bind any necessary function callbacks to DOM events (click, mousemove, etc.). // Bind any necessary function callbacks to DOM events (click,
// mousemove, etc.).
function bindHandlers() { function bindHandlers() {
$(window).bind('resize', this.videoCaption.resize); $(window).bind('resize', this.videoCaption.resize);
this.videoCaption.hideSubtitlesEl.on('click', this.videoCaption.toggle); this.videoCaption.hideSubtitlesEl.on(
'click', this.videoCaption.toggle
);
this.videoCaption.subtitlesEl this.videoCaption.subtitlesEl
.on( .on(
...@@ -132,14 +152,41 @@ function () { ...@@ -132,14 +152,41 @@ function () {
this.videoCaption.onMovement this.videoCaption.onMovement
); );
if (this.videoType === 'html5') { if ((this.videoType === 'html5') && (this.config.autohideHtml5)) {
this.el.on('mousemove', this.videoCaption.autoShowCaptions); this.el.on({
this.el.on('keydown', this.videoCaption.autoShowCaptions); mousemove: this.videoCaption.autoShowCaptions,
keydown: this.videoCaption.autoShowCaptions
});
// Moving slider on subtitles is not a mouse move, but captions and
// controls should be shown.
this.videoCaption.subtitlesEl
.on(
'scroll', this.videoCaption.autoShowCaptions
)
.on(
'scroll', this.videoControl.showControls
);
} else if (!this.config.autohideHtml5) {
this.videoCaption.subtitlesEl.on({
keydown: this.videoCaption.autoShowCaptions,
focus: this.videoCaption.autoShowCaptions,
// Moving slider on subtitles is not a mouse move, // Moving slider on subtitles is not a mouse move, but captions
// but captions and controls should be showed. // should not be auto-hidden.
this.videoCaption.subtitlesEl.on('scroll', this.videoCaption.autoShowCaptions); scroll: this.videoCaption.autoShowCaptions,
this.videoCaption.subtitlesEl.on('scroll', this.videoControl.showControls);
mouseout: this.videoCaption.autoHideCaptions,
blur: this.videoCaption.autoHideCaptions
});
this.videoCaption.hideSubtitlesEl.on({
mousemove: this.videoCaption.autoShowCaptions,
focus: this.videoCaption.autoShowCaptions,
mouseout: this.videoCaption.autoHideCaptions,
blur: this.videoCaption.autoHideCaptions
});
} }
} }
...@@ -209,7 +256,8 @@ function () { ...@@ -209,7 +256,8 @@ function () {
} }
function captionURL() { function captionURL() {
return '' + this.config.caption_asset_path + this.youtubeId('1.0') + '.srt.sjson'; return '' + this.config.caption_asset_path +
this.youtubeId('1.0') + '.srt.sjson';
} }
function autoShowCaptions(event) { function autoShowCaptions(event) {
...@@ -224,13 +272,19 @@ function () { ...@@ -224,13 +272,19 @@ function () {
this.videoCaption.subtitlesEl.show(); this.videoCaption.subtitlesEl.show();
this.captionState = 'visible'; this.captionState = 'visible';
} else if (this.captionState === 'hiding') { } else if (this.captionState === 'hiding') {
this.videoCaption.subtitlesEl.stop(true, false).css('opacity', 1).show(); this.videoCaption.subtitlesEl
.stop(true, false).css('opacity', 1).show();
this.captionState = 'visible'; this.captionState = 'visible';
} else if (this.captionState === 'visible') { } else if (this.captionState === 'visible') {
clearTimeout(this.captionHideTimeout); clearTimeout(this.captionHideTimeout);
} }
this.captionHideTimeout = setTimeout(this.videoCaption.autoHideCaptions, this.videoCaption.fadeOutTimeout); if (this.config.autohideHtml5) {
this.captionHideTimeout = setTimeout(
this.videoCaption.autoHideCaptions,
this.videoCaption.fadeOutTimeout
);
}
this.captionsShowLock = false; this.captionsShowLock = false;
} }
...@@ -249,15 +303,21 @@ function () { ...@@ -249,15 +303,21 @@ function () {
_this = this; _this = this;
this.videoCaption.subtitlesEl.fadeOut(this.videoCaption.fadeOutTimeout, function () { this.videoCaption.subtitlesEl
.fadeOut(
this.videoCaption.fadeOutTimeout,
function () {
_this.captionState = 'invisible'; _this.captionState = 'invisible';
}); }
);
} }
function resize() { function resize() {
this.videoCaption.subtitlesEl this.videoCaption.subtitlesEl
.find('.spacing:first').height(this.videoCaption.topSpacingHeight()) .find('.spacing:first')
.find('.spacing:last').height(this.videoCaption.bottomSpacingHeight()); .height(this.videoCaption.topSpacingHeight())
.find('.spacing:last')
.height(this.videoCaption.bottomSpacingHeight());
this.videoCaption.scrollCaption(); this.videoCaption.scrollCaption();
...@@ -269,7 +329,10 @@ function () { ...@@ -269,7 +329,10 @@ function () {
clearTimeout(this.videoCaption.frozen); clearTimeout(this.videoCaption.frozen);
} }
this.videoCaption.frozen = setTimeout(this.videoCaption.onMouseLeave, 10000); this.videoCaption.frozen = setTimeout(
this.videoCaption.onMouseLeave,
this.config.captionsFreezeTime
);
} }
function onMouseLeave() { function onMouseLeave() {
...@@ -285,6 +348,10 @@ function () { ...@@ -285,6 +348,10 @@ function () {
} }
function onMovement() { function onMovement() {
if (!this.config.autohideHtml5) {
this.videoCaption.autoShowCaptions();
}
this.videoCaption.onMouseEnter(); this.videoCaption.onMouseEnter();
} }
...@@ -292,16 +359,28 @@ function () { ...@@ -292,16 +359,28 @@ function () {
var container = $('<ol>'), var container = $('<ol>'),
_this = this; _this = this;
this.el.find('.video-wrapper').after(this.videoCaption.subtitlesEl); this.elVideoWrapper.after(this.videoCaption.subtitlesEl);
this.el.find('.video-controls .secondary-controls').append(this.videoCaption.hideSubtitlesEl); this.el.find('.video-controls .secondary-controls')
.append(this.videoCaption.hideSubtitlesEl);
this.videoCaption.setSubtitlesHeight(); this.videoCaption.setSubtitlesHeight();
if (this.videoType === 'html5') { if ((this.videoType === 'html5') && (this.config.autohideHtml5)) {
this.videoCaption.fadeOutTimeout = this.config.fadeOutTimeout; this.videoCaption.fadeOutTimeout = this.config.fadeOutTimeout;
this.videoCaption.subtitlesEl.addClass('html5'); this.videoCaption.subtitlesEl.addClass('html5');
this.captionHideTimeout = setTimeout(this.videoCaption.autoHideCaptions, this.videoCaption.fadeOutTimeout); this.captionHideTimeout = setTimeout(
this.videoCaption.autoHideCaptions,
this.videoCaption.fadeOutTimeout
);
} else if (!this.config.autohideHtml5) {
this.videoCaption.fadeOutTimeout = this.config.fadeOutTimeout;
this.videoCaption.subtitlesEl.addClass('html5');
this.captionHideTimeout = setTimeout(
this.videoCaption.autoHideCaptions,
0
);
} }
this.videoCaption.hideCaptions(this.hide_captions); this.videoCaption.hideCaptions(this.hide_captions);
...@@ -322,9 +401,10 @@ function () { ...@@ -322,9 +401,10 @@ function () {
container.append(liEl); container.append(liEl);
}); });
this.videoCaption.subtitlesEl.html(container.html()); this.videoCaption.subtitlesEl
.html(container.html())
this.videoCaption.subtitlesEl.find('li[data-index]').on({ .find('li[data-index]')
.on({
mouseover: this.videoCaption.captionMouseOverOut, mouseover: this.videoCaption.captionMouseOverOut,
mouseout: this.videoCaption.captionMouseOverOut, mouseout: this.videoCaption.captionMouseOverOut,
mousedown: this.videoCaption.captionMouseDown, mousedown: this.videoCaption.captionMouseDown,
...@@ -344,16 +424,24 @@ function () { ...@@ -344,16 +424,24 @@ function () {
this.videoCaption.autoScrolling = true; this.videoCaption.autoScrolling = true;
// Keeps track of where the focus is situated in the array of captions. // Keeps track of where the focus is situated in the array of captions.
// Used to implement the automatic scrolling behavior and decide if the // 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 // outline around a caption has to be hidden or shown on a mouseenter
// mouseleave. Initially, no caption has the focus, set the index to -1. // or mouseleave. Initially, no caption has the focus, set the
// index to -1.
this.videoCaption.currentCaptionIndex = -1; this.videoCaption.currentCaptionIndex = -1;
// Used to track if the focus is coming from a click or tabbing. This // 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 // has to be known to decide if, when a caption gets the focus, an
// outline has to be drawn (tabbing) or not (mouse click). // outline has to be drawn (tabbing) or not (mouse click).
this.videoCaption.isMouseFocus = false; this.videoCaption.isMouseFocus = false;
this.videoCaption.subtitlesEl.prepend($('<li class="spacing">').height(this.videoCaption.topSpacingHeight())); this.videoCaption.subtitlesEl
this.videoCaption.subtitlesEl.append($('<li class="spacing">').height(this.videoCaption.bottomSpacingHeight())); .prepend(
$('<li class="spacing">')
.height(this.videoCaption.topSpacingHeight())
)
.append(
$('<li class="spacing">')
.height(this.videoCaption.bottomSpacingHeight())
);
this.videoCaption.rendered = true; this.videoCaption.rendered = true;
} }
...@@ -403,7 +491,10 @@ function () { ...@@ -403,7 +491,10 @@ function () {
caption.addClass('focused'); caption.addClass('focused');
// The second and second to last elements turn automatic scrolling // The second and second to last elements turn automatic scrolling
// off again as it may have been enabled in captionBlur. // off again as it may have been enabled in captionBlur.
if (captionIndex <= 1 || captionIndex >= this.videoCaption.captions.length-2) { if (
captionIndex <= 1 ||
captionIndex >= this.videoCaption.captions.length - 2
) {
this.videoCaption.autoScrolling = false; this.videoCaption.autoScrolling = false;
} }
} }
...@@ -413,13 +504,15 @@ function () { ...@@ -413,13 +504,15 @@ function () {
var caption = $(event.target), var caption = $(event.target),
captionIndex = parseInt(caption.attr('data-index'), 10); captionIndex = parseInt(caption.attr('data-index'), 10);
caption.removeClass('focused'); caption.removeClass('focused');
// If we are on first or last index, we have to turn automatic scroll on // If we are on first or last index, we have to turn automatic scroll
// again when losing focus. There is no way to know in what direction we // on again when losing focus. There is no way to know in what
// are tabbing. So we could be on the first element and tabbing back out // direction we are tabbing. So we could be on the first element and
// of the captions or on the last element and tabbing forward out of the // tabbing back out of the captions or on the last element and tabbing
// captions. // forward out of the captions.
if (captionIndex === 0 || if (captionIndex === 0 ||
captionIndex === this.videoCaption.captions.length-1) { captionIndex === this.videoCaption.captions.length-1) {
this.videoCaption.autoHideCaptions();
this.videoCaption.autoScrolling = true; this.videoCaption.autoScrolling = true;
} }
} }
...@@ -434,9 +527,13 @@ function () { ...@@ -434,9 +527,13 @@ function () {
function scrollCaption() { function scrollCaption() {
var el = this.videoCaption.subtitlesEl.find('.current:first'); var el = this.videoCaption.subtitlesEl.find('.current:first');
// Automatic scrolling gets disabled if one of the captions has received // Automatic scrolling gets disabled if one of the captions has
// focus through tabbing. // received focus through tabbing.
if (!this.videoCaption.frozen && el.length && this.videoCaption.autoScrolling) { if (
!this.videoCaption.frozen &&
el.length &&
this.videoCaption.autoScrolling
) {
this.videoCaption.subtitlesEl.scrollTo( this.videoCaption.subtitlesEl.scrollTo(
el, el,
{ {
...@@ -565,11 +662,15 @@ function () { ...@@ -565,11 +662,15 @@ function () {
} }
function topSpacingHeight() { function topSpacingHeight() {
return this.videoCaption.calculateOffset(this.videoCaption.subtitlesEl.find('li:not(.spacing):first')); return this.videoCaption.calculateOffset(
this.videoCaption.subtitlesEl.find('li:not(.spacing):first')
);
} }
function bottomSpacingHeight() { function bottomSpacingHeight() {
return this.videoCaption.calculateOffset(this.videoCaption.subtitlesEl.find('li:not(.spacing):last')); return this.videoCaption.calculateOffset(
this.videoCaption.subtitlesEl.find('li:not(.spacing):last')
);
} }
function toggle(event) { function toggle(event) {
...@@ -579,23 +680,45 @@ function () { ...@@ -579,23 +680,45 @@ function () {
this.videoCaption.hideCaptions(false); this.videoCaption.hideCaptions(false);
} else { } else {
this.videoCaption.hideCaptions(true); this.videoCaption.hideCaptions(true);
// In the case when captions are not auto-hidden based on mouse
// movement anywhere on the video, we must hide them explicitly
// after the "CC" button has been clicked (to hide captions).
//
// Otherwise, in order for the captions to disappear again, the
// user must move the mouse button over the "CC" button, or over
// the captions themselves. In this case, an "autoShow" will be
// triggered, and after a timeout, an "autoHide".
if (!this.config.autohideHtml5) {
this.captionHideTimeout = setTimeout(
this.videoCaption.autoHideCaptions(),
0
);
}
} }
} }
function hideCaptions(hide_captions) { function hideCaptions(hide_captions, update_cookie) {
var type; var hideSubtitlesEl = this.videoCaption.hideSubtitlesEl,
type;
if (hide_captions) { if (hide_captions) {
type = 'hide_transcript'; type = 'hide_transcript';
this.captionsHidden = true; this.captionsHidden = true;
this.videoCaption.hideSubtitlesEl.attr('title', gettext('Turn on captions'));
this.videoCaption.hideSubtitlesEl.text(gettext('Turn on captions')); hideSubtitlesEl
.attr('title', gettext('Turn on captions'))
.text(gettext('Turn on captions'));
this.el.addClass('closed'); this.el.addClass('closed');
} else { } else {
type = 'show_transcript'; type = 'show_transcript';
this.captionsHidden = false; this.captionsHidden = false;
this.videoCaption.hideSubtitlesEl.attr('title', gettext('Turn off captions'));
this.videoCaption.hideSubtitlesEl.text(gettext('Turn off captions')); hideSubtitlesEl
.attr('title', gettext('Turn off captions'))
.text(gettext('Turn off captions'));
this.el.removeClass('closed'); this.el.removeClass('closed');
this.videoCaption.scrollCaption(); this.videoCaption.scrollCaption();
} }
...@@ -615,27 +738,43 @@ function () { ...@@ -615,27 +738,43 @@ function () {
} }
function captionHeight() { function captionHeight() {
var paddingTop;
if (this.isFullScreen) { if (this.isFullScreen) {
return $(window).height() - this.el.find('.video-controls').height() - paddingTop = parseInt(
this.videoCaption.subtitlesEl.css('padding-top'), 10
);
return $(window).height() -
this.videoControl.el.height() -
0.5 * this.videoControl.sliderEl.height() - 0.5 * this.videoControl.sliderEl.height() -
2 * parseInt(this.videoCaption.subtitlesEl.css('padding-top'), 10); 2 * paddingTop;
} else { } else {
return this.el.find('.video-wrapper').height(); return this.elVideoWrapper.height();
} }
} }
function setSubtitlesHeight() { function setSubtitlesHeight() {
var height = 0; var height = 0;
if (this.videoType === 'html5'){ if (
((this.videoType === 'html5') && (this.config.autohideHtml5)) ||
(!this.config.autohideHtml5)
){
// on page load captionHidden = undefined // on page load captionHidden = undefined
if ( if (
(this.captionsHidden === undefined && this.hide_captions === true ) || (
(this.captionsHidden === true) ) { this.captionsHidden === undefined &&
// In case of html5 autoshowing subtitles, this.hide_captions === true
// we ajdust height of subs, by height of scrollbar ) ||
height = this.videoControl.el.height() + 0.5 * this.videoControl.sliderEl.height(); (this.captionsHidden === true)
// height of videoControl does not contain height of slider. ) {
// (css is set to absolute, to avoid yanking when slider autochanges its height) // In case of html5 autoshowing subtitles, we adjust height of
// subs, by height of scrollbar.
height = this.videoControl.el.height() +
0.5 * this.videoControl.sliderEl.height();
// Height of videoControl does not contain height of slider.
// css is set to absolute, to avoid yanking when slider
// autochanges its height.
} }
} }
this.videoCaption.subtitlesEl.css({ this.videoCaption.subtitlesEl.css({
......
...@@ -2,38 +2,45 @@ ...@@ -2,38 +2,45 @@
Feature: LMS.Video component Feature: LMS.Video component
As a student, I want to view course videos in LMS. As a student, I want to view course videos in LMS.
# 1
Scenario: Video component is fully rendered in the LMS in HTML5 mode Scenario: Video component is fully rendered in the LMS in HTML5 mode
Given the course has a Video component in HTML5 mode Given the course has a Video component in HTML5 mode
Then when I view the video it has rendered in HTML5 mode Then when I view the video it has rendered in HTML5 mode
And all sources are correct And all sources are correct
# 2
# Firefox doesn't have HTML5 (only mp4 - fix here) # Firefox doesn't have HTML5 (only mp4 - fix here)
@skip_firefox @skip_firefox
Scenario: Autoplay is disabled in LMS for a Video component Scenario: Autoplay is disabled in LMS for a Video component
Given the course has a Video component in HTML5 mode Given the course has a Video component in HTML5 mode
Then when I view the video it does not have autoplay enabled Then when I view the video it does not have autoplay enabled
# 3
# Youtube testing # Youtube testing
Scenario: Video component is fully rendered in the LMS in Youtube mode with HTML5 sources Scenario: Video component is fully rendered in the LMS in Youtube mode with HTML5 sources
Given youtube server is up and response time is 0.4 seconds Given youtube server is up and response time is 0.4 seconds
And the course has a Video component in Youtube_HTML5 mode And the course has a Video component in Youtube_HTML5 mode
Then when I view the video it has rendered in Youtube mode Then when I view the video it has rendered in Youtube mode
# 4
Scenario: Video component is not rendered in the LMS in Youtube mode with HTML5 sources Scenario: Video component is not rendered in the LMS in Youtube mode with HTML5 sources
Given youtube server is up and response time is 2 seconds Given youtube server is up and response time is 2 seconds
And the course has a Video component in Youtube_HTML5 mode And the course has a Video component in Youtube_HTML5 mode
Then when I view the video it has rendered in HTML5 mode Then when I view the video it has rendered in HTML5 mode
# 5
Scenario: Video component is rendered in the LMS in Youtube mode without HTML5 sources Scenario: Video component is rendered in the LMS in Youtube mode without HTML5 sources
Given youtube server is up and response time is 2 seconds Given youtube server is up and response time is 2 seconds
And the course has a Video component in Youtube mode And the course has a Video component in Youtube mode
Then when I view the video it has rendered in Youtube mode Then when I view the video it has rendered in Youtube mode
# 6
Scenario: Video component is rendered in the LMS in Youtube mode with HTML5 sources that doesn't supported by browser Scenario: Video component is rendered in the LMS in Youtube mode with HTML5 sources that doesn't supported by browser
Given youtube server is up and response time is 2 seconds Given youtube server is up and response time is 2 seconds
And the course has a Video component in Youtube_HTML5_Unsupported_Video mode And the course has a Video component in Youtube_HTML5_Unsupported_Video mode
Then when I view the video it has rendered in Youtube mode Then when I view the video it has rendered in Youtube mode
# 7
Scenario: Video component is rendered in the LMS in HTML5 mode with HTML5 sources that doesn't supported by browser Scenario: Video component is rendered in the LMS in HTML5 mode with HTML5 sources that doesn't supported by browser
Given the course has a Video component in HTML5_Unsupported_Video mode Given the course has a Video component in HTML5_Unsupported_Video mode
Then error message is shown Then error message is shown
......
...@@ -26,6 +26,19 @@ ...@@ -26,6 +26,19 @@
data-yt-test-timeout="${yt_test_timeout}" data-yt-test-timeout="${yt_test_timeout}"
data-yt-test-url="${yt_test_url}" data-yt-test-url="${yt_test_url}"
## For now, the option "data-autohide-html5" is hard coded. This option
## either enables or disables autohiding of controls and captions on mouse
## inactivity. If set to true, controls and captions will autohide for
## HTML5 sources (non-YouTube) after a period of mouse inactivity over the
## whole video. When the mouse moves (or a key is pressed while any part of
## the video player is focused), the captions and controls will be shown
## once again.
##
## There is no option in the "Advanced Editor" to set this option. However,
## this option will have an effect if changed to "True". The code on
## front-end exists.
data-autohide-html5="False"
tabindex="-1" tabindex="-1"
> >
<div class="focus_grabber first"></div> <div class="focus_grabber first"></div>
......
Markdown is supported
0% or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment