diff --git a/common/lib/xmodule/xmodule/css/videoalpha/display.scss b/common/lib/xmodule/xmodule/css/videoalpha/display.scss
index c677584484..d115c0743c 100644
--- a/common/lib/xmodule/xmodule/css/videoalpha/display.scss
+++ b/common/lib/xmodule/xmodule/css/videoalpha/display.scss
@@ -519,7 +519,7 @@ div.videoalpha {
}
ol.subtitles.html5 {
- background-color: rgba(243, 243, 243, 0.5);
+ background-color: rgba(243, 243, 243, 0.8);
height: 380px;
position: absolute;
right: 0;
@@ -550,12 +550,22 @@ div.videoalpha {
}
}
+ article.video-wrapper div.video-player-pre, article.video-wrapper div.video-player-post {
+ height: 0px;
+ }
+
+ article.video-wrapper {
+ position: static;
+ }
+
div.tc-wrapper {
@include clearfix;
display: table;
width: 100%;
height: 100%;
+ position: static;
+
article.video-wrapper {
width: 100%;
display: table-cell;
diff --git a/common/lib/xmodule/xmodule/js/src/videoalpha/display/html5_video.js b/common/lib/xmodule/xmodule/js/src/videoalpha/display/html5_video.js
index 91f36556b7..5372108aba 100644
--- a/common/lib/xmodule/xmodule/js/src/videoalpha/display/html5_video.js
+++ b/common/lib/xmodule/xmodule/js/src/videoalpha/display/html5_video.js
@@ -17,9 +17,7 @@ define(
'videoalpha/display/html5_video.js',
[],
function () {
- var HTML5Video;
-
- HTML5Video = {};
+ var HTML5Video = {};
HTML5Video.Player = (function () {
Player.prototype.callStateChangeCallback = function () {
@@ -129,9 +127,21 @@ function () {
// If el is string, we assume it is an ID of a DOM element. Get the element, and check that the ID
// really belongs to an element. If we didn't get a DOM element, return. At this stage, nothing will
// break because other parts of the video player are waiting for 'onReady' callback to be called.
+
+ // REFACTOR: Use .length === 0
+
+ this.el = $(el);
+ // REFACTOR: Simplify chck.
+ if (this.el.length === 0) {
+ return;
+ }
+
+
+
+
if (typeof el === 'string') {
this.el = $(el);
-
+ // REFACTOR: Simplify chck.
if (this.el.length === 0) {
return;
}
@@ -140,7 +150,7 @@ function () {
} else {
return;
}
-
+
// A simple test to see that the 'config' is a normal object.
if ($.isPlainObject(config)) {
this.config = config;
@@ -294,6 +304,7 @@ function () {
}
}());
+ // REFACTOR: Doc.
HTML5Video.PlayerState = {
'UNSTARTED': -1,
'ENDED': 0,
diff --git a/common/lib/xmodule/xmodule/js/src/videoalpha/display/initialize.js b/common/lib/xmodule/xmodule/js/src/videoalpha/display/initialize.js
index 25a44aee50..049746b47e 100644
--- a/common/lib/xmodule/xmodule/js/src/videoalpha/display/initialize.js
+++ b/common/lib/xmodule/xmodule/js/src/videoalpha/display/initialize.js
@@ -64,20 +64,20 @@ function (VideoPlayer) {
// We store all settings passed to us by the server in one place. These are "read only", so don't
// modify them. All variable content lives in 'state' object.
state.config = {
- 'element': element,
+ element: element,
- 'start': state.el.data('start'),
- 'end': state.el.data('end'),
+ start: state.el.data('start'),
+ end: state.el.data('end'),
- 'caption_data_dir': state.el.data('caption-data-dir'),
- 'caption_asset_path': state.el.data('caption-asset-path'),
- 'show_captions': (state.el.data('show-captions').toString().toLowerCase === 'true'),
- 'youtubeStreams': state.el.data('streams'),
+ caption_data_dir: state.el.data('caption-data-dir'),
+ caption_asset_path: state.el.data('caption-asset-path'),
+ show_captions: (state.el.data('show-captions').toString().toLowerCase() === 'true'),
+ youtubeStreams: state.el.data('streams'),
- 'sub': state.el.data('sub'),
- 'mp4Source': state.el.data('mp4-source'),
- 'webmSource': state.el.data('webm-source'),
- 'oggSource': state.el.data('ogg-source')
+ sub: state.el.data('sub'),
+ mp4Source: state.el.data('mp4-source'),
+ webmSource: state.el.data('webm-source'),
+ oggSource: state.el.data('ogg-source')
};
// Try to parse YouTube stream ID's. If
@@ -101,7 +101,7 @@ function (VideoPlayer) {
}
);
- if (!state.config.sub.length) {
+ if (!state.config.sub || !state.config.sub.length) {
state.config.sub = '';
state.config.show_captions = false;
}
@@ -149,14 +149,14 @@ function (VideoPlayer) {
// in a browser that doesn't fully support HTML5. When we have this setting in cookies, we can select
// the proper mode from the start (not having to change mode later on).
(function (currentPlayerMode) {
- if ((currentPlayerMode !== 'html5') && (currentPlayerMode !== 'flash')) {
+ if ((currentPlayerMode === 'html5') || (currentPlayerMode === 'flash')) {
+ state.currentPlayerMode = currentPlayerMode;
+ } else {
$.cookie('current_player_mode', 'html5', {
'expires': 3650,
'path': '/'
});
state.currentPlayerMode = 'html5';
- } else {
- state.currentPlayerMode = currentPlayerMode;
}
}($.cookie('current_player_mode')));
@@ -222,7 +222,7 @@ function (VideoPlayer) {
state.html5Sources = { 'mp4': null, 'webm': null, 'ogg': null };
$.each(sources, function (name, source) {
- if (source.length) {
+ if (source && source.length) {
state.html5Sources[name] = source;
}
});
@@ -255,6 +255,14 @@ function (VideoPlayer) {
}
function checkForNativeFunctions() {
+ // REFACTOR:
+ // 1.) IE8 doc.
+ // 2.) Move to separate file.
+ // 3.) Write about a generic soluction system wide.
+
+ //
+ // IE browser supports Function.bind() only starting with version 8.
+ //
// The bind function is a recent addition to ECMA-262, 5th edition; as such it may not be present in all
// browsers. You can partially work around this by inserting the following code at the beginning of your
// scripts, allowing use of much of the functionality of bind() in implementations that do not natively support
diff --git a/common/lib/xmodule/xmodule/js/src/videoalpha/display/video_caption.js b/common/lib/xmodule/xmodule/js/src/videoalpha/display/video_caption.js
index 8c8511e7c1..095dc784a0 100644
--- a/common/lib/xmodule/xmodule/js/src/videoalpha/display/video_caption.js
+++ b/common/lib/xmodule/xmodule/js/src/videoalpha/display/video_caption.js
@@ -53,10 +53,8 @@ function () {
function renderElements(state) {
state.videoCaption.loaded = false;
- state.videoCaption.subtitlesEl = $('
');
- state.videoCaption.hideSubtitlesEl = $(
- 'Captions'
- );
+ state.videoCaption.subtitlesEl = state.el.find('ol.subtitles');
+ state.videoCaption.hideSubtitlesEl = state.el.find('a.hide-subtitles');
state.el.find('.video-wrapper').after(state.videoCaption.subtitlesEl);
state.el.find('.video-controls .secondary-controls').append(state.videoCaption.hideSubtitlesEl);
@@ -67,6 +65,7 @@ function () {
fetchCaption(state);
+ // REFACTOR. Const.
if (state.videoType === 'html5') {
state.videoCaption.fadeOutTimeout = 1400;
@@ -81,6 +80,8 @@ function () {
function bindHandlers(state) {
$(window).bind('resize', state.videoCaption.resize);
state.videoCaption.hideSubtitlesEl.click(state.videoCaption.toggle);
+
+ // REFACTOR: Use .on()
state.videoCaption.subtitlesEl.mouseenter(
state.videoCaption.onMouseEnter
).mouseleave(
@@ -136,6 +137,8 @@ function () {
this.captionsShowLock = true;
+ // REFACTOR.
+
if (this.captionState === 'invisible') {
this.videoCaption.subtitlesEl.show();
this.captionState = 'visible';
@@ -168,6 +171,7 @@ function () {
_this = this;
+ // REFACTOR.
this.videoCaption.subtitlesEl.fadeOut(1000, function () {
_this.captionState = 'invisible';
});
@@ -178,6 +182,7 @@ function () {
'maxHeight': this.videoCaption.captionHeight()
});
+ // REFACTOR: Chain.
this.videoCaption.subtitlesEl.find('.spacing:first').height(this.videoCaption.topSpacingHeight());
this.videoCaption.subtitlesEl.find('.spacing:last').height(this.videoCaption.bottomSpacingHeight());
@@ -189,6 +194,7 @@ function () {
clearTimeout(this.videoCaption.frozen);
}
+ // REFACTOR.
this.videoCaption.frozen = setTimeout(this.videoCaption.onMouseLeave, 10000);
}
@@ -209,23 +215,25 @@ function () {
}
function renderCaption() {
- var container, _this;
-
- _this = this;
+ var container, _this = this;
container = $('');
$.each(this.videoCaption.captions, function(index, text) {
+ // REFACTOR: Use .data()
container.append($('- ').html(text).attr({
'data-index': index,
'data-start': _this.videoCaption.start[index]
}));
});
+ // REFACTOR: Chain.
this.videoCaption.subtitlesEl.html(container.html());
this.videoCaption.subtitlesEl.find('li[data-index]').on('click', this.videoCaption.seekPlayer);
- this.videoCaption.subtitlesEl.prepend(
+ this.videoCaption.subtitlesEl
+ .prepend(
$('
- ').height(this.videoCaption.topSpacingHeight())
- ).append(
+ )
+ .append(
$('
- ').height(this.videoCaption.bottomSpacingHeight())
);
@@ -233,10 +241,17 @@ function () {
}
function scrollCaption() {
- if (!this.videoCaption.frozen && this.videoCaption.subtitlesEl.find('.current:first').length) {
- this.videoCaption.subtitlesEl.scrollTo(this.videoCaption.subtitlesEl.find('.current:first'), {
- 'offset': -this.videoCaption.calculateOffset(this.videoCaption.subtitlesEl.find('.current:first'))
- });
+ // REFACTOR: Cache current:first
+ if (
+ !this.videoCaption.frozen &&
+ this.videoCaption.subtitlesEl.find('.current:first').length
+ ) {
+ this.videoCaption.subtitlesEl.scrollTo(
+ this.videoCaption.subtitlesEl.find('.current:first'),
+ {
+ 'offset': -this.videoCaption.calculateOffset(this.videoCaption.subtitlesEl.find('.current:first'))
+ }
+ );
}
}
@@ -352,6 +367,7 @@ function () {
}
function captionHeight() {
+ // REFACTOR: Use property instead of class.
if (this.el.hasClass('fullscreen')) {
return $(window).height() - this.el.find('.video-controls').height();
} else {
diff --git a/common/lib/xmodule/xmodule/js/src/videoalpha/display/video_control.js b/common/lib/xmodule/xmodule/js/src/videoalpha/display/video_control.js
index e8c2a83c3f..cc2a85a803 100644
--- a/common/lib/xmodule/xmodule/js/src/videoalpha/display/video_control.js
+++ b/common/lib/xmodule/xmodule/js/src/videoalpha/display/video_control.js
@@ -40,23 +40,10 @@ function () {
// 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) {
- var el, qTipConfig;
- // REFACTOR move templates and css to one file- to python part
- el = $(
- '' +
- '
' +
- '
' +
- ' ' +
- '0:00 / 0:00
' +
- '
' +
- '
' +
- '
'
- );
+ var qTipConfig;
state.videoControl.el = state.el.find('.video-controls');
- state.videoControl.el.append(el);
+ // state.videoControl.el.append(el);
state.videoControl.sliderEl = state.videoControl.el.find('.slider');
state.videoControl.playPauseEl = state.videoControl.el.find('.video_control');
@@ -83,6 +70,8 @@ function () {
}
if (state.videoType === 'html5') {
+ // REFACTOR: constants move to initialize()
+
state.videoControl.fadeOutTimeout = 1400;
state.videoControl.el.addClass('html5');
@@ -118,6 +107,9 @@ function () {
this.controlShowLock = true;
// Refactor: separate UI state in object. No code duplication.
+ // REFACTOR:
+ // 1.) Chain jQuery calls.
+ // 2.) Drop out common code.
if (this.controlState === 'invisible') {
this.videoControl.el.show();
this.controlState = 'visible';
@@ -156,6 +148,7 @@ function () {
}
function play() {
+ // REFACTOR: this.videoControl.playPauseState should be bool.
this.videoControl.playPauseEl.removeClass('play').addClass('pause').attr('title', 'Pause');
this.videoControl.playPauseState = 'playing';
}
@@ -181,17 +174,18 @@ function () {
if (this.videoControl.fullScreenState) {
this.videoControl.fullScreenState = false;
this.el.removeClass('fullscreen');
- this.videoControl.fullScreenEl.attr('title', 'Fill browser');
+ this.videoControl.fullScreenEl.attr('title', 'Fullscreen');
} else {
this.videoControl.fullScreenState = true;
this.el.addClass('fullscreen');
- this.videoControl.fullScreenEl.attr('title', 'Exit fill browser');
+ this.videoControl.fullScreenEl.attr('title', 'Exit fullscreen');
}
this.trigger(['videoCaption', 'resize'], null);
}
function exitFullScreen(event) {
+ // REFACTOR: Add variable instead of class.
if ((this.el.hasClass('fullscreen')) && (event.keyCode === 27)) {
this.videoControl.toggleFullScreen(event);
}
diff --git a/common/lib/xmodule/xmodule/js/src/videoalpha/display/video_player.js b/common/lib/xmodule/xmodule/js/src/videoalpha/display/video_player.js
index daf0e8728b..f14769e0b4 100644
--- a/common/lib/xmodule/xmodule/js/src/videoalpha/display/video_player.js
+++ b/common/lib/xmodule/xmodule/js/src/videoalpha/display/video_player.js
@@ -249,6 +249,8 @@ function (HTML5Video) {
function onReady() {
var availablePlaybackRates, baseSpeedSubs, _this;
+
+ // REFACTOR: Check if logic.
availablePlaybackRates = this.videoPlayer.player.getAvailablePlaybackRates();
if ((this.currentPlayerMode === 'html5') && (this.videoType === 'youtube')) {
diff --git a/common/lib/xmodule/xmodule/js/src/videoalpha/display/video_progress_slider.js b/common/lib/xmodule/xmodule/js/src/videoalpha/display/video_progress_slider.js
index d2d9af953b..612beb9abf 100644
--- a/common/lib/xmodule/xmodule/js/src/videoalpha/display/video_progress_slider.js
+++ b/common/lib/xmodule/xmodule/js/src/videoalpha/display/video_progress_slider.js
@@ -97,7 +97,6 @@ function () {
function onSlide(event, ui) {
this.videoProgressSlider.frozen = true;
this.videoProgressSlider.updateTooltip(ui.value);
-
this.trigger(['videoPlayer', 'onSeek'], ui.value);
}
@@ -106,9 +105,7 @@ function () {
}
function onStop(event, ui) {
- var _this;
-
- _this = this;
+ var _this = this;
this.videoProgressSlider.frozen = true;
@@ -125,6 +122,7 @@ function () {
function updatePlayTime(params) {
if ((this.videoProgressSlider.slider) && (!this.videoProgressSlider.frozen)) {
+ // REFACTOR: Check if you can chain.
this.videoProgressSlider.slider.slider('option', 'max', params.duration);
this.videoProgressSlider.slider.slider('value', params.time);
}
diff --git a/common/lib/xmodule/xmodule/js/src/videoalpha/display/video_quality_control.js b/common/lib/xmodule/xmodule/js/src/videoalpha/display/video_quality_control.js
index 370e33ab0f..1d559e45cd 100644
--- a/common/lib/xmodule/xmodule/js/src/videoalpha/display/video_quality_control.js
+++ b/common/lib/xmodule/xmodule/js/src/videoalpha/display/video_quality_control.js
@@ -39,14 +39,12 @@ function () {
// 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.videoQualityControl.el = $(
- 'HD'
- );
- state.videoControl.secondaryControlsEl.append(state.videoQualityControl.el);
+ state.videoQualityControl.el = state.el.find('a.quality_control');
state.videoQualityControl.quality = null;
if (!onTouchBasedDevice()) {
+ // REFACTOR: Move qtip config to state.config
state.videoQualityControl.el.qtip({
'position': {
'my': 'top right',
@@ -72,6 +70,7 @@ function () {
function onQualityChange(value) {
this.videoQualityControl.quality = value;
+ // refactor: Move constants to state.config.
if ((value === 'hd720') || (value === 'hd1080') || (value === 'highres')) {
this.videoQualityControl.el.addClass('active');
} else {
@@ -86,6 +85,7 @@ function () {
_ref = this.videoQualityControl.quality;
+ // refactor: Move constants to state.config.
if ((_ref === 'hd720') || (_ref === 'hd1080') || (_ref === 'highres')) {
newQuality = 'large';
} else {
diff --git a/common/lib/xmodule/xmodule/js/src/videoalpha/display/video_speed_control.js b/common/lib/xmodule/xmodule/js/src/videoalpha/display/video_speed_control.js
index d9a79b2bc3..2c8d8ca9b7 100644
--- a/common/lib/xmodule/xmodule/js/src/videoalpha/display/video_speed_control.js
+++ b/common/lib/xmodule/xmodule/js/src/videoalpha/display/video_speed_control.js
@@ -37,27 +37,19 @@ function () {
function renderElements(state) {
state.videoSpeedControl.speeds = state.speeds;
- state.videoSpeedControl.el = $(
- ''
- );
+ state.videoSpeedControl.el = state.el.find('div.speeds');
state.videoSpeedControl.videoSpeedsEl = state.videoSpeedControl.el.find('.video_speeds');
state.videoControl.secondaryControlsEl.prepend(state.videoSpeedControl.el);
$.each(state.videoSpeedControl.speeds, function(index, speed) {
- var link;
-
- link = $('').attr({
+ // REFACTOR: Move all HTML into one function call.
+ var link = $('').attr({
'href': '#'
}).html('' + speed + 'x');
+ // REFACTOR: Use jQuery .data()
state.videoSpeedControl.videoSpeedsEl.prepend($('- ').attr('data-speed', speed).html(link));
});
@@ -76,6 +68,7 @@ function () {
$(this).toggleClass('open');
});
} else {
+ // REFACTOR: Chain.
state.videoSpeedControl.el.on('mouseenter', function() {
$(this).addClass('open');
});
@@ -98,6 +91,7 @@ function () {
// ***************************************************************
function setSpeed(speed) {
+ // REFACTOR: Use chaining.
this.videoSpeedControl.videoSpeedsEl.find('li').removeClass('active');
this.videoSpeedControl.videoSpeedsEl.find("li[data-speed='" + speed + "']").addClass('active');
this.videoSpeedControl.el.find('p.active').html('' + speed + 'x');
@@ -106,10 +100,12 @@ function () {
function changeVideoSpeed(event) {
event.preventDefault();
+ // REFACTOR: Cache parent el.
if (!$(event.target).parent().hasClass('active')) {
this.videoSpeedControl.currentSpeed = $(event.target).parent().data('speed');
this.videoSpeedControl.setSpeed(
+ // To meet the API expected format.
parseFloat(this.videoSpeedControl.currentSpeed).toFixed(2).replace(/\.00$/, '.0')
);
@@ -117,6 +113,7 @@ function () {
}
}
+ // REFACTOR.
function reRender(params /*newSpeeds, currentSpeed*/) {
var _this;
diff --git a/common/lib/xmodule/xmodule/js/src/videoalpha/display/video_volume_control.js b/common/lib/xmodule/xmodule/js/src/videoalpha/display/video_volume_control.js
index ed62b3c7b7..3d979a0d1a 100644
--- a/common/lib/xmodule/xmodule/js/src/videoalpha/display/video_volume_control.js
+++ b/common/lib/xmodule/xmodule/js/src/videoalpha/display/video_volume_control.js
@@ -34,14 +34,7 @@ function () {
// 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.videoVolumeControl.el = $(
- ''
- );
+ state.videoVolumeControl.el = state.el.find('div.volume');
state.videoVolumeControl.buttonEl = state.videoVolumeControl.el.find('a');
state.videoVolumeControl.volumeSliderEl = state.videoVolumeControl.el.find('.volume-slider');
@@ -51,6 +44,7 @@ function () {
// Figure out what the current volume is. Set it up so that muting/unmuting works correctly.
// If no information about volume level could be retrieved, then we will use the default
// 100 level (full volume).
+ // REFACTOR: Remove unnecessary checks.
state.videoVolumeControl.currentVolume = parseInt($.cookie('video_player_volume_level'), 10);
state.videoVolumeControl.previousVolume = 100;
if (
diff --git a/common/lib/xmodule/xmodule/js/src/videoalpha/main.js b/common/lib/xmodule/xmodule/js/src/videoalpha/main.js
index edd383250f..ac29e5f16d 100644
--- a/common/lib/xmodule/xmodule/js/src/videoalpha/main.js
+++ b/common/lib/xmodule/xmodule/js/src/videoalpha/main.js
@@ -1,5 +1,7 @@
(function (requirejs, require, define) {
+// REFACTOR. Build JS doc. Add docs on how to build docs.
+
// Main module.
require(
[
@@ -49,7 +51,10 @@ function (
VideoProgressSlider(state);
VideoVolumeControl(state);
VideoSpeedControl(state);
- VideoCaption(state);
+
+ if (state.config.show_captions) {
+ VideoCaption(state);
+ }
};
});
diff --git a/lms/envs/common.py b/lms/envs/common.py
index 6c64cf1d90..4f796d8534 100644
--- a/lms/envs/common.py
+++ b/lms/envs/common.py
@@ -35,7 +35,7 @@ from .discussionsettings import *
PLATFORM_NAME = "edX"
COURSEWARE_ENABLED = True
-ENABLE_JASMINE = False
+ENABLE_JASMINE = True
PERFSTATS = False
diff --git a/lms/templates/videoalpha.html b/lms/templates/videoalpha.html
index f6ed6bfd27..2af0896fdf 100644
--- a/lms/templates/videoalpha.html
+++ b/lms/templates/videoalpha.html
@@ -34,8 +34,42 @@
-
+
+
+ % if show_captions == 'true':
+
+ % endif
+