Commit aefb1aa9 by Anton Stupak Committed by Alexander Kryklia

Hides Error notification when subtitle file is missing

Refactors bind and indexOf.
Adds error message when specify the wrong selector.
Adds some of the requested documentation.
Refactors 01_initialize.js.
Fixes to 03_video_player.js
parent 7d215e12
......@@ -10,7 +10,7 @@ window.YT =
window.STATUS = window.YT.PlayerState
oldGetWithPrefix = window.jQuery.getWithPrefix
oldAjaxWithPrefix = window.jQuery.ajaxWithPrefix
jasmine.stubbedCaption =
end: [3120, 6270, 8490, 21620, 24920, 25750, 27900, 34380, 35550, 40250]
......@@ -28,8 +28,9 @@ jasmine.stubbedCaption =
"And some will have quite a bit of energy, just for a moment."
]
# For our purposes, we need to make sure that the function $.getWithPrefix doe not fail
# when during tests a captions file is requested. It is originally defined in
# For our purposes, we need to make sure that the function $.ajaxWithPrefix
# does not fail when during tests a captions file is requested.
# It is originally defined in
#
# common/static/coffee/src/ajax_prefix.js
#
......@@ -37,14 +38,21 @@ jasmine.stubbedCaption =
#
# 1.) Return a hard coded captions object if the file name contains 'test_name_of_the_subtitles'.
# 2.) Behaves the same a as the origianl in all other cases.
window.jQuery.getWithPrefix = (url, data, callback, type) ->
window.jQuery.ajaxWithPrefix = (url, settings) ->
if not settings
settings = url
url = settings.url
success = settings.success
data = settings.data
if url.match(/test_name_of_the_subtitles/g) isnt null or url.match(/slowerSpeedYoutubeId/g) isnt null or url.match(/normalSpeedYoutubeId/g) isnt null
if window.jQuery.isFunction(callback) is true
callback jasmine.stubbedCaption
if window.jQuery.isFunction(success) is true
success jasmine.stubbedCaption
else if window.jQuery.isFunction(data) is true
data jasmine.stubbedCaption
else
oldGetWithPrefix.apply this, arguments
oldAjaxWithPrefix.apply @, arguments
# Time waitsFor() should wait for before failing a test.
window.WAIT_TIMEOUT = 1000
......
......@@ -27,7 +27,7 @@
describe('constructor', function() {
describe('always', function() {
beforeEach(function() {
spyOn($, 'getWithPrefix').andCallThrough();
spyOn($, 'ajaxWithPrefix').andCallThrough();
initialize();
});
......@@ -49,7 +49,11 @@
}, 'Expect captions to be loaded.', 1000);
runs(function () {
expect($.getWithPrefix).toHaveBeenCalledWith(videoCaption.captionURL(), jasmine.any(Function));
expect($.ajaxWithPrefix).toHaveBeenCalledWith({
url: videoCaption.captionURL(),
notifyOnError: false,
success: jasmine.any(Function)
});
});
});
......
......@@ -2,3 +2,7 @@
# For each of the xmodules subdirectories, add a .gitignore file that
# will version any *.js file that is specifically written, not compiled.
*.js
# Videoalpha are written in pure JavaScript.
!videoalpha/*.js
\ No newline at end of file
// IE browser supports Function.bind() only starting with version 9.
//
// 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
// it.
//
// https://developer.mozilla.org/en-US/docs/JavaScript/Reference/Global_Objects/Function/bind
if (!Function.prototype.bind) {
Function.prototype.bind = function (oThis) {
var aArgs, fToBind, fNOP, fBound;
if (typeof this !== 'function') {
// closest thing possible to the ECMAScript 5 internal IsCallable function
throw new TypeError('Function.prototype.bind - what is trying to be bound is not callable');
}
aArgs = Array.prototype.slice.call(arguments, 1);
fToBind = this;
fNOP = function () {};
fBound = function () {
return fToBind.apply(
this instanceof fNOP && oThis ? this : oThis,
aArgs.concat(Array.prototype.slice.call(arguments))
);
};
fNOP.prototype = this.prototype;
fBound.prototype = new fNOP();
return fBound;
};
}
// IE browser supports Array.indexOf() only starting with version 9.
//
// indexOf is a recent addition to the ECMA-262 standard; as such it may not be present in all browsers. You can work
// around this by utilizing the following code at the beginning of your scripts. This will allow you to use indexOf
// when there is still no native support. This algorithm matches the one specified in ECMA-262, 5th edition, assuming
// Object, TypeError, Number, Math.floor, Math.abs, and Math.max have their original values.
//
// https://developer.mozilla.org/en-US/docs/JavaScript/Reference/Global_Objects/Array/indexOf
if (!Array.prototype.indexOf) {
Array.prototype.indexOf = function (searchElement /*, fromIndex */ ) {
'use strict';
if (this == null) {
throw new TypeError();
}
var t = Object(this);
var len = t.length >>> 0;
if (len === 0) {
return -1;
}
var n = 0;
if (arguments.length > 1) {
n = Number(arguments[1]);
if (n != n) { // shortcut for verifying if it's NaN
n = 0;
} else if (n != 0 && n != Infinity && n != -Infinity) {
n = (n > 0 || -1) * Math.floor(Math.abs(n));
}
}
if (n >= len) {
return -1;
}
var k = n >= 0 ? n : Math.max(len - Math.abs(n), 0);
for (; k < len; k++) {
if (k in t && t[k] === searchElement) {
return k;
}
}
return -1;
}
}
if (!window.onTouchBasedDevice) {
window.onTouchBasedDevice = function() {
return navigator.userAgent.match(/iPhone|iPod|iPad/i);
};
}
......@@ -12,8 +12,8 @@
(function (requirejs, require, define) {
define(
'videoalpha/02_initialize.js',
['videoalpha/04_video_player.js'],
'videoalpha/01_initialize.js',
['videoalpha/03_video_player.js'],
function (VideoPlayer) {
/**
......@@ -25,70 +25,66 @@ function (VideoPlayer) {
* @param {DOM element} element Container of the entire Video Alpha DOM element.
*/
return function (state, element) {
makeFunctionsPublic(state);
state.renderElements(element);
_makeFunctionsPublic(state);
_initialize(state, element);
_renderElements(state);
};
// ***************************************************************
// Private functions start here.
// Private functions start here. Private functions start with underscore.
// ***************************************************************
/**
* @function makeFunctionsPublic
* @function _makeFunctionsPublic
*
* Functions which will be accessible via 'state' object. When called, these functions will get the 'state'
* object as a context.
*
* @param {Object} state A place for all properties, and methods of Video Alpha.
*/
function makeFunctionsPublic(state) {
state.setSpeed = setSpeed.bind(state);
state.youtubeId = youtubeId.bind(state);
state.getDuration = getDuration.bind(state);
state.trigger = trigger.bind(state);
function _makeFunctionsPublic(state) {
state.setSpeed = _.bind(setSpeed, state);
state.youtubeId = _.bind(youtubeId, state);
state.getDuration = _.bind(getDuration, state);
state.trigger = _.bind(trigger, state);
// Old private functions. Now also public so that can be
// tested by Jasmine.
state.renderElements = renderElements.bind(state);
state.parseSpeed = parseSpeed.bind(state);
state.fetchMetadata = fetchMetadata.bind(state);
state.parseYoutubeStreams = parseYoutubeStreams.bind(state);
state.parseVideoSources = parseVideoSources.bind(state);
state.parseSpeed = _.bind(parseSpeed, state);
state.fetchMetadata = _.bind(fetchMetadata, state);
state.parseYoutubeStreams = _.bind(parseYoutubeStreams, state);
state.parseVideoSources = _.bind(parseVideoSources, state);
}
// function renderElements(state)
//
// Create any necessary DOM elements, attach them, and set their initial configuration. Also
// make the created DOM elements available via the 'state' object. Much easier to work this
// way - you don't have to do repeated jQuery element selects.
function renderElements(element) {
var onPlayerReadyFunc,
_this = this;
// function _initialize(element)
// The function set initial configuration and preparation.
function _initialize(state, element) {
// This is used in places where we instead would have to check if an element has a CSS class 'fullscreen'.
this.isFullScreen = false;
state.isFullScreen = false;
// The parent element of the video, and the ID.
this.el = $(element).find('.videoalpha');
this.id = this.el.attr('id').replace(/video_/, '');
state.el = $(element).find('.videoalpha');
state.id = state.el.attr('id').replace(/video_/, '');
// 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.
this.config = {
state.config = {
element: element,
start: this.el.data('start'),
end: this.el.data('end'),
start: state.el.data('start'),
end: state.el.data('end'),
caption_data_dir: this.el.data('caption-data-dir'),
caption_asset_path: this.el.data('caption-asset-path'),
show_captions: (this.el.data('show-captions').toString().toLowerCase() === 'true'),
youtubeStreams: this.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: this.el.data('sub'),
mp4Source: this.el.data('mp4-source'),
webmSource: this.el.data('webm-source'),
oggSource: this.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'),
fadeOutTimeout: 1400,
......@@ -101,111 +97,147 @@ function (VideoPlayer) {
}
},
inCms: this.el.data('in-studio')
inCms: state.el.data('in-studio')
};
// Try to parse YouTube stream ID's. If
if (this.parseYoutubeStreams(this.config.youtubeStreams)) {
this.videoType = 'youtube';
this.fetchMetadata();
this.parseSpeed();
if (!(_parseYouTubeIDs(state))) {
// If we do not have YouTube ID's, try parsing HTML5 video sources.
_prepareHTML5Video(state);
}
// If we do not have YouTube ID's, try parsing HTML5 video sources.
else {
this.videoType = 'html5';
_configureCaptions(state);
_setPlayerMode(state);
this.parseVideoSources(
{
mp4: this.config.mp4Source,
webm: this.config.webmSource,
ogg: this.config.oggSource
// Possible value are: 'visible', 'hiding', and 'invisible'.
state.controlState = 'visible';
state.controlHideTimeout = null;
state.captionState = 'visible';
state.captionHideTimeout = null;
}
);
if (!this.config.sub || !this.config.sub.length) {
this.config.sub = '';
this.config.show_captions = false;
// function _renderElements(state)
//
// Create any necessary DOM elements, attach them, and set their initial configuration. Also
// make the created DOM elements available via the 'state' object. Much easier to work this
// way - you don't have to do repeated jQuery element selects.
function _renderElements(state) {
// Launch embedding of actual video content, or set it up so that it will be done as soon as the
// appropriate video player (YouTube or stand alone HTML5) is loaded, and can handle embedding.
//
// Note that the loading of stand alone HTML5 player API is handled by Require JS. At the time
// when we reach this code, the stand alone HTML5 player is already loaded, so no further testing
// in that case is required.
var onPlayerReadyFunc;
if (
((state.videoType === 'youtube') && (window.YT) && (window.YT.Player)) ||
(state.videoType === 'html5')
) {
VideoPlayer(state);
} else {
onPlayerReadyFunc = (this.videoType === 'youtube') ? 'onYouTubePlayerAPIReady' : 'onHTML5PlayerAPIReady';
window[onPlayerReadyFunc] = _.bind(window.VideoPlayer, state);
}
this.speeds = ['0.75', '1.0', '1.25', '1.50'];
this.videos = {
'0.75': this.config.sub,
'1.0': this.config.sub,
'1.25': this.config.sub,
'1.5': this.config.sub
};
this.setSpeed($.cookie('video_speed'));
}
// function _configureCaptions(state)
// Configure displaying of captions.
//
// Option
//
// this.config.show_captions = true | false
//
// defines whether to turn off/on the captions altogether. User will not have the ability to turn them on/off.
//
// Option
//
// this.hide_captions = true | false
//
// represents the user's choice of having the subtitles shown or hidden. This choice is stored in cookies.
if (this.config.show_captions) {
this.hide_captions = ($.cookie('hide_captions') === 'true');
function _configureCaptions(state) {
if (state.config.show_captions) {
state.hide_captions = ($.cookie('hide_captions') === 'true');
} else {
this.hide_captions = true;
state.hide_captions = true;
$.cookie('hide_captions', this.hide_captions, {
$.cookie('hide_captions', state.hide_captions, {
expires: 3650,
path: '/'
});
this.el.addClass('closed');
state.el.addClass('closed');
}
}
// function _setPlayerMode(state)
// By default we will be forcing HTML5 player mode. Only in the case when, after initializtion, we will
// get one available playback rate, we will change to Flash player mode. There is a need to store this
// setting in cookies because otherwise we will have to change from HTML5 to Flash on every page load
// 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 _setPlayerMode(state) {
(function (currentPlayerMode) {
if ((currentPlayerMode === 'html5') || (currentPlayerMode === 'flash')) {
_this.currentPlayerMode = currentPlayerMode;
state.currentPlayerMode = currentPlayerMode;
} else {
$.cookie('current_player_mode', 'html5', {
expires: 3650,
path: '/'
});
_this.currentPlayerMode = 'html5';
state.currentPlayerMode = 'html5';
}
}($.cookie('current_player_mode')));
}
// Possible value are: 'visible', 'hiding', and 'invisible'.
this.controlState = 'visible';
this.controlHideTimeout = null;
this.captionState = 'visible';
this.captionHideTimeout = null;
// function _parseYouTubeIDs(state)
// The function parse YouTube stream ID's.
// @return
// false: We don't have YouTube video IDs to work with; most likely we have HTML5 video sources.
// true: Parsing of YouTube video IDs went OK, and we can proceed onwards to play YouTube videos.
function _parseYouTubeIDs(state) {
if (state.parseYoutubeStreams(state.config.youtubeStreams)) {
state.videoType = 'youtube';
// Launch embedding of actual video content, or set it up so that it will be done as soon as the
// appropriate video player (YouTube or stand alone HTML5) is loaded, and can handle embedding.
//
// Note that the loading of stand alone HTML5 player API is handled by Require JS. At the time
// when we reach this code, the stand alone HTML5 player is already loaded, so no further testing
// in that case is required.
if (
((this.videoType === 'youtube') && (window.YT) && (window.YT.Player)) ||
(this.videoType === 'html5')
) {
VideoPlayer(this);
} else {
onPlayerReadyFunc = (this.videoType === 'youtube') ? 'onYouTubePlayerAPIReady' : 'onHTML5PlayerAPIReady';
window[onPlayerReadyFunc] = VideoPlayer.bind(window, this);
state.fetchMetadata();
state.parseSpeed();
return true;
}
return false;
}
// function _prepareHTML5Video(state)
// The function prepare HTML5 video, parse HTML5
// video sources etc.
function _prepareHTML5Video(state) {
state.videoType = 'html5';
state.parseVideoSources(
{
mp4: state.config.mp4Source,
webm: state.config.webmSource,
ogg: state.config.oggSource
}
);
if (!state.config.sub || !state.config.sub.length) {
state.config.sub = '';
state.config.show_captions = false;
}
state.speeds = ['0.75', '1.0', '1.25', '1.50'];
state.videos = {
'0.75': state.config.sub,
'1.0': state.config.sub,
'1.25': state.config.sub,
'1.5': state.config.sub
};
state.setSpeed($.cookie('video_speed'));
}
// ***************************************************************
// Public functions start here.
// These are available via the 'state' object. Their context ('this' keyword) is the 'state' object.
// The magic private function that makes them available and sets up their context is makeFunctionsPublic().
// ***************************************************************
// function parseYoutubeStreams(state, youtubeStreams)
//
// Take a string in the form:
......@@ -286,14 +318,8 @@ function (VideoPlayer) {
this.setSpeed($.cookie('video_speed'));
}
// ***************************************************************
// Public functions start here.
// These are available via the 'state' object. Their context ('this' keyword) is the 'state' object.
// The magic private function that makes them available and sets up their context is makeFunctionsPublic().
// ***************************************************************
function setSpeed(newSpeed, updateCookie) {
if (this.speeds.indexOf(newSpeed) !== -1) {
if (_.indexOf(this.speeds, newSpeed) !== -1) {
this.speed = newSpeed;
} else {
this.speed = '1.0';
......@@ -315,7 +341,7 @@ function (VideoPlayer) {
return this.metadata[this.youtubeId()].duration;
}
/* he function .trigger() expects the parameter @callType one of
/* The function .trigger() expects the parameter @callType one of
*
* 'event'
* 'method'
......
......@@ -14,7 +14,7 @@
(function (requirejs, require, define) {
define(
'videoalpha/03_html5_video.js',
'videoalpha/02_html5_video.js',
[],
function () {
var HTML5Video = {};
......@@ -128,7 +128,7 @@ function () {
* }
*/
function Player(el, config) {
var sourceStr, _this;
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,
......@@ -139,6 +139,12 @@ function () {
this.el = $('#' + el);
if (this.el.length === 0) {
errorMessage = 'VideoPlayer: Element corresponding to the given selector does not found.';
if (window.console && console.log) {
console.log(errorMessage);
} else {
throw new Error(errorMessage);
}
return;
}
}
......
......@@ -2,8 +2,8 @@
// VideoPlayer module.
define(
'videoalpha/04_video_player.js',
['videoalpha/03_html5_video.js'],
'videoalpha/03_video_player.js',
['videoalpha/02_html5_video.js'],
function (HTML5Video) {
// VideoPlayer() function - what this module "exports".
......@@ -12,7 +12,7 @@ function (HTML5Video) {
makeFunctionsPublic(state);
renderElements(state);
bindHandlers();
// No callbacks to DOM events (click, mousemove, etc.).
};
// ***************************************************************
......@@ -24,25 +24,25 @@ function (HTML5Video) {
// Functions which will be accessible via 'state' object. When called, these functions will
// get the 'state' object as a context.
function makeFunctionsPublic(state) {
state.videoPlayer.pause = pause.bind(state);
state.videoPlayer.play = play.bind(state);
state.videoPlayer.update = update.bind(state);
state.videoPlayer.onSpeedChange = onSpeedChange.bind(state);
state.videoPlayer.onCaptionSeek = onSeek.bind(state);
state.videoPlayer.onSlideSeek = onSeek.bind(state);
state.videoPlayer.onEnded = onEnded.bind(state);
state.videoPlayer.onPause = onPause.bind(state);
state.videoPlayer.onPlay = onPlay.bind(state);
state.videoPlayer.onUnstarted = onUnstarted.bind(state);
state.videoPlayer.handlePlaybackQualityChange = handlePlaybackQualityChange.bind(state);
state.videoPlayer.onPlaybackQualityChange = onPlaybackQualityChange.bind(state);
state.videoPlayer.onStateChange = onStateChange.bind(state);
state.videoPlayer.onReady = onReady.bind(state);
state.videoPlayer.updatePlayTime = updatePlayTime.bind(state);
state.videoPlayer.isPlaying = isPlaying.bind(state);
state.videoPlayer.log = log.bind(state);
state.videoPlayer.duration = duration.bind(state);
state.videoPlayer.onVolumeChange = onVolumeChange.bind(state);
state.videoPlayer.pause = _.bind(pause, state);
state.videoPlayer.play = _.bind(play, state);
state.videoPlayer.update = _.bind(update, state);
state.videoPlayer.onSpeedChange = _.bind(onSpeedChange, state);
state.videoPlayer.onCaptionSeek = _.bind(onSeek, state);
state.videoPlayer.onSlideSeek = _.bind(onSeek, state);
state.videoPlayer.onEnded = _.bind(onEnded, state);
state.videoPlayer.onPause = _.bind(onPause, state);
state.videoPlayer.onPlay = _.bind(onPlay, state);
state.videoPlayer.onUnstarted = _.bind(onUnstarted, state);
state.videoPlayer.handlePlaybackQualityChange = _.bind(handlePlaybackQualityChange, state);
state.videoPlayer.onPlaybackQualityChange = _.bind(onPlaybackQualityChange, state);
state.videoPlayer.onStateChange = _.bind(onStateChange, state);
state.videoPlayer.onReady = _.bind(onReady, state);
state.videoPlayer.updatePlayTime = _.bind(updatePlayTime, state);
state.videoPlayer.isPlaying = _.bind(isPlaying, state);
state.videoPlayer.log = _.bind(log, state);
state.videoPlayer.duration = _.bind(duration, state);
state.videoPlayer.onVolumeChange = _.bind(onVolumeChange, state);
}
// function renderElements(state)
......@@ -123,19 +123,12 @@ function (HTML5Video) {
}
}
// function bindHandlers(state)
//
// Bind any necessary function callbacks to DOM events (click, mousemove, etc.).
function bindHandlers() {
}
// function reinitAsFlash(state)
// function restartUsingFlash(state)
//
// When we are about to play a YouTube video in HTML5 mode and discover that we only
// have one available playback rate, we will switch to Flash mode. In Flash speed
// switching is done by reloading videos recorded at differtn frame rates.
function reinitAsFlash(state) {
// switching is done by reloading videos recorded at different frame rates.
function restartUsingFlash(state) {
// Remove from the page current iFrame with HTML5 video.
state.videoPlayer.player.destroy();
......@@ -149,7 +142,7 @@ function (HTML5Video) {
// Removed configuration option that requests the HTML5 mode.
delete state.videoPlayer.playerVars.html5;
// Reuqest for the creation of a new Flash player
// Request for the creation of a new Flash player
state.videoPlayer.player = new YT.Player(state.id, {
'playerVars': state.videoPlayer.playerVars,
'videoId': state.youtubeId(),
......@@ -179,6 +172,9 @@ function (HTML5Video) {
}
}
// This function gets the video's current play position in time
// (currentTime) and its duration.
// It is called at a regular interval when the video is playing (see below).
function update() {
this.videoPlayer.currentTime = this.videoPlayer.player.getCurrentTime();
......@@ -187,11 +183,6 @@ function (HTML5Video) {
}
}
// We request the reloading of the video in the case when YouTube is in
// Flash player mode, or when we are in Firefox, and the new speed is 1.0.
// The second case is necessary to avoid the bug where in Firefox speed
// switching to 1.0 in HTML5 player mode is handled incorrectly by YouTube
// API.
function onSpeedChange(newSpeed, updateCookie) {
if (this.currentPlayerMode === 'flash') {
this.videoPlayer.currentTime = Time.convert(
......@@ -218,7 +209,12 @@ function (HTML5Video) {
!(this.browserIsFirefox && newSpeed === '1.0' && this.videoType === 'youtube')
) {
this.videoPlayer.player.setPlaybackRate(newSpeed);
} else { // if (this.currentPlayerMode === 'flash') {
} else {
// We request the reloading of the video in the case when YouTube is in
// Flash player mode, or when we are in Firefox, and the new speed is 1.0.
// The second case is necessary to avoid the bug where in Firefox speed
// switching to 1.0 in HTML5 player mode is handled incorrectly by YouTube
// API.
if (this.videoPlayer.isPlaying()) {
this.videoPlayer.player.loadVideoById(this.youtubeId(), this.videoPlayer.currentTime);
} else {
......@@ -229,6 +225,10 @@ function (HTML5Video) {
}
}
// Every 200 ms, if the video is playing, we call the function update, via
// clearInterval. This interval is called updateInterval.
// It is created on a onPlay event. Cleared on a onPause event.
// Reinitialized on a onSeek event.
function onSeek(params) {
this.videoPlayer.log(
'seek_video',
......@@ -318,18 +318,24 @@ function (HTML5Video) {
availablePlaybackRates = this.videoPlayer.player.getAvailablePlaybackRates();
if ((this.currentPlayerMode === 'html5') && (this.videoType === 'youtube')) {
if (availablePlaybackRates.length === 1) {
reinitAsFlash(this);
restartUsingFlash(this);
return;
} else if (availablePlaybackRates.length > 1) {
// We need to synchronize available frame rates with the ones that the user specified.
// We need to synchronize available frame rates with the ones
// that the user specified.
baseSpeedSubs = this.videos['1.0'];
_this = this;
// this.videos is a dictionary containing various frame rates
// and their associated subs.
// First clear the dictionary.
$.each(this.videos, function(index, value) {
delete _this.videos[index];
});
this.speeds = [];
// Recreate it with the supplied frame rates.
$.each(availablePlaybackRates, function(index, value) {
_this.videos[value.toFixed(2).replace(/\.00$/, '.0')] = baseSpeedSubs;
......@@ -411,11 +417,9 @@ function (HTML5Video) {
if (this.videoType === 'youtube') {
logInfo.code = this.youtubeId();
} else {
if (this.videoType === 'html5') {
} else if (this.videoType === 'html5') {
logInfo.code = 'html5';
}
}
Logger.log(eventName, logInfo);
}
......
......@@ -2,7 +2,7 @@
// VideoControl module.
define(
'videoalpha/05_video_control.js',
'videoalpha/04_video_control.js',
[],
function () {
......@@ -24,14 +24,14 @@ function () {
// Functions which will be accessible via 'state' object. When called, these functions will
// get the 'state' object as a context.
function makeFunctionsPublic(state) {
state.videoControl.showControls = showControls.bind(state);
state.videoControl.hideControls = hideControls.bind(state);
state.videoControl.play = play.bind(state);
state.videoControl.pause = pause.bind(state);
state.videoControl.togglePlayback = togglePlayback.bind(state);
state.videoControl.toggleFullScreen = toggleFullScreen.bind(state);
state.videoControl.exitFullScreen = exitFullScreen.bind(state);
state.videoControl.updateVcrVidTime = updateVcrVidTime.bind(state);
state.videoControl.showControls = _.bind(showControls,state);
state.videoControl.hideControls = _.bind(hideControls,state);
state.videoControl.play = _.bind(play,state);
state.videoControl.pause = _.bind(pause,state);
state.videoControl.togglePlayback = _.bind(togglePlayback,state);
state.videoControl.toggleFullScreen = _.bind(toggleFullScreen,state);
state.videoControl.exitFullScreen = _.bind(exitFullScreen,state);
state.videoControl.updateVcrVidTime = _.bind(updateVcrVidTime,state);
}
// function renderElements(state)
......
......@@ -2,7 +2,7 @@
// VideoQualityControl module.
define(
'videoalpha/06_video_quality_control.js',
'videoalpha/05_video_quality_control.js',
[],
function () {
......@@ -29,8 +29,8 @@ function () {
// Functions which will be accessible via 'state' object. When called, these functions will
// get the 'state' object as a context.
function makeFunctionsPublic(state) {
state.videoQualityControl.onQualityChange = onQualityChange.bind(state);
state.videoQualityControl.toggleQuality = toggleQuality.bind(state);
state.videoQualityControl.onQualityChange = _.bind(onQualityChange, state);
state.videoQualityControl.toggleQuality = _.bind(toggleQuality, state);
}
// function renderElements(state)
......@@ -65,7 +65,7 @@ function () {
function onQualityChange(value) {
this.videoQualityControl.quality = value;
if (this.config.availableQualities.indexOf(value) !== -1) {
if (_.indexOf(this.config.availableQualities, value) !== -1) {
this.videoQualityControl.el.addClass('active');
} else {
this.videoQualityControl.el.removeClass('active');
......@@ -84,7 +84,7 @@ function () {
event.preventDefault();
if (this.config.availableQualities.indexOf(value) !== -1) {
if (_.indexOf(this.config.availableQualities, value) !== -1) {
newQuality = 'large';
} else {
newQuality = 'hd720';
......
......@@ -9,7 +9,7 @@ mind, or whether to act, and in acting, to live."
// VideoProgressSlider module.
define(
'videoalpha/07_video_progress_slider.js',
'videoalpha/06_video_progress_slider.js',
[],
function () {
......@@ -31,13 +31,13 @@ function () {
// Functions which will be accessible via 'state' object. When called, these functions will
// get the 'state' object as a context.
function makeFunctionsPublic(state) {
state.videoProgressSlider.onSlide = onSlide.bind(state);
state.videoProgressSlider.onChange = onChange.bind(state);
state.videoProgressSlider.onStop = onStop.bind(state);
state.videoProgressSlider.updateTooltip = updateTooltip.bind(state);
state.videoProgressSlider.updatePlayTime = updatePlayTime.bind(state);
state.videoProgressSlider.onSlide = _.bind(onSlide, state);
state.videoProgressSlider.onChange = _.bind(onChange, state);
state.videoProgressSlider.onStop = _.bind(onStop, state);
state.videoProgressSlider.updateTooltip = _.bind(updateTooltip, state);
state.videoProgressSlider.updatePlayTime = _.bind(updatePlayTime, state);
//Added for tests -- JM
state.videoProgressSlider.buildSlider = buildSlider.bind(state);
state.videoProgressSlider.buildSlider = _.bind(buildSlider, state);
}
// function renderElements(state)
......
......@@ -2,7 +2,7 @@
// VideoVolumeControl module.
define(
'videoalpha/08_video_volume_control.js',
'videoalpha/07_video_volume_control.js',
[],
function () {
......@@ -24,8 +24,8 @@ function () {
// Functions which will be accessible via 'state' object. When called, these functions will
// get the 'state' object as a context.
function makeFunctionsPublic(state) {
state.videoVolumeControl.onChange = onChange.bind(state);
state.videoVolumeControl.toggleMute = toggleMute.bind(state);
state.videoVolumeControl.onChange = _.bind(onChange, state);
state.videoVolumeControl.toggleMute = _.bind(toggleMute, state);
}
// function renderElements(state)
......
......@@ -2,7 +2,7 @@
// VideoSpeedControl module.
define(
'videoalpha/09_video_speed_control.js',
'videoalpha/08_video_speed_control.js',
[],
function () {
......@@ -24,9 +24,9 @@ function () {
// Functions which will be accessible via 'state' object. When called, these functions will
// get the 'state' object as a context.
function makeFunctionsPublic(state) {
state.videoSpeedControl.changeVideoSpeed = changeVideoSpeed.bind(state);
state.videoSpeedControl.setSpeed = setSpeed.bind(state);
state.videoSpeedControl.reRender = reRender.bind(state);
state.videoSpeedControl.changeVideoSpeed = _.bind(changeVideoSpeed, state);
state.videoSpeedControl.setSpeed = _.bind(setSpeed, state);
state.videoSpeedControl.reRender = _.bind(reRender, state);
}
// function renderElements(state)
......
......@@ -2,7 +2,7 @@
// VideoCaption module.
define(
'videoalpha/10_video_caption.js',
'videoalpha/09_video_caption.js',
[],
function () {
......@@ -24,30 +24,30 @@ function () {
// Functions which will be accessible via 'state' object. When called, these functions will
// get the 'state' object as a context.
function makeFunctionsPublic(state) {
state.videoCaption.autoShowCaptions = autoShowCaptions.bind(state);
state.videoCaption.autoHideCaptions = autoHideCaptions.bind(state);
state.videoCaption.resize = resize.bind(state);
state.videoCaption.toggle = toggle.bind(state);
state.videoCaption.onMouseEnter = onMouseEnter.bind(state);
state.videoCaption.onMouseLeave = onMouseLeave.bind(state);
state.videoCaption.onMovement = onMovement.bind(state);
state.videoCaption.renderCaption = renderCaption.bind(state);
state.videoCaption.captionHeight = captionHeight.bind(state);
state.videoCaption.topSpacingHeight = topSpacingHeight.bind(state);
state.videoCaption.bottomSpacingHeight = bottomSpacingHeight.bind(state);
state.videoCaption.scrollCaption = scrollCaption.bind(state);
state.videoCaption.search = search.bind(state);
state.videoCaption.play = play.bind(state);
state.videoCaption.pause = pause.bind(state);
state.videoCaption.seekPlayer = seekPlayer.bind(state);
state.videoCaption.hideCaptions = hideCaptions.bind(state);
state.videoCaption.calculateOffset = calculateOffset.bind(state);
state.videoCaption.updatePlayTime = updatePlayTime.bind(state);
state.videoCaption.renderElements = renderElements.bind(state);
state.videoCaption.bindHandlers = bindHandlers.bind(state);
state.videoCaption.fetchCaption = fetchCaption.bind(state);
state.videoCaption.captionURL = captionURL.bind(state);
state.videoCaption.autoShowCaptions = _.bind(autoShowCaptions, state);
state.videoCaption.autoHideCaptions = _.bind(autoHideCaptions, state);
state.videoCaption.resize = _.bind(resize, state);
state.videoCaption.toggle = _.bind(toggle, state);
state.videoCaption.onMouseEnter = _.bind(onMouseEnter, state);
state.videoCaption.onMouseLeave = _.bind(onMouseLeave, state);
state.videoCaption.onMovement = _.bind(onMovement, state);
state.videoCaption.renderCaption = _.bind(renderCaption, state);
state.videoCaption.captionHeight = _.bind(captionHeight, state);
state.videoCaption.topSpacingHeight = _.bind(topSpacingHeight, state);
state.videoCaption.bottomSpacingHeight = _.bind(bottomSpacingHeight, state);
state.videoCaption.scrollCaption = _.bind(scrollCaption, state);
state.videoCaption.search = _.bind(search, state);
state.videoCaption.play = _.bind(play, state);
state.videoCaption.pause = _.bind(pause, state);
state.videoCaption.seekPlayer = _.bind(seekPlayer, state);
state.videoCaption.hideCaptions = _.bind(hideCaptions, state);
state.videoCaption.calculateOffset = _.bind(calculateOffset, state);
state.videoCaption.updatePlayTime = _.bind(updatePlayTime, state);
state.videoCaption.renderElements = _.bind(renderElements, state);
state.videoCaption.bindHandlers = _.bind(bindHandlers, state);
state.videoCaption.fetchCaption = _.bind(fetchCaption, state);
state.videoCaption.captionURL = _.bind(captionURL, state);
}
// function renderElements()
......@@ -109,11 +109,14 @@ function () {
}
function fetchCaption() {
var _this = this, jQueryObject;
var _this = this;
this.videoCaption.hideCaptions(this.hide_captions);
jQueryObject = $.getWithPrefix(this.videoCaption.captionURL(), function(captions) {
$.ajaxWithPrefix({
url: _this.videoCaption.captionURL(),
notifyOnError: false,
success: function(captions) {
_this.videoCaption.captions = captions.text;
_this.videoCaption.start = captions.start;
_this.videoCaption.loaded = true;
......@@ -125,11 +128,8 @@ function () {
} else {
_this.videoCaption.renderCaption();
}
});
if (typeof jQueryObject === 'undefined') {
console.error('Subtitles not found. Upload subtitles to server!');
}
});
}
function captionURL() {
......
......@@ -3,13 +3,13 @@
// Main module.
require(
[
'videoalpha/02_initialize.js',
'videoalpha/05_video_control.js',
'videoalpha/06_video_quality_control.js',
'videoalpha/07_video_progress_slider.js',
'videoalpha/08_video_volume_control.js',
'videoalpha/09_video_speed_control.js',
'videoalpha/10_video_caption.js'
'videoalpha/01_initialize.js',
'videoalpha/04_video_control.js',
'videoalpha/05_video_quality_control.js',
'videoalpha/06_video_progress_slider.js',
'videoalpha/07_video_volume_control.js',
'videoalpha/08_video_speed_control.js',
'videoalpha/09_video_caption.js'
],
function (
Initialize,
......
......@@ -69,17 +69,16 @@ class VideoAlphaModule(VideoAlphaFields, XModule):
js = {
'js': [
resource_string(__name__, 'js/src/videoalpha/01_helper_utils.js'),
resource_string(__name__, 'js/src/videoalpha/02_initialize.js'),
resource_string(__name__, 'js/src/videoalpha/03_html5_video.js'),
resource_string(__name__, 'js/src/videoalpha/04_video_player.js'),
resource_string(__name__, 'js/src/videoalpha/05_video_control.js'),
resource_string(__name__, 'js/src/videoalpha/06_video_quality_control.js'),
resource_string(__name__, 'js/src/videoalpha/07_video_progress_slider.js'),
resource_string(__name__, 'js/src/videoalpha/08_video_volume_control.js'),
resource_string(__name__, 'js/src/videoalpha/09_video_speed_control.js'),
resource_string(__name__, 'js/src/videoalpha/10_video_caption.js'),
resource_string(__name__, 'js/src/videoalpha/11_main.js')
resource_string(__name__, 'js/src/videoalpha/01_initialize.js'),
resource_string(__name__, 'js/src/videoalpha/02_html5_video.js'),
resource_string(__name__, 'js/src/videoalpha/03_video_player.js'),
resource_string(__name__, 'js/src/videoalpha/04_video_control.js'),
resource_string(__name__, 'js/src/videoalpha/05_video_quality_control.js'),
resource_string(__name__, 'js/src/videoalpha/06_video_progress_slider.js'),
resource_string(__name__, 'js/src/videoalpha/07_video_volume_control.js'),
resource_string(__name__, 'js/src/videoalpha/08_video_speed_control.js'),
resource_string(__name__, 'js/src/videoalpha/09_video_caption.js'),
resource_string(__name__, 'js/src/videoalpha/10_main.js')
]
}
css = {'scss': [resource_string(__name__, 'css/videoalpha/display.scss')]}
......
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