Commit 869d0922 by Valera Rozuvan

Merge pull request #771 from edx/valera/fix_empty_captions_panel_no_captions

Valera/fix empty captions panel no captions
parents 3194e544 0a110b67
...@@ -53,7 +53,8 @@ ...@@ -53,7 +53,8 @@
expect($.ajaxWithPrefix).toHaveBeenCalledWith({ expect($.ajaxWithPrefix).toHaveBeenCalledWith({
url: videoCaption.captionURL(), url: videoCaption.captionURL(),
notifyOnError: false, notifyOnError: false,
success: jasmine.any(Function) success: jasmine.any(Function),
error: jasmine.any(Function),
}); });
}); });
}); });
...@@ -126,6 +127,22 @@ ...@@ -126,6 +127,22 @@
expect(videoCaption.rendered).toBeFalsy(); expect(videoCaption.rendered).toBeFalsy();
}); });
}); });
describe('when no captions file was specified', function () {
beforeEach(function () {
loadFixtures('video_all.html');
// Unspecify the captions file.
$('#example').find('#video_id').data('sub', '');
state = new Video('#example');
videoCaption = state.videoCaption;
});
it('captions panel is not shown', function () {
expect(videoCaption.hideSubtitlesEl).toBeHidden();
});
});
}); });
describe('mouse movement', function() { describe('mouse movement', function() {
...@@ -446,7 +463,7 @@ ...@@ -446,7 +463,7 @@
}); });
// Temporarily disabled due to intermittent failures // Temporarily disabled due to intermittent failures
// Fails with error: "InvalidStateError: An attempt was made to // Fails with error: "InvalidStateError: An attempt was made to
// use an object that is not, or is no longer, usable // use an object that is not, or is no longer, usable
// Expected 0 to equal 14.91." // Expected 0 to equal 14.91."
// on Firefox // on Firefox
......
...@@ -25,7 +25,9 @@ function (VideoPlayer) { ...@@ -25,7 +25,9 @@ function (VideoPlayer) {
* *
* Initialize module exports this function. * Initialize module exports this function.
* *
* @param {Object} state A place for all properties, and methods of Video. * @param {object} state The object containg the state of the video player.
* All other modules, their parameters, public variables, etc. are
* available via this object.
* @param {DOM element} element Container of the entire Video DOM element. * @param {DOM element} element Container of the entire Video DOM element.
*/ */
return function (state, element) { return function (state, element) {
...@@ -40,10 +42,12 @@ function (VideoPlayer) { ...@@ -40,10 +42,12 @@ function (VideoPlayer) {
/** /**
* @function _makeFunctionsPublic * @function _makeFunctionsPublic
* *
* Functions which will be accessible via 'state' object. When called, these functions will get the 'state' * Functions which will be accessible via 'state' object. When called,
* these functions will get the 'state'
* object as a context. * object as a context.
* *
* @param {Object} state A place for all properties, and methods of Video. * @param {object} state The object containg the state (properties,
* methods, modules) of the Video player.
*/ */
function _makeFunctionsPublic(state) { function _makeFunctionsPublic(state) {
state.setSpeed = _.bind(setSpeed, state); state.setSpeed = _.bind(setSpeed, state);
......
...@@ -6,13 +6,26 @@ define( ...@@ -6,13 +6,26 @@ define(
[], [],
function () { function () {
// VideoCaption() function - what this module "exports". /**
* @desc VideoCaption module exports a function.
*
* @type {function}
* @access public
*
* @param {object} state - The object containg the state of the video
* player. All other modules, their parameters, public variables, etc.
* are available via this object.
*
* @this {object} The global window object.
*
* @returns {undefined}
*/
return function (state) { return function (state) {
state.videoCaption = {}; state.videoCaption = {};
_makeFunctionsPublic(state); _makeFunctionsPublic(state);
state.videoCaption.renderElements(); state.videoCaption.renderElements();
state.videoCaption.bindHandlers();
}; };
// *************************************************************** // ***************************************************************
...@@ -57,28 +70,34 @@ function () { ...@@ -57,28 +70,34 @@ function () {
// The magic private function that makes them available and sets up their context is makeFunctionsPublic(). // The magic private function that makes them available and sets up their context is makeFunctionsPublic().
// *************************************************************** // ***************************************************************
// function renderElements() /**
// * @desc Create any necessary DOM elements, attach them, and set their
// Create any necessary DOM elements, attach them, and set their initial configuration. Also * initial configuration. Also make the created DOM elements available
// make the created DOM elements available via the 'state' object. Much easier to work this * via the 'state' object. Much easier to work this way - you don't
// way - you don't have to do repeated jQuery element selects. * have to do repeated jQuery element selects.
*
* @type {function}
* @access public
*
* @this {object} - The object containg the state of the video
* player. All other modules, their parameters, public variables, etc.
* are available via this object.
*
* @returns {boolean}
* true: The function fethched captions successfully, and compltely
* rendered everything related to captions.
* false: The captions were not fetched. Nothing will be rendered,
* and the CC button will be hidden.
*/
function renderElements() { function renderElements() {
this.videoCaption.loaded = false; this.videoCaption.loaded = false;
this.videoCaption.subtitlesEl = this.el.find('ol.subtitles'); this.videoCaption.subtitlesEl = this.el.find('ol.subtitles');
this.videoCaption.hideSubtitlesEl = this.el.find('a.hide-subtitles'); this.videoCaption.hideSubtitlesEl = this.el.find('a.hide-subtitles');
this.el.find('.video-wrapper').after(this.videoCaption.subtitlesEl); if (!this.videoCaption.fetchCaption()) {
this.el.find('.video-controls .secondary-controls').append(this.videoCaption.hideSubtitlesEl); this.videoCaption.hideCaptions(true);
this.videoCaption.hideSubtitlesEl.hide();
this.videoCaption.fetchCaption();
this.videoCaption.setSubtitlesHeight();
if (this.videoType === 'html5') {
this.videoCaption.fadeOutTimeout = this.config.fadeOutTimeout;
this.videoCaption.subtitlesEl.addClass('html5');
this.captionHideTimeout = setTimeout(this.videoCaption.autoHideCaptions, this.videoCaption.fadeOutTimeout);
} }
} }
...@@ -118,32 +137,69 @@ function () { ...@@ -118,32 +137,69 @@ function () {
} }
} }
/**
* @desc Fetch the caption file specified by the user. Upn successful
* receival of the file, the captions will be rendered.
*
* @type {function}
* @access public
*
* @this {object} - The object containg the state of the video
* player. All other modules, their parameters, public variables, etc.
* are available via this object.
*
* @returns {boolean}
* true: The user specified a caption file. NOTE: if an error happens
* while the specified file is being retrieved (for example the
* file is missing on the server), this function will still return
* true.
* false: No caption file was specified, or an empty string was
* specified.
*/
function fetchCaption() { function fetchCaption() {
var _this = this; var _this = this;
this.videoCaption.hideCaptions(this.hide_captions); // Check whether the captions file was specified. This is the point
// where we either stop with the caption panel (so that a white empty
// panel to the right of the video will not be shown), or carry on
// further.
if (!this.youtubeId('1.0')) { if (!this.youtubeId('1.0')) {
return; return false;
} }
// Fetch the captions file. If no file was specified, or if an error
// occurred, then we hide the captions panel, and the "CC" button
$.ajaxWithPrefix({ $.ajaxWithPrefix({
url: _this.videoCaption.captionURL(), url: _this.videoCaption.captionURL(),
notifyOnError: false, notifyOnError: false,
success: function(captions) { success: function (captions) {
_this.videoCaption.captions = captions.text; _this.videoCaption.captions = captions.text;
_this.videoCaption.start = captions.start; _this.videoCaption.start = captions.start;
_this.videoCaption.loaded = true; _this.videoCaption.loaded = true;
if (onTouchBasedDevice()) { if (onTouchBasedDevice()) {
_this.videoCaption.subtitlesEl.find('li').html( _this.videoCaption.subtitlesEl.find('li').html(
gettext('Caption will be displayed when you start playing the video.') gettext(
'Caption will be displayed when ' +
'you start playing the video.'
)
); );
} else { } else {
_this.videoCaption.renderCaption(); _this.videoCaption.renderCaption();
} }
},
error: function (jqXHR, textStatus, errorThrown) {
console.log('ERROR while fetching captions.');
console.log(
'STATUS:', textStatus + ', MESSAGE:', '' + errorThrown
);
_this.videoCaption.hideCaptions(true);
_this.videoCaption.hideSubtitlesEl.hide();
} }
}); });
return true;
} }
function captionURL() { function captionURL() {
...@@ -227,9 +283,24 @@ function () { ...@@ -227,9 +283,24 @@ function () {
} }
function renderCaption() { function renderCaption() {
var container, var container = $('<ol>'),
_this = this; _this = this;
container = $('<ol>');
this.el.find('.video-wrapper').after(this.videoCaption.subtitlesEl);
this.el.find('.video-controls .secondary-controls').append(this.videoCaption.hideSubtitlesEl);
this.videoCaption.setSubtitlesHeight();
if (this.videoType === 'html5') {
this.videoCaption.fadeOutTimeout = this.config.fadeOutTimeout;
this.videoCaption.subtitlesEl.addClass('html5');
this.captionHideTimeout = setTimeout(this.videoCaption.autoHideCaptions, this.videoCaption.fadeOutTimeout);
}
this.videoCaption.hideCaptions(this.hide_captions);
this.videoCaption.bindHandlers();
$.each(this.videoCaption.captions, function(index, text) { $.each(this.videoCaption.captions, function(index, text) {
var liEl = $('<li>'); var liEl = $('<li>');
......
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