Commit 0b58c22b by Valera Rozuvan

Merge pull request #593 from edx/valera/captions_keyboard_access_2

Valera/captions keyboard access 2
parents bc2a9fc2 1efea116
......@@ -133,7 +133,6 @@ div.videoalpha {
line-height: 46px;
padding: 0 lh(.75);
text-indent: -9999px;
@include transition(background-color 0.75s linear 0s, opacity 0.75s linear 0s);
width: 14px;
background: url('../images/vcr.png') 15px 15px no-repeat;
outline: 0;
......@@ -150,7 +149,7 @@ div.videoalpha {
&.play {
background-position: 17px -114px;
&:hover {
&:hover, &:focus {
background-color: #444;
}
}
......@@ -158,7 +157,7 @@ div.videoalpha {
&.pause {
background-position: 16px -50px;
&:hover {
&:hover, &:focus {
background-color: #444;
}
}
......@@ -300,12 +299,15 @@ div.videoalpha {
&.muted {
&>a {
background: url('../images/mute.png') 10px center no-repeat;
background-image: url('../images/mute.png');
}
}
> a {
background: url('../images/volume.png') 10px center no-repeat;
background-image: url('../images/volume.png');
background-position: 10px center;
background-repeat: no-repeat;
border-right: 1px solid #000;
box-shadow: 1px 0 0 #555, inset 1px 0 0 #555;
@include clearfix();
......@@ -382,7 +384,7 @@ div.videoalpha {
@include transition(none);
width: 30px;
&:hover {
&:hover, &:active, &:focus {
background-color: #444;
color: #fff;
text-decoration: none;
......@@ -403,7 +405,7 @@ div.videoalpha {
@include transition(none);
width: 30px;
&:hover {
&:hover, &:focus {
background-color: #444;
color: #fff;
text-decoration: none;
......@@ -419,7 +421,6 @@ div.videoalpha {
a.hide-subtitles {
background: url('../images/cc.png') center no-repeat;
display: block;
float: left;
font-weight: 800;
line-height: 46px; //height of play pause buttons
......@@ -432,7 +433,7 @@ div.videoalpha {
-webkit-font-smoothing: antialiased;
width: 30px;
&:hover {
&:hover, &:focus {
background-color: #444;
color: #fff;
text-decoration: none;
......@@ -442,9 +443,7 @@ div.videoalpha {
opacity: 0.7;
}
background-color: #444;
color: #fff;
text-decoration: none;
color: #797979;
}
}
}
......@@ -513,12 +512,6 @@ div.videoalpha {
z-index: 1;
}
article.video-wrapper section.video-controls div.secondary-controls a.hide-subtitles {
background-color: inherit;
color: #797979;
text-decoration: inherit;
}
article.video-wrapper div.video-player-pre, article.video-wrapper div.video-player-post {
height: 0px;
}
......
......@@ -2,8 +2,8 @@
<div id="video_example">
<div id="example">
<div id="video_id" class="video"
data-youtube-id-0-75="slowerSpeedYoutubeId"
data-youtube-id-1-0="normalSpeedYoutubeId"
data-youtube-id-0-75="7tqY6eQzVhE"
data-youtube-id-1-0="cogebirgzzM"
data-show-captions="true"
data-start=""
data-end=""
......
......@@ -4,7 +4,7 @@
<div
id="video_id"
class="videoalpha"
data-streams="0.75:slowerSpeedYoutubeId,1.0:normalSpeedYoutubeId"
data-streams="0.75:7tqY6eQzVhE,1.0:cogebirgzzM"
data-show-captions="true"
data-start=""
data-end=""
......
......@@ -8,7 +8,7 @@
data-start=""
data-end=""
data-caption-asset-path="/static/subs/"
data-sub="test_name_of_the_subtitles"
data-sub="Z5KLxerq05Y"
data-mp4-source="test_files/test.mp4"
data-webm-source="test_files/test.webm"
data-ogg-source="test_files/test.ogv"
......
......@@ -8,7 +8,7 @@
data-start=""
data-end=""
data-caption-asset-path="/static/subs/"
data-sub="test_name_of_the_subtitles"
data-sub="Z5KLxerq05Y"
data-mp4-source="test_files/test.mp4"
data-webm-source="test_files/test.webm"
data-ogg-source="test_files/test.ogv"
......
......@@ -4,7 +4,7 @@
<div
id="video_id"
class="videoalpha"
data-streams="0.75:slowerSpeedYoutubeId,1.0:normalSpeedYoutubeId"
data-streams="0.75:7tqY6eQzVhE,1.0:cogebirgzzM"
data-show-captions="false"
data-start=""
data-end=""
......
......@@ -12,6 +12,9 @@ window.STATUS = window.YT.PlayerState
oldAjaxWithPrefix = window.jQuery.ajaxWithPrefix
window.onTouchBasedDevice = ->
navigator.userAgent.match /iPhone|iPod|iPad/i
jasmine.stubbedCaption =
end: [3120, 6270, 8490, 21620, 24920, 25750, 27900, 34380, 35550, 40250]
start: [1180, 3120, 6270, 14910, 21620, 24920, 25750, 27900, 34380, 35550]
......@@ -36,7 +39,7 @@ jasmine.stubbedCaption =
#
# We will replace it with a function that does:
#
# 1.) Return a hard coded captions object if the file name contains 'test_name_of_the_subtitles'.
# 1.) Return a hard coded captions object if the file name contains 'Z5KLxerq05Y'.
# 2.) Behaves the same a as the origianl in all other cases.
window.jQuery.ajaxWithPrefix = (url, settings) ->
......@@ -46,7 +49,7 @@ window.jQuery.ajaxWithPrefix = (url, settings) ->
success = settings.success
data = settings.data
if url.match(/test_name_of_the_subtitles/g) isnt null or url.match(/slowerSpeedYoutubeId/g) isnt null or url.match(/normalSpeedYoutubeId/g) isnt null
if url.match(/Z5KLxerq05Y/g) isnt null or url.match(/7tqY6eQzVhE/g) isnt null or url.match(/cogebirgzzM/g) isnt null
if window.jQuery.isFunction(success) is true
success jasmine.stubbedCaption
else if window.jQuery.isFunction(data) is true
......@@ -60,11 +63,11 @@ window.WAIT_TIMEOUT = 1000
jasmine.getFixtures().fixturesPath = 'xmodule/js/fixtures'
jasmine.stubbedMetadata =
slowerSpeedYoutubeId:
id: 'slowerSpeedYoutubeId'
'7tqY6eQzVhE':
id: '7tqY6eQzVhE'
duration: 300
normalSpeedYoutubeId:
id: 'normalSpeedYoutubeId'
'cogebirgzzM':
id: 'cogebirgzzM'
duration: 200
bogus:
duration: 100
......@@ -117,7 +120,7 @@ jasmine.stubVideoPlayer = (context, enableParts, createPlayer=true) ->
loadFixtures 'video.html'
jasmine.stubRequests()
YT.Player = undefined
videosDefinition = '0.75:slowerSpeedYoutubeId,1.0:normalSpeedYoutubeId'
videosDefinition = '0.75:7tqY6eQzVhE,1.0:cogebirgzzM'
context.video = new Video '#example', videosDefinition
jasmine.stubYoutubePlayer()
if createPlayer
......@@ -135,7 +138,7 @@ jasmine.stubVideoPlayerAlpha = (context, enableParts, html5=false) ->
YT.Player = undefined
window.OldVideoPlayerAlpha = undefined
jasmine.stubYoutubePlayer()
return new VideoAlpha '#example', '.75:slowerSpeedYoutubeId,1.0:normalSpeedYoutubeId'
return new VideoAlpha '#example', '.75:7tqY6eQzVhE,1.0:cogebirgzzM'
# Stub jQuery.cookie
......
......@@ -19,7 +19,7 @@ describe 'VideoCaption', ->
@caption = @player.caption
it 'set the youtube id', ->
expect(@caption.youtubeId).toEqual 'normalSpeedYoutubeId'
expect(@caption.youtubeId).toEqual 'cogebirgzzM'
it 'create the caption element', ->
expect($('.video')).toContain 'ol.subtitles'
......
......@@ -35,7 +35,7 @@ describe 'VideoPlayer', ->
expect(window.VideoCaption.prototype.initialize).toHaveBeenCalled()
expect(@player.caption).toBeDefined()
expect(@player.caption.el).toBe @player.el
expect(@player.caption.youtubeId).toEqual 'normalSpeedYoutubeId'
expect(@player.caption.youtubeId).toEqual 'cogebirgzzM'
expect(@player.caption.currentSpeed).toEqual '1.0'
expect(@player.caption.captionAssetPath).toEqual '/static/subs/'
......@@ -60,7 +60,7 @@ describe 'VideoPlayer', ->
showinfo: 0
enablejsapi: 1
modestbranding: 1
videoId: 'normalSpeedYoutubeId'
videoId: 'cogebirgzzM'
events:
onReady: @player.onReady
onStateChange: @player.onStateChange
......@@ -290,7 +290,7 @@ describe 'VideoPlayer', ->
@player.onSpeedChange {}, '0.75'
it 'load the video', ->
expect(@player.player.loadVideoById).toHaveBeenCalledWith 'slowerSpeedYoutubeId', '80.000'
expect(@player.player.loadVideoById).toHaveBeenCalledWith '7tqY6eQzVhE', '80.000'
it 'trigger updatePlayTime event', ->
expect(@player.updatePlayTime).toHaveBeenCalledWith '80.000'
......@@ -301,7 +301,7 @@ describe 'VideoPlayer', ->
@player.onSpeedChange {}, '0.75'
it 'cue the video', ->
expect(@player.player.cueVideoById).toHaveBeenCalledWith 'slowerSpeedYoutubeId', '80.000'
expect(@player.player.cueVideoById).toHaveBeenCalledWith '7tqY6eQzVhE', '80.000'
it 'trigger updatePlayTime event', ->
expect(@player.updatePlayTime).toHaveBeenCalledWith '80.000'
......
......@@ -5,14 +5,14 @@ describe 'Video', ->
loadFixtures 'video.html'
jasmine.stubRequests()
@slowerSpeedYoutubeId = 'slowerSpeedYoutubeId'
@normalSpeedYoutubeId = 'normalSpeedYoutubeId'
@['7tqY6eQzVhE'] = '7tqY6eQzVhE'
@['cogebirgzzM'] = 'cogebirgzzM'
metadata =
slowerSpeedYoutubeId:
id: @slowerSpeedYoutubeId
'7tqY6eQzVhE':
id: @['7tqY6eQzVhE']
duration: 300
normalSpeedYoutubeId:
id: @normalSpeedYoutubeId
'cogebirgzzM':
id: @['cogebirgzzM']
duration: 200
afterEach ->
......@@ -38,8 +38,8 @@ describe 'Video', ->
it 'parse the videos', ->
expect(@video.videos).toEqual
'0.75': @slowerSpeedYoutubeId
'1.0': @normalSpeedYoutubeId
'0.75': @['7tqY6eQzVhE']
'1.0': @['cogebirgzzM']
it 'fetch the video metadata', ->
expect(@video.fetchMetadata).toHaveBeenCalled
......@@ -102,12 +102,12 @@ describe 'Video', ->
describe 'with speed', ->
it 'return the video id for given speed', ->
expect(@video.youtubeId('0.75')).toEqual @slowerSpeedYoutubeId
expect(@video.youtubeId('1.0')).toEqual @normalSpeedYoutubeId
expect(@video.youtubeId('0.75')).toEqual @['7tqY6eQzVhE']
expect(@video.youtubeId('1.0')).toEqual @['cogebirgzzM']
describe 'without speed', ->
it 'return the video id for current speed', ->
expect(@video.youtubeId()).toEqual @normalSpeedYoutubeId
expect(@video.youtubeId()).toEqual @cogebirgzzM
describe 'setSpeed', ->
beforeEach ->
......@@ -148,6 +148,6 @@ describe 'Video', ->
it 'call the logger with valid parameters', ->
expect(Logger.log).toHaveBeenCalledWith 'someEvent',
id: 'id'
code: @normalSpeedYoutubeId
code: @cogebirgzzM
currentTime: 25
speed: '1.0'
......@@ -6,9 +6,9 @@
jasmine.stubRequests();
oldOTBD = window.onTouchBasedDevice;
window.onTouchBasedDevice = jasmine.createSpy('onTouchBasedDevice').andReturn(false);
this.videosDefinition = '0.75:slowerSpeedYoutubeId,1.0:normalSpeedYoutubeId';
this.slowerSpeedYoutubeId = 'slowerSpeedYoutubeId';
this.normalSpeedYoutubeId = 'normalSpeedYoutubeId';
this.videosDefinition = '0.75:7tqY6eQzVhE,1.0:cogebirgzzM';
this['7tqY6eQzVhE'] = '7tqY6eQzVhE';
this['cogebirgzzM'] = 'cogebirgzzM';
});
afterEach(function () {
......@@ -45,8 +45,8 @@
it('parse the videos', function () {
expect(this.state.videos).toEqual({
'0.75': this.slowerSpeedYoutubeId,
'1.0': this.normalSpeedYoutubeId
'0.75': this['7tqY6eQzVhE'],
'1.0': this['cogebirgzzM']
});
});
......@@ -91,7 +91,7 @@
});
it('parse the videos if subtitles exist', function () {
var sub = 'test_name_of_the_subtitles';
var sub = 'Z5KLxerq05Y';
expect(state.videos).toEqual({
'0.75': sub,
......@@ -165,14 +165,14 @@
describe('with speed', function () {
it('return the video id for given speed', function () {
expect(state.youtubeId('0.75')).toEqual(this.slowerSpeedYoutubeId);
expect(state.youtubeId('1.0')).toEqual(this.normalSpeedYoutubeId);
expect(state.youtubeId('0.75')).toEqual(this['7tqY6eQzVhE']);
expect(state.youtubeId('1.0')).toEqual(this['cogebirgzzM']);
});
});
describe('without speed', function () {
it('return the video id for current speed', function () {
expect(state.youtubeId()).toEqual(this.normalSpeedYoutubeId);
expect(state.youtubeId()).toEqual(this.cogebirgzzM);
});
});
});
......
Jasmine JavaScript tests status
-------------------------------
As of 22.07.2013, all the tests in this directory pass. To disable each of them, change the top level "describe(" to "xdescribe(".
As of 22.07.2013, all the tests in this directory pass. To enable a test file, change
the top level "xdescribe(" to "describe(".
PS: When you are running the tests in chrome locally, make sure that chrome is started
with the option "--allow-file-access-from-files".
......@@ -130,7 +130,6 @@
describe('mouse movement', function() {
beforeEach(function() {
//initialize();
window.setTimeout.andReturn(100);
spyOn(window, 'clearTimeout');
});
......@@ -221,10 +220,6 @@
});
describe('search', function() {
beforeEach(function() {
//initialize();
});
it('return a correct caption index', function() {
expect(videoCaption.search(0)).toEqual(0);
expect(videoCaption.search(3120)).toEqual(1);
......@@ -277,7 +272,6 @@
describe('pause', function() {
beforeEach(function() {
//initialize();
videoCaption.playing = true;
videoCaption.pause();
});
......@@ -288,10 +282,6 @@
});
describe('updatePlayTime', function() {
/*beforeEach(function() {
initialize();
});*/
describe('when the video speed is 1.0x', function() {
beforeEach(function() {
videoSpeedControl.currentSpeed = '1.0';
......@@ -369,16 +359,21 @@
});
it('when CC button is disabled ', function() {
var realHeight = parseInt($('.subtitles').css('maxHeight'), 10),
videoWrapperHeight = $('.video-wrapper').height(),
controlsHeight = videoControl.el.height(),
progressSliderHeight = videoControl.sliderEl.height(),
shouldBeHeight = videoWrapperHeight - controlsHeight \
- 0.5 * controlsHeight;
var realHeight, videoWrapperHeight, progressSliderHeight,
controlHeight, shouldBeHeight;
state.captionsHidden = true;
videoCaption.setSubtitlesHeight();
expect(realHeight).toBeCloseTo($('.video-wrapper').height(shouldBeHeight, 2));
realHeight = parseInt($('.subtitles').css('maxHeight'), 10);
videoWrapperHeight = $('.video-wrapper').height();
progressSliderHeight = videoControl.sliderEl.height();
controlHeight = videoControl.el.height();
shouldBeHeight = videoWrapperHeight -
0.5 * progressSliderHeight -
controlHeight;
expect(realHeight).toBe(shouldBeHeight);
});
});
......@@ -434,17 +429,6 @@
});
it('scroll to current caption', function() {
// Check for calledWith(parameters) for some reason fails...
//
// var offset = -0.5 * ($('.video-wrapper').height() - $('.subtitles .current:first').height());
//
// expect($.fn.scrollTo).toHaveBeenCalledWith(
// $('.subtitles .current:first', videoCaption.el),
// {
// offset: offset
// }
// );
expect($.fn.scrollTo).toHaveBeenCalled();
});
});
......@@ -454,7 +438,6 @@
describe('seekPlayer', function() {
describe('when the video speed is 1.0x', function() {
beforeEach(function() {
//initialize();
videoSpeedControl.currentSpeed = '1.0';
$('.subtitles li[data-start="14910"]').trigger('click');
});
......
......@@ -34,12 +34,6 @@
});
describe('constructor', function() {
beforeEach(function() {
$.fn.qtip.andCallFake(function() {
$(this).data('qtip', true);
});
});
describe('always', function() {
beforeEach(function() {
initialize();
......@@ -60,7 +54,7 @@
it('create video caption', function() {
expect(videoCaption).toBeDefined();
expect(state.youtubeId()).toEqual('test_name_of_the_subtitles');
expect(state.youtubeId()).toEqual('Z5KLxerq05Y');
expect(state.speed).toEqual('1.0');
expect(state.config.caption_asset_path).toEqual('/static/subs/');
});
......@@ -80,38 +74,6 @@
// All the toHandleWith() expect tests are not necessary for this version of Video Alpha.
// jQuery event system is not used to trigger and invoke methods. This is an artifact from
// previous version of Video Alpha.
//
// xit('bind to video control play event', function() {
// expect($(videoControl)).toHandleWith('play', player.play);
// });
//
// xit('bind to video control pause event', function() {
// expect($(videoControl)).toHandleWith('pause', player.pause);
// });
//
// xit('bind to video caption seek event', function() {
// expect($(videoCaption)).toHandleWith('caption_seek', player.onSeek);
// });
//
// xit('bind to video speed control speedChange event', function() {
// expect($(videoSpeedControl)).toHandleWith('speedChange', player.onSpeedChange);
// });
//
// xit('bind to video progress slider seek event', function() {
// expect($(videoProgressSlider)).toHandleWith('slide_seek', player.onSeek);
// });
//
// xit('bind to video volume control volumeChange event', function() {
// expect($(videoVolumeControl)).toHandleWith('volumeChange', player.onVolumeChange);
// });
//
// xit('bind to key press', function() {
// expect($(document.documentElement)).toHandleWith('keyup', player.bindExitFullScreen);
// });
//
// xit('bind to fullscreen switching button', function() {
// expect($('.add-fullscreen')).toHandleWith('click', player.toggleFullScreen);
// });
});
it('create Youtube player', function() {
......@@ -136,7 +98,7 @@
modestbranding: 1,
html5: 1
},
videoId: 'normalSpeedYoutubeId',
videoId: 'cogebirgzzM',
events: {
onReady: videoPlayer.onReady,
onStateChange: videoPlayer.onStateChange,
......@@ -149,20 +111,6 @@
// We can't test the invocation of HTML5Video because it is not available
// globally. It is defined within the scope of Require JS.
//
// xit('create HTML5 player', function() {
// spyOn(state.HTML5Video, 'Player').andCallThrough();
// initialize();
//
// expect(window.HTML5Video.Player).toHaveBeenCalledWith(this.video.el, {
// playerVars: playerVars,
// videoSources: this.video.html5Sources,
// events: {
// onReady: player.onReady,
// onStateChange: player.onStateChange
// }
// });
// });
describe('when not on a touch based device', function() {
beforeEach(function() {
......@@ -170,10 +118,6 @@
initialize();
});
it('does not add the tooltip to fullscreen button', function() {
expect($('.add-fullscreen')).not.toHaveData('qtip');
});
it('create video volume control', function() {
expect(videoVolumeControl).toBeDefined();
expect(videoVolumeControl.el).toHaveClass('volume');
......@@ -187,10 +131,6 @@
initialize();
});
it('add the tooltip to fullscreen button', function() {
expect($('.add-fullscreen')).toHaveData('qtip');
});
it('controls are in paused state', function() {
expect(videoControl.isPlaying).toBe(false);
});
......@@ -433,11 +373,9 @@
expect(state.setSpeed).toHaveBeenCalledWith('0.75', false);
});
// Not relevant any more.
// Not relevant any more:
//
// it('tell video caption that the speed has changed', function() {
// expect(this.player.caption.currentSpeed).toEqual('0.75');
// });
// expect( "tell video caption that the speed has changed" ) ...
});
describe('when the video is playing', function() {
......@@ -548,8 +486,9 @@
expect(true).toBe(false);
}
// The below test has been replaced by above trickery.
// expect($('.vidtime')).toHaveHtml('1:00 / 1:01');
// The below test has been replaced by above trickery:
//
// expect($('.vidtime')).toHaveHtml('1:00 / 1:01');
});
});
......
......@@ -39,21 +39,6 @@
it('build the seek handle', function() {
expect(videoProgressSlider.handle).toBe('.slider .ui-slider-handle');
expect($.fn.qtip).toHaveBeenCalledWith({
content: "0:00",
position: {
my: 'bottom center',
at: 'top center',
container: videoProgressSlider.handle
},
hide: {
delay: 700
},
style: {
classes: 'ui-tooltip-slider',
widget: true
}
});
});
});
......@@ -69,7 +54,6 @@
// We can't expect $.fn.slider not to have been called,
// because sliders are used in other parts of VideoAlpha.
// expect($.fn.slider).not.toHaveBeenCalled();
});
});
});
......@@ -94,43 +78,6 @@
});
// Currently, the slider is not rebuilt if it does not exist.
//
// describe('when the slider was not already built', function() {
// beforeEach(function() {
// spyOn($.fn, 'slider').andCallThrough();
// videoProgressSlider.slider = null;
// videoPlayer.play();
// });
//
// it('build the slider', function() {
// expect(videoProgressSlider.slider).toBe('.slider');
// expect($.fn.slider).toHaveBeenCalledWith({
// range: 'min',
// change: videoProgressSlider.onChange,
// slide: videoProgressSlider.onSlide,
// stop: videoProgressSlider.onStop
// });
// });
//
// it('build the seek handle', function() {
// expect(videoProgressSlider.handle).toBe('.ui-slider-handle');
// expect($.fn.qtip).toHaveBeenCalledWith({
// content: "0:00",
// position: {
// my: 'bottom center',
// at: 'top center',
// container: videoProgressSlider.handle
// },
// hide: {
// delay: 700
// },
// style: {
// classes: 'ui-tooltip-slider',
// widget: true
// }
// });
// });
// });
});
describe('updatePlayTime', function() {
......@@ -181,10 +128,6 @@
expect(videoProgressSlider.frozen).toBeTruthy();
});
it('update the tooltip', function() {
expect($.fn.qtip).toHaveBeenCalled();
});
it('trigger seek event', function() {
expect(videoPlayer.onSlideSeek).toHaveBeenCalled();
expect(videoPlayer.currentTime).toEqual(20);
......@@ -199,9 +142,6 @@
value: 20
});
});
it('update the tooltip', function() {
expect($.fn.qtip).toHaveBeenCalled();
});
});
describe('onStop', function() {
......@@ -228,18 +168,6 @@
expect(videoProgressSlider.frozen).toBeFalsy();
});
});
describe('updateTooltip', function() {
beforeEach(function() {
initialize();
spyOn($.fn, 'slider').andCallThrough();
videoProgressSlider.updateTooltip(90);
});
it('set the tooltip value', function() {
expect($.fn.qtip).toHaveBeenCalledWith('option', 'content.text', '1:30');
});
});
});
}).call(this);
......@@ -90,19 +90,7 @@
// detect (and do not do anything) if there is a request for a speed that
// is already set.
//
// describe('when new speed is the same', function() {
// beforeEach(function() {
// initialize();
// videoSpeedControl.setSpeed(1.0);
// spyOn(videoPlayer, 'onSpeedChange').andCallThrough();
//
// $('li[data-speed="1.0"] a').click();
// });
//
// it('does not trigger speedChange event', function() {
// expect(videoPlayer.onSpeedChange).not.toHaveBeenCalled();
// });
// });
// describe("when new speed is the same") ...
describe('when new speed is not the same', function() {
beforeEach(function() {
......
......@@ -39,7 +39,6 @@
range: "min",
min: 0,
max: 100,
/* value: 100, */
value: videoVolumeControl.currentVolume,
change: videoVolumeControl.onChange,
slide: videoVolumeControl.onChange
......
......@@ -93,14 +93,7 @@ function (VideoPlayer) {
fadeOutTimeout: 1400,
availableQualities: ['hd720', 'hd1080', 'highres'],
qTipConfig: {
position: {
my: 'top right',
at: 'top center'
}
}
availableQualities: ['hd720', 'hd1080', 'highres']
};
if (!(_parseYouTubeIDs(state))) {
......
......@@ -53,9 +53,6 @@ function () {
if (!onTouchBasedDevice()) {
state.videoControl.pause();
state.videoControl.playPauseEl.qtip(state.config.qTipConfig);
state.videoControl.fullScreenEl.qtip(state.config.qTipConfig);
} else {
state.videoControl.play();
}
......@@ -77,7 +74,8 @@ function () {
$(document).on('keyup', state.videoControl.exitFullScreen);
if (state.videoType === 'html5') {
state.el.on('mousemove', state.videoControl.showControls)
state.el.on('mousemove', state.videoControl.showControls);
state.el.on('keydown', state.videoControl.showControls);
}
}
......
......@@ -43,10 +43,6 @@ function () {
state.videoQualityControl.el.show();
state.videoQualityControl.quality = null;
if (!onTouchBasedDevice()) {
state.videoQualityControl.el.qtip(state.config.qTipConfig);
}
}
// function _bindHandlers(state)
......
......@@ -32,9 +32,7 @@ function () {
// get the 'state' object as a context.
function _makeFunctionsPublic(state) {
state.videoProgressSlider.onSlide = _.bind(onSlide, state);
state.videoProgressSlider.onChange = _.bind(onChange, state);
state.videoProgressSlider.onStop = _.bind(onStop, state);
state.videoProgressSlider.updateTooltip = _.bind(updateTooltip, state);
state.videoProgressSlider.updatePlayTime = _.bind(updatePlayTime, state);
//Added for tests -- JM
state.videoProgressSlider.buildSlider = _.bind(buildSlider, state);
......@@ -56,22 +54,6 @@ function () {
function _buildHandle(state) {
state.videoProgressSlider.handle = state.videoProgressSlider.el.find('.ui-slider-handle');
state.videoProgressSlider.handle.qtip({
content: '' + Time.format(state.videoProgressSlider.slider.slider('value')),
position: {
my: 'bottom center',
at: 'top center',
container: state.videoProgressSlider.handle
},
hide: {
delay: 700
},
style: {
classes: 'ui-tooltip-slider',
widget: true
}
});
}
// ***************************************************************
......@@ -83,7 +65,6 @@ function () {
function buildSlider(state) {
state.videoProgressSlider.slider = state.videoProgressSlider.el.slider({
range: 'min',
change: state.videoProgressSlider.onChange,
slide: state.videoProgressSlider.onSlide,
stop: state.videoProgressSlider.onStop
});
......@@ -91,15 +72,10 @@ function () {
function onSlide(event, ui) {
this.videoProgressSlider.frozen = true;
this.videoProgressSlider.updateTooltip(ui.value);
this.trigger('videoPlayer.onSlideSeek', {'type': 'onSlideSeek', 'time': ui.value});
}
function onChange(event, ui) {
this.videoProgressSlider.updateTooltip(ui.value);
}
function onStop(event, ui) {
var _this = this;
......@@ -112,10 +88,6 @@ function () {
}, 200);
}
function updateTooltip(value) {
this.videoProgressSlider.handle.qtip('option', 'content.text', '' + Time.format(value));
}
//Changed for tests -- JM: Check if it is the cause of Chrome Bug Valera noticed
function updatePlayTime(params) {
if ((this.videoProgressSlider.slider) && (!this.videoProgressSlider.frozen)) {
......
......@@ -61,6 +61,9 @@ function () {
slide: state.videoVolumeControl.onChange
});
// Make sure that we can focus the actual volume slider while Tabing.
state.videoVolumeControl.volumeSliderEl.find('a').attr('tabindex', '0');
state.videoVolumeControl.el.toggleClass('muted', state.videoVolumeControl.currentVolume === 0);
}
......@@ -74,9 +77,21 @@ function () {
$(this).addClass('open');
});
state.videoVolumeControl.buttonEl.on('focus', function() {
$(this).parent().addClass('open');
});
state.videoVolumeControl.el.on('mouseleave', function() {
$(this).removeClass('open');
});
state.videoVolumeControl.buttonEl.on('blur', function() {
state.videoVolumeControl.volumeSliderEl.find('a').focus();
});
state.videoVolumeControl.volumeSliderEl.find('a').on('blur', function () {
state.videoVolumeControl.el.removeClass('open');
});
}
// ***************************************************************
......
......@@ -21,34 +21,41 @@ function () {
// function _makeFunctionsPublic(state)
//
// Functions which will be accessible via 'state' object. When called, these functions will
// get the 'state' object as a context.
// Functions which will be accessible via 'state' object. When called,
// these functions will get the 'state' object as a context.
function _makeFunctionsPublic(state) {
state.videoSpeedControl.changeVideoSpeed = _.bind(changeVideoSpeed, state);
state.videoSpeedControl.changeVideoSpeed = _.bind(
changeVideoSpeed, state
);
state.videoSpeedControl.setSpeed = _.bind(setSpeed, state);
state.videoSpeedControl.reRender = _.bind(reRender, state);
}
// function _renderElements(state)
//
// Create any necessary DOM elements, attach them, and set their initial configuration. Also
// make the created DOM elements available via the 'state' object. Much easier to work this
// way - you don't have to do repeated jQuery element selects.
// Create any necessary DOM elements, attach them, and set their
// initial configuration. Also make the created DOM elements available
// via the 'state' object. Much easier to work this way - you don't
// have to do repeated jQuery element selects.
function _renderElements(state) {
state.videoSpeedControl.speeds = state.speeds;
state.videoSpeedControl.el = state.el.find('div.speeds');
state.videoSpeedControl.videoSpeedsEl = state.videoSpeedControl.el.find('.video_speeds');
state.videoSpeedControl.videoSpeedsEl = state.videoSpeedControl.el
.find('.video_speeds');
state.videoControl.secondaryControlsEl.prepend(state.videoSpeedControl.el);
state.videoControl.secondaryControlsEl.prepend(
state.videoSpeedControl.el
);
$.each(state.videoSpeedControl.speeds, function(index, speed) {
var link = '<a class="speed_link" href="#">' + speed + 'x</a>';
//var link = $('<a href="#">' + speed + 'x</a>');
var link = '<a href="#">' + speed + 'x</a>';
state.videoSpeedControl.videoSpeedsEl.prepend($('<li data-speed="' + speed + '">' + link + '</li>'));
state.videoSpeedControl.videoSpeedsEl
.prepend(
$('<li data-speed="' + speed + '">' + link + '</li>')
);
});
state.videoSpeedControl.setSpeed(state.speed);
......@@ -56,9 +63,11 @@ function () {
// function _bindHandlers(state)
//
// Bind any necessary function callbacks to DOM events (click, mousemove, etc.).
// Bind any necessary function callbacks to DOM events (click,
// mousemove, etc.).
function _bindHandlers(state) {
state.videoSpeedControl.videoSpeedsEl.find('a').on('click', state.videoSpeedControl.changeVideoSpeed);
state.videoSpeedControl.videoSpeedsEl.find('a')
.on('click', state.videoSpeedControl.changeVideoSpeed);
if (onTouchBasedDevice()) {
state.videoSpeedControl.el.on('click', function(event) {
......@@ -77,18 +86,36 @@ function () {
event.preventDefault();
$(this).removeClass('open');
});
state.videoSpeedControl.el.children('a')
.on('focus', function () {
$(this).parent().addClass('open');
})
.on('blur', function () {
state.videoSpeedControl.videoSpeedsEl
.find('a.speed_link:first')
.focus();
});
state.videoSpeedControl.videoSpeedsEl.find('a.speed_link:last')
.on('blur', function () {
state.videoSpeedControl.el.removeClass('open');
});
}
}
// ***************************************************************
// Public functions start here.
// These are available via the 'state' object. Their context ('this' keyword) is the 'state' object.
// The magic private function that makes them available and sets up their context is makeFunctionsPublic().
// These are available via the 'state' object. Their context ('this'
// keyword) is the 'state' object. The magic private function that makes
// them available and sets up their context is makeFunctionsPublic().
// ***************************************************************
function setSpeed(speed) {
this.videoSpeedControl.videoSpeedsEl.find('li').removeClass('active');
this.videoSpeedControl.videoSpeedsEl.find("li[data-speed='" + speed + "']").addClass('active');
this.videoSpeedControl.videoSpeedsEl
.find("li[data-speed='" + speed + "']")
.addClass('active');
this.videoSpeedControl.el.find('p.active').html('' + speed + 'x');
}
......@@ -102,10 +129,15 @@ function () {
this.videoSpeedControl.setSpeed(
// To meet the API expected format.
parseFloat(this.videoSpeedControl.currentSpeed).toFixed(2).replace(/\.00$/, '.0')
parseFloat(this.videoSpeedControl.currentSpeed)
.toFixed(2)
.replace(/\.00$/, '.0')
);
this.trigger('videoPlayer.onSpeedChange', this.videoSpeedControl.currentSpeed);
this.trigger(
'videoPlayer.onSpeedChange',
this.videoSpeedControl.currentSpeed
);
}
}
......@@ -119,7 +151,6 @@ function () {
$.each(this.videoSpeedControl.speeds, function(index, speed) {
var link, listItem;
//link = $('<a href="#">' + speed + 'x</a>');
link = '<a href="#">' + speed + 'x</a>';
listItem = $('<li data-speed="' + speed + '">' + link + '</li>');
......@@ -131,7 +162,11 @@ function () {
_this.videoSpeedControl.videoSpeedsEl.prepend(listItem);
});
this.videoSpeedControl.videoSpeedsEl.find('a').on('click', this.videoSpeedControl.changeVideoSpeed);
this.videoSpeedControl.videoSpeedsEl.find('a')
.on('click', this.videoSpeedControl.changeVideoSpeed);
// TODO: After the control was re-rendered, we should attach 'focus'
// and 'blur' events once more.
}
});
......
......@@ -109,6 +109,7 @@ function () {
if (this.videoType === 'html5') {
this.el.on('mousemove', this.videoCaption.autoShowCaptions);
this.el.on('keydown', this.videoCaption.autoShowCaptions);
// Moving slider on subtitles is not a mouse move,
// but captions and controls should be showed.
......@@ -122,6 +123,10 @@ function () {
this.videoCaption.hideCaptions(this.hide_captions);
if (!this.youtubeId('1.0')) {
return;
}
$.ajaxWithPrefix({
url: _this.videoCaption.captionURL(),
notifyOnError: false,
......
<%! from django.utils.translation import ugettext as _ %>
% if display_name is not UNDEFINED and display_name is not None:
<h2> ${display_name} </h2>
<h2>${display_name}</h2>
% endif
<div
id="video_${id}"
class="videoalpha"
id="video_${id}"
class="videoalpha"
% if not settings.MITX_FEATURES['STUB_VIDEO_FOR_TESTING']:
data-streams="${youtube_streams}"
% endif
% if not settings.MITX_FEATURES['STUB_VIDEO_FOR_TESTING']:
data-streams="${youtube_streams}"
% endif
${'data-sub="{}"'.format(sub) if sub else ''}
${'data-autoplay="{}"'.format(autoplay) if autoplay else ''}
% if not settings.MITX_FEATURES['STUB_VIDEO_FOR_TESTING']:
${'data-mp4-source="{}"'.format(sources.get('mp4')) if sources.get('mp4') else ''}
${'data-webm-source="{}"'.format(sources.get('webm')) if sources.get('webm') else ''}
${'data-ogg-source="{}"'.format(sources.get('ogv')) if sources.get('ogv') else ''}
% endif
${'data-sub="{}"'.format(sub) if sub else ''}
${'data-autoplay="{}"'.format(autoplay) if autoplay else ''}
data-caption-data-dir="${data_dir}"
data-show-captions="${show_captions}"
data-start="${start}"
data-end="${end}"
data-caption-asset-path="${caption_asset_path}"
data-autoplay="${autoplay}"
% if not settings.MITX_FEATURES['STUB_VIDEO_FOR_TESTING']:
${'data-mp4-source="{}"'.format(sources.get('mp4')) if sources.get('mp4') else ''}
${'data-webm-source="{}"'.format(sources.get('webm')) if sources.get('webm') else ''}
${'data-ogg-source="{}"'.format(sources.get('ogv')) if sources.get('ogv') else ''}
% endif
data-caption-data-dir="${data_dir}"
data-show-captions="${show_captions}"
data-start="${start}"
data-end="${end}"
data-caption-asset-path="${caption_asset_path}"
data-autoplay="${autoplay}"
>
<div class="tc-wrapper">
<article class="video-wrapper">
<div class="video-player-pre"></div>
<section class="video-player">
<div id="${id}"></div>
</section>
<div class="video-player-post"></div>
<section class="video-controls">
<div class="slider"></div>
<div>
<ul class="vcr">
<li><a class="video_control" href="#" title="${_('Play')}"></a></li>
<li><div class="vidtime">0:00 / 0:00</div></li>
</ul>
<div class="secondary-controls">
<div class="speeds">
<a href="#">
<h3>${_('Speed')}</h3>
<p class="active"></p>
</a>
<ol class="video_speeds"></ol>
</div>
<div class="volume">
<a href="#"></a>
<div class="volume-slider-container">
<div class="volume-slider"></div>
<div class="tc-wrapper">
<article class="video-wrapper">
<div class="video-player-pre"></div>
<section class="video-player">
<div id="${id}"></div>
</section>
<div class="video-player-post"></div>
<section class="video-controls">
<div class="slider" tabindex="0" title="Video position"></div>
<div>
<ul class="vcr">
<li><a class="video_control" href="#" tabindex="0" title="${_('Play')}"></a></li>
<li><div class="vidtime">0:00 / 0:00</div></li>
</ul>
<div class="secondary-controls">
<div class="speeds">
<a href="#" tabindex="0" title="Speeds">
<h3 tabindex="-1">${_('Speed')}</h3>
<p tabindex="-1" class="active"></p>
</a>
<ol tabindex="-1" class="video_speeds"></ol>
</div>
</div>
<a href="#" class="add-fullscreen" title="${_('Fill browser')}">${_('Fill browser')}</a>
<a href="#" class="quality_control" title="${_('HD')}">${_('HD')}</a>
<div class="volume">
<a href="#" tabindex="0" title="Volume"></a>
<div tabindex="-1" class="volume-slider-container">
<div tabindex="-1" class="volume-slider"></div>
</div>
</div>
<a href="#" class="add-fullscreen" tabindex="0" title="${_('Fill browser')}">${_('Fill browser')}</a>
<a href="#" class="quality_control" tabindex="0" title="${_('HD')}">${_('HD')}</a>
<a href="#" class="hide-subtitles" title="${_('Turn off captions')}">Captions</a>
<a href="#" class="hide-subtitles" title="${_('Turn off captions')}">${_('Captions')}</a>
</div>
</div>
</div>
</section>
</article>
<ol class="subtitles"><li></li></ol>
</section>
</article>
</div>
<ol class="subtitles" tabindex="0" title="Captions"><li></li></ol>
</div>
</div>
% if sources.get('main'):
<div class="video-sources">
<p>${_('Download video <a href="%s">here</a>.') % sources.get('main')}</p>
</div>
<div class="video-sources">
<p>${(_('Download video') + ' <a href="%s">' + _('here') + '</a>.') % sources.get('main')}</p>
</div>
% endif
% if track:
<div class="video-tracks">
<p>${_('Download subtitles <a href="%s">here</a>.') % track}</p>
</div>
<div class="video-tracks">
<p>${(_('Download subtitles') + ' <a href="%s">' + _('here') + '</a>.') % track}</p>
</div>
% endif
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