diff --git a/CHANGELOG.rst b/CHANGELOG.rst
index 277d2753ab..3bc0544bfb 100644
--- a/CHANGELOG.rst
+++ b/CHANGELOG.rst
@@ -5,6 +5,10 @@ These are notable changes in edx-platform. This is a rolling list of changes,
in roughly chronological order, most recent first. Add your entries at or near
the top. Include a label indicating the component affected.
+Blades: Video start and end times now function the same for both YouTube and
+HTML5 videos. If end time is set, the video can still play until the end, after
+it pauses on the end time.
+
Blades: Disallow users to enter video url's in http.
Blades: Fix bug when the speed can only be changed when the video is playing.
@@ -48,7 +52,7 @@ on the request instead of overwriting the POST attr
---------- split mongo backend refactoring changelog section ------------
-Studio: course catalog, assets, checklists, course outline pages now use course
+Studio: course catalog, assets, checklists, course outline pages now use course
id syntax w/ restful api style
Common:
@@ -57,7 +61,7 @@ Common:
Common: location mapper: % encode periods and dollar signs when used as key in the mapping dict
-Common: location mapper: added a bunch of new helper functions for generating
+Common: location mapper: added a bunch of new helper functions for generating
old location style info from a CourseLocator
Common: locators: allow - ~ and . in course, branch, and block ids.
diff --git a/common/lib/xmodule/xmodule/js/spec/video/general_spec.js b/common/lib/xmodule/xmodule/js/spec/video/general_spec.js
index c6cd4eba27..8921e819e4 100644
--- a/common/lib/xmodule/xmodule/js/spec/video/general_spec.js
+++ b/common/lib/xmodule/xmodule/js/spec/video/general_spec.js
@@ -96,7 +96,10 @@
});
});
- it('parse the videos if subtitles do not exist', function () {
+ it(
+ 'parse the videos if subtitles do not exist',
+ function ()
+ {
var sub = '';
$('#example').find('.video').data('sub', '');
@@ -117,16 +120,41 @@
ogg: null
}, v = document.createElement('video');
- if (!!(v.canPlayType && v.canPlayType('video/webm; codecs="vp8, vorbis"').replace(/no/, ''))) {
- html5Sources['webm'] = 'xmodule/include/fixtures/test.webm';
+ if (
+ !!(
+ v.canPlayType &&
+ v.canPlayType(
+ 'video/webm; codecs="vp8, vorbis"'
+ ).replace(/no/, '')
+ )
+ ) {
+ html5Sources['webm'] =
+ 'xmodule/include/fixtures/test.webm';
}
- if (!!(v.canPlayType && v.canPlayType('video/mp4; codecs="avc1.42E01E, mp4a.40.2"').replace(/no/, ''))) {
- html5Sources['mp4'] = 'xmodule/include/fixtures/test.mp4';
+ if (
+ !!(
+ v.canPlayType &&
+ v.canPlayType(
+ 'video/mp4; codecs="avc1.42E01E, ' +
+ 'mp4a.40.2"'
+ ).replace(/no/, '')
+ )
+ ) {
+ html5Sources['mp4'] =
+ 'xmodule/include/fixtures/test.mp4';
}
- if (!!(v.canPlayType && v.canPlayType('video/ogg; codecs="theora"').replace(/no/, ''))) {
- html5Sources['ogg'] = 'xmodule/include/fixtures/test.ogv';
+ if (
+ !!(
+ v.canPlayType &&
+ v.canPlayType(
+ 'video/ogg; codecs="theora"'
+ ).replace(/no/, '')
+ )
+ ) {
+ html5Sources['ogg'] =
+ 'xmodule/include/fixtures/test.ogv';
}
expect(state.html5Sources).toEqual(html5Sources);
@@ -143,10 +171,10 @@
});
});
- // Note that the loading of stand alone HTML5 player API is handled by
- // Require JS. When state.videoPlayer is created, the stand alone HTML5
- // player object is already loaded, so no further testing in that case
- // is required.
+ // Note that the loading of stand alone HTML5 player API is
+ // handled by Require JS. When state.videoPlayer is created,
+ // the stand alone HTML5 player object is already loaded, so no
+ // further testing in that case is required.
describe('HTML5 API is available', function () {
beforeEach(function () {
state = new Video('#example');
@@ -172,8 +200,10 @@
describe('with speed', function () {
it('return the video id for given speed', function () {
- expect(state.youtubeId('0.75')).toEqual(this['7tqY6eQzVhE']);
- expect(state.youtubeId('1.0')).toEqual(this['cogebirgzzM']);
+ expect(state.youtubeId('0.75'))
+ .toEqual(this['7tqY6eQzVhE']);
+ expect(state.youtubeId('1.0'))
+ .toEqual(this['cogebirgzzM']);
});
});
@@ -210,7 +240,7 @@
itDescription: 'start time is greater than end time',
data: {start: 42, end: 24},
expectData: {start: 42, end: null}
- },
+ }
];
beforeEach(function () {
@@ -234,8 +264,8 @@
state = new Video('#example');
- expect(state.config.start).toBe(expectData.start);
- expect(state.config.end).toBe(expectData.end);
+ expect(state.config.startTime).toBe(expectData.start);
+ expect(state.config.endTime).toBe(expectData.end);
});
}
});
@@ -263,7 +293,10 @@
state3 = new Video('#example3');
});
- it('check for YT availability is performed only once', function () {
+ it(
+ 'check for YT availability is performed only once',
+ function ()
+ {
var numAjaxCalls = 0;
// Total ajax calls made.
@@ -307,10 +340,14 @@
});
it('save setting for new speed', function () {
- expect($.cookie).toHaveBeenCalledWith('video_speed', '0.75', {
- expires: 3650,
- path: '/'
- });
+ expect($.cookie).toHaveBeenCalledWith(
+ 'video_speed',
+ '0.75',
+ {
+ expires: 3650,
+ path: '/'
+ }
+ );
});
});
@@ -341,10 +378,14 @@
});
it('save setting for new speed', function () {
- expect($.cookie).toHaveBeenCalledWith('video_speed', '0.75', {
- expires: 3650,
- path: '/'
- });
+ expect($.cookie).toHaveBeenCalledWith(
+ 'video_speed',
+ '0.75',
+ {
+ expires: 3650,
+ path: '/'
+ }
+ );
});
});
diff --git a/common/lib/xmodule/xmodule/js/spec/video/html5_video_spec.js b/common/lib/xmodule/xmodule/js/spec/video/html5_video_spec.js
index 8851aee4d8..ae2b8a276e 100644
--- a/common/lib/xmodule/xmodule/js/spec/video/html5_video_spec.js
+++ b/common/lib/xmodule/xmodule/js/spec/video/html5_video_spec.js
@@ -10,7 +10,8 @@
beforeEach(function () {
oldOTBD = window.onTouchBasedDevice;
- window.onTouchBasedDevice = jasmine.createSpy('onTouchBasedDevice').andReturn(false);
+ window.onTouchBasedDevice = jasmine
+ .createSpy('onTouchBasedDevice').andReturn(false);
initialize();
player.config.events.onReady = jasmine.createSpy('onReady');
});
@@ -46,17 +47,22 @@
}, 'Player state should be changed', WAIT_TIMEOUT);
runs(function () {
- expect(player.getPlayerState()).toBe(STATUS.PLAYING);
+ expect(player.getPlayerState())
+ .toBe(STATUS.PLAYING);
});
});
it('callback was called', function () {
waitsFor(function () {
- return state.videoPlayer.player.getPlayerState() !== STATUS.PAUSED;
+ var stateStatus = state.videoPlayer.player
+ .getPlayerState();
+
+ return stateStatus !== STATUS.PAUSED;
}, 'Player state should be changed', WAIT_TIMEOUT);
runs(function () {
- expect(player.callStateChangeCallback).toHaveBeenCalled();
+ expect(player.callStateChangeCallback)
+ .toHaveBeenCalled();
});
});
});
@@ -78,7 +84,8 @@
}, 'Player state should be changed', WAIT_TIMEOUT);
runs(function () {
- expect(player.getPlayerState()).toBe(STATUS.PAUSED);
+ expect(player.getPlayerState())
+ .toBe(STATUS.PAUSED);
});
});
@@ -88,7 +95,8 @@
}, 'Player state should be changed', WAIT_TIMEOUT);
runs(function () {
- expect(player.callStateChangeCallback).toHaveBeenCalled();
+ expect(player.callStateChangeCallback)
+ .toHaveBeenCalled();
});
});
});
@@ -121,7 +129,8 @@
}, 'Player state should be changed', WAIT_TIMEOUT);
runs(function () {
- expect(player.callStateChangeCallback).toHaveBeenCalled();
+ expect(player.callStateChangeCallback)
+ .toHaveBeenCalled();
});
});
});
@@ -156,39 +165,26 @@
return player.getPlayerState() !== STATUS.PLAYING;
}, 'Player state should be changed', WAIT_TIMEOUT);
runs(function () {
- expect(player.callStateChangeCallback).toHaveBeenCalled();
+ expect(player.callStateChangeCallback)
+ .toHaveBeenCalled();
});
});
});
describe('[canplay]', function () {
- beforeEach(function () {
+ it(
+ 'player state was changed, start/end was defined, ' +
+ 'onReady called', function ()
+ {
waitsFor(function () {
return player.getPlayerState() !== STATUS.UNSTARTED;
}, 'Video cannot be played', WAIT_TIMEOUT);
- });
- it('player state was changed', function () {
runs(function () {
expect(player.getPlayerState()).toBe(STATUS.PAUSED);
- });
- });
-
- it('end property was defined', function () {
- runs(function () {
- expect(player.end).not.toBeNull();
- });
- });
-
- it('start position was defined', function () {
- runs(function () {
- expect(player.video.currentTime).toBe(player.start);
- });
- });
-
- it('onReady callback was called', function () {
- runs(function () {
- expect(player.config.events.onReady).toHaveBeenCalled();
+ expect(player.video.currentTime).toBe(0);
+ expect(player.config.events.onReady)
+ .toHaveBeenCalled();
});
});
});
@@ -276,7 +272,8 @@
it('getCurrentTime', function () {
runs(function () {
player.video.currentTime = 3;
- expect(player.getCurrentTime()).toBe(player.video.currentTime);
+ expect(player.getCurrentTime())
+ .toBe(player.video.currentTime);
});
});
@@ -330,7 +327,8 @@
});
it('getAvailablePlaybackRates', function () {
- expect(player.getAvailablePlaybackRates()).toEqual(playbackRates);
+ expect(player.getAvailablePlaybackRates())
+ .toEqual(playbackRates);
});
});
});
diff --git a/common/lib/xmodule/xmodule/js/spec/video/resizer_spec.js b/common/lib/xmodule/xmodule/js/spec/video/resizer_spec.js
index a05e9e8bb8..788f37e3ba 100644
--- a/common/lib/xmodule/xmodule/js/spec/video/resizer_spec.js
+++ b/common/lib/xmodule/xmodule/js/spec/video/resizer_spec.js
@@ -6,13 +6,19 @@ function (Resizer) {
describe('Resizer', function () {
var html = [
- '
',
- '
',
+ '
',
+ '
',
'Content',
'
',
'
'
].join(''),
- config, container, element;
+ config, container, element, originalConsoleLog;
beforeEach(function () {
setFixtures(html);
@@ -23,12 +29,17 @@ function (Resizer) {
container: container,
element: element
};
+
+ originalConsoleLog = window.console.log;
+ spyOn(console, 'log');
+ });
+
+ afterEach(function () {
+ window.console.log = originalConsoleLog;
});
it('When Initialize without required parameters, log message is shown',
function () {
- spyOn(console, 'log');
-
new Resizer({ });
expect(console.log).toHaveBeenCalled();
}
diff --git a/common/lib/xmodule/xmodule/js/spec/video/video_caption_spec.js b/common/lib/xmodule/xmodule/js/spec/video/video_caption_spec.js
index 7035ace0b7..56973fe10d 100644
--- a/common/lib/xmodule/xmodule/js/spec/video/video_caption_spec.js
+++ b/common/lib/xmodule/xmodule/js/spec/video/video_caption_spec.js
@@ -22,7 +22,12 @@
afterEach(function () {
YT.Player = undefined;
$('.subtitles').remove();
+
+ // `source` tags should be removed to avoid memory leak bug that we
+ // had before. Removing of `source` tag, not `video` tag, stops
+ // loading video source and clears the memory.
$('source').remove();
+
window.onTouchBasedDevice = oldOTBD;
});
@@ -442,7 +447,8 @@
expect(videoCaption.currentIndex).toEqual(5);
});
- it('scroll caption to new position', function () {
+ // Disabled 10/25/13 due to flakiness in master
+ xit('scroll caption to new position', function () {
expect($.fn.scrollTo).toHaveBeenCalled();
});
});
@@ -640,6 +646,8 @@
beforeEach(function () {
state.el.addClass('closed');
videoCaption.toggle(jQuery.Event('click'));
+
+ jasmine.Clock.useMock();
});
it('log the show_transcript event', function () {
@@ -655,8 +663,19 @@
expect(state.el).not.toHaveClass('closed');
});
- it('scroll the caption', function () {
- expect($.fn.scrollTo).toHaveBeenCalled();
+ // Test turned off due to flakiness (30.10.2013).
+ xit('scroll the caption', function () {
+ // After transcripts are shown, and the video plays for a
+ // bit.
+ jasmine.Clock.tick(1000);
+
+ // The transcripts should have advanced by at least one
+ // position. When they advance, the list scrolls. The
+ // current transcript position should be constantly
+ // visible.
+ runs(function () {
+ expect($.fn.scrollTo).toHaveBeenCalled();
+ });
});
});
});
diff --git a/common/lib/xmodule/xmodule/js/spec/video/video_player_spec.js b/common/lib/xmodule/xmodule/js/spec/video/video_player_spec.js
index e21faa4a4a..80299c6e7f 100644
--- a/common/lib/xmodule/xmodule/js/spec/video/video_player_spec.js
+++ b/common/lib/xmodule/xmodule/js/spec/video/video_player_spec.js
@@ -1,717 +1,770 @@
-(function() {
- describe('VideoPlayer', function() {
- var state, videoPlayer, player, videoControl, videoCaption, videoProgressSlider, videoSpeedControl, videoVolumeControl, oldOTBD;
+(function () {
+ describe('VideoPlayer', function () {
+ var state, videoPlayer, player, videoControl, videoCaption,
+ videoProgressSlider, videoSpeedControl, videoVolumeControl,
+ oldOTBD;
- function initialize(fixture) {
- if (typeof fixture === 'undefined') {
- loadFixtures('video_all.html');
- } else {
- loadFixtures(fixture);
- }
+ function initialize(fixture) {
+ if (typeof fixture === 'undefined') {
+ loadFixtures('video_all.html');
+ } else {
+ loadFixtures(fixture);
+ }
- state = new Video('#example');
+ state = new Video('#example');
- state.videoEl = $('video, iframe');
- videoPlayer = state.videoPlayer;
- player = videoPlayer.player;
- videoControl = state.videoControl;
- videoCaption = state.videoCaption;
- videoProgressSlider = state.videoProgressSlider;
- videoSpeedControl = state.videoSpeedControl;
- videoVolumeControl = state.videoVolumeControl;
+ state.videoEl = $('video, iframe');
+ videoPlayer = state.videoPlayer;
+ player = videoPlayer.player;
+ videoControl = state.videoControl;
+ videoCaption = state.videoCaption;
+ videoProgressSlider = state.videoProgressSlider;
+ videoSpeedControl = state.videoSpeedControl;
+ videoVolumeControl = state.videoVolumeControl;
- state.resizer = (function () {
- var methods = [
- 'align', 'alignByWidthOnly', 'alignByHeightOnly', 'setParams', 'setMode'
- ],
- obj = {};
+ state.resizer = (function () {
+ var methods = [
+ 'align',
+ 'alignByWidthOnly',
+ 'alignByHeightOnly',
+ 'setParams',
+ 'setMode'
+ ],
+ obj = {};
- $.each(methods, function(index, method) {
- obj[method] = jasmine.createSpy(method).andReturn(obj);
+ $.each(methods, function (index, method) {
+ obj[method] = jasmine.createSpy(method).andReturn(obj);
+ });
+
+ return obj;
+ }());
+ }
+
+ function initializeYouTube() {
+ initialize('video.html');
+ }
+
+ beforeEach(function () {
+ oldOTBD = window.onTouchBasedDevice;
+ window.onTouchBasedDevice = jasmine.createSpy('onTouchBasedDevice')
+ .andReturn(false);
});
- return obj;
- })();
- }
+ afterEach(function () {
+ $('source').remove();
+ window.onTouchBasedDevice = oldOTBD;
+ });
- function initializeYouTube() {
- initialize('video.html');
- }
+ describe('constructor', function () {
+ describe('always', function () {
+ beforeEach(function () {
+ initialize();
+ });
- beforeEach(function () {
- oldOTBD = window.onTouchBasedDevice;
- window.onTouchBasedDevice = jasmine.createSpy('onTouchBasedDevice').andReturn(false);
+ it('instanticate current time to zero', function () {
+ expect(videoPlayer.currentTime).toEqual(0);
+ });
+
+ it('set the element', function () {
+ expect(state.el).toHaveId('video_id');
+ });
+
+ it('create video control', function () {
+ expect(videoControl).toBeDefined();
+ expect(videoControl.el).toHaveClass('video-controls');
+ });
+
+ it('create video caption', function () {
+ expect(videoCaption).toBeDefined();
+ expect(state.youtubeId()).toEqual('Z5KLxerq05Y');
+ expect(state.speed).toEqual('1.0');
+ expect(state.config.caption_asset_path)
+ .toEqual('/static/subs/');
+ });
+
+ it('create video speed control', function () {
+ expect(videoSpeedControl).toBeDefined();
+ expect(videoSpeedControl.el).toHaveClass('speeds');
+ expect(videoSpeedControl.speeds)
+ .toEqual([ '0.75', '1.0', '1.25', '1.50' ]);
+ expect(state.speed).toEqual('1.0');
+ });
+
+ it('create video progress slider', function () {
+ expect(videoProgressSlider).toBeDefined();
+ expect(videoProgressSlider.el).toHaveClass('slider');
+ });
+
+ // All the toHandleWith() expect tests are not necessary for
+ // this version of Video. jQuery event system is not used to
+ // trigger and invoke methods. This is an artifact from
+ // previous version of Video.
+ });
+
+ it('create Youtube player', function () {
+ var oldYT = window.YT, events;
+
+ jasmine.stubRequests();
+
+ window.YT = {
+ Player: function () { },
+ PlayerState: oldYT.PlayerState,
+ ready: function (f) {
+ f();
+ }
+ };
+
+ spyOn(window.YT, 'Player');
+
+ initializeYouTube();
+
+ events = {
+ onReady: videoPlayer.onReady,
+ onStateChange: videoPlayer.onStateChange,
+ onPlaybackQualityChange: videoPlayer
+ .onPlaybackQualityChange
+ };
+
+ expect(YT.Player).toHaveBeenCalledWith('id', {
+ playerVars: {
+ controls: 0,
+ wmode: 'transparent',
+ rel: 0,
+ showinfo: 0,
+ enablejsapi: 1,
+ modestbranding: 1,
+ html5: 1
+ },
+ videoId: 'cogebirgzzM',
+ events: events
+ });
+
+ window.YT = oldYT;
+ });
+
+ // We can't test the invocation of HTML5Video because it is not
+ // available globally. It is defined within the scope of Require
+ // JS.
+
+ describe('when not on a touch based device', function () {
+ beforeEach(function () {
+ window.onTouchBasedDevice.andReturn(true);
+ initialize();
+ });
+
+ it('create video volume control', function () {
+ expect(videoVolumeControl).toBeDefined();
+ expect(videoVolumeControl.el).toHaveClass('volume');
+ });
+ });
+
+ describe('when on a touch based device', function () {
+ var oldOTBD;
+
+ beforeEach(function () {
+ initialize();
+ });
+
+ it('controls are in paused state', function () {
+ expect(videoControl.isPlaying).toBe(false);
+ });
+ });
+ });
+
+ describe('onReady', function () {
+ beforeEach(function () {
+ initialize();
+
+ spyOn(videoPlayer, 'log').andCallThrough();
+ spyOn(videoPlayer, 'play').andCallThrough();
+ videoPlayer.onReady();
+ });
+
+ it('log the load_video event', function () {
+ expect(videoPlayer.log).toHaveBeenCalledWith('load_video');
+ });
+
+ it('autoplay the first video', function () {
+ expect(videoPlayer.play).not.toHaveBeenCalled();
+ });
+ });
+
+ describe('onStateChange', function () {
+ describe('when the video is unstarted', function () {
+ beforeEach(function () {
+ initialize();
+
+ spyOn(videoControl, 'pause').andCallThrough();
+ spyOn(videoCaption, 'pause').andCallThrough();
+
+ videoPlayer.onStateChange({
+ data: YT.PlayerState.PAUSED
+ });
+ });
+
+ it('pause the video control', function () {
+ expect(videoControl.pause).toHaveBeenCalled();
+ });
+
+ it('pause the video caption', function () {
+ expect(videoCaption.pause).toHaveBeenCalled();
+ });
+ });
+
+ describe('when the video is playing', function () {
+ var oldState;
+
+ beforeEach(function () {
+ // Create the first instance of the player.
+ initialize();
+ oldState = state;
+
+ spyOn(oldState.videoPlayer, 'onPause').andCallThrough();
+
+ // Now initialize a second instance.
+ initialize();
+
+ spyOn(videoPlayer, 'log').andCallThrough();
+ spyOn(window, 'setInterval').andReturn(100);
+ spyOn(videoControl, 'play');
+ spyOn(videoCaption, 'play');
+
+ videoPlayer.onStateChange({
+ data: YT.PlayerState.PLAYING
+ });
+ });
+
+ it('log the play_video event', function () {
+ expect(videoPlayer.log).toHaveBeenCalledWith(
+ 'play_video', { currentTime: 0 }
+ );
+ });
+
+ it('pause other video player', function () {
+ expect(oldState.videoPlayer.onPause).toHaveBeenCalled();
+ });
+
+ it('set update interval', function () {
+ expect(window.setInterval).toHaveBeenCalledWith(
+ videoPlayer.update, 200
+ );
+ expect(videoPlayer.updateInterval).toEqual(100);
+ });
+
+ it('play the video control', function () {
+ expect(videoControl.play).toHaveBeenCalled();
+ });
+
+ it('play the video caption', function () {
+ expect(videoCaption.play).toHaveBeenCalled();
+ });
+ });
+
+ describe('when the video is paused', function () {
+ var currentUpdateIntrval;
+
+ beforeEach(function () {
+ initialize();
+
+ spyOn(videoPlayer, 'log').andCallThrough();
+ spyOn(videoControl, 'pause').andCallThrough();
+ spyOn(videoCaption, 'pause').andCallThrough();
+
+ videoPlayer.onStateChange({
+ data: YT.PlayerState.PLAYING
+ });
+
+ currentUpdateIntrval = videoPlayer.updateInterval;
+
+ videoPlayer.onStateChange({
+ data: YT.PlayerState.PAUSED
+ });
+ });
+
+ it('log the pause_video event', function () {
+ expect(videoPlayer.log).toHaveBeenCalledWith(
+ 'pause_video', { currentTime: 0 }
+ );
+ });
+
+ it('clear update interval', function () {
+ expect(videoPlayer.updateInterval).toBeUndefined();
+ });
+
+ it('pause the video control', function () {
+ expect(videoControl.pause).toHaveBeenCalled();
+ });
+
+ it('pause the video caption', function () {
+ expect(videoCaption.pause).toHaveBeenCalled();
+ });
+ });
+
+ describe('when the video is ended', function () {
+ beforeEach(function () {
+ initialize();
+
+ spyOn(videoControl, 'pause').andCallThrough();
+ spyOn(videoCaption, 'pause').andCallThrough();
+
+ videoPlayer.onStateChange({
+ data: YT.PlayerState.ENDED
+ });
+ });
+
+ it('pause the video control', function () {
+ expect(videoControl.pause).toHaveBeenCalled();
+ });
+
+ it('pause the video caption', function () {
+ expect(videoCaption.pause).toHaveBeenCalled();
+ });
+ });
+ });
+
+ describe('onSeek', function () {
+ beforeEach(function () {
+ initialize();
+
+ spyOn(videoPlayer, 'updatePlayTime');
+ spyOn(videoPlayer, 'log');
+ spyOn(videoPlayer.player, 'seekTo');
+
+ state.videoPlayer.play();
+
+ waitsFor(function () {
+ var duration = videoPlayer.duration(),
+ currentTime = videoPlayer.currentTime;
+
+ return (
+ isFinite(currentTime) &&
+ currentTime > 0 &&
+ isFinite(duration) &&
+ duration > 0
+ );
+ }, 'video begins playing', 10000);
+ });
+
+ it('Slider event causes log update', function () {
+ runs(function () {
+ var currentTime = videoPlayer.currentTime;
+
+ videoProgressSlider.onSlide(
+ jQuery.Event('slide'), { value: 2 }
+ );
+
+ expect(videoPlayer.log).toHaveBeenCalledWith(
+ 'seek_video',
+ {
+ old_time: currentTime,
+ new_time: 2,
+ type: 'onSlideSeek'
+ }
+ );
+ });
+ });
+
+ it('seek the player', function () {
+ runs(function () {
+ videoProgressSlider.onSlide(
+ jQuery.Event('slide'), { value: 60 }
+ );
+
+ expect(videoPlayer.player.seekTo)
+ .toHaveBeenCalledWith(60, true);
+ });
+ });
+
+ it('call updatePlayTime on player', function () {
+ runs(function () {
+ videoProgressSlider.onSlide(
+ jQuery.Event('slide'), { value: 60 }
+ );
+
+ expect(videoPlayer.updatePlayTime)
+ .toHaveBeenCalledWith(60);
+ });
+ });
+
+ // Disabled 10/25/13 due to flakiness in master
+ xit(
+ 'when the player is not playing: set the current time',
+ function ()
+ {
+ runs(function () {
+ videoProgressSlider.onSlide(
+ jQuery.Event('slide'), { value: 20 }
+ );
+ videoPlayer.pause();
+ videoProgressSlider.onSlide(
+ jQuery.Event('slide'), { value: 10 }
+ );
+
+ waitsFor(function () {
+ return Math.round(videoPlayer.currentTime) === 10;
+ }, 'currentTime got updated', 10000);
+ });
+ });
+ });
+
+ describe('onSpeedChange', function () {
+ beforeEach(function () {
+ initialize();
+
+ videoPlayer.currentTime = 60;
+
+ spyOn(videoPlayer, 'updatePlayTime').andCallThrough();
+ spyOn(state, 'setSpeed').andCallThrough();
+ spyOn(videoPlayer, 'log').andCallThrough();
+ spyOn(videoPlayer.player, 'setPlaybackRate').andCallThrough();
+ });
+
+ describe('always', function () {
+ beforeEach(function () {
+ videoPlayer.onSpeedChange('0.75', false);
+ });
+
+ it('check if speed_change_video is logged', function () {
+ expect(videoPlayer.log).toHaveBeenCalledWith(
+ 'speed_change_video',
+ {
+ current_time: videoPlayer.currentTime,
+ old_speed: '1.0',
+ new_speed: '0.75'
+ }
+ );
+ });
+
+ it('convert the current time to the new speed', function () {
+ expect(videoPlayer.currentTime).toEqual(60);
+ });
+
+ it('set video speed to the new speed', function () {
+ expect(state.setSpeed).toHaveBeenCalledWith('0.75', false);
+ });
+ });
+
+ describe('when the video is playing', function () {
+ beforeEach(function () {
+ videoPlayer.play();
+
+ videoPlayer.onSpeedChange('0.75', false);
+ });
+
+ it('trigger updatePlayTime event', function () {
+ expect(videoPlayer.player.setPlaybackRate)
+ .toHaveBeenCalledWith('0.75');
+ });
+ });
+
+ describe('when the video is not playing', function () {
+ beforeEach(function () {
+ videoPlayer.pause();
+
+ videoPlayer.onSpeedChange('0.75', false);
+ });
+
+ it('trigger updatePlayTime event', function () {
+ expect(videoPlayer.player.setPlaybackRate)
+ .toHaveBeenCalledWith('0.75');
+ });
+ });
+ });
+
+ describe('onVolumeChange', function () {
+ beforeEach(function () {
+ initialize();
+
+ spyOn(videoPlayer.player, 'setVolume');
+ videoPlayer.onVolumeChange(60);
+ });
+
+ it('set the volume on player', function () {
+ expect(videoPlayer.player.setVolume).toHaveBeenCalledWith(60);
+ });
+ });
+
+ describe('update', function () {
+ beforeEach(function () {
+ initialize();
+
+ spyOn(videoPlayer, 'updatePlayTime').andCallThrough();
+ });
+
+ describe(
+ 'when the current time is unavailable from the player',
+ function ()
+ {
+ beforeEach(function () {
+ videoPlayer.player.getCurrentTime = function () {
+ return NaN;
+ };
+ videoPlayer.update();
+ });
+
+ it('does not trigger updatePlayTime event', function () {
+ expect(videoPlayer.updatePlayTime).not.toHaveBeenCalled();
+ });
+ });
+
+ describe(
+ 'when the current time is available from the player',
+ function ()
+ {
+ beforeEach(function () {
+ videoPlayer.player.getCurrentTime = function () {
+ return 60;
+ };
+ videoPlayer.update();
+ });
+
+ it('trigger updatePlayTime event', function () {
+ expect(videoPlayer.updatePlayTime)
+ .toHaveBeenCalledWith(60);
+ });
+ });
+ });
+
+ // Disabled 10/24/13 due to flakiness in master
+ xdescribe('updatePlayTime', function () {
+ beforeEach(function () {
+ initialize();
+
+ spyOn(videoCaption, 'updatePlayTime').andCallThrough();
+ spyOn(videoProgressSlider, 'updatePlayTime').andCallThrough();
+ });
+
+ it('update the video playback time', function () {
+ var duration = 0;
+
+ waitsFor(function () {
+ duration = videoPlayer.duration();
+
+ if (duration > 0) {
+ return true;
+ }
+
+ return false;
+ }, 'Video is fully loaded.', 1000);
+
+ runs(function () {
+ var htmlStr;
+
+ videoPlayer.updatePlayTime(60);
+
+ htmlStr = $('.vidtime').html();
+
+ // We resort to this trickery because Firefox and Chrome
+ // round the total time a bit differently.
+ if (
+ htmlStr.match('1:00 / 1:01') ||
+ htmlStr.match('1:00 / 1:00')
+ ) {
+ expect(true).toBe(true);
+ } else {
+ expect(true).toBe(false);
+ }
+
+ // The below test has been replaced by above trickery:
+ //
+ // expect($('.vidtime')).toHaveHtml('1:00 / 1:01');
+ });
+ });
+
+ it('update the playback time on caption', function () {
+ waitsFor(function () {
+ return videoPlayer.duration() > 0;
+ }, 'Video is fully loaded.', 1000);
+
+ runs(function () {
+ videoPlayer.updatePlayTime(60);
+
+ expect(videoCaption.updatePlayTime)
+ .toHaveBeenCalledWith(60);
+ });
+ });
+
+ it('update the playback time on progress slider', function () {
+ var duration = 0;
+
+ waitsFor(function () {
+ duration = videoPlayer.duration();
+
+ return duration > 0;
+ }, 'Video is fully loaded.', 1000);
+
+ runs(function () {
+ videoPlayer.updatePlayTime(60);
+
+ expect(videoProgressSlider.updatePlayTime)
+ .toHaveBeenCalledWith({
+ time: 60,
+ duration: duration
+ });
+ });
+ });
+ });
+
+ describe('toggleFullScreen', function () {
+ describe('when the video player is not full screen', function () {
+ beforeEach(function () {
+ initialize();
+ spyOn(videoCaption, 'resize').andCallThrough();
+ videoControl.toggleFullScreen(jQuery.Event('click'));
+ });
+
+ it('replace the full screen button tooltip', function () {
+ expect($('.add-fullscreen'))
+ .toHaveAttr('title', 'Exit full browser');
+ });
+
+ it('add the video-fullscreen class', function () {
+ expect(state.el).toHaveClass('video-fullscreen');
+ });
+
+ it('tell VideoCaption to resize', function () {
+ expect(videoCaption.resize).toHaveBeenCalled();
+ expect(state.resizer.setMode).toHaveBeenCalled();
+ });
+ });
+
+ describe('when the video player already full screen', function () {
+ beforeEach(function () {
+ initialize();
+ spyOn(videoCaption, 'resize').andCallThrough();
+
+ state.el.addClass('video-fullscreen');
+ videoControl.fullScreenState = true;
+ isFullScreen = true;
+ videoControl.fullScreenEl.attr('title', 'Exit-fullscreen');
+
+ videoControl.toggleFullScreen(jQuery.Event('click'));
+ });
+
+ it('replace the full screen button tooltip', function () {
+ expect($('.add-fullscreen'))
+ .toHaveAttr('title', 'Fill browser');
+ });
+
+ it('remove the video-fullscreen class', function () {
+ expect(state.el).not.toHaveClass('video-fullscreen');
+ });
+
+ it('tell VideoCaption to resize', function () {
+ expect(videoCaption.resize).toHaveBeenCalled();
+ expect(state.resizer.setMode)
+ .toHaveBeenCalledWith('width');
+ });
+ });
+ });
+
+ describe('play', function () {
+ beforeEach(function () {
+ initialize();
+ spyOn(player, 'playVideo').andCallThrough();
+ });
+
+ describe('when the player is not ready', function () {
+ beforeEach(function () {
+ player.playVideo = void 0;
+ videoPlayer.play();
+ });
+
+ it('does nothing', function () {
+ expect(player.playVideo).toBeUndefined();
+ });
+ });
+
+ describe('when the player is ready', function () {
+ beforeEach(function () {
+ player.playVideo.andReturn(true);
+ videoPlayer.play();
+ });
+
+ it('delegate to the player', function () {
+ expect(player.playVideo).toHaveBeenCalled();
+ });
+ });
+ });
+
+ describe('isPlaying', function () {
+ beforeEach(function () {
+ initialize();
+ spyOn(player, 'getPlayerState').andCallThrough();
+ });
+
+ describe('when the video is playing', function () {
+ beforeEach(function () {
+ player.getPlayerState.andReturn(YT.PlayerState.PLAYING);
+ });
+
+ it('return true', function () {
+ expect(videoPlayer.isPlaying()).toBeTruthy();
+ });
+ });
+
+ describe('when the video is not playing', function () {
+ beforeEach(function () {
+ player.getPlayerState.andReturn(YT.PlayerState.PAUSED);
+ });
+
+ it('return false', function () {
+ expect(videoPlayer.isPlaying()).toBeFalsy();
+ });
+ });
+ });
+
+ describe('pause', function () {
+ beforeEach(function () {
+ initialize();
+ spyOn(player, 'pauseVideo').andCallThrough();
+ videoPlayer.pause();
+ });
+
+ it('delegate to the player', function () {
+ expect(player.pauseVideo).toHaveBeenCalled();
+ });
+ });
+
+ describe('duration', function () {
+ beforeEach(function () {
+ initialize();
+ spyOn(player, 'getDuration').andCallThrough();
+ videoPlayer.duration();
+ });
+
+ it('delegate to the player', function () {
+ expect(player.getDuration).toHaveBeenCalled();
+ });
+ });
+
+ describe('playback rate', function () {
+ beforeEach(function () {
+ initialize();
+ player.setPlaybackRate(1.5);
+ });
+
+ it('set the player playback rate', function () {
+ expect(player.video.playbackRate).toEqual(1.5);
+ });
+ });
+
+ describe('volume', function () {
+ beforeEach(function () {
+ initialize();
+ spyOn(player, 'getVolume').andCallThrough();
+ });
+
+ it('set the player volume', function () {
+ var expectedValue = 60,
+ realValue;
+
+ player.setVolume(60);
+ realValue = Math.round(player.getVolume()*100);
+
+ expect(realValue).toEqual(expectedValue);
+ });
+ });
});
- afterEach(function() {
- $('source').remove();
- window.onTouchBasedDevice = oldOTBD;
- });
-
- describe('constructor', function() {
- describe('always', function() {
- beforeEach(function() {
- initialize();
- });
-
- it('instanticate current time to zero', function() {
- expect(videoPlayer.currentTime).toEqual(0);
- });
-
- it('set the element', function() {
- expect(state.el).toHaveId('video_id');
- });
-
- it('create video control', function() {
- expect(videoControl).toBeDefined();
- expect(videoControl.el).toHaveClass('video-controls');
- });
-
- it('create video caption', function() {
- expect(videoCaption).toBeDefined();
- expect(state.youtubeId()).toEqual('Z5KLxerq05Y');
- expect(state.speed).toEqual('1.0');
- expect(state.config.caption_asset_path).toEqual('/static/subs/');
- });
-
- it('create video speed control', function() {
- expect(videoSpeedControl).toBeDefined();
- expect(videoSpeedControl.el).toHaveClass('speeds');
- expect(videoSpeedControl.speeds).toEqual([ '0.75', '1.0', '1.25', '1.50' ]);
- expect(state.speed).toEqual('1.0');
- });
-
- it('create video progress slider', function() {
- expect(videoProgressSlider).toBeDefined();
- expect(videoProgressSlider.el).toHaveClass('slider');
- });
-
- // All the toHandleWith() expect tests are not necessary for this version of Video.
- // jQuery event system is not used to trigger and invoke methods. This is an artifact from
- // previous version of Video.
- });
-
- it('create Youtube player', function() {
- var oldYT = window.YT;
-
- jasmine.stubRequests();
-
- window.YT = {
- Player: function () { },
- PlayerState: oldYT.PlayerState,
- ready: function(f){f();}
- };
-
- spyOn(window.YT, 'Player');
-
- initializeYouTube();
-
- expect(YT.Player).toHaveBeenCalledWith('id', {
- playerVars: {
- controls: 0,
- wmode: 'transparent',
- rel: 0,
- showinfo: 0,
- enablejsapi: 1,
- modestbranding: 1,
- html5: 1,
- start: 0,
- end: null
- },
- videoId: 'cogebirgzzM',
- events: {
- onReady: videoPlayer.onReady,
- onStateChange: videoPlayer.onStateChange,
- onPlaybackQualityChange: videoPlayer.onPlaybackQualityChange
- }
- });
-
- window.YT = oldYT;
- });
-
- // We can't test the invocation of HTML5Video because it is not available
- // globally. It is defined within the scope of Require JS.
-
- describe('when not on a touch based device', function() {
- beforeEach(function() {
- window.onTouchBasedDevice.andReturn(true);
- initialize();
- });
-
- it('create video volume control', function() {
- expect(videoVolumeControl).toBeDefined();
- expect(videoVolumeControl.el).toHaveClass('volume');
- });
- });
-
- describe('when on a touch based device', function() {
- var oldOTBD;
-
- beforeEach(function() {
- initialize();
- });
-
- it('controls are in paused state', function() {
- expect(videoControl.isPlaying).toBe(false);
- });
- });
- });
-
- describe('onReady', function() {
- beforeEach(function() {
- initialize();
-
- spyOn(videoPlayer, 'log').andCallThrough();
- spyOn(videoPlayer, 'play').andCallThrough();
- videoPlayer.onReady();
- });
-
- it('log the load_video event', function() {
- expect(videoPlayer.log).toHaveBeenCalledWith('load_video');
- });
-
- it('autoplay the first video', function() {
- expect(videoPlayer.play).not.toHaveBeenCalled();
- });
- });
-
- describe('onStateChange', function() {
- describe('when the video is unstarted', function() {
- beforeEach(function() {
- initialize();
-
- spyOn(videoControl, 'pause').andCallThrough();
- spyOn(videoCaption, 'pause').andCallThrough();
-
- videoPlayer.onStateChange({
- data: YT.PlayerState.PAUSED
- });
- });
-
- it('pause the video control', function() {
- expect(videoControl.pause).toHaveBeenCalled();
- });
-
- it('pause the video caption', function() {
- expect(videoCaption.pause).toHaveBeenCalled();
- });
- });
-
- describe('when the video is playing', function() {
- var oldState;
-
- beforeEach(function() {
- // Create the first instance of the player.
- initialize();
- oldState = state;
-
- spyOn(oldState.videoPlayer, 'onPause').andCallThrough();
-
- // Now initialize a second instance.
- initialize();
-
- spyOn(videoPlayer, 'log').andCallThrough();
- spyOn(window, 'setInterval').andReturn(100);
- spyOn(videoControl, 'play');
- spyOn(videoCaption, 'play');
-
- videoPlayer.onStateChange({
- data: YT.PlayerState.PLAYING
- });
- });
-
- it('log the play_video event', function() {
- expect(videoPlayer.log).toHaveBeenCalledWith('play_video', {
- currentTime: 0
- });
- });
-
- it('pause other video player', function() {
- expect(oldState.videoPlayer.onPause).toHaveBeenCalled();
- });
-
- it('set update interval', function() {
- expect(window.setInterval).toHaveBeenCalledWith(videoPlayer.update, 200);
- expect(videoPlayer.updateInterval).toEqual(100);
- });
-
- it('play the video control', function() {
- expect(videoControl.play).toHaveBeenCalled();
- });
-
- it('play the video caption', function() {
- expect(videoCaption.play).toHaveBeenCalled();
- });
- });
-
- describe('when the video is paused', function() {
- var currentUpdateIntrval;
-
- beforeEach(function() {
- initialize();
-
- spyOn(videoPlayer, 'log').andCallThrough();
- spyOn(window, 'clearInterval').andCallThrough();
- spyOn(videoControl, 'pause').andCallThrough();
- spyOn(videoCaption, 'pause').andCallThrough();
-
- videoPlayer.onStateChange({
- data: YT.PlayerState.PLAYING
- });
-
- currentUpdateIntrval = videoPlayer.updateInterval;
-
- videoPlayer.onStateChange({
- data: YT.PlayerState.PAUSED
- });
- });
-
- it('log the pause_video event', function() {
- expect(videoPlayer.log).toHaveBeenCalledWith('pause_video', {
- currentTime: 0
- });
- });
-
- it('clear update interval', function() {
- expect(window.clearInterval).toHaveBeenCalledWith(currentUpdateIntrval);
- expect(videoPlayer.updateInterval).toBeUndefined();
- });
-
- it('pause the video control', function() {
- expect(videoControl.pause).toHaveBeenCalled();
- });
-
- it('pause the video caption', function() {
- expect(videoCaption.pause).toHaveBeenCalled();
- });
- });
-
- describe('when the video is ended', function() {
- beforeEach(function() {
- initialize();
-
- spyOn(videoControl, 'pause').andCallThrough();
- spyOn(videoCaption, 'pause').andCallThrough();
-
- videoPlayer.onStateChange({
- data: YT.PlayerState.ENDED
- });
- });
-
- it('pause the video control', function() {
- expect(videoControl.pause).toHaveBeenCalled();
- });
-
- it('pause the video caption', function() {
- expect(videoCaption.pause).toHaveBeenCalled();
- });
- });
- });
-
- describe('onSeek', function() {
- beforeEach(function() {
- spyOn(window, 'clearInterval').andCallThrough();
-
- initialize();
-
- videoPlayer.updateInterval = 100;
-
- spyOn(videoPlayer, 'updatePlayTime');
- spyOn(videoPlayer, 'log');
- spyOn(videoPlayer.player, 'seekTo');
- });
-
- it('Slider event causes log update', function () {
- videoProgressSlider.onSlide(jQuery.Event('slide'), {value: 60});
-
- expect(videoPlayer.log).toHaveBeenCalledWith(
- 'seek_video',
- {
- old_time: 0,
- new_time: 60,
- type: 'onSlideSeek'
- }
- );
- });
-
- it('seek the player', function() {
- videoProgressSlider.onSlide(jQuery.Event('slide'), {value: 60});
-
- expect(videoPlayer.player.seekTo).toHaveBeenCalledWith(60, true);
- });
-
- it('call updatePlayTime on player', function() {
- videoProgressSlider.onSlide(jQuery.Event('slide'), {value: 60});
-
- expect(videoPlayer.updatePlayTime).toHaveBeenCalledWith(60);
- });
-
- it('when the player is playing: reset the update interval', function() {
- videoProgressSlider.onSlide(jQuery.Event('slide'), {value: 60});
-
- expect(window.clearInterval).toHaveBeenCalledWith(100);
- });
-
- it('when the player is not playing: set the current time', function() {
- videoProgressSlider.onSlide(jQuery.Event('slide'), {value: 60});
- videoPlayer.pause();
-
- expect(videoPlayer.currentTime).toEqual(60);
- });
- });
-
- describe('onSpeedChange', function() {
- beforeEach(function() {
- initialize();
-
- videoPlayer.currentTime = 60;
-
- spyOn(videoPlayer, 'updatePlayTime').andCallThrough();
- spyOn(state, 'setSpeed').andCallThrough();
- spyOn(videoPlayer, 'log').andCallThrough();
- spyOn(videoPlayer.player, 'setPlaybackRate').andCallThrough();
- });
-
- describe('always', function() {
- beforeEach(function() {
- videoPlayer.onSpeedChange('0.75', false);
- });
-
- it('check if speed_change_video is logged', function() {
- expect(videoPlayer.log).toHaveBeenCalledWith('speed_change_video', {
- current_time: videoPlayer.currentTime,
- old_speed: '1.0',
- new_speed: '0.75'
- });
- });
-
- it('convert the current time to the new speed', function() {
- expect(videoPlayer.currentTime).toEqual(60);
- });
-
- it('set video speed to the new speed', function() {
- expect(state.setSpeed).toHaveBeenCalledWith('0.75', false);
- });
-
- // Not relevant any more:
- //
- // expect( "tell video caption that the speed has changed" ) ...
- });
-
- describe('when the video is playing', function() {
- beforeEach(function() {
- videoPlayer.play();
-
- videoPlayer.onSpeedChange('0.75', false);
- });
-
- it('trigger updatePlayTime event', function() {
- expect(videoPlayer.player.setPlaybackRate).toHaveBeenCalledWith('0.75');
- });
- });
-
- describe('when the video is not playing', function() {
- beforeEach(function() {
- videoPlayer.pause();
-
- videoPlayer.onSpeedChange('0.75', false);
- });
-
- it('trigger updatePlayTime event', function() {
- expect(videoPlayer.player.setPlaybackRate).toHaveBeenCalledWith('0.75');
- });
- });
- });
-
- describe('onVolumeChange', function() {
- beforeEach(function() {
- initialize();
-
- spyOn(videoPlayer.player, 'setVolume');
- videoPlayer.onVolumeChange(60);
- });
-
- it('set the volume on player', function() {
- expect(videoPlayer.player.setVolume).toHaveBeenCalledWith(60);
- });
- });
-
- describe('update', function() {
- beforeEach(function() {
- initialize();
-
- spyOn(videoPlayer, 'updatePlayTime').andCallThrough();
- });
-
- describe('when the current time is unavailable from the player', function() {
- beforeEach(function() {
- videoPlayer.player.getCurrentTime = function () {
- return NaN;
- };
- videoPlayer.update();
- });
-
- it('does not trigger updatePlayTime event', function() {
- expect(videoPlayer.updatePlayTime).not.toHaveBeenCalled();
- });
- });
-
- describe('when the current time is available from the player', function() {
- beforeEach(function() {
- videoPlayer.player.getCurrentTime = function () {
- return 60;
- };
- videoPlayer.update();
- });
-
- it('trigger updatePlayTime event', function() {
- expect(videoPlayer.updatePlayTime).toHaveBeenCalledWith(60);
- });
- });
- });
-
- describe('updatePlayTime', function() {
- beforeEach(function() {
- initialize();
-
- spyOn(videoCaption, 'updatePlayTime').andCallThrough();
- spyOn(videoProgressSlider, 'updatePlayTime').andCallThrough();
- });
-
- it('update the video playback time', function() {
- var duration = 0;
-
- waitsFor(function () {
- duration = videoPlayer.duration();
-
- if (duration > 0) {
- return true;
- }
-
- return false;
- }, 'Video is fully loaded.', 1000);
-
- runs(function () {
- var htmlStr;
-
- videoPlayer.updatePlayTime(60);
-
- htmlStr = $('.vidtime').html();
-
- // We resort to this trickery because Firefox and Chrome
- // round the total time a bit differently.
- if (htmlStr.match('1:00 / 1:01') || htmlStr.match('1:00 / 1:00')) {
- expect(true).toBe(true);
- } else {
- expect(true).toBe(false);
- }
-
- // The below test has been replaced by above trickery:
- //
- // expect($('.vidtime')).toHaveHtml('1:00 / 1:01');
- });
- });
-
- it('update the playback time on caption', function() {
- var duration = 0;
-
- waitsFor(function () {
- duration = videoPlayer.duration();
-
- if (duration > 0) {
- return true;
- }
-
- return false;
- }, 'Video is fully loaded.', 1000);
-
- runs(function () {
- videoPlayer.updatePlayTime(60);
-
- expect(videoCaption.updatePlayTime).toHaveBeenCalledWith(60);
- });
- });
-
- it('update the playback time on progress slider', function() {
- var duration = 0;
-
- waitsFor(function () {
- duration = videoPlayer.duration();
-
- if (duration > 0) {
- return true;
- }
-
- return false;
- }, 'Video is fully loaded.', 1000);
-
- runs(function () {
- videoPlayer.updatePlayTime(60);
-
- expect(videoProgressSlider.updatePlayTime).toHaveBeenCalledWith({
- time: 60,
- duration: duration
- });
- });
- });
- });
-
- describe('toggleFullScreen', function() {
- describe('when the video player is not full screen', function() {
- beforeEach(function() {
- initialize();
- spyOn(videoCaption, 'resize').andCallThrough();
- videoControl.toggleFullScreen(jQuery.Event("click"));
- });
-
- it('replace the full screen button tooltip', function() {
- expect($('.add-fullscreen')).toHaveAttr('title', 'Exit full browser');
- });
-
- it('add the video-fullscreen class', function() {
- expect(state.el).toHaveClass('video-fullscreen');
- });
-
- it('tell VideoCaption to resize', function() {
- expect(videoCaption.resize).toHaveBeenCalled();
- expect(state.resizer.setMode).toHaveBeenCalled();
- });
- });
-
- describe('when the video player already full screen', function() {
- beforeEach(function() {
- initialize();
- spyOn(videoCaption, 'resize').andCallThrough();
-
- state.el.addClass('video-fullscreen');
- videoControl.fullScreenState = true;
- isFullScreen = true;
- videoControl.fullScreenEl.attr('title', 'Exit-fullscreen');
-
- videoControl.toggleFullScreen(jQuery.Event("click"));
- });
-
- it('replace the full screen button tooltip', function() {
- expect($('.add-fullscreen')).toHaveAttr('title', 'Fill browser');
- });
-
- it('remove the video-fullscreen class', function() {
- expect(state.el).not.toHaveClass('video-fullscreen');
- });
-
- it('tell VideoCaption to resize', function() {
- expect(videoCaption.resize).toHaveBeenCalled();
- expect(state.resizer.setMode).toHaveBeenCalledWith('width');
- });
- });
- });
-
- describe('play', function() {
- beforeEach(function() {
- initialize();
- spyOn(player, 'playVideo').andCallThrough();
- });
-
- describe('when the player is not ready', function() {
- beforeEach(function() {
- player.playVideo = void 0;
- videoPlayer.play();
- });
- it('does nothing', function() {
- expect(player.playVideo).toBeUndefined();
- });
- });
-
- describe('when the player is ready', function() {
- beforeEach(function() {
- player.playVideo.andReturn(true);
- videoPlayer.play();
- });
-
- it('delegate to the player', function() {
- expect(player.playVideo).toHaveBeenCalled();
- });
- });
- });
-
- describe('isPlaying', function() {
- beforeEach(function() {
- initialize();
- spyOn(player, 'getPlayerState').andCallThrough();
- });
-
- describe('when the video is playing', function() {
- beforeEach(function() {
- player.getPlayerState.andReturn(YT.PlayerState.PLAYING);
- });
-
- it('return true', function() {
- expect(videoPlayer.isPlaying()).toBeTruthy();
- });
- });
-
- describe('when the video is not playing', function() {
- beforeEach(function() {
- player.getPlayerState.andReturn(YT.PlayerState.PAUSED);
- });
-
- it('return false', function() {
- expect(videoPlayer.isPlaying()).toBeFalsy();
- });
- });
- });
-
- describe('pause', function() {
- beforeEach(function() {
- initialize();
- spyOn(player, 'pauseVideo').andCallThrough();
- videoPlayer.pause();
- });
-
- it('delegate to the player', function() {
- expect(player.pauseVideo).toHaveBeenCalled();
- });
- });
-
- describe('duration', function() {
- beforeEach(function() {
- initialize();
- spyOn(player, 'getDuration').andCallThrough();
- videoPlayer.duration();
- });
-
- it('delegate to the player', function() {
- expect(player.getDuration).toHaveBeenCalled();
- });
- });
-
- describe('playback rate', function() {
- beforeEach(function() {
- initialize();
- player.setPlaybackRate(1.5);
- });
-
- it('set the player playback rate', function() {
- expect(player.video.playbackRate).toEqual(1.5);
- });
- });
-
- describe('volume', function() {
- beforeEach(function() {
- initialize();
- spyOn(player, 'getVolume').andCallThrough();
- });
-
- it('set the player volume', function() {
- var expectedValue = 60,
- realValue;
-
- player.setVolume(60);
- realValue = Math.round(player.getVolume()*100);
-
- expect(realValue).toEqual(expectedValue);
- });
- });
- });
-
}).call(this);
diff --git a/common/lib/xmodule/xmodule/js/spec/video/video_progress_slider_spec.js b/common/lib/xmodule/xmodule/js/spec/video/video_progress_slider_spec.js
index 1c7ecf4edc..8ed9f657ac 100644
--- a/common/lib/xmodule/xmodule/js/spec/video/video_progress_slider_spec.js
+++ b/common/lib/xmodule/xmodule/js/spec/video/video_progress_slider_spec.js
@@ -1,192 +1,253 @@
(function() {
- describe('VideoProgressSlider', function() {
- var state, videoPlayer, videoProgressSlider, oldOTBD;
+ describe('VideoProgressSlider', function() {
+ var state, videoPlayer, videoProgressSlider, oldOTBD;
- function initialize() {
- loadFixtures('video_all.html');
- state = new Video('#example');
- videoPlayer = state.videoPlayer;
- videoProgressSlider = state.videoProgressSlider;
- }
-
- beforeEach(function() {
- oldOTBD = window.onTouchBasedDevice;
- window.onTouchBasedDevice = jasmine.createSpy('onTouchBasedDevice').andReturn(false);
- });
-
-
- afterEach(function() {
- $('source').remove();
- window.onTouchBasedDevice = oldOTBD;
- });
-
- describe('constructor', function() {
- describe('on a non-touch based device', function() {
- beforeEach(function() {
- spyOn($.fn, 'slider').andCallThrough();
- initialize();
- });
-
- 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('.slider .ui-slider-handle');
- });
- });
-
- describe('on a touch-based device', function() {
- beforeEach(function() {
- window.onTouchBasedDevice.andReturn(true);
- spyOn($.fn, 'slider').andCallThrough();
- initialize();
- });
-
- it('does not build the slider', function() {
- expect(videoProgressSlider.slider).toBeUndefined();
-
- // We can't expect $.fn.slider not to have been called,
- // because sliders are used in other parts of Video.
- });
- });
- });
-
- describe('play', function() {
- beforeEach(function() {
- initialize();
- });
-
- describe('when the slider was already built', function() {
- var spy;
+ function initialize() {
+ loadFixtures('video_all.html');
+ state = new Video('#example');
+ videoPlayer = state.videoPlayer;
+ videoProgressSlider = state.videoProgressSlider;
+ }
beforeEach(function() {
- spy = spyOn(videoProgressSlider, 'buildSlider');
- spy.andCallThrough();
- videoPlayer.play();
+ oldOTBD = window.onTouchBasedDevice;
+ window.onTouchBasedDevice = jasmine.createSpy('onTouchBasedDevice')
+ .andReturn(false);
});
- it('does not build the slider', function() {
- expect(spy.callCount).toEqual(0);
+ afterEach(function() {
+ $('source').remove();
+ window.onTouchBasedDevice = oldOTBD;
});
- });
- // Currently, the slider is not rebuilt if it does not exist.
+ describe('constructor', function() {
+ describe('on a non-touch based device', function() {
+ beforeEach(function() {
+ spyOn($.fn, 'slider').andCallThrough();
+ initialize();
+ });
+
+ 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('.slider .ui-slider-handle');
+ });
+ });
+
+ describe('on a touch-based device', function() {
+ beforeEach(function() {
+ window.onTouchBasedDevice.andReturn(true);
+ spyOn($.fn, 'slider').andCallThrough();
+ initialize();
+ });
+
+ it('does not build the slider', function() {
+ expect(videoProgressSlider.slider).toBeUndefined();
+
+ // We can't expect $.fn.slider not to have been called,
+ // because sliders are used in other parts of Video.
+ });
+ });
+ });
+
+ describe('play', function() {
+ beforeEach(function() {
+ initialize();
+ });
+
+ describe('when the slider was already built', function() {
+ var spy;
+
+ beforeEach(function() {
+ spy = spyOn(videoProgressSlider, 'buildSlider');
+ spy.andCallThrough();
+ videoPlayer.play();
+ });
+
+ it('does not build the slider', function() {
+ expect(spy.callCount).toEqual(0);
+ });
+ });
+
+ // Currently, the slider is not rebuilt if it does not exist.
+ });
+
+ describe('updatePlayTime', function() {
+ beforeEach(function() {
+ initialize();
+ });
+
+ describe('when frozen', function() {
+ beforeEach(function() {
+ spyOn($.fn, 'slider').andCallThrough();
+ videoProgressSlider.frozen = true;
+ videoProgressSlider.updatePlayTime(20, 120);
+ });
+
+ it('does not update the slider', function() {
+ expect($.fn.slider).not.toHaveBeenCalled();
+ });
+ });
+
+ describe('when not frozen', function() {
+ beforeEach(function() {
+ spyOn($.fn, 'slider').andCallThrough();
+ videoProgressSlider.frozen = false;
+ videoProgressSlider.updatePlayTime({
+ time: 20,
+ duration: 120
+ });
+ });
+
+ it('update the max value of the slider', function() {
+ expect($.fn.slider).toHaveBeenCalledWith(
+ 'option', 'max', 120
+ );
+ });
+
+ it('update current value of the slider', function() {
+ expect($.fn.slider).toHaveBeenCalledWith(
+ 'option', 'value', 20
+ );
+ });
+ });
+ });
+
+ describe('onSlide', function() {
+ beforeEach(function() {
+ initialize();
+ spyOn($.fn, 'slider').andCallThrough();
+ spyOn(videoPlayer, 'onSlideSeek').andCallThrough();
+
+ state.videoPlayer.play();
+
+ waitsFor(function () {
+ var duration = videoPlayer.duration(),
+ currentTime = videoPlayer.currentTime;
+
+ return (
+ isFinite(currentTime) &&
+ currentTime > 0 &&
+ isFinite(duration) &&
+ duration > 0
+ );
+ }, 'video begins playing', 10000);
+ });
+
+ it('freeze the slider', function() {
+ runs(function () {
+ videoProgressSlider.onSlide(
+ jQuery.Event('slide'), { value: 20 }
+ );
+
+ expect(videoProgressSlider.frozen).toBeTruthy();
+ });
+ });
+
+ // Turned off test due to flakiness (30.10.2013).
+ xit('trigger seek event', function() {
+ runs(function () {
+ videoProgressSlider.onSlide(
+ jQuery.Event('slide'), { value: 20 }
+ );
+
+ expect(videoPlayer.onSlideSeek).toHaveBeenCalled();
+
+ waitsFor(function () {
+ return Math.round(videoPlayer.currentTime) === 20;
+ }, 'currentTime got updated', 10000);
+ });
+ });
+ });
+
+ describe('onStop', function() {
+ // We will store default window.setTimeout() function here.
+ var oldSetTimeout = null;
+
+ beforeEach(function() {
+ // Store original window.setTimeout() function. If we do not do
+ // this, then all other tests that rely on code which uses
+ // window.setTimeout() function might (and probably will) fail.
+ oldSetTimeout = window.setTimeout;
+ // Redefine window.setTimeout() function as a spy.
+ window.setTimeout = jasmine.createSpy()
+ .andCallFake(function (callback, timeout) {
+ return 5;
+ });
+ window.setTimeout.andReturn(100);
+
+ initialize();
+ spyOn(videoPlayer, 'onSlideSeek').andCallThrough();
+ videoPlayer.play();
+
+ waitsFor(function () {
+ var duration = videoPlayer.duration(),
+ currentTime = videoPlayer.currentTime;
+
+ return (
+ isFinite(currentTime) &&
+ currentTime > 0 &&
+ isFinite(duration) &&
+ duration > 0
+ );
+ }, 'video begins playing', 10000);
+ });
+
+ afterEach(function () {
+ // Reset the default window.setTimeout() function. If we do not
+ // do this, then all other tests that rely on code which uses
+ // window.setTimeout() function might (and probably will) fail.
+ window.setTimeout = oldSetTimeout;
+ });
+
+ it('freeze the slider', function() {
+ runs(function () {
+ videoProgressSlider.onStop(
+ jQuery.Event('stop'), { value: 20 }
+ );
+
+ expect(videoProgressSlider.frozen).toBeTruthy();
+ });
+ });
+
+ // Turned off test due to flakiness (30.10.2013).
+ xit('trigger seek event', function() {
+ runs(function () {
+ videoProgressSlider.onStop(
+ jQuery.Event('stop'), { value: 20 }
+ );
+
+ expect(videoPlayer.onSlideSeek).toHaveBeenCalled();
+
+ waitsFor(function () {
+ return Math.round(videoPlayer.currentTime) === 20;
+ }, 'currentTime got updated', 10000);
+ });
+ });
+
+ it('set timeout to unfreeze the slider', function() {
+ runs(function () {
+ videoProgressSlider.onStop(
+ jQuery.Event('stop'), { value: 20 }
+ );
+
+ expect(window.setTimeout).toHaveBeenCalledWith(
+ jasmine.any(Function), 200
+ );
+ window.setTimeout.mostRecentCall.args[0]();
+ expect(videoProgressSlider.frozen).toBeFalsy();
+ });
+ });
+ });
});
- describe('updatePlayTime', function() {
- beforeEach(function() {
- initialize();
- });
-
- describe('when frozen', function() {
- beforeEach(function() {
- spyOn($.fn, 'slider').andCallThrough();
- videoProgressSlider.frozen = true;
- videoProgressSlider.updatePlayTime(20, 120);
- });
-
- it('does not update the slider', function() {
- expect($.fn.slider).not.toHaveBeenCalled();
- });
- });
-
- describe('when not frozen', function() {
- beforeEach(function() {
- spyOn($.fn, 'slider').andCallThrough();
- videoProgressSlider.frozen = false;
- videoProgressSlider.updatePlayTime({time:20, duration:120});
- });
-
- it('update the max value of the slider', function() {
- expect($.fn.slider).toHaveBeenCalledWith('option', 'max', 120);
- });
-
- it('update current value of the slider', function() {
- expect($.fn.slider).toHaveBeenCalledWith('option', 'value', 20);
- });
- });
- });
-
- describe('onSlide', function() {
- beforeEach(function() {
- initialize();
- spyOn($.fn, 'slider').andCallThrough();
- spyOn(videoPlayer, 'onSlideSeek').andCallThrough();
- videoProgressSlider.onSlide({}, {
- value: 20
- });
- });
-
- it('freeze the slider', function() {
- expect(videoProgressSlider.frozen).toBeTruthy();
- });
-
- it('trigger seek event', function() {
- expect(videoPlayer.onSlideSeek).toHaveBeenCalled();
- expect(videoPlayer.currentTime).toEqual(20);
- });
- });
-
- describe('onChange', function() {
- beforeEach(function() {
- initialize();
- spyOn($.fn, 'slider').andCallThrough();
- videoProgressSlider.onChange({}, {
- value: 20
- });
- });
- });
-
- describe('onStop', function() {
- // We will store default window.setTimeout() function here.
- var oldSetTimeout = null;
-
- beforeEach(function() {
- // Store original window.setTimeout() function. If we do not do this, then
- // all other tests that rely on code which uses window.setTimeout()
- // function might (and probably will) fail.
- oldSetTimeout = window.setTimeout;
- // Redefine window.setTimeout() function as a spy.
- window.setTimeout = jasmine.createSpy().andCallFake(function(callback, timeout) { return 5; });
- window.setTimeout.andReturn(100);
-
- initialize();
- spyOn(videoPlayer, 'onSlideSeek').andCallThrough();
- videoProgressSlider.onStop({}, {
- value: 20
- });
- });
-
- afterEach(function () {
- // Reset the default window.setTimeout() function. If we do not do this,
- // then all other tests that rely on code which uses window.setTimeout()
- // function might (and probably will) fail.
- window.setTimeout = oldSetTimeout;
- });
-
- it('freeze the slider', function() {
- expect(videoProgressSlider.frozen).toBeTruthy();
- });
-
- it('trigger seek event', function() {
- expect(videoPlayer.onSlideSeek).toHaveBeenCalled();
- expect(videoPlayer.currentTime).toEqual(20);
- });
-
- // Disabled 10/9/13 after failing in master
- xit('set timeout to unfreeze the slider', function() {
- expect(window.setTimeout).toHaveBeenCalledWith(jasmine.any(Function), 200);
- window.setTimeout.mostRecentCall.args[0]();
- expect(videoProgressSlider.frozen).toBeFalsy();
- });
- });
- });
-
}).call(this);
diff --git a/common/lib/xmodule/xmodule/js/src/video/00_resizer.js b/common/lib/xmodule/xmodule/js/src/video/00_resizer.js
index e715fc930f..bbe75b0aeb 100644
--- a/common/lib/xmodule/xmodule/js/src/video/00_resizer.js
+++ b/common/lib/xmodule/xmodule/js/src/video/00_resizer.js
@@ -23,7 +23,9 @@ function () {
}
if (!config.element) {
- console.log('Required parameter `element` is not passed.');
+ console.log(
+ '[Video info]: Required parameter `element` is not passed.'
+ );
}
return this;
@@ -55,7 +57,7 @@ function () {
};
};
- var align = function() {
+ var align = function () {
var data = getData();
switch (mode) {
diff --git a/common/lib/xmodule/xmodule/js/src/video/01_initialize.js b/common/lib/xmodule/xmodule/js/src/video/01_initialize.js
index 7df3131793..66e8cdda12 100644
--- a/common/lib/xmodule/xmodule/js/src/video/01_initialize.js
+++ b/common/lib/xmodule/xmodule/js/src/video/01_initialize.js
@@ -262,8 +262,8 @@ function (VideoPlayer) {
this.config = {
element: element,
- start: data['start'],
- end: data['end'],
+ startTime: data['start'],
+ endTime: data['end'],
caption_data_dir: data['captionDataDir'],
caption_asset_path: data['captionAssetPath'],
show_captions: regExp.test(data['showCaptions'].toString()),
@@ -369,7 +369,7 @@ function (VideoPlayer) {
/*
* function checkStartEndTimes()
*
- * Validate config.start and config.end times.
+ * Validate config.startTime and config.endTime times.
*
* We can check at this time if the times are proper integers, and if they
* make general sense. I.e. if start time is => 0 and <= end time.
@@ -379,14 +379,18 @@ function (VideoPlayer) {
* if start time and/or end time are greater than the length of the video.
*/
function checkStartEndTimes() {
- this.config.start = parseInt(this.config.start, 10);
- if ((!isFinite(this.config.start)) || (this.config.start < 0)) {
- this.config.start = 0;
+ this.config.startTime = parseInt(this.config.startTime, 10);
+ if (!isFinite(this.config.startTime) || this.config.startTime < 0) {
+ this.config.startTime = 0;
}
- this.config.end = parseInt(this.config.end, 10);
- if ((!isFinite(this.config.end)) || (this.config.end < this.config.start)) {
- this.config.end = null;
+ this.config.endTime = parseInt(this.config.endTime, 10);
+ if (
+ !isFinite(this.config.endTime) ||
+ this.config.endTime < this.config.startTime ||
+ this.config.endTime === 0
+ ) {
+ this.config.endTime = null;
}
}
diff --git a/common/lib/xmodule/xmodule/js/src/video/025_focus_grabber.js b/common/lib/xmodule/xmodule/js/src/video/025_focus_grabber.js
index 7d95871b50..c79345774f 100644
--- a/common/lib/xmodule/xmodule/js/src/video/025_focus_grabber.js
+++ b/common/lib/xmodule/xmodule/js/src/video/025_focus_grabber.js
@@ -44,8 +44,12 @@ function () {
// Private functions.
function _makeFunctionsPublic(state) {
- state.focusGrabber.enableFocusGrabber = _.bind(enableFocusGrabber, state);
- state.focusGrabber.disableFocusGrabber = _.bind(disableFocusGrabber, state);
+ state.focusGrabber.enableFocusGrabber = _.bind(
+ enableFocusGrabber, state
+ );
+ state.focusGrabber.disableFocusGrabber = _.bind(
+ disableFocusGrabber, state
+ );
state.focusGrabber.onFocus = _.bind(onFocus, state);
}
diff --git a/common/lib/xmodule/xmodule/js/src/video/02_html5_video.js b/common/lib/xmodule/xmodule/js/src/video/02_html5_video.js
index caddc3eb12..2635398937 100644
--- a/common/lib/xmodule/xmodule/js/src/video/02_html5_video.js
+++ b/common/lib/xmodule/xmodule/js/src/video/02_html5_video.js
@@ -1,10 +1,12 @@
/**
- * @file HTML5 video player module. Provides methods to control the in-browser HTML5 video player.
+ * @file HTML5 video player module. Provides methods to control the in-browser
+ * HTML5 video player.
*
- * The goal was to write this module so that it closely resembles the YouTube API. The main reason
- * for this is because initially the edX video player supported only YouTube videos. When HTML5
- * support was added, for greater compatibility, and to reduce the amount of code that needed to
- * be modified, it was decided to write a similar API as the one provided by YouTube.
+ * The goal was to write this module so that it closely resembles the YouTube
+ * API. The main reason for this is because initially the edX video player
+ * supported only YouTube videos. When HTML5 support was added, for greater
+ * compatibility, and to reduce the amount of code that needed to be modified,
+ * it was decided to write a similar API as the one provided by YouTube.
*
* @external RequireJS
*
@@ -33,16 +35,17 @@ function () {
};
Player.prototype.seekTo = function (value) {
- if ((typeof value === 'number') && (value <= this.video.duration) && (value >= 0)) {
- this.start = 0;
- this.end = this.video.duration;
-
+ if (
+ typeof value === 'number' &&
+ value <= this.video.duration &&
+ value >= 0
+ ) {
this.video.currentTime = value;
}
};
Player.prototype.setVolume = function (value) {
- if ((typeof value === 'number') && (value <= 100) && (value >= 0)) {
+ if (typeof value === 'number' && value <= 100 && value >= 0) {
this.video.volume = value * 0.01;
}
};
@@ -92,35 +95,33 @@ function () {
/*
* Constructor function for HTML5 Video player.
*
- * @param {String|Object} el A DOM element where the HTML5 player will be inserted (as returned by jQuery(selector) function),
- * or a selector string which will be used to select an element. This is a required parameter.
+ * @param {String|Object} el A DOM element where the HTML5 player will
+ * be inserted (as returned by jQuery(selector) function), or a
+ * selector string which will be used to select an element. This is a
+ * required parameter.
*
- * @param config - An object whose properties will be used as configuration options for the HTML5 video
- * player. This is an optional parameter. In the case if this parameter is missing, or some of the config
- * object's properties are missing, defaults will be used. The available options (and their defaults) are as
+ * @param config - An object whose properties will be used as
+ * configuration options for the HTML5 video player. This is an
+ * optional parameter. In the case if this parameter is missing, or
+ * some of the config object's properties are missing, defaults will be
+ * used. The available options (and their defaults) are as
* follows:
*
* config = {
*
- * videoSources: {}, // An object with properties being video sources. The property name is the
- * // video format of the source. Supported video formats are: 'mp4', 'webm', and
- * // 'ogg'.
+ * videoSources: {}, // An object with properties being video
+ * // sources. The property name is the
+ * // video format of the source. Supported
+ * // video formats are: 'mp4', 'webm', and
+ * // 'ogg'.
*
- * playerVars: { // Object's properties identify player parameters.
- * start: 0, // Possible values: positive integer. Position from which to start playing the
- * // video. Measured in seconds. If value is non-numeric, or 'start' property is
- * // not specified, the video will start playing from the beginning.
- *
- * end: null // Possible values: positive integer. Position when to stop playing the
- * // video. Measured in seconds. If value is null, or 'end' property is not
- * // specified, the video will end playing at the end.
- *
- * },
- *
- * events: { // Object's properties identify the events that the API fires, and the
- * // functions (event listeners) that the API will call when those events occur.
- * // If value is null, or property is not specified, then no callback will be
- * // called for that event.
+ * events: { // Object's properties identify the
+ * // events that the API fires, and the
+ * // functions (event listeners) that the
+ * // API will call when those events occur.
+ * // If value is null, or property is not
+ * // specified, then no callback will be
+ * // called for that event.
*
* onReady: null,
* onStateChange: null
@@ -130,16 +131,19 @@ function () {
function Player(el, config) {
var sourceStr, _this, errorMessage;
- // Initially we assume that el is a DOM element. If jQuery selector fails to select something, we
- // assume that el is an ID of a DOM element. We try to select by ID. If jQuery fails this time,
- // we return. Nothing breaks because the player 'onReady' event will never be fired.
+ // Initially we assume that el is a DOM element. If jQuery selector
+ // fails to select something, we assume that el is an ID of a DOM
+ // element. We try to select by ID. If jQuery fails this time, we
+ // return. Nothing breaks because the player 'onReady' event will
+ // never be fired.
this.el = $(el);
if (this.el.length === 0) {
this.el = $('#' + el);
if (this.el.length === 0) {
- errorMessage = 'VideoPlayer: Element corresponding to the given selector does not found.';
+ errorMessage = 'VideoPlayer: Element corresponding to ' +
+ 'the given selector does not found.';
if (window.console && console.log) {
console.log(errorMessage);
} else {
@@ -156,12 +160,14 @@ function () {
return;
}
- // We should have at least one video source. Otherwise there is no point to continue.
+ // We should have at least one video source. Otherwise there is no
+ // point to continue.
if (!config.videoSources) {
return;
}
- // From the start, all sources are empty. We will populate this object below.
+ // From the start, all sources are empty. We will populate this
+ // object below.
sourceStr = {
mp4: ' ',
webm: ' ',
@@ -171,7 +177,8 @@ function () {
// Will be used in inner functions to point to the current object.
_this = this;
- // Create HTML markup for individual sources of the HTML5