From 009b8475dc802bf5df0a8e20d0c5be4e5df03de0 Mon Sep 17 00:00:00 2001 From: Valera Rozuvan Date: Fri, 15 Feb 2013 17:42:53 +0200 Subject: [PATCH] Tracing bug in Firefox whereby the HTML5 native video freezes. Turns out that setting currentTime property tiggers a canplay event. And this becomes cyclic because the callback for canplay event updates the currentTime property. Video alpha 2. Work in progress. --- .../js/src/videoalpha/display/initialize.js | 37 +- .../src/videoalpha/display/video_control.js | 145 ++++++ .../js/src/videoalpha/display/video_player.js | 440 +++++++++--------- .../xmodule/xmodule/js/src/videoalpha/main.js | 32 +- .../lib/xmodule/xmodule/videoalpha_module.py | 1 + 5 files changed, 433 insertions(+), 222 deletions(-) create mode 100644 common/lib/xmodule/xmodule/js/src/videoalpha/display/video_control.js diff --git a/common/lib/xmodule/xmodule/js/src/videoalpha/display/initialize.js b/common/lib/xmodule/xmodule/js/src/videoalpha/display/initialize.js index a87088d147..31a0736929 100644 --- a/common/lib/xmodule/xmodule/js/src/videoalpha/display/initialize.js +++ b/common/lib/xmodule/xmodule/js/src/videoalpha/display/initialize.js @@ -3,8 +3,8 @@ // Initialize module. define( 'videoalpha/display/initialize.js', -['videoalpha/display/bind.js'], -function (bind) { +['videoalpha/display/bind.js', 'videoalpha/display/video_player.js'], +function (bind, VideoPlayer) { // Initialize() function - what this module "exports". return function (state, element) { @@ -99,6 +99,23 @@ function (bind) { state.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')) { + $.cookie('current_player_mode', 'html5', { + expires: 3650, + path: '/' + }); + state.currentPlayerMode = 'html5'; + } else { + state.currentPlayerMode = currentPlayerMode; + } + }($.cookie('current_player_mode'))); + // 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. if ( @@ -139,7 +156,7 @@ function (bind) { var speed; video = video.split(/:/); - speed = parseFloat(video[0]).toFixed(2).replace(/\.00$/, ".0"); + speed = parseFloat(video[0]).toFixed(2).replace(/\.00$/, '.0'); state.videos[speed] = video[1]; }); @@ -179,22 +196,26 @@ function (bind) { state.setSpeed($.cookie('video_speed')); } - function embed(state) { } + function embed(state) { + VideoPlayer(state); + } // 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) { + function setSpeed(newSpeed, updateCookie) { if (this.speeds.indexOf(newSpeed) !== -1) { this.speed = newSpeed; + } else { + this.speed = '1.0'; + } - $.cookie('video_speed', '' + newSpeed, { + if (updateCookie !== false) { + $.cookie('video_speed', this.speed, { expires: 3650, path: '/' }); - } else { - this.speed = '1.0'; } } diff --git a/common/lib/xmodule/xmodule/js/src/videoalpha/display/video_control.js b/common/lib/xmodule/xmodule/js/src/videoalpha/display/video_control.js new file mode 100644 index 0000000000..074fd07682 --- /dev/null +++ b/common/lib/xmodule/xmodule/js/src/videoalpha/display/video_control.js @@ -0,0 +1,145 @@ +(function (requirejs, require, define) { + +// VideoPlayer module. +define( +'videoalpha/display/video_control.js', +['videoalpha/display/bind.js'], +function (bind) { + + // VideoControl() function - what this module "exports". + return function (state) { + state.videoControl = {}; + + // Functions which will be accessible via 'state' object. + makeFunctionsPublic(state); + + // TODO. + console.log('We are inside VideoControl() function.'); + + renderElements(state); + bindHandlers(); + }; + + // Private functions start here. + + function makeFunctionsPublic(state) { + state.videoControl.play = bind(play, state); + state.videoControl.pause = bind(pause, state); + state.videoControl.togglePlayback = bind(togglePlayback, state); + } + + function renderElements(state) { + var el; + + el = $( + '
' + + '
' + + '' + + '
' + + 'Fill Browser' + + '
' + + '
' + ); + + state.videoControl.el = state.el.find('.video-controls'); + state.videoControl.el.append(el); + + state.videoControl.playPauseEl = state.videoControl.el.find('.video_control'); + + if (!onTouchBasedDevice()) { + state.videoControl.playPauseEl.addClass('play').html('Play'); + } + } + + function bindHandlers(state) { + state.videoControl.playPauseEl.click(state.videoControl.togglePlayback); + } + + // 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 play() { + this.videoControl.playPauseEl.removeClass('play').addClass('pause').html('Pause'); + this.videoControl.state = 'playing'; + } + + function pause() { + this.videoControl.playPauseEl.removeClass('pause').addClass('play').html('Play'); + this.videoControl.state = 'paused'; + } + + function togglePlayback(event) { + + event.preventDefault(); + + console.log('We are in togglePlayback() function. this ='); + console.log(this); + + /* + if (this.$('.video_control').hasClass('play')) { + $(this).trigger('play'); + } else if (this.$('.video_control').hasClass('pause')) { + $(this).trigger('pause'); + } + */ + } + +}); + +}(RequireJS.requirejs, RequireJS.require, RequireJS.define)); + + +/* +// Generated by CoffeeScript 1.4.0 +(function() { + var __bind = function(fn, me){ return function(){ return fn.apply(me, arguments); }; }, + __hasProp = {}.hasOwnProperty, + __extends = function(child, parent) { for (var key in parent) { if (__hasProp.call(parent, key)) child[key] = parent[key]; } function ctor() { this.constructor = child; } ctor.prototype = parent.prototype; child.prototype = new ctor(); child.__super__ = parent.prototype; return child; }; + + this.VideoControlAlpha = (function(_super) { + + __extends(VideoControlAlpha, _super); + + function VideoControlAlpha() { + this.togglePlayback = __bind(this.togglePlayback, this); + return VideoControlAlpha.__super__.constructor.apply(this, arguments); + } + + VideoControlAlpha.prototype.bind = function() { + return this.$('.video_control').click(this.togglePlayback); + }; + + VideoControlAlpha.prototype.render = function() { + this.el.append("
\n
\n \n \n
"); + if (!onTouchBasedDevice()) { + return this.$('.video_control').addClass('play').html('Play'); + } + }; + + VideoControlAlpha.prototype.play = function() { + return this.$('.video_control').removeClass('play').addClass('pause').html('Pause'); + }; + + VideoControlAlpha.prototype.pause = function() { + return this.$('.video_control').removeClass('pause').addClass('play').html('Play'); + }; + + VideoControlAlpha.prototype.togglePlayback = function(event) { + event.preventDefault(); + if (this.$('.video_control').hasClass('play')) { + return $(this).trigger('play'); + } else if (this.$('.video_control').hasClass('pause')) { + return $(this).trigger('pause'); + } + }; + + return VideoControlAlpha; + + })(SubviewAlpha); + +}).call(this); +*/ diff --git a/common/lib/xmodule/xmodule/js/src/videoalpha/display/video_player.js b/common/lib/xmodule/xmodule/js/src/videoalpha/display/video_player.js index bc8b76867b..4af1f58407 100644 --- a/common/lib/xmodule/xmodule/js/src/videoalpha/display/video_player.js +++ b/common/lib/xmodule/xmodule/js/src/videoalpha/display/video_player.js @@ -3,12 +3,233 @@ // VideoPlayer module. define( 'videoalpha/display/video_player.js', -['videoalpha/display/html5_video.js'], -function (HTML5Video) { +['videoalpha/display/html5_video.js', 'videoalpha/display/bind.js'], +function (HTML5Video, bind) { + + // VideoPlayer() function - what this module "exports". return function (state) { - console.log('HTML5Video object:'); - console.log(HTML5Video); + state.videoPlayer = {}; + + // Functions which will be accessible via 'state' object. + makeFunctionsPublic(state); + + if (state.videoType === 'youtube') { + state.videoPlayer.PlayerState = YT.PlayerState; + state.videoPlayer.PlayerState.UNSTARTED = -1; + } else { // if (state.videoType === 'html5') { + state.videoPlayer.PlayerState = HTML5Video.PlayerState; + } + state.videoPlayer.currentTime = 0; + + renderElements(state); + bindHandlers(); }; + + // Private functions start here. + + function makeFunctionsPublic(state) { + state.videoPlayer.pause = bind(pause, state); + state.videoPlayer.play = bind(play, state); + state.videoPlayer.toggleFullScreen = bind(toggleFullScreen, state); + state.videoPlayer.update = bind(update, state); + state.videoPlayer.onVolumeChange = bind(onVolumeChange, state); + state.videoPlayer.onSpeedChange = bind(onSpeedChange, state); + state.videoPlayer.onSeek = 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.bindExitFullScreen = bind(bindExitFullScreen, state); + } + + function renderElements(state) { + var youTubeId; + + state.videoPlayer.playerVars = { + 'controls': 0, + 'wmode': 'transparent', + 'rel': 0, + 'showinfo': 0, + 'enablejsapi': 1, + 'modestbranding': 1 + }; + + if (state.currentPlayerMode !== 'flash') { + state.videoPlayer.playerVars.html5 = 1; + } + + if (state.config.start) { + state.videoPlayer.playerVars.start = state.config.start; + state.videoPlayer.playerVars.wmode = 'window'; + } + if (state.config.end) { + state.videoPlayer.playerVars.end = state.config.end; + } + + if (state.videoType === 'html5') { + state.videoPlayer.player = new HTML5Video.Player(state.el, { + 'playerVars': state.videoPlayer.playerVars, + 'videoSources': state.html5Sources, + 'events': { + 'onReady': state.videoPlayer.onReady, + 'onStateChange': state.videoPlayer.onStateChange + } + }); + } else if (state.videoType === 'youtube') { + if (state.currentPlayerMode === 'flash') { + youTubeId = state.youtubeId(); + } else { + youTubeId = state.youtubeId('1.0'); + } + state.videoPlayer.player = new YT.Player(state.id, { + 'playerVars': state.videoPlayer.playerVars, + 'videoId': youTubeId, + 'events': { + 'onReady': state.videoPlayer.onReady, + 'onStateChange': state.videoPlayer.onStateChange, + 'onPlaybackQualityChange': state.videoPlayer.onPlaybackQualityChange + } + }); + } + } + + function bindHandlers() { + + } + + function reinitAsFlash(state) { + state.videoPlayer.player.destroy(); + + $.cookie('current_player_mode', 'flash', { + expires: 3650, + path: '/' + }); + state.currentPlayerMode = 'flash'; + + delete state.videoPlayer.playerVars.html5; + + state.videoPlayer.player = new YT.Player(state.id, { + 'playerVars': state.videoPlayer.playerVars, + 'videoId': state.youtubeId(), + 'events': { + 'onReady': state.videoPlayer.onReady, + 'onStateChange': state.videoPlayer.onStateChange, + 'onPlaybackQualityChange': state.videoPlayer.onPlaybackQualityChange + } + }); + } + + // 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 pause() { } + + function play() { + if (this.videoPlayer.player.playVideo) { + this.videoPlayer.player.playVideo(); + } + + console.log('state is:'); + console.log(this); + } + + function toggleFullScreen() { } + + function update() { } + + function onVolumeChange() { } + + function onSpeedChange() { } + + function onSeek() { } + + function onEnded() { + console.log('this.videoPlayer.PlayerState.ENDED'); + } + + function onPause() { + console.log('this.videoPlayer.PlayerState.PAUSED'); + } + + function onPlay() { + console.log('this.videoPlayer.PlayerState.PLAYING'); + } + + function onUnstarted() { + console.log('this.videoPlayer.PlayerState.UNSTARTED'); + } + + function handlePlaybackQualityChange() { } + + function onPlaybackQualityChange() { } + + function onReady() { + var availablePlaybackRates, baseSpeedSubs, _this; + + console.log('We are in ready function.'); + + availablePlaybackRates = this.videoPlayer.player.getAvailablePlaybackRates(); + if ((this.currentPlayerMode === 'html5') && (this.videoType === 'youtube')) { + if (availablePlaybackRates.length === 1) { + console.log('We are playing YouTube video in HTML5 mode but have only one speed. Will reload in Flash mode.'); + reinitAsFlash(this); + + return; + } else if (availablePlaybackRates.length > 1) { + // We need to synchronize available frame rates with the ones that the user specified. + console.log('We are a YouTube video in HTML5 player mode.'); + + baseSpeedSubs = this.videos['1.0']; + _this = this; + $.each(this.videos, function(index, value) { + delete _this.videos[index]; + }); + this.speeds = []; + $.each(availablePlaybackRates, function(index, value) { + _this.videos[value.toFixed(2).replace(/\.00$/, '.0')] = baseSpeedSubs; + _this.speeds.push(value.toFixed(2).replace(/\.00$/, '.0')); + }); + + this.setSpeed($.cookie('video_speed')); + } + } + + if (this.currentPlayerMode === 'html5') { + this.videoPlayer.player.setPlaybackRate(this.speed); + } + + if (!onTouchBasedDevice()) { + this.videoPlayer.play(); + } + } + + function onStateChange() { + console.log('function onStateChange()'); + } + + function onStateChange(event) { + switch (event.data) { + case this.videoPlayer.PlayerState.UNSTARTED: + this.videoPlayer.onUnstarted(); + break; + case this.videoPlayer.PlayerState.PLAYING: + this.videoPlayer.onPlay(); + break; + case this.videoPlayer.PlayerState.PAUSED: + this.videoPlayer.onPause(); + break; + case this.videoPlayer.PlayerState.ENDED: + this.videoPlayer.onEnded(); + break; + } + } + + function bindExitFullScreen() { } }); }(RequireJS.requirejs, RequireJS.require, RequireJS.define)); @@ -17,66 +238,6 @@ function (HTML5Video) { /* -// Generated by CoffeeScript 1.4.0 -(function() { - var __bind = function(fn, me){ return function(){ return fn.apply(me, arguments); }; }, - __hasProp = {}.hasOwnProperty, - __extends = function(child, parent) { for (var key in parent) { if (__hasProp.call(parent, key)) child[key] = parent[key]; } function ctor() { this.constructor = child; } ctor.prototype = parent.prototype; child.prototype = new ctor(); child.__super__ = parent.prototype; return child; }; - - this.VideoPlayerAlpha = (function(_super) { - - __extends(VideoPlayerAlpha, _super); - - function VideoPlayerAlpha() { - this.pause = __bind(this.pause, this); - - this.play = __bind(this.play, this); - - this.toggleFullScreen = __bind(this.toggleFullScreen, this); - - this.update = __bind(this.update, this); - - this.onVolumeChange = __bind(this.onVolumeChange, this); - - this.onSpeedChange = __bind(this.onSpeedChange, this); - - this.onSeek = __bind(this.onSeek, this); - - this.onEnded = __bind(this.onEnded, this); - - this.onPause = __bind(this.onPause, this); - - this.onPlay = __bind(this.onPlay, this); - - this.onUnstarted = __bind(this.onUnstarted, this); - - this.handlePlaybackQualityChange = __bind(this.handlePlaybackQualityChange, this); - - this.onPlaybackQualityChange = __bind(this.onPlaybackQualityChange, this); - - this.onStateChange = __bind(this.onStateChange, this); - - this.onReady = __bind(this.onReady, this); - - this.bindExitFullScreen = __bind(this.bindExitFullScreen, this); - return VideoPlayerAlpha.__super__.constructor.apply(this, arguments); - } - - VideoPlayerAlpha.prototype.initialize = function() { - if (window.OldVideoPlayerAlpha && window.OldVideoPlayerAlpha.onPause) { - window.OldVideoPlayerAlpha.onPause(); - } - window.OldVideoPlayerAlpha = this; - if (this.video.videoType === 'youtube') { - this.PlayerState = YT.PlayerState; - this.PlayerState.UNSTARTED = -1; - } else if (this.video.videoType === 'html5') { - this.PlayerState = HTML5Video.PlayerState; - } - this.currentTime = 0; - return this.el = $("#video_" + this.video.id); - }; - VideoPlayerAlpha.prototype.bind = function() { $(this.control).bind('play', this.play).bind('pause', this.pause); if (this.video.videoType === 'youtube') { @@ -103,83 +264,6 @@ function (HTML5Video) { } }; - VideoPlayerAlpha.prototype.render = function() { - var prev_player_type, youTubeId; - this.control = new VideoControlAlpha({ - el: this.$('.video-controls') - }); - if (this.video.videoType === 'youtube') { - this.qualityControl = new VideoQualityControlAlpha({ - el: this.$('.secondary-controls') - }); - } - if (this.video.show_captions === true) { - this.caption = new VideoCaptionAlpha({ - el: this.el, - youtubeId: this.video.youtubeId('1.0'), - currentSpeed: this.currentSpeed(), - captionAssetPath: this.video.caption_asset_path - }); - } - if (!onTouchBasedDevice()) { - this.volumeControl = new VideoVolumeControlAlpha({ - el: this.$('.secondary-controls') - }); - } - this.speedControl = new VideoSpeedControlAlpha({ - el: this.$('.secondary-controls'), - speeds: this.video.speeds, - currentSpeed: this.currentSpeed() - }); - this.progressSlider = new VideoProgressSliderAlpha({ - el: this.$('.slider') - }); - this.playerVars = { - controls: 0, - wmode: 'transparent', - rel: 0, - showinfo: 0, - enablejsapi: 1, - modestbranding: 1 - }; - if (this.video.start) { - this.playerVars.start = this.video.start; - this.playerVars.wmode = 'window'; - } - if (this.video.end) { - this.playerVars.end = this.video.end; - } - if (this.video.videoType === 'html5') { - this.player = new HTML5Video.Player(this.video.el, { - playerVars: this.playerVars, - videoSources: this.video.html5Sources, - events: { - onReady: this.onReady, - onStateChange: this.onStateChange - } - }); - } else if (this.video.videoType === 'youtube') { - prev_player_type = $.cookie('prev_player_type'); - if (prev_player_type === 'html5') { - youTubeId = this.video.videos['1.0']; - } else { - youTubeId = this.video.youtubeId(); - } - this.player = new YT.Player(this.video.id, { - playerVars: this.playerVars, - videoId: youTubeId, - events: { - onReady: this.onReady, - onStateChange: this.onStateChange, - onPlaybackQualityChange: this.onPlaybackQualityChange - } - }); - } - if (this.video.show_captions === true) { - return this.caption.hideCaptions(this['video'].hide_captions); - } - }; - VideoPlayerAlpha.prototype.addToolTip = function() { return this.$('.add-fullscreen, .hide-subtitles').qtip({ position: { @@ -189,67 +273,7 @@ function (HTML5Video) { }); }; - VideoPlayerAlpha.prototype.onReady = function(event) { - if (this.video.videoType === 'html5') { - this.player.setPlaybackRate(this.video.speed); - } - if (!onTouchBasedDevice()) { - return $('.video-load-complete:first').data('video').player.play(); - } - }; - VideoPlayerAlpha.prototype.onStateChange = function(event) { - var availableSpeeds, baseSpeedSubs, prev_player_type, _this; - _this = this; - switch (event.data) { - case this.PlayerState.UNSTARTED: - if (this.video.videoType === "youtube") { - availableSpeeds = this.player.getAvailablePlaybackRates(); - prev_player_type = $.cookie('prev_player_type'); - if (availableSpeeds.length > 1) { - if (prev_player_type === 'youtube') { - $.cookie('prev_player_type', 'html5', { - expires: 3650, - path: '/' - }); - this.onSpeedChange(null, '1.0'); - } else if (prev_player_type !== 'html5') { - $.cookie('prev_player_type', 'html5', { - expires: 3650, - path: '/' - }); - } - baseSpeedSubs = this.video.videos["1.0"]; - $.each(this.video.videos, function(index, value) { - return delete _this.video.videos[index]; - }); - this.video.speeds = []; - $.each(availableSpeeds, function(index, value) { - _this.video.videos[value.toFixed(2).replace(/\.00$/, ".0")] = baseSpeedSubs; - return _this.video.speeds.push(value.toFixed(2).replace(/\.00$/, ".0")); - }); - this.speedControl.reRender(this.video.speeds, this.video.speed); - this.video.videoType = 'html5'; - this.video.setSpeed($.cookie('video_speed')); - this.player.setPlaybackRate(this.video.speed); - } else { - if (prev_player_type !== 'youtube') { - $.cookie('prev_player_type', 'youtube', { - expires: 3650, - path: '/' - }); - } - } - } - return this.onUnstarted(); - case this.PlayerState.PLAYING: - return this.onPlay(); - case this.PlayerState.PAUSED: - return this.onPause(); - case this.PlayerState.ENDED: - return this.onEnded(); - } - }; VideoPlayerAlpha.prototype.onPlaybackQualityChange = function(event, value) { var quality; @@ -308,12 +332,12 @@ function (HTML5Video) { return this.updatePlayTime(time); }; - VideoPlayerAlpha.prototype.onSpeedChange = function(event, newSpeed) { + VideoPlayerAlpha.prototype.onSpeedChange = function(event, newSpeed, updateCookie) { if (this.video.videoType === 'youtube') { this.currentTime = Time.convert(this.currentTime, parseFloat(this.currentSpeed()), newSpeed); } newSpeed = parseFloat(newSpeed).toFixed(2).replace(/\.00$/, '.0'); - this.video.setSpeed(newSpeed); + this.video.setSpeed(newSpeed, updateCookie); if (this.video.videoType === 'youtube') { if (this.video.show_captions === true) { this.caption.currentSpeed = newSpeed; @@ -384,12 +408,12 @@ function (HTML5Video) { }; VideoPlayerAlpha.prototype.duration = function() { - if (this.video.videoType === "youtube") { - return this.video.getDuration(); - } else if (this.video.videoType === "html5") { - return this.player.getDuration(); + var duration; + duration = this.player.getDuration(); + if (isFinite(duration) === false) { + duration = this.video.getDuration(); } - return 0; + return duration; }; VideoPlayerAlpha.prototype.currentSpeed = function() { diff --git a/common/lib/xmodule/xmodule/js/src/videoalpha/main.js b/common/lib/xmodule/xmodule/js/src/videoalpha/main.js index 582c151afb..3602967ff3 100644 --- a/common/lib/xmodule/xmodule/js/src/videoalpha/main.js +++ b/common/lib/xmodule/xmodule/js/src/videoalpha/main.js @@ -1,18 +1,38 @@ (function (requirejs, require, define) { -// Main module +// Main module. require( -['videoalpha/display/initialize.js', 'videoalpha/display/video_player.js'], -function (Initialize, VideoPlayer) { +[ + 'videoalpha/display/initialize.js', + 'videoalpha/display/video_control.js', +], +function (Initialize, VideoControl) { + var previousState; + + // Because this constructor can be called multiple times on a single page (when + // the user switches verticals, the page doesn't reload, but the content changes), we must + // will check each time if there is a previous copy of 'state' object. If there is, we + // will make sure that copy exists cleanly. We have to do this because when verticals switch, + // the code does not handle any Xmodule JS code that is running - it simply removes DOM + // elements from the page. Any functions that were running during this, and that will run + // afterwards (expecting the DOM elements to be present) must be stopped by hand. + previousState = null; + window.VideoAlpha = function (element) { var state; + // Check for existance of previous state, uninitialize it if necessary, and create a new state. + // Store new state for future invocation of this module consturctor function. + if (previousState !== null) { + previousState.videoPlayer.onPause(); + } state = {}; + previousState = state; - new Initialize(state, element); - new VideoPlayer(state); + Initialize(state, element); + VideoControl(state); - console.log('Finished constructing "state" object. state = '); + console.log('state is:'); console.log(state); }; }); diff --git a/common/lib/xmodule/xmodule/videoalpha_module.py b/common/lib/xmodule/xmodule/videoalpha_module.py index 20bab318a9..20b95ec382 100644 --- a/common/lib/xmodule/xmodule/videoalpha_module.py +++ b/common/lib/xmodule/xmodule/videoalpha_module.py @@ -73,6 +73,7 @@ class VideoAlphaModule(VideoAlphaFields, XModule): resource_string(__name__, 'js/src/videoalpha/display/initialize.js'), resource_string(__name__, 'js/src/videoalpha/display/html5_video.js'), resource_string(__name__, 'js/src/videoalpha/display/video_player.js'), + resource_string(__name__, 'js/src/videoalpha/display/video_control.js'), resource_string(__name__, 'js/src/videoalpha/main.js') ] }