Commit 7c59947a by Vasyl Nakvasiuk

refactoring JS -> HTML

second part of refactoring: JS -> Python HTML
Updated JS code to reflect the change that some HTML generation was moved to python side.
Fixed fullscreen bug - now controls are shown properly below the video. Made the transparency a bit more faded for captions in normal mode.
Fixed bug with captions. Now the attribute show_captions correctly removes them when set to true.
Work in progress.
parent 0e24ff14
......@@ -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;
......
......@@ -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,
......
......@@ -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
......
......@@ -53,10 +53,8 @@ function () {
function renderElements(state) {
state.videoCaption.loaded = false;
state.videoCaption.subtitlesEl = $('<ol class="subtitles"></ol>');
state.videoCaption.hideSubtitlesEl = $(
'<a href="#" class="hide-subtitles" title="Turn off captions">Captions</a>'
);
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 = $('<ol>');
$.each(this.videoCaption.captions, function(index, text) {
// REFACTOR: Use .data()
container.append($('<li>').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(
$('<li class="spacing">').height(this.videoCaption.topSpacingHeight())
).append(
)
.append(
$('<li class="spacing">').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 {
......
......@@ -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 = $(
'<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">' +
'<a href="#" class="add-fullscreen" title="Fill browser">Fill Browser</a>' +
'</div>' +
'</div>'
);
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);
}
......
......@@ -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')) {
......
......@@ -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);
}
......
......@@ -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 = $(
'<a href="#" class="quality_control" title="HD">HD</a>'
);
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 {
......
......@@ -37,27 +37,19 @@ function () {
function renderElements(state) {
state.videoSpeedControl.speeds = state.speeds;
state.videoSpeedControl.el = $(
'<div class="speeds">' +
'<a href="#">' +
'<h3>Speed</h3>' +
'<p class="active"></p>' +
'</a>' +
'<ol class="video_speeds"></ol>' +
'</div>'
);
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 = $('<a>').attr({
// REFACTOR: Move all HTML into one function call.
var link = $('<a>').attr({
'href': '#'
}).html('' + speed + 'x');
// REFACTOR: Use jQuery .data()
state.videoSpeedControl.videoSpeedsEl.prepend($('<li>').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;
......
......@@ -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 = $(
'<div class="volume">' +
'<a href="#"></a>' +
'<div class="volume-slider-container">' +
'<div class="volume-slider"></div>' +
'</div>' +
'</div>'
);
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 (
......
(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);
}
};
});
......
......@@ -35,7 +35,7 @@ from .discussionsettings import *
PLATFORM_NAME = "edX"
COURSEWARE_ENABLED = True
ENABLE_JASMINE = False
ENABLE_JASMINE = True
PERFSTATS = False
......
......@@ -34,8 +34,42 @@
<div id="${id}"></div>
</section>
<div class="video-player-post"></div>
<section class="video-controls"></section>
<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>
</div>
<a href="#" class="add-fullscreen" title="Fill browser">Fill Browser</a>
<a href="#" class="quality_control" title="HD">HD</a>
% if show_captions == 'true':
<a href="#" class="hide-subtitles" title="Turn off captions">Captions</a>
% endif
</div>
</div>
</section>
</article>
% if show_captions == 'true':
<ol class="subtitles"></ol>
% endif
</div>
</div>
......
Markdown is supported
0% or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment