diff --git a/common/lib/xmodule/xmodule/js/src/video/01_initialize.js b/common/lib/xmodule/xmodule/js/src/video/01_initialize.js index 30b5ac5778f45d8816c80478e8ff1795638b6b01..7f8057c02523b953371aa467523a1a3c83a0feaf 100644 --- a/common/lib/xmodule/xmodule/js/src/video/01_initialize.js +++ b/common/lib/xmodule/xmodule/js/src/video/01_initialize.js @@ -1,8 +1,9 @@ /** - * @file Initialize module works with the JSON config, and sets up various settings, parameters, - * variables. After all setup actions are performed, it invokes the video player to play the - * specified video. This module must be invoked first. It provides several functions which do not - * fit in with other modules. + * @file Initialize module works with the JSON config, and sets up various + * settings, parameters, variables. After all setup actions are performed, it + * invokes the video player to play the specified video. This module must be + * invoked first. It provides several functions which do not fit in with other + * modules. * * @external VideoPlayer * @@ -16,18 +17,8 @@ define( ['video/03_video_player.js'], function (VideoPlayer) { - // In case if console.log() is unavailable for some reason. - // - // console.log() will be used to put case critical messages to the browser - // JavaScript console to allow for better and quicker debugging. - // - // This is placed here because '01_initialize.js' gets loaded first. - if (typeof window.console === 'undefined') { - window.console = {}; - } - if ($.isFunction(window.console.log) === false) { - window.console.log = function () {}; - } + // window.console.log() is expected to be available. We do not support + // browsers which lack this functionality. // The function gettext() is defined by a vendor library. If, however, it // is undefined, it is a simple wrapper. It is used to return a different @@ -69,43 +60,54 @@ function (VideoPlayer) { * methods, modules) of the Video player. */ function _makeFunctionsPublic(state) { - state.setSpeed = _.bind(setSpeed, state); - state.youtubeId = _.bind(youtubeId, state); - state.getDuration = _.bind(getDuration, state); - state.trigger = _.bind(trigger, state); + state.setSpeed = _.bind(setSpeed, state); + state.youtubeId = _.bind(youtubeId, state); + state.getDuration = _.bind(getDuration, state); + state.trigger = _.bind(trigger, state); state.stopBuffering = _.bind(stopBuffering, state); // Old private functions. Now also public so that can be // tested by Jasmine. - state.initialize = _.bind(initialize, state); - state.parseSpeed = _.bind(parseSpeed, state); - state.fetchMetadata = _.bind(fetchMetadata, state); + state.initialize = _.bind(initialize, state); + state.parseSpeed = _.bind(parseSpeed, state); + state.fetchMetadata = _.bind(fetchMetadata, state); state.parseYoutubeStreams = _.bind(parseYoutubeStreams, state); - state.parseVideoSources = _.bind(parseVideoSources, state); - state.getVideoMetadata = _.bind(getVideoMetadata, state); + state.parseVideoSources = _.bind(parseVideoSources, state); + state.getVideoMetadata = _.bind(getVideoMetadata, 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. + // 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. + // 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. + // Note that the loading of stand alone HTML5 player API is handled by + // Require JS. At the time when we reach this code, the stand alone + // HTML5 player is already loaded, so no further testing in that case + // is required. var onPlayerReadyFunc; if ( - ((state.videoType === 'youtube') && (window.YT) && (window.YT.Player)) || + ( + (state.videoType === 'youtube') && + (window.YT) && + (window.YT.Player) + ) || (state.videoType === 'html5') ) { VideoPlayer(state); } else { - onPlayerReadyFunc = (state.videoType === 'youtube') ? 'onYouTubePlayerAPIReady' : 'onHTML5PlayerAPIReady'; + if (state.videoType === 'youtube') { + onPlayerReadyFunc = 'onYouTubePlayerAPIReady'; + } else { + onPlayerReadyFunc = 'onHTML5PlayerAPIReady'; + } window[onPlayerReadyFunc] = _.bind(VideoPlayer, window, state); } } @@ -121,7 +123,8 @@ function (VideoPlayer) { // Option // this.hide_captions = true | false // - // represents the user's choice of having the subtitles shown or hidden. This choice is stored in cookies. + // 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'); @@ -138,14 +141,19 @@ function (VideoPlayer) { } // 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 + // 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')) { + if ( + (currentPlayerMode === 'html5') || + (currentPlayerMode === 'flash') + ) { state.currentPlayerMode = currentPlayerMode; } else { $.cookie('current_player_mode', 'html5', { @@ -154,20 +162,32 @@ function (VideoPlayer) { }); state.currentPlayerMode = 'html5'; } + + console.log( + '[Video info]: YouTube player mode is "' + + state.currentPlayerMode + '".' + ); }($.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. + // 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'; return true; } + + console.log( + '[Video info]: Youtube Video IDs are incorrect or absent.' + ); + return false; } @@ -203,6 +223,10 @@ function (VideoPlayer) { state.el.find('.video-player div').addClass('hidden'); state.el.find('.video-player h3').removeClass('hidden'); + console.log( + '[Video info]: Non-youtube video sources aren\'t available.' + ); + return false; } @@ -231,8 +255,9 @@ function (VideoPlayer) { // *************************************************************** // 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(). + // 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 initialize(element) @@ -240,17 +265,21 @@ function (VideoPlayer) { function initialize(element) { var _this = this, tempYtTestTimeout; - // This is used in places where we instead would have to check if an element has a CSS class 'fullscreen'. + // This is used in places where we instead would have to check if an + // element has a CSS class 'fullscreen'. this.isFullScreen = false; // The parent element of the video, and the ID. this.el = $(element).find('.video'); this.id = this.el.attr('id').replace(/video_/, ''); - console.log('[Video info]: Initializing video with id "' + this.id + '".'); + console.log( + '[Video info]: Initializing video with id "' + this.id + '".' + ); - // 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. + // 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 = { element: element, @@ -259,7 +288,10 @@ function (VideoPlayer) { 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'), + show_captions: ( + this.el.data('show-captions') + .toString().toLowerCase() === 'true' + ), youtubeStreams: this.el.data('streams'), sub: this.el.data('sub'), @@ -282,62 +314,70 @@ function (VideoPlayer) { } this.config.ytTestTimeout = tempYtTestTimeout; - console.log('[Video info]: Try parsing YouTube IDs.'); if (!(_parseYouTubeIDs(this))) { - console.log('[Video info]: Could not parse YouTube IDs. Try parsing non-YouTube video sources.'); // If we do not have YouTube ID's, try parsing HTML5 video sources. if (!_prepareHTML5Video(this, true)) { - console.log('[Video info]: No video sources available at all.'); // Non-YouTube sources were not found either. return; } + console.log('[Video info]: Start player in HTML5 mode.'); + _setConfigurations(this); _renderElements(this); } else { - console.log('[Video info]: Valid YouTube IDs found.'); if (!this.youtubeXhr) { - console.log('[Video info]: Making request to see if YouTube responds.'); this.youtubeXhr = this.getVideoMetadata(); } - console.log('[Video info]: Waiting for YouTube to respond.'); - this.youtubeXhr - .always(function(json, status) { + .always(function (json, status) { var err = $.isPlainObject(json.error) || - (status !== 'success' && status !== 'notmodified'); + ( + status !== 'success' && + status !== 'notmodified' + ); if (err) { - console.log('[Video info]: An error happened while waiting for YouTube to respond.'); - console.log('[Video info]: Checking if alternate non-YouTube video sources are available.'); + console.log( + '[Video info]: YouTube returned an error for ' + + 'video with id "' + _this.id + '".' + ); // When the youtube link doesn't work for any reason // (for example, the great firewall in china) any // alternate sources should automatically play. if (!_prepareHTML5Video(_this)) { - console.log('[Video info]: No alternative non-YouTube video sources available.'); - console.log('[Video info]: Will try to continue loading YouTube video. Maybe the response timeout is longer than was specified.'); + console.log( + '[Video info]: Continue loading ' + + 'YouTube video.' + ); // Non-YouTube sources were not found either. - _this.el.find('.video-player div').removeClass('hidden'); - _this.el.find('.video-player h3').addClass('hidden'); + _this.el.find('.video-player div') + .removeClass('hidden'); + _this.el.find('.video-player h3') + .addClass('hidden'); // If in reality the timeout was to short, try to // continue loading the YouTube video anyways. _this.fetchMetadata(); _this.parseSpeed(); } else { - console.log('[Video info]: Alternative non-YouTube video sources were found and will be loaded.'); + console.log( + '[Video info]: Change player mode to HTML5.' + ); // In-browser HTML5 player does not support quality // control. _this.el.find('a.quality_control').hide(); } } else { - console.log('[Video info]: YouTube responded with OK. Loading YouTube video.'); + console.log( + '[Video info]: Start player in YouTube mode.' + ); _this.fetchMetadata(); _this.parseSpeed(); @@ -353,23 +393,28 @@ function (VideoPlayer) { // // Take a string in the form: // "iCawTYPtehk:0.75,KgpclqP-LBA:1.0,9-2670d5nvU:1.5" - // parse it, and make it available via the 'state' object. If we are not given a string, or - // it's length is zero, then we return false. + // parse it, and make it available via the 'state' object. If we are + // not given a string, or it's length is zero, then we return false. // // @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. + // 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 parseYoutubeStreams(youtubeStreams) { var _this; - if (typeof youtubeStreams === 'undefined' || youtubeStreams.length === 0) { + if ( + typeof youtubeStreams === 'undefined' || + youtubeStreams.length === 0 + ) { return false; } _this = this; this.videos = {}; - $.each(youtubeStreams.split(/,/), function(index, video) { + $.each(youtubeStreams.split(/,/), function (index, video) { var speed; video = video.split(/:/); @@ -383,8 +428,8 @@ function (VideoPlayer) { // function parseVideoSources(, mp4Source, webmSource, oggSource) // - // Take the HTML5 sources (URLs of videos), and make them available explictly for each type - // of video format (mp4, webm, ogg). + // Take the HTML5 sources (URLs of videos), and make them available + // explictly for each type of video format (mp4, webm, ogg). function parseVideoSources(sources) { var _this = this, v = document.createElement('video'), @@ -416,16 +461,17 @@ function (VideoPlayer) { // function fetchMetadata() // - // When dealing with YouTube videos, we must fetch meta data that has certain key facts - // not available while the video is loading. For example the length of the video can be - // determined from the meta data. + // When dealing with YouTube videos, we must fetch meta data that has + // certain key facts not available while the video is loading. For + // example the length of the video can be determined from the meta + // data. function fetchMetadata() { var _this = this; this.metadata = {}; $.each(this.videos, function (speed, url) { - _this.getVideoMetadata(url, function(data) { + _this.getVideoMetadata(url, function (data) { if (data.data) { _this.metadata[data.data.id] = data.data; } @@ -437,7 +483,7 @@ function (VideoPlayer) { // // Create a separate array of available speeds. function parseSpeed() { - this.speeds = ($.map(this.videos, function(url, speed) { + this.speeds = ($.map(this.videos, function (url, speed) { return speed; })).sort(); @@ -479,7 +525,7 @@ function (VideoPlayer) { function stopBuffering() { var video; - if (this.videoType === 'html5'){ + if (this.videoType === 'html5') { // HTML5 player haven't default way to abort bufferization. // In this case we simply resetting source and call load(). video = this.videoPlayer.player.video; @@ -497,9 +543,9 @@ function (VideoPlayer) { } /* - * The trigger() function will assume that the @objChain is a complete chain with a method - * (function) at the end. It will call this function. So for example, when trigger() is - * called like so: + * The trigger() function will assume that the @objChain is a complete + * chain with a method (function) at the end. It will call this function. + * So for example, when trigger() is called like so: * * state.trigger('videoPlayer.pause', {'param1': 10}); * @@ -514,10 +560,10 @@ function (VideoPlayer) { tmpObj = this; chain = objChain.split('.'); - // At the end of the loop the variable 'tmpObj' will either be the correct - // object/function to trigger/invoke. If the 'chain' chain of object is - // incorrect (one of the link is non-existent), then the loop will immediately - // exit. + // At the end of the loop the variable 'tmpObj' will either be the + // correct object/function to trigger/invoke. If the 'chain' chain of + // object is incorrect (one of the link is non-existent), then the loop + // will immediately exit. while (chain.length) { i = chain.shift(); diff --git a/common/lib/xmodule/xmodule/js/src/video/03_video_player.js b/common/lib/xmodule/xmodule/js/src/video/03_video_player.js index 25617283f59a0af08b6a162467c9586fe0adbf96..649dd9cf668d4cd5a9854a5045dbc318fe5a7319 100644 --- a/common/lib/xmodule/xmodule/js/src/video/03_video_player.js +++ b/common/lib/xmodule/xmodule/js/src/video/03_video_player.js @@ -21,35 +21,46 @@ function (HTML5Video) { // function _makeFunctionsPublic(state) // - // Functions which will be accessible via 'state' object. When called, these functions will - // get the 'state' object as a context. + // 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 = _.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); + 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 _initialize(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. + // 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 _initialize(state) { var youTubeId; @@ -92,9 +103,10 @@ function (HTML5Video) { // // TODO: Check the status of // http://code.google.com/p/gdata-issues/issues/detail?id=4654 - // When the YouTube team fixes the API bug, we can remove this temporary - // bug fix. - state.browserIsFirefox = navigator.userAgent.toLowerCase().indexOf('firefox') > -1; + // When the YouTube team fixes the API bug, we can remove this + // temporary bug fix. + state.browserIsFirefox = navigator.userAgent + .toLowerCase().indexOf('firefox') > -1; if (state.videoType === 'html5') { state.videoPlayer.player = new HTML5Video.Player(state.el, { @@ -117,7 +129,8 @@ function (HTML5Video) { events: { onReady: state.videoPlayer.onReady, onStateChange: state.videoPlayer.onStateChange, - onPlaybackQualityChange: state.videoPlayer.onPlaybackQualityChange + onPlaybackQualityChange: state.videoPlayer + .onPlaybackQualityChange } }); } @@ -125,9 +138,10 @@ function (HTML5Video) { // 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 different frame rates. + // 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 different frame rates. function _restartUsingFlash(state) { // Remove from the page current iFrame with HTML5 video. state.videoPlayer.player.destroy(); @@ -139,25 +153,29 @@ function (HTML5Video) { }); state.currentPlayerMode = 'flash'; + console.log('[Video info]: Changing YouTube player mode to "flash".'); + // Removed configuration option that requests the HTML5 mode. delete state.videoPlayer.playerVars.html5; // Request for the creation of a new Flash player 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 + 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(). + // 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() { @@ -174,9 +192,11 @@ 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). + // It is called at a regular interval when the video is playing (see + // below). function update() { - this.videoPlayer.currentTime = this.videoPlayer.player.getCurrentTime(); + this.videoPlayer.currentTime = this.videoPlayer.player + .getCurrentTime(); if (isFinite(this.videoPlayer.currentTime)) { this.videoPlayer.updatePlayTime(this.videoPlayer.currentTime); @@ -206,19 +226,27 @@ function (HTML5Video) { if ( this.currentPlayerMode === 'html5' && - !(this.browserIsFirefox && newSpeed === '1.0' && this.videoType === 'youtube') + !( + this.browserIsFirefox && + newSpeed === '1.0' && + this.videoType === 'youtube' + ) ) { this.videoPlayer.player.setPlaybackRate(newSpeed); } 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. + // 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); + this.videoPlayer.player.loadVideoById( + this.youtubeId(), this.videoPlayer.currentTime + ); } else { - this.videoPlayer.player.cueVideoById(this.youtubeId(), this.videoPlayer.currentTime); + this.videoPlayer.player.cueVideoById( + this.youtubeId(), this.videoPlayer.currentTime + ); } this.videoPlayer.updatePlayTime(this.videoPlayer.currentTime); @@ -243,7 +271,9 @@ function (HTML5Video) { if (this.videoPlayer.isPlaying()) { clearInterval(this.videoPlayer.updateInterval); - this.videoPlayer.updateInterval = setInterval(this.videoPlayer.update, 200); + this.videoPlayer.updateInterval = setInterval( + this.videoPlayer.update, 200 + ); } else { this.videoPlayer.currentTime = params.time; } @@ -286,7 +316,9 @@ function (HTML5Video) { ); if (!this.videoPlayer.updateInterval) { - this.videoPlayer.updateInterval = setInterval(this.videoPlayer.update, 200); + this.videoPlayer.updateInterval = setInterval( + this.videoPlayer.update, 200 + ); } this.trigger('videoControl.play', null); @@ -325,19 +357,26 @@ function (HTML5Video) { // https://bugzilla.mozilla.org/show_bug.cgi?id=840745 // https://developer.mozilla.org/en-US/docs/DOM/HTMLMediaElement - availablePlaybackRates = _.filter(availablePlaybackRates, function(item){ - var speed = Number(item); - return speed > 0.25 && speed <= 5; - }); + availablePlaybackRates = _.filter( + availablePlaybackRates, + function (item) { + var speed = Number(item); + return speed > 0.25 && speed <= 5; + } + ); - if ((this.currentPlayerMode === 'html5') && (this.videoType === 'youtube')) { + if ( + this.currentPlayerMode === 'html5' && + this.videoType === 'youtube' + ) { if (availablePlaybackRates.length === 1) { - // This condition is needed in cases when Firefox version is less than 20. In those versions - // HTML5 playback could only happen at 1 speed (no speed changing). Therefore, in this case, - // we need to switch back to Flash. + // This condition is needed in cases when Firefox version is + // less than 20. In those versions HTML5 playback could only + // happen at 1 speed (no speed changing). Therefore, in this + // case, we need to switch back to Flash. // - // This might also happen in other browsers, therefore when we have 1 speed available, we fall - // back to Flash. + // This might also happen in other browsers, therefore when we + // have 1 speed available, we fall back to Flash. _restartUsingFlash(this); @@ -352,18 +391,26 @@ function (HTML5Video) { // and their associated subs. // First clear the dictionary. - $.each(this.videos, function(index, value) { + $.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; + $.each(availablePlaybackRates, function (index, value) { + var key = value.toFixed(2).replace(/\.00$/, '.0'); + + _this.videos[key] = baseSpeedSubs; - _this.speeds.push(value.toFixed(2).replace(/\.00$/, '.0')); + _this.speeds.push(key); }); - this.trigger('videoSpeedControl.reRender', {'newSpeeds': this.speeds, 'currentSpeed': this.speed}); + this.trigger( + 'videoSpeedControl.reRender', + { + newSpeeds: this.speeds, + currentSpeed: this.speed + } + ); this.setSpeed($.cookie('video_speed')); } @@ -373,7 +420,10 @@ function (HTML5Video) { this.videoPlayer.player.setPlaybackRate(this.speed); } - if (!onTouchBasedDevice() && $('.video:first').data('autoplay') === 'True') { + if ( + !onTouchBasedDevice() && + $('.video:first').data('autoplay') === 'True' + ) { this.videoPlayer.play(); } } @@ -400,19 +450,37 @@ function (HTML5Video) { duration = this.videoPlayer.duration(); - this.trigger('videoProgressSlider.updatePlayTime', {'time': time, 'duration': duration}); - this.trigger('videoControl.updateVcrVidTime', {'time': time, 'duration': duration}); + this.trigger( + 'videoProgressSlider.updatePlayTime', + { + time: time, + duration: duration + } + ); + + this.trigger( + 'videoControl.updateVcrVidTime', + { + time: time, + duration: duration + } + ); + this.trigger('videoCaption.updatePlayTime', time); } function isPlaying() { - return this.videoPlayer.player.getPlayerState() === this.videoPlayer.PlayerState.PLAYING; + var playerState = this.videoPlayer.player.getPlayerState(), + PLAYING = this.videoPlayer.PlayerState.PLAYING; + + return playerState === PLAYING; } function duration() { var dur; dur = this.videoPlayer.player.getDuration(); + if (!isFinite(dur)) { dur = this.getDuration(); } @@ -431,7 +499,7 @@ function (HTML5Video) { // If extra parameters were passed to the log. if (data) { - $.each(data, function(paramName, value) { + $.each(data, function (paramName, value) { logInfo[paramName] = value; }); } diff --git a/common/lib/xmodule/xmodule/js/src/video/08_video_speed_control.js b/common/lib/xmodule/xmodule/js/src/video/08_video_speed_control.js index 6a6587186da2d1316f5a7c5816e8f3d81ba178ad..9db56ffc0d9b7f4dd9644216594b862aa990e1b6 100644 --- a/common/lib/xmodule/xmodule/js/src/video/08_video_speed_control.js +++ b/common/lib/xmodule/xmodule/js/src/video/08_video_speed_control.js @@ -19,6 +19,10 @@ function () { } if (state.videoType === 'html5' && !(_checkPlaybackRates())) { + console.log( + '[Video info]: HTML5 mode - playbackRate is not supported.' + ); + _hideSpeedControl(state); return; @@ -65,7 +69,7 @@ function () { state.videoSpeedControl.el ); - $.each(state.videoSpeedControl.speeds, function(index, speed) { + $.each(state.videoSpeedControl.speeds, function (index, speed) { var link = '<a class="speed_link" href="#">' + speed + 'x</a>'; state.videoSpeedControl.videoSpeedsEl @@ -78,26 +82,27 @@ function () { } /** - * @desc Check if playbackRate supports by browser. - * - * @type {function} - * @access private - * - * @param {object} state The object containg the state of the video player. - * All other modules, their parameters, public variables, etc. are - * available via this object. - * - * @this {object} The global window object. - * - * @returns {Boolean} - * true: Browser support playbackRate functionality. - * false: Browser doesn't support playbackRate functionality. - */ + * @desc Check if playbackRate supports by browser. + * + * @type {function} + * @access private + * + * @param {object} state The object containg the state of the video player. + * All other modules, their parameters, public variables, etc. are + * available via this object. + * + * @this {object} The global window object. + * + * @returns {Boolean} + * true: Browser support playbackRate functionality. + * false: Browser doesn't support playbackRate functionality. + */ function _checkPlaybackRates() { var video = document.createElement('video'); - // If browser supports, 1.0 should be returned by playbackRate property. - // In this case, function return True. Otherwise, False will be returned. + // If browser supports, 1.0 should be returned by playbackRate + // property. In this case, function return True. Otherwise, False will + // be returned. return Boolean(video.playbackRate); } @@ -128,7 +133,7 @@ function () { .on('click', state.videoSpeedControl.changeVideoSpeed); if (onTouchBasedDevice()) { - state.videoSpeedControl.el.on('click', function(event) { + state.videoSpeedControl.el.on('click', function (event) { // So that you can't highlight this control via a drag // operation, we disable the default browser actions on a // click event. @@ -287,7 +292,7 @@ function () { this.videoSpeedControl.videoSpeedsEl.find('li').removeClass('active'); this.videoSpeedControl.speeds = params.newSpeeds; - $.each(this.videoSpeedControl.speeds, function(index, speed) { + $.each(this.videoSpeedControl.speeds, function (index, speed) { var link, listItem; link = '<a class="speed_link" href="#">' + speed + 'x</a>';