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:
committed by
Alexander Kryklia
parent
7d215e12b7
commit
aefb1aa9c8
@@ -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)
|
||||
});
|
||||
});
|
||||
});
|
||||
|
||||
|
||||
4
common/lib/xmodule/xmodule/js/src/.gitignore
vendored
4
common/lib/xmodule/xmodule/js/src/.gitignore
vendored
@@ -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
|
||||
@@ -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);
|
||||
};
|
||||
}
|
||||
@@ -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'
|
||||
@@ -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,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);
|
||||
@@ -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.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() {
|
||||
@@ -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')]}
|
||||
|
||||
Reference in New Issue
Block a user