diff --git a/common/lib/xmodule/xmodule/js/src/.gitignore b/common/lib/xmodule/xmodule/js/src/.gitignore index 03534687ca..bbd93c90e3 100644 --- a/common/lib/xmodule/xmodule/js/src/.gitignore +++ b/common/lib/xmodule/xmodule/js/src/.gitignore @@ -1,2 +1 @@ -*.js - +# Please do not ignore *.js files. Some xmodules are written in JS. diff --git a/common/lib/xmodule/xmodule/js/src/videoalpha/display.coffee b/common/lib/xmodule/xmodule/js/src/videoalpha/display.coffee index 1876330340..b97b02e68c 100644 --- a/common/lib/xmodule/xmodule/js/src/videoalpha/display.coffee +++ b/common/lib/xmodule/xmodule/js/src/videoalpha/display.coffee @@ -1,4 +1,4 @@ -class @Video +class @VideoAlpha constructor: (element) -> @el = $(element).find('.video') @id = @el.attr('id').replace(/video_/, '') @@ -9,40 +9,77 @@ class @Video @show_captions = @el.data('show-captions') == "true" window.player = null @el = $("#video_#{@id}") - @parseVideos @el.data('streams') - @fetchMetadata() - @parseSpeed() + + if @parseVideos(@el.data("streams")) is true + @videoType = "youtube" + @fetchMetadata() + @parseSpeed() + else + @videoType = "html5" + @parseVideoSources @el.data("mp4-source"), @el.data("webm-source"), @el.data("ogg-source") + @speeds = ["0.75", "1.0", "1.25", "1.5"] + @setSpeed($.cookie('video_speed')) + $("#video_#{@id}").data('video', this).addClass('video-load-complete') @hide_captions = $.cookie('hide_captions') == 'true' - if YT.Player + if ((@videoType is "youtube") and (YT.Player)) or ((@videoType is "html5") and (HTML5Video.Player)) + console.log 'one' @embed() else - window.onYouTubePlayerAPIReady = => - @el.each -> - $(this).data('video').embed() + console.log 'two' + if @videoType is "youtube" + console.log 'three' + window.onYouTubePlayerAPIReady = -> + _this.embed() + else if @videoType is "html5" + console.log 'four' + console.log @videoType + console.log HTML5Video.Player + window.onHTML5PlayerAPIReady = -> + _this.embed() youtubeId: (speed)-> @videos[speed || @speed] - parseVideos: (videos) -> + VideoAlpha::parseVideos = (videos) -> + return false if (typeof videos isnt "string") or (videos.length is 0) + + console.log 'We got this far' + console.log videos + @videos = {} - $.each videos.split(/,/), (index, video) => + _this = this + $.each videos.split(/,/), (index, video) -> + speed = undefined video = video.split(/:/) - speed = parseFloat(video[0]).toFixed(2).replace /\.00$/, '.0' - @videos[speed] = video[1] + speed = parseFloat(video[0]).toFixed(2).replace(/\.00$/, ".0") + _this.videos[speed] = video[1] + true + + VideoAlpha::parseVideoSources = (mp4Source, webmSource, oggSource) -> + @html5Sources = + mp4: null + webm: null + ogg: null + + @html5Sources.mp4 = mp4Source if (typeof mp4Source is "string") and (mp4Source.length > 0) + @html5Sources.webm = webmSource if (typeof webmSource is "string") and (webmSource.length > 0) + @html5Sources.ogg = oggSource if (typeof oggSource is "string") and (oggSource.length > 0) parseSpeed: -> - @setSpeed($.cookie('video_speed')) @speeds = ($.map @videos, (url, speed) -> speed).sort() + @setSpeed($.cookie('video_speed')) - setSpeed: (newSpeed) -> - if @videos[newSpeed] != undefined + VideoAlpha::setSpeed = (newSpeed) -> + if @speeds.indexOf(newSpeed) isnt -1 @speed = newSpeed - $.cookie('video_speed', "#{newSpeed}", expires: 3650, path: '/') + $.cookie "video_speed", "" + newSpeed, + expires: 3650 + path: "/" else - @speed = '1.0' + @speed = "1.0" embed: -> @player = new VideoPlayer video: this @@ -55,9 +92,14 @@ class @Video getDuration: -> @metadata[@youtubeId()].duration - log: (eventName) -> - Logger.log eventName, + VideoAlpha::log = (eventName) -> + logInfo = id: @id code: @youtubeId() currentTime: @player.currentTime speed: @speed + + if @videoType is "youtube" + logInfo.code = @youtubeId() + else logInfo.code = "html5" if @videoType is "html5" + Logger.log eventName, logInfo diff --git a/common/lib/xmodule/xmodule/js/src/videoalpha/display/html5_video.js b/common/lib/xmodule/xmodule/js/src/videoalpha/display/html5_video.js new file mode 100644 index 0000000000..3db8bb97ed --- /dev/null +++ b/common/lib/xmodule/xmodule/js/src/videoalpha/display/html5_video.js @@ -0,0 +1,196 @@ +console.log('We are in "html5_video.js" script.'); + +this.HTML5Video = (function () { + var HTML5Video = {}; + + HTML5Video.Player = (function () { + + /* + * Constructor function for HTML5 Video player. + * + * @el - A DOM element where the HTML5 player will be inserted (as returned by jQuery(selector) function), + * or a selector string which will be used to select an element. This is a required parameter. + * + * @config - An object whose properties will be used as configuration options for the HTML5 video + * player. This is an optional parameter. In the case if this parameter is missing, or some of the config + * object's properties are missing, defaults will be used. The available options (and their defaults) are as + * follows: + * + * config = { + * 'width': 640, + * + * 'height': 390, + * + * 'videoSources': null, // An object of with properties being video sources. The property name is the + * // video format of the source. Supported video formats are: 'mp4', 'webm', and + * // 'ogg'. By default videoSources property is null. This means that the + * // player will initialize, and not play anything. If you do not provide a + * // 'videoSource' option, you can later call loadVideoBySource() method to load + * // a video and start playing it. + * + * 'playerVars': { // Object's properties identify player parameters. + * + * 'controls': 1, // Possible values: 0, or 1. Value of 1 will enable the default browser video + * // controls. + * + * 'start': null, // Possible values: positive integer. Position from which to start playing the + * // video. Measured in seconds. If value is null, or 'start' property is not + * // specified, the video will start playing from the beginning. + * + * 'end': null // Possible values: positive integer. Position when to stop playing the + * // video. Measured in seconds. If value is null, or 'end' property is not + * // specified, the video will end playing at the end. + * + * }, + * + * 'events': { // Object's properties identify the events that the API fires, and the + * // functions (event listeners) that the API will call when those events occur. + * // If value is null, or property is not specified, then no callback will be + * // called for that event. + * + * 'onReady': null, + * 'onStateChange': null, + * 'onPlaybackQualityChange': null + * } + * } + */ + function Player(el, config) { + console.log('We are inside HTML5Video.Player constructor.'); + + if (typeof el === 'string') { + this.el = $(el); + } else if ($.isPlainObject(el) === true) { + this.el = el; + } else { + // Error. el parameter is required. + + // TODO: Make sure that nothing breaks if one of the methods available via this object's prototype + // is called after we return. + + return; + } + + console.log('We got a proper DOM element.'); + + if ($.isPlainObject(config) === true) { + this.config = config; + } else { + this.config = { + 'width': 640, + 'height': 390, + 'videoSource': '', + 'playerVars': { + 'controls': 1, + 'start': null, + 'end': null + }, + 'events': { + 'onReady': null, + 'onStateChange': null, + 'onPlaybackQualityChange': null + } + }; + } + + console.log('The config is:'); + console.log(this.config); + } + + /* + * This function returns the quality of the video. Possible return values are (type String) + * + * highres + * hd1080 + * hd720 + * large + * medium + * small + * + * It returns undefined if there is no current video. + * + * If there is a current video, but it is impossible to determine it's quality, the function will return + * 'medium'. + */ + Player.prototype.getPlayBackQuality = function () { + if (this.config.videoSource === '') { + return undefined; + } + + // TODO: Figure out if we can get the quality of a video from a source (when it is loaded by the browser). + + return 'medium'; + }; + + /* + * The original YouTube API function player.setPlayBackQuality changed (if it was possible) the quality of the + * played video. In our case, this function will not do anything because we can't change the quality of HTML5 + * video since we only get one source of video with one quality. + */ + Player.prototype.setPlayBackQuality = function (value) { + + }; + + Player.prototype.pauseVideo = function () { + + }; + + Player.prototype.sekkTo = function () { + + }; + + // YouTube API has player.loadVideoById, but since we are working with a video source, we will rename this + // function accordingly. + Player.prototype.loadVideoBySource = function () { + + }; + + // YouTube API has player.cueVideoById, but since we are working with a video source, we will rename this + // function accordingly. + Player.prototype.cueVideoBySource = function () { + + }; + + Player.prototype.setVolume = function () { + + }; + + Player.prototype.getCurrentTime = function () { + + }; + + Player.prototype.playVideo = function () { + + }; + + Player.prototype.getPlayerState = function () { + + }; + + Player.prototype.pauseVideo = function () { + + }; + + Player.prototype.setVolume = function () { + + }; + + Player.prototype.getVolume = function () { + + }; + + return Player; + }()); + + HTML5Video.PlayerState = { + 'UNSTARTED': -1, + 'ENDED': 0, + 'PLAYING': 1, + 'PAUSED': 2, + 'BUFFERING': 3, + 'CUED': 5 + }; + + return HTML5Video; +}()); + +console.log(HTML5Video); diff --git a/common/lib/xmodule/xmodule/js/src/videoalpha/display/video_player.coffee b/common/lib/xmodule/xmodule/js/src/videoalpha/display/video_player.coffee index 22308a5568..3bee570bc8 100644 --- a/common/lib/xmodule/xmodule/js/src/videoalpha/display/video_player.coffee +++ b/common/lib/xmodule/xmodule/js/src/videoalpha/display/video_player.coffee @@ -1,7 +1,8 @@ class @VideoPlayer extends Subview initialize: -> - # Define a missing constant of Youtube API - YT.PlayerState.UNSTARTED = -1 + if @video.videoType is 'youtube' + # Define a missing constant of Youtube API + YT.PlayerState.UNSTARTED = -1 @currentTime = 0 @el = $("#video_#{@video.id}") @@ -25,6 +26,7 @@ class @VideoPlayer extends Subview @toggleFullScreen(event) render: -> + console.log '1.1' @control = new VideoControl el: @$('.video-controls') @qualityControl = new VideoQualityControl el: @$('.secondary-controls') @caption = new VideoCaption @@ -34,6 +36,7 @@ class @VideoPlayer extends Subview captionAssetPath: @video.caption_asset_path unless onTouchBasedDevice() @volumeControl = new VideoVolumeControl el: @$('.secondary-controls') + console.log '1.2' @speedControl = new VideoSpeedControl el: @$('.secondary-controls'), speeds: @video.speeds, currentSpeed: @currentSpeed() @progressSlider = new VideoProgressSlider el: @$('.slider') @playerVars = @@ -43,20 +46,31 @@ class @VideoPlayer extends Subview showinfo: 0 enablejsapi: 1 modestbranding: 1 + console.log '1.3' if @video.start @playerVars.start = @video.start @playerVars.wmode = 'window' if @video.end # work in AS3, not HMLT5. but iframe use AS3 @playerVars.end = @video.end + console.log '1.4' - @player = new YT.Player @video.id, - playerVars: @playerVars - videoId: @video.youtubeId() - events: - onReady: @onReady - onStateChange: @onStateChange - onPlaybackQualityChange: @onPlaybackQualityChange + if @video.videoType is 'html5' + @player = new HTML5Video.Player @video.id, + playerVars: @playerVars, + videoSources: @video.html5Sources, + events: + onReady: @onReady + onStateChange: @onStateChange + onPlaybackQualityChange: @onPlaybackQualityChange + else if @video.videoType is 'youtube' + @player = new YT.Player @video.id, + playerVars: @playerVars + videoId: @video.youtubeId() + events: + onReady: @onReady + onStateChange: @onStateChange + onPlaybackQualityChange: @onPlaybackQualityChange @caption.hideCaptions(@['video'].hide_captions) addToolTip: -> diff --git a/common/lib/xmodule/xmodule/videoalpha_module.py b/common/lib/xmodule/xmodule/videoalpha_module.py index e41f9783e4..912505d0a6 100644 --- a/common/lib/xmodule/xmodule/videoalpha_module.py +++ b/common/lib/xmodule/xmodule/videoalpha_module.py @@ -19,11 +19,13 @@ import time log = logging.getLogger(__name__) -class VideoModule(XModule): +class VideoAlphaModule(XModule): video_time = 0 icon_class = 'video' - js = {'coffee': + js = { + 'js': [resource_string(__name__, 'js/src/videoalpha/display/html5_video.js')], + 'coffee': [resource_string(__name__, 'js/src/time.coffee'), resource_string(__name__, 'js/src/videoalpha/display.coffee')] + [resource_string(__name__, 'js/src/videoalpha/display/' + filename) @@ -31,7 +33,7 @@ class VideoModule(XModule): in sorted(resource_listdir(__name__, 'js/src/videoalpha/display')) if filename.endswith('.coffee')]} css = {'scss': [resource_string(__name__, 'css/videoalpha/display.scss')]} - js_module_name = "Video" + js_module_name = "VideoAlpha" def __init__(self, system, location, definition, descriptor, instance_state=None, shared_state=None, **kwargs): @@ -145,6 +147,6 @@ class VideoModule(XModule): class VideoAlphaDescriptor(RawDescriptor): - module_class = VideoModule + module_class = VideoAlphaModule stores_state = True template_dir_name = "videoalpha" diff --git a/lms/templates/videoalpha.html b/lms/templates/videoalpha.html index 6cee9ed39b..58704ed6b1 100644 --- a/lms/templates/videoalpha.html +++ b/lms/templates/videoalpha.html @@ -2,11 +2,24 @@