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
This commit is contained in:
Anton Stupak
2013-07-25 15:00:50 +03:00
committed by Alexander Kryklia
parent 7d215e12b7
commit aefb1aa9c8
15 changed files with 322 additions and 351 deletions

View File

@@ -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

View File

@@ -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)
});
});
});

View File

@@ -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

View File

@@ -1,80 +0,0 @@
// 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);
};
}

View File

@@ -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';
this.parseVideoSources(
{
mp4: this.config.mp4Source,
webm: this.config.webmSource,
ogg: this.config.oggSource
}
);
if (!this.config.sub || !this.config.sub.length) {
this.config.sub = '';
this.config.show_captions = false;
}
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'));
}
// 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');
} else {
this.hide_captions = true;
$.cookie('hide_captions', this.hide_captions, {
expires: 3650,
path: '/'
});
this.el.addClass('closed');
}
// 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 (currentPlayerMode) {
if ((currentPlayerMode === 'html5') || (currentPlayerMode === 'flash')) {
_this.currentPlayerMode = currentPlayerMode;
} else {
$.cookie('current_player_mode', 'html5', {
expires: 3650,
path: '/'
});
_this.currentPlayerMode = 'html5';
}
}($.cookie('current_player_mode')));
_configureCaptions(state);
_setPlayerMode(state);
// Possible value are: 'visible', 'hiding', and 'invisible'.
this.controlState = 'visible';
this.controlHideTimeout = null;
this.captionState = 'visible';
this.captionHideTimeout = null;
state.controlState = 'visible';
state.controlHideTimeout = null;
state.captionState = 'visible';
state.captionHideTimeout = null;
}
// 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 (
((this.videoType === 'youtube') && (window.YT) && (window.YT.Player)) ||
(this.videoType === 'html5')
((state.videoType === 'youtube') && (window.YT) && (window.YT.Player)) ||
(state.videoType === 'html5')
) {
VideoPlayer(this);
VideoPlayer(state);
} else {
onPlayerReadyFunc = (this.videoType === 'youtube') ? 'onYouTubePlayerAPIReady' : 'onHTML5PlayerAPIReady';
window[onPlayerReadyFunc] = VideoPlayer.bind(window, this);
window[onPlayerReadyFunc] = _.bind(window.VideoPlayer, state);
}
}
// 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.
function _configureCaptions(state) {
if (state.config.show_captions) {
state.hide_captions = ($.cookie('hide_captions') === 'true');
} else {
state.hide_captions = true;
$.cookie('hide_captions', state.hide_captions, {
expires: 3650,
path: '/'
});
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')) {
state.currentPlayerMode = currentPlayerMode;
} else {
$.cookie('current_player_mode', 'html5', {
expires: 3650,
path: '/'
});
state.currentPlayerMode = 'html5';
}
}($.cookie('current_player_mode')));
}
// 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';
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'

View File

@@ -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;
}
}

View File

@@ -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,10 +417,8 @@ 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);

View File

@@ -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)

View File

@@ -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';

View File

@@ -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)

View File

@@ -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)

View File

@@ -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)

View File

@@ -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.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 = renderElements.bind(state);
state.videoCaption.bindHandlers = bindHandlers.bind(state);
state.videoCaption.fetchCaption = fetchCaption.bind(state);
state.videoCaption.captionURL = captionURL.bind(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,27 +109,27 @@ function () {
}
function fetchCaption() {
var _this = this, jQueryObject;
var _this = this;
this.videoCaption.hideCaptions(this.hide_captions);
jQueryObject = $.getWithPrefix(this.videoCaption.captionURL(), function(captions) {
_this.videoCaption.captions = captions.text;
_this.videoCaption.start = captions.start;
_this.videoCaption.loaded = true;
$.ajaxWithPrefix({
url: _this.videoCaption.captionURL(),
notifyOnError: false,
success: function(captions) {
_this.videoCaption.captions = captions.text;
_this.videoCaption.start = captions.start;
_this.videoCaption.loaded = true;
if (onTouchBasedDevice()) {
_this.videoCaption.subtitlesEl.find('li').html(
'Caption will be displayed when you start playing the video.'
);
} else {
_this.videoCaption.renderCaption();
if (onTouchBasedDevice()) {
_this.videoCaption.subtitlesEl.find('li').html(
'Caption will be displayed when you start playing the video.'
);
} else {
_this.videoCaption.renderCaption();
}
}
});
if (typeof jQueryObject === 'undefined') {
console.error('Subtitles not found. Upload subtitles to server!');
}
}
function captionURL() {

View File

@@ -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,

View File

@@ -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')]}