diff --git a/cms/static/sass/elements/_xmodules.scss b/cms/static/sass/elements/_xmodules.scss index a8ec208b02..db1a50b40c 100644 --- a/cms/static/sass/elements/_xmodules.scss +++ b/cms/static/sass/elements/_xmodules.scss @@ -2,7 +2,7 @@ // ==================== // Video Alpha -.xmodule_VideoAlphaModule { +.xmodule_VideoModule { // display mode &.xmodule_display { diff --git a/cms/templates/widgets/videoalpha/codemirror-edit.html b/cms/templates/widgets/video/codemirror-edit.html similarity index 100% rename from cms/templates/widgets/videoalpha/codemirror-edit.html rename to cms/templates/widgets/video/codemirror-edit.html diff --git a/cms/templates/widgets/videoalpha/subtitles.html b/cms/templates/widgets/video/subtitles.html similarity index 100% rename from cms/templates/widgets/videoalpha/subtitles.html rename to cms/templates/widgets/video/subtitles.html diff --git a/common/lib/xmodule/xmodule/css/video/display.scss b/common/lib/xmodule/xmodule/css/video/display.scss index 879aee3f72..533ab2aec0 100644 --- a/common/lib/xmodule/xmodule/css/video/display.scss +++ b/common/lib/xmodule/xmodule/css/video/display.scss @@ -10,11 +10,30 @@ div.video { padding: 12px; border-radius: 5px; + div.tc-wrapper { + position: relative; + @include clearfix; + } + article.video-wrapper { float: left; margin-right: flex-gutter(9); width: flex-grid(6, 9); + background-color: black; + + position: relative; + + div.video-player-pre { + height: 50px; + background-color: black; + } + + div.video-player-post { + height: 50px; + background-color: black; + } + section.video-player { height: 0; overflow: hidden; @@ -52,10 +71,19 @@ div.video { border-radius: 0; border-top: 1px solid #000; box-shadow: inset 0 1px 0 #eee, 0 1px 0 #555; - height: 7px; + position: absolute; + z-index: 1; + bottom: 100%; + left: 0; + right: 0; + height: 14px; margin-left: -1px; margin-right: -1px; - @include transition(height 2.0s ease-in-out 0s); + -webkit-transition: -webkit-transform 0.7s ease-in-out; + -moz-transition: -moz-transform 0.7s ease-in-out; + -ms-transition: -ms-transform 0.7s ease-in-out; + transition: transform 0.7s ease-in-out; + @include transform(scaleY(0.5) translate3d(0, 50%, 0)); div.ui-widget-header { background: #777; @@ -66,14 +94,18 @@ div.video { background: $pink url(../images/slider-handle.png) center center no-repeat; background-size: 50%; border: 1px solid darken($pink, 20%); - border-radius: 15px; + border-radius: 50%; box-shadow: inset 0 1px 0 lighten($pink, 10%); cursor: pointer; - height: 15px; - margin-left: -7px; - top: -4px; - @include transition(height 2.0s ease-in-out 0s, width 2.0s ease-in-out 0s); - width: 15px; + height: 20px; + margin-left: 0; + top: 0; + -webkit-transition: -webkit-transform 0.7s ease-in-out; + -moz-transition: -moz-transform 0.7s ease-in-out; + -ms-transition: -ms-transform 0.7s ease-in-out; + transition: transform 0.7s ease-in-out; + @include transform(scale(.7, 1.3) translate3d(-80%, -15%, 0)); + width: 20px; &:focus, &:hover { background-color: lighten($pink, 10%); @@ -101,7 +133,6 @@ div.video { line-height: 46px; padding: 0 lh(.75); text-indent: -9999px; - @include transition(background-color 0.75s linear 0s, opacity 0.75s linear 0s); width: 14px; background: url('../images/vcr.png') 15px 15px no-repeat; outline: 0; @@ -118,7 +149,7 @@ div.video { &.play { background-position: 17px -114px; - &:hover { + &:hover, &:focus { background-color: #444; } } @@ -126,7 +157,7 @@ div.video { &.pause { background-position: 16px -50px; - &:hover { + &:hover, &:focus { background-color: #444; } } @@ -213,7 +244,7 @@ div.video { // fix for now ol.video_speeds { - box-shadow: inset 1px 0 0 #555, 0 3px 0 #444; + box-shadow: inset 1px 0 0 #555, 0 4px 0 #444; @include transition(none); background-color: #444; border: 1px solid #000; @@ -221,7 +252,7 @@ div.video { display: none; opacity: 0.0; position: absolute; - width: 133px; + width: 131px; z-index: 10; li { @@ -268,12 +299,15 @@ div.video { &.muted { &>a { - background: url('../images/mute.png') 10px center no-repeat; + background-image: url('../images/mute.png'); } } > a { - background: url('../images/volume.png') 10px center no-repeat; + background-image: url('../images/volume.png'); + background-position: 10px center; + background-repeat: no-repeat; + border-right: 1px solid #000; box-shadow: 1px 0 0 #555, inset 1px 0 0 #555; @include clearfix(); @@ -350,7 +384,7 @@ div.video { @include transition(none); width: 30px; - &:hover { + &:hover, &:active, &:focus { background-color: #444; color: #fff; text-decoration: none; @@ -362,7 +396,7 @@ div.video { border-right: 1px solid #000; box-shadow: 1px 0 0 #555, inset 1px 0 0 #555; color: #797979; - display: block; + display: none; float: left; line-height: 46px; //height of play pause buttons margin-left: 0; @@ -371,7 +405,7 @@ div.video { @include transition(none); width: 30px; - &:hover { + &:hover, &:focus { background-color: #444; color: #fff; text-decoration: none; @@ -387,8 +421,6 @@ div.video { a.hide-subtitles { background: url('../images/cc.png') center no-repeat; - color: #797979; - display: block; float: left; font-weight: 800; line-height: 46px; //height of play pause buttons @@ -401,7 +433,7 @@ div.video { -webkit-font-smoothing: antialiased; width: 30px; - &:hover { + &:hover, &:focus { background-color: #444; color: #fff; text-decoration: none; @@ -410,6 +442,8 @@ div.video { &.off { opacity: 0.7; } + + color: #797979; } } } @@ -420,15 +454,10 @@ div.video { } div.slider { - height: 14px; - margin-top: -7px; + @include transform(scaleY(1) translate3d(0, 0, 0)); a.ui-slider-handle { - border-radius: 20px; - height: 20px; - margin-left: -10px; - top: -4px; - width: 20px; + @include transform(scale(1) translate3d(-50%, -15%, 0)); } } } @@ -471,22 +500,47 @@ div.video { article.video-wrapper { width: flex-grid(9,9); + + background-color: inherit; + } + + article.video-wrapper section.video-controls.html5 { + bottom: 0px; + left: 0px; + right: 0px; + position: absolute; + z-index: 1; + } + + article.video-wrapper div.video-player-pre, article.video-wrapper div.video-player-post { + height: 0px; } ol.subtitles { - width: 0; - height: 0; + width: 0; + height: 0; + } + + ol.subtitles.html5 { + background-color: rgba(243, 243, 243, 0.8); + height: 100%; + position: absolute; + right: 0; + bottom: 0; + top: 0; + width: 275px; + padding: 0 20px; + z-index: 0; } } - &.fullscreen { + &.video-fullscreen { background: rgba(#000, .95); border: 0; bottom: 0; height: 100%; left: 0; margin: 0; - overflow: hidden; padding: 0; position: fixed; top: 0; @@ -501,12 +555,22 @@ div.video { } } + article.video-wrapper div.video-player-pre, article.video-wrapper div.video-player-post { + height: 0px; + } + + article.video-wrapper { + position: static; + } + div.tc-wrapper { @include clearfix; display: table; width: 100%; height: 100%; + position: static; + article.video-wrapper { width: 100%; display: table-cell; @@ -536,7 +600,7 @@ div.video { background: rgba(#000, .8); bottom: 0; height: 100%; - max-height: 100%; + max-height: 460px; max-width: flex-grid(3); padding: lh(); position: fixed; diff --git a/common/lib/xmodule/xmodule/css/videoalpha/common_tabs_edit.scss b/common/lib/xmodule/xmodule/css/videoalpha/common_tabs_edit.scss deleted file mode 100644 index e69de29bb2..0000000000 diff --git a/common/lib/xmodule/xmodule/css/videoalpha/display.scss b/common/lib/xmodule/xmodule/css/videoalpha/display.scss deleted file mode 100644 index 93c387315a..0000000000 --- a/common/lib/xmodule/xmodule/css/videoalpha/display.scss +++ /dev/null @@ -1,620 +0,0 @@ -& { - margin-bottom: 30px; -} - -div.videoalpha { - @include clearfix(); - background: #f3f3f3; - display: block; - margin: 0 -12px; - padding: 12px; - border-radius: 5px; - - div.tc-wrapper { - position: relative; - @include clearfix; - } - - article.video-wrapper { - float: left; - margin-right: flex-gutter(9); - width: flex-grid(6, 9); - - background-color: black; - - position: relative; - - div.video-player-pre { - height: 50px; - background-color: black; - } - - div.video-player-post { - height: 50px; - background-color: black; - } - - section.video-player { - height: 0; - overflow: hidden; - padding-bottom: 56.25%; - position: relative; - - object, iframe { - border: none; - height: 100%; - left: 0; - position: absolute; - top: 0; - width: 100%; - } - } - - section.video-controls { - @include clearfix(); - background: #333; - border: 1px solid #000; - border-top: 0; - color: #ccc; - position: relative; - - &:hover { - ul, div { - opacity: 1.0; - } - } - - div.slider { - @include clearfix(); - background: #c2c2c2; - border: 1px solid #000; - border-radius: 0; - border-top: 1px solid #000; - box-shadow: inset 0 1px 0 #eee, 0 1px 0 #555; - position: absolute; - z-index: 1; - bottom: 100%; - left: 0; - right: 0; - height: 14px; - margin-left: -1px; - margin-right: -1px; - -webkit-transition: -webkit-transform 0.7s ease-in-out; - -moz-transition: -moz-transform 0.7s ease-in-out; - -ms-transition: -ms-transform 0.7s ease-in-out; - transition: transform 0.7s ease-in-out; - @include transform(scaleY(0.5) translate3d(0, 50%, 0)); - - div.ui-widget-header { - background: #777; - box-shadow: inset 0 1px 0 #999; - } - - a.ui-slider-handle { - background: $pink url(../images/slider-handle.png) center center no-repeat; - background-size: 50%; - border: 1px solid darken($pink, 20%); - border-radius: 50%; - box-shadow: inset 0 1px 0 lighten($pink, 10%); - cursor: pointer; - height: 20px; - margin-left: 0; - top: 0; - -webkit-transition: -webkit-transform 0.7s ease-in-out; - -moz-transition: -moz-transform 0.7s ease-in-out; - -ms-transition: -ms-transform 0.7s ease-in-out; - transition: transform 0.7s ease-in-out; - @include transform(scale(.7, 1.3) translate3d(-80%, -15%, 0)); - width: 20px; - - &:focus, &:hover { - background-color: lighten($pink, 10%); - outline: none; - } - } - } - - ul.vcr { - float: left; - list-style: none; - margin: 0 lh() 0 0; - padding: 0; - - li { - float: left; - margin-bottom: 0; - - a { - border-bottom: none; - border-right: 1px solid #000; - box-shadow: 1px 0 0 #555; - cursor: pointer; - display: block; - line-height: 46px; - padding: 0 lh(.75); - text-indent: -9999px; - width: 14px; - background: url('../images/vcr.png') 15px 15px no-repeat; - outline: 0; - - &:focus { - outline: 0; - } - - &:empty { - height: 46px; - background: url('../images/vcr.png') 15px 15px no-repeat; - } - - &.play { - background-position: 17px -114px; - - &:hover, &:focus { - background-color: #444; - } - } - - &.pause { - background-position: 16px -50px; - - &:hover, &:focus { - background-color: #444; - } - } - } - - div.vidtime { - padding-left: lh(.75); - font-weight: bold; - line-height: 46px; //height of play pause buttons - padding-left: lh(.75); - -webkit-font-smoothing: antialiased; - } - } - } - - div.secondary-controls { - float: right; - - div.speeds { - float: left; - position: relative; - - &.open { - &>a { - background: url('../images/open-arrow.png') 10px center no-repeat; - } - - ol.video_speeds { - display: block; - opacity: 1.0; - padding: 0; - margin: 0; - list-style: none; - } - } - - &>a { - background: url('../images/closed-arrow.png') 10px center no-repeat; - border-left: 1px solid #000; - border-right: 1px solid #000; - box-shadow: 1px 0 0 #555, inset 1px 0 0 #555; - @include clearfix(); - color: #fff; - cursor: pointer; - display: block; - line-height: 46px; //height of play pause buttons - margin-right: 0; - padding-left: 15px; - position: relative; - @include transition(none); - -webkit-font-smoothing: antialiased; - width: 116px; - outline: 0; - - &:focus { - outline: 0; - } - - h3 { - color: #999; - float: left; - font-size: em(14); - font-weight: normal; - letter-spacing: 1px; - padding: 0 lh(.25) 0 lh(.5); - line-height: 46px; - text-transform: uppercase; - } - - p.active { - float: left; - font-weight: bold; - margin-bottom: 0; - padding: 0 lh(.5) 0 0; - line-height: 46px; - color: #fff; - } - - &:hover, &:active, &:focus { - opacity: 1.0; - background-color: #444; - } - } - - // fix for now - ol.video_speeds { - box-shadow: inset 1px 0 0 #555, 0 4px 0 #444; - @include transition(none); - background-color: #444; - border: 1px solid #000; - bottom: 46px; - display: none; - opacity: 0.0; - position: absolute; - width: 131px; - z-index: 10; - - li { - box-shadow: 0 1px 0 #555; - border-bottom: 1px solid #000; - color: #fff; - cursor: pointer; - - a { - border: 0; - color: #fff; - display: block; - padding: lh(.5); - - &:hover { - background-color: #666; - color: #aaa; - } - } - - &.active { - font-weight: bold; - } - - &:last-child { - box-shadow: none; - border-bottom: 0; - margin-top: 0; - } - } - } - } - - div.volume { - float: left; - position: relative; - - &.open { - .volume-slider-container { - display: block; - opacity: 1.0; - } - } - - &.muted { - &>a { - background-image: url('../images/mute.png'); - } - } - - > a { - background-image: url('../images/volume.png'); - background-position: 10px center; - background-repeat: no-repeat; - - border-right: 1px solid #000; - box-shadow: 1px 0 0 #555, inset 1px 0 0 #555; - @include clearfix(); - color: #fff; - cursor: pointer; - display: block; - height: 46px; - margin-right: 0; - padding-left: 15px; - position: relative; - @include transition(none); - -webkit-font-smoothing: antialiased; - width: 30px; - - &:hover, &:active, &:focus { - background-color: #444; - } - } - - .volume-slider-container { - box-shadow: inset 1px 0 0 #555, 0 3px 0 #444; - @include transition(none); - background-color: #444; - border: 1px solid #000; - bottom: 46px; - display: none; - opacity: 0.0; - position: absolute; - width: 45px; - height: 125px; - margin-left: -1px; - z-index: 10; - - .volume-slider { - height: 100px; - border: 0; - width: 5px; - margin: 14px auto; - background: #666; - border: 1px solid #000; - box-shadow: 0 1px 0 #333; - - a.ui-slider-handle { - background: $pink url(../images/slider-handle.png) center center no-repeat; - background-size: 50%; - border: 1px solid darken($pink, 20%); - border-radius: 15px; - box-shadow: inset 0 1px 0 lighten($pink, 10%); - cursor: pointer; - height: 15px; - left: -6px; - @include transition(height 2.0s ease-in-out 0s, width 2.0s ease-in-out 0s); - width: 15px; - } - - .ui-slider-range { - background: #ddd; - } - } - } - } - - a.add-fullscreen { - background: url(../images/fullscreen.png) center no-repeat; - border-right: 1px solid #000; - box-shadow: 1px 0 0 #555, inset 1px 0 0 #555; - color: #797979; - display: block; - float: left; - line-height: 46px; //height of play pause buttons - margin-left: 0; - padding: 0 lh(.5); - text-indent: -9999px; - @include transition(none); - width: 30px; - - &:hover, &:active, &:focus { - background-color: #444; - color: #fff; - text-decoration: none; - } - } - - a.quality_control { - background: url(../images/hd.png) center no-repeat; - border-right: 1px solid #000; - box-shadow: 1px 0 0 #555, inset 1px 0 0 #555; - color: #797979; - display: none; - float: left; - line-height: 46px; //height of play pause buttons - margin-left: 0; - padding: 0 lh(.5); - text-indent: -9999px; - @include transition(none); - width: 30px; - - &:hover, &:focus { - background-color: #444; - color: #fff; - text-decoration: none; - } - - &.active { - background-color: #F44; - color: #0ff; - text-decoration: none; - } - } - - - a.hide-subtitles { - background: url('../images/cc.png') center no-repeat; - float: left; - font-weight: 800; - line-height: 46px; //height of play pause buttons - margin-left: 0; - opacity: 1.0; - padding: 0 lh(.5); - position: relative; - text-indent: -9999px; - @include transition(none); - -webkit-font-smoothing: antialiased; - width: 30px; - - &:hover, &:focus { - background-color: #444; - color: #fff; - text-decoration: none; - } - - &.off { - opacity: 0.7; - } - - color: #797979; - } - } - } - - &:hover section.video-controls { - ul, div { - opacity: 1.0; - } - - div.slider { - @include transform(scaleY(1) translate3d(0, 0, 0)); - - a.ui-slider-handle { - @include transform(scale(1) translate3d(-50%, -15%, 0)); - } - } - } - } - - ol.subtitles { - padding-left: 0; - float: left; - max-height: 460px; - overflow: auto; - width: flex-grid(3, 9); - margin: 0; - font-size: 14px; - list-style: none; - - li { - border: 0; - color: #666; - cursor: pointer; - margin-bottom: 8px; - padding: 0; - line-height: lh(); - - &.current { - color: #333; - font-weight: 700; - } - - &:hover { - color: $blue; - } - - &:empty { - margin-bottom: 0px; - } - } - } - - &.closed { - - article.video-wrapper { - width: flex-grid(9,9); - - background-color: inherit; - } - - article.video-wrapper section.video-controls.html5 { - bottom: 0px; - left: 0px; - right: 0px; - position: absolute; - z-index: 1; - } - - article.video-wrapper div.video-player-pre, article.video-wrapper div.video-player-post { - height: 0px; - } - - ol.subtitles { - width: 0; - height: 0; - } - - ol.subtitles.html5 { - background-color: rgba(243, 243, 243, 0.8); - height: 100%; - position: absolute; - right: 0; - bottom: 0; - top: 0; - width: 275px; - padding: 0 20px; - z-index: 0; - } - } - - &.video-fullscreen { - background: rgba(#000, .95); - border: 0; - bottom: 0; - height: 100%; - left: 0; - margin: 0; - padding: 0; - position: fixed; - top: 0; - width: 100%; - z-index: 999; - vertical-align: middle; - - &.closed { - ol.subtitles { - right: -(flex-grid(4)); - width: auto; - } - } - - article.video-wrapper div.video-player-pre, article.video-wrapper div.video-player-post { - height: 0px; - } - - article.video-wrapper { - position: static; - } - - div.tc-wrapper { - @include clearfix; - display: table; - width: 100%; - height: 100%; - - position: static; - - article.video-wrapper { - width: 100%; - display: table-cell; - vertical-align: middle; - float: none; - } - - object, iframe { - bottom: 0; - height: 100%; - left: 0; - overflow: hidden; - position: fixed; - top: 0; - } - - section.video-controls { - bottom: 0; - left: 0; - position: absolute; - width: 100%; - z-index: 9999; - } - } - - ol.subtitles { - background: rgba(#000, .8); - bottom: 0; - height: 100%; - max-height: 460px; - max-width: flex-grid(3); - padding: lh(); - position: fixed; - right: 0; - top: 0; - @include transition(none); - - li { - color: #aaa; - - &.current { - color: #fff; - } - } - } - } -} diff --git a/common/lib/xmodule/xmodule/js/fixtures/video_all.html b/common/lib/xmodule/xmodule/js/fixtures/video_all.html index a98e2bf0a2..25a3c2c0ab 100644 --- a/common/lib/xmodule/xmodule/js/fixtures/video_all.html +++ b/common/lib/xmodule/xmodule/js/fixtures/video_all.html @@ -3,7 +3,7 @@
- @el = $(element).find('.video') - @id = @el.attr('id').replace(/video_/, '') - @start = @el.data('start') - @end = @el.data('end') - @caption_asset_path = @el.data('caption-asset-path') - @show_captions = @el.data('show-captions') - window.player = null - @el = $("#video_#{@id}") - @parseVideos() - @fetchMetadata() - @parseSpeed() - $("#video_#{@id}").data('video', this).addClass('video-load-complete') - - @hide_captions = $.cookie('hide_captions') == 'true' or (not @show_captions) - - if YT.Player - @embed() - else - window.onYouTubePlayerAPIReady = => - @el.each -> - $(this).data('video').embed() - - youtubeId: (speed)-> - @videos[speed || @speed] - - parseVideos: (videos) -> - @videos = {} - if @el.data('youtube-id-0-75') - @videos['0.75'] = @el.data('youtube-id-0-75') - if @el.data('youtube-id-1-0') - @videos['1.0'] = @el.data('youtube-id-1-0') - if @el.data('youtube-id-1-25') - @videos['1.25'] = @el.data('youtube-id-1-25') - if @el.data('youtube-id-1-5') - @videos['1.50'] = @el.data('youtube-id-1-5') - - parseSpeed: -> - @setSpeed($.cookie('video_speed')) - @speeds = ($.map @videos, (url, speed) -> speed).sort() - - setSpeed: (newSpeed) -> - if @videos[newSpeed] != undefined - @speed = newSpeed - $.cookie('video_speed', "#{newSpeed}", expires: 3650, path: '/') - else - @speed = '1.0' - - embed: -> - @player = new VideoPlayer video: this - - fetchMetadata: (url) -> - @metadata = {} - $.each @videos, (speed, url) => - $.get "https://gdata.youtube.com/feeds/api/videos/#{url}?v=2&alt=jsonc", ((data) => @metadata[data.data.id] = data.data) , 'jsonp' - - getDuration: -> - @metadata[@youtubeId()].duration - - log: (eventName) -> - Logger.log eventName, - id: @id - code: @youtubeId() - currentTime: @player.currentTime - speed: @speed diff --git a/common/lib/xmodule/xmodule/js/src/video/display/_subview.coffee b/common/lib/xmodule/xmodule/js/src/video/display/_subview.coffee deleted file mode 100644 index 2e14289843..0000000000 --- a/common/lib/xmodule/xmodule/js/src/video/display/_subview.coffee +++ /dev/null @@ -1,14 +0,0 @@ -class @Subview - constructor: (options) -> - $.each options, (key, value) => - @[key] = value - @initialize() - @render() - @bind() - - $: (selector) -> - $(selector, @el) - - initialize: -> - render: -> - bind: -> diff --git a/common/lib/xmodule/xmodule/js/src/video/display/video_caption.coffee b/common/lib/xmodule/xmodule/js/src/video/display/video_caption.coffee deleted file mode 100644 index c72067b0dc..0000000000 --- a/common/lib/xmodule/xmodule/js/src/video/display/video_caption.coffee +++ /dev/null @@ -1,155 +0,0 @@ -class @VideoCaption extends Subview - initialize: -> - @loaded = false - - bind: -> - $(window).bind('resize', @resize) - @$('.hide-subtitles').click @toggle - @$('.subtitles').mouseenter(@onMouseEnter).mouseleave(@onMouseLeave) - .mousemove(@onMovement).bind('mousewheel', @onMovement) - .bind('DOMMouseScroll', @onMovement) - - captionURL: -> - "#{@captionAssetPath}#{@youtubeId}.srt.sjson" - - render: -> - # TODO: make it so you can have a video with no captions. - #@$('.video-wrapper').after """ - #
  1. Attempting to load captions...
- # """ - @$('.video-wrapper').after """ -
    - """ - @$('.video-controls .secondary-controls').append """ - Captions - """#" - @$('.subtitles').css maxHeight: @$('.video-wrapper').height() - 5 - @fetchCaption() - - fetchCaption: -> - $.ajaxWithPrefix - url: @captionURL() - notifyOnError: false - success: (captions) => - @captions = captions.text - @start = captions.start - - @loaded = true - - if onTouchBasedDevice() - $('.subtitles').html "
  1. Caption will be displayed when you start playing the video.
  2. " - else - @renderCaption() - - renderCaption: -> - container = $('
      ') - - $.each @captions, (index, text) => - container.append $('
    1. ').html(text).attr - 'data-index': index - 'data-start': @start[index] - - @$('.subtitles').html(container.html()) - @$('.subtitles li[data-index]').click @seekPlayer - - # prepend and append an empty
    2. for cosmetic reason - @$('.subtitles').prepend($('
    3. ').height(@topSpacingHeight())) - .append($('
    4. ').height(@bottomSpacingHeight())) - - @rendered = true - - search: (time) -> - if @loaded - min = 0 - max = @start.length - 1 - - while min < max - index = Math.ceil((max + min) / 2) - if time < @start[index] - max = index - 1 - if time >= @start[index] - min = index - return min - - play: -> - if @loaded - @renderCaption() unless @rendered - @playing = true - - pause: -> - if @loaded - @playing = false - - updatePlayTime: (time) -> - if @loaded - # This 250ms offset is required to match the video speed - time = Math.round(Time.convert(time, @currentSpeed, '1.0') * 1000 + 250) - newIndex = @search time - - if newIndex != undefined && @currentIndex != newIndex - if @currentIndex - @$(".subtitles li.current").removeClass('current') - @$(".subtitles li[data-index='#{newIndex}']").addClass('current') - - @currentIndex = newIndex - @scrollCaption() - - resize: => - @$('.subtitles').css maxHeight: @captionHeight() - @$('.subtitles .spacing:first').height(@topSpacingHeight()) - @$('.subtitles .spacing:last').height(@bottomSpacingHeight()) - @scrollCaption() - - onMouseEnter: => - clearTimeout @frozen if @frozen - @frozen = setTimeout @onMouseLeave, 10000 - - onMovement: => - @onMouseEnter() - - onMouseLeave: => - clearTimeout @frozen if @frozen - @frozen = null - @scrollCaption() if @playing - - scrollCaption: -> - if !@frozen && @$('.subtitles .current:first').length - @$('.subtitles').scrollTo @$('.subtitles .current:first'), - offset: - @calculateOffset(@$('.subtitles .current:first')) - - seekPlayer: (event) => - event.preventDefault() - time = Math.round(Time.convert($(event.target).data('start'), '1.0', @currentSpeed) / 1000) - $(@).trigger('seek', time) - - calculateOffset: (element) -> - @captionHeight() / 2 - element.height() / 2 - - topSpacingHeight: -> - @calculateOffset(@$('.subtitles li:not(.spacing):first')) - - bottomSpacingHeight: -> - @calculateOffset(@$('.subtitles li:not(.spacing):last')) - - toggle: (event) => - event.preventDefault() - if @el.hasClass('closed') # Captions are "closed" e.g. turned off - @hideCaptions(false) - else # Captions are on - @hideCaptions(true) - - hideCaptions: (hide_captions) => - if hide_captions - @$('.hide-subtitles').attr('title', 'Turn on captions') - @el.addClass('closed') - else - @$('.hide-subtitles').attr('title', 'Turn off captions') - @el.removeClass('closed') - @scrollCaption() - $.cookie('hide_captions', hide_captions, expires: 3650, path: '/') - - captionHeight: -> - if @el.hasClass('fullscreen') - $(window).height() - @$('.video-controls').height() - else - @$('.video-wrapper').height() diff --git a/common/lib/xmodule/xmodule/js/src/video/display/video_control.coffee b/common/lib/xmodule/xmodule/js/src/video/display/video_control.coffee deleted file mode 100644 index 856549c3e2..0000000000 --- a/common/lib/xmodule/xmodule/js/src/video/display/video_control.coffee +++ /dev/null @@ -1,35 +0,0 @@ -class @VideoControl extends Subview - bind: -> - @$('.video_control').click @togglePlayback - - render: -> - @el.append """ -
      -
      -
        -
      • -
      • -
        0:00 / 0:00
        -
      • -
      - -
      - """#" - - unless onTouchBasedDevice() - @$('.video_control').addClass('play').html('Play') - - play: -> - @$('.video_control').removeClass('play').addClass('pause').html('Pause') - - pause: -> - @$('.video_control').removeClass('pause').addClass('play').html('Play') - - togglePlayback: (event) => - event.preventDefault() - if @$('.video_control').hasClass('play') - $(@).trigger('play') - else if @$('.video_control').hasClass('pause') - $(@).trigger('pause') diff --git a/common/lib/xmodule/xmodule/js/src/video/display/video_player.coffee b/common/lib/xmodule/xmodule/js/src/video/display/video_player.coffee deleted file mode 100644 index 73ff3512e2..0000000000 --- a/common/lib/xmodule/xmodule/js/src/video/display/video_player.coffee +++ /dev/null @@ -1,180 +0,0 @@ -class @VideoPlayer extends Subview - initialize: -> - # Define a missing constant of Youtube API - YT.PlayerState.UNSTARTED = -1 - - @currentTime = 0 - @el = $("#video_#{@video.id}") - - bind: -> - $(@control).bind('play', @play) - .bind('pause', @pause) - $(@qualityControl).bind('changeQuality', @handlePlaybackQualityChange) - $(@caption).bind('seek', @onSeek) - $(@speedControl).bind('speedChange', @onSpeedChange) - $(@progressSlider).bind('seek', @onSeek) - if @volumeControl - $(@volumeControl).bind('volumeChange', @onVolumeChange) - $(document.documentElement).keyup @bindExitFullScreen - - @$('.add-fullscreen').click @toggleFullScreen - @addToolTip() unless onTouchBasedDevice() - - bindExitFullScreen: (event) => - if @el.hasClass('fullscreen') && event.keyCode == 27 - @toggleFullScreen(event) - - render: -> - @control = new VideoControl el: @$('.video-controls') - @qualityControl = new VideoQualityControl el: @$('.secondary-controls') - @caption = new VideoCaption - el: @el - youtubeId: @video.youtubeId('1.0') - currentSpeed: @currentSpeed() - captionAssetPath: @video.caption_asset_path - unless onTouchBasedDevice() - @volumeControl = new VideoVolumeControl el: @$('.secondary-controls') - @speedControl = new VideoSpeedControl el: @$('.secondary-controls'), speeds: @video.speeds, currentSpeed: @currentSpeed() - @progressSlider = new VideoProgressSlider el: @$('.slider') - @playerVars = - controls: 0 - wmode: 'transparent' - rel: 0 - showinfo: 0 - enablejsapi: 1 - modestbranding: 1 - 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 - - @player = new YT.Player @video.id, - playerVars: @playerVars - videoId: @video.youtubeId() - events: - onReady: @onReady - onStateChange: @onStateChange - onPlaybackQualityChange: @onPlaybackQualityChange - @caption.hideCaptions(@['video'].hide_captions) - - addToolTip: -> - @$('.add-fullscreen, .hide-subtitles').qtip - position: - my: 'top right' - at: 'top center' - - onReady: (event) => - unless onTouchBasedDevice() or $('.video:first').data('autoplay') == 'False' - $('.video-load-complete:first').data('video').player.play() - - onStateChange: (event) => - switch event.data - when YT.PlayerState.UNSTARTED - @onUnstarted() - when YT.PlayerState.PLAYING - @onPlay() - when YT.PlayerState.PAUSED - @onPause() - when YT.PlayerState.ENDED - @onEnded() - - onPlaybackQualityChange: (event, value) => - quality = @player.getPlaybackQuality() - @qualityControl.onQualityChange(quality) - - handlePlaybackQualityChange: (event, value) => - @player.setPlaybackQuality(value) - - onUnstarted: => - @control.pause() - @caption.pause() - - onPlay: => - @video.log 'play_video' - window.player.pauseVideo() if window.player && window.player != @player - window.player = @player - unless @player.interval - @player.interval = setInterval(@update, 200) - @caption.play() - @control.play() - @progressSlider.play() - - onPause: => - @video.log 'pause_video' - window.player = null if window.player == @player - clearInterval(@player.interval) - @player.interval = null - @caption.pause() - @control.pause() - - onEnded: => - @control.pause() - @caption.pause() - - onSeek: (event, time) => - @player.seekTo(time, true) - if @isPlaying() - clearInterval(@player.interval) - @player.interval = setInterval(@update, 200) - else - @currentTime = time - @updatePlayTime time - - onSpeedChange: (event, newSpeed) => - @currentTime = Time.convert(@currentTime, parseFloat(@currentSpeed()), newSpeed) - newSpeed = parseFloat(newSpeed).toFixed(2).replace /\.00$/, '.0' - @video.setSpeed(newSpeed) - @caption.currentSpeed = newSpeed - - if @isPlaying() - @player.loadVideoById(@video.youtubeId(), @currentTime) - else - @player.cueVideoById(@video.youtubeId(), @currentTime) - @updatePlayTime @currentTime - - onVolumeChange: (event, volume) => - @player.setVolume volume - - update: => - if @currentTime = @player.getCurrentTime() - @updatePlayTime @currentTime - - updatePlayTime: (time) -> - progress = Time.format(time) + ' / ' + Time.format(@duration()) - @$(".vidtime").html(progress) - @caption.updatePlayTime(time) - @progressSlider.updatePlayTime(time, @duration()) - - toggleFullScreen: (event) => - event.preventDefault() - if @el.hasClass('fullscreen') - @$('.add-fullscreen').attr('title', 'Fill browser') - @el.removeClass('fullscreen') - else - @el.addClass('fullscreen') - @$('.add-fullscreen').attr('title', 'Exit fill browser') - @caption.resize() - - # Delegates - play: => - @player.playVideo() if @player.playVideo - - isPlaying: -> - @player.getPlayerState() == YT.PlayerState.PLAYING - - pause: => - @player.pauseVideo() if @player.pauseVideo - - duration: -> - @video.getDuration() - - currentSpeed: -> - @video.speed - - volume: (value) -> - if value? - @player.setVolume value - else - @player.getVolume() diff --git a/common/lib/xmodule/xmodule/js/src/video/display/video_progress_slider.coffee b/common/lib/xmodule/xmodule/js/src/video/display/video_progress_slider.coffee deleted file mode 100644 index ef2f38698b..0000000000 --- a/common/lib/xmodule/xmodule/js/src/video/display/video_progress_slider.coffee +++ /dev/null @@ -1,49 +0,0 @@ -class @VideoProgressSlider extends Subview - initialize: -> - @buildSlider() unless onTouchBasedDevice() - - buildSlider: -> - @slider = @el.slider - range: 'min' - change: @onChange - slide: @onSlide - stop: @onStop - @buildHandle() - - buildHandle: -> - @handle = @$('.ui-slider-handle') - @handle.qtip - content: "#{Time.format(@slider.slider('value'))}" - position: - my: 'bottom center' - at: 'top center' - container: @handle - hide: - delay: 700 - style: - classes: 'ui-tooltip-slider' - widget: true - - play: => - @buildSlider() unless @slider - - updatePlayTime: (currentTime, duration) -> - if @slider && !@frozen - @slider.slider('option', 'max', duration) - @slider.slider('value', currentTime) - - onSlide: (event, ui) => - @frozen = true - @updateTooltip(ui.value) - $(@).trigger('seek', ui.value) - - onChange: (event, ui) => - @updateTooltip(ui.value) - - onStop: (event, ui) => - @frozen = true - $(@).trigger('seek', ui.value) - setTimeout (=> @frozen = false), 200 - - updateTooltip: (value)-> - @handle.qtip('option', 'content.text', "#{Time.format(value)}") diff --git a/common/lib/xmodule/xmodule/js/src/video/display/video_quality_control.coffee b/common/lib/xmodule/xmodule/js/src/video/display/video_quality_control.coffee deleted file mode 100644 index f8f6167075..0000000000 --- a/common/lib/xmodule/xmodule/js/src/video/display/video_quality_control.coffee +++ /dev/null @@ -1,26 +0,0 @@ -class @VideoQualityControl extends Subview - initialize: -> - @quality = null; - - bind: -> - @$('.quality_control').click @toggleQuality - - render: -> - @el.append """ - HD - """#" - - onQualityChange: (value) -> - @quality = value - if @quality in ['hd720', 'hd1080', 'highres'] - @el.addClass('active') - else - @el.removeClass('active') - - toggleQuality: (event) => - event.preventDefault() - if @quality in ['hd720', 'hd1080', 'highres'] - newQuality = 'large' - else - newQuality = 'hd720' - $(@).trigger('changeQuality', newQuality) \ No newline at end of file diff --git a/common/lib/xmodule/xmodule/js/src/video/display/video_speed_control.coffee b/common/lib/xmodule/xmodule/js/src/video/display/video_speed_control.coffee deleted file mode 100644 index 1d0d8b7d44..0000000000 --- a/common/lib/xmodule/xmodule/js/src/video/display/video_speed_control.coffee +++ /dev/null @@ -1,43 +0,0 @@ -class @VideoSpeedControl extends Subview - bind: -> - @$('.video_speeds a').click @changeVideoSpeed - if onTouchBasedDevice() - @$('.speeds').click (event) -> - event.preventDefault() - $(this).toggleClass('open') - else - @$('.speeds').mouseenter -> - $(this).addClass('open') - @$('.speeds').mouseleave -> - $(this).removeClass('open') - @$('.speeds').click (event) -> - event.preventDefault() - $(this).removeClass('open') - - render: -> - @el.prepend """ - - """ - - $.each @speeds, (index, speed) => - link = $('').attr(href: "#").html("#{speed}x") - @$('.video_speeds').prepend($('
    5. ').attr('data-speed', speed).html(link)) - @setSpeed(@currentSpeed) - - changeVideoSpeed: (event) => - event.preventDefault() - unless $(event.target).parent().hasClass('active') - @currentSpeed = $(event.target).parent().data('speed') - $(@).trigger 'speedChange', $(event.target).parent().data('speed') - @setSpeed(parseFloat(@currentSpeed).toFixed(2).replace /\.00$/, '.0') - - setSpeed: (speed) -> - @$('.video_speeds li').removeClass('active') - @$(".video_speeds li[data-speed='#{speed}']").addClass('active') - @$('.speeds p.active').html("#{speed}x") diff --git a/common/lib/xmodule/xmodule/js/src/video/display/video_volume_control.coffee b/common/lib/xmodule/xmodule/js/src/video/display/video_volume_control.coffee deleted file mode 100644 index 096b50042d..0000000000 --- a/common/lib/xmodule/xmodule/js/src/video/display/video_volume_control.coffee +++ /dev/null @@ -1,40 +0,0 @@ -class @VideoVolumeControl extends Subview - initialize: -> - @currentVolume = 100 - - bind: -> - @$('.volume').mouseenter -> - $(this).addClass('open') - @$('.volume').mouseleave -> - $(this).removeClass('open') - @$('.volume>a').click(@toggleMute) - - render: -> - @el.prepend """ -
      - -
      -
      -
      -
      - """#" - @slider = @$('.volume-slider').slider - orientation: "vertical" - range: "min" - min: 0 - max: 100 - value: 100 - change: @onChange - slide: @onChange - - onChange: (event, ui) => - @currentVolume = ui.value - $(@).trigger 'volumeChange', @currentVolume - @$('.volume').toggleClass 'muted', @currentVolume == 0 - - toggleMute: => - if @currentVolume > 0 - @previousVolume = @currentVolume - @slider.slider 'option', 'value', 0 - else - @slider.slider 'option', 'value', @previousVolume diff --git a/lms/templates/video.html b/lms/templates/video.html index 4c9d178242..f5f8ed29c6 100644 --- a/lms/templates/video.html +++ b/lms/templates/video.html @@ -1,56 +1,86 @@ <%! from django.utils.translation import ugettext as _ %> % if display_name is not UNDEFINED and display_name is not None: -

      ${display_name}

      +

      ${display_name}

      % endif -%if settings.MITX_FEATURES.get('USE_YOUTUBE_OBJECT_API') and normal_speed_video_id: - - - % endif - - - - -%else: -
      -
      -
      -
      -
      -
      -
      -
      -
      -
      -%endif +
      -

      ${_('Download video here.') % source}

      + % if not settings.MITX_FEATURES['STUB_VIDEO_FOR_TESTING']: + data-streams="${youtube_streams}" + % endif + + ${'data-sub="{}"'.format(sub) if sub else ''} + ${'data-autoplay="{}"'.format(autoplay) if autoplay else ''} + + % if not settings.MITX_FEATURES['STUB_VIDEO_FOR_TESTING']: + ${'data-mp4-source="{}"'.format(sources.get('mp4')) if sources.get('mp4') else ''} + ${'data-webm-source="{}"'.format(sources.get('webm')) if sources.get('webm') else ''} + ${'data-ogg-source="{}"'.format(sources.get('ogv')) if sources.get('ogv') else ''} + % endif + + data-caption-data-dir="${data_dir}" + data-show-captions="${show_captions}" + data-start="${start}" + data-end="${end}" + data-caption-asset-path="${caption_asset_path}" + data-autoplay="${autoplay}" +> +
      + + +
      +
      + +% if sources.get('main'): +
      +

      ${(_('Download video') + ' ' + _('here') + '.') % sources.get('main')}

      +
      % endif % if track: -
      -

      ${_('Download subtitles here.') % track}

      -
      +
      +

      ${(_('Download subtitles') + ' ' + _('here') + '.') % track}

      +
      % endif diff --git a/lms/templates/videoalpha.html b/lms/templates/videoalpha.html deleted file mode 100644 index d0eb7290a7..0000000000 --- a/lms/templates/videoalpha.html +++ /dev/null @@ -1,86 +0,0 @@ -<%! from django.utils.translation import ugettext as _ %> - -% if display_name is not UNDEFINED and display_name is not None: -

      ${display_name}

      -% endif - -
      -
      - - -
      -
      -
      - -% if sources.get('main'): -
      -

      ${(_('Download video') + ' ' + _('here') + '.') % sources.get('main')}

      -
      -% endif - -% if track: -
      -

      ${(_('Download subtitles') + ' ' + _('here') + '.') % track}

      -
      -% endif diff --git a/test_root/data/videoalpha/gizmo.mp4 b/test_root/data/video/gizmo.mp4 similarity index 100% rename from test_root/data/videoalpha/gizmo.mp4 rename to test_root/data/video/gizmo.mp4 diff --git a/test_root/data/videoalpha/gizmo.ogv b/test_root/data/video/gizmo.ogv similarity index 100% rename from test_root/data/videoalpha/gizmo.ogv rename to test_root/data/video/gizmo.ogv diff --git a/test_root/data/videoalpha/gizmo.webm b/test_root/data/video/gizmo.webm similarity index 100% rename from test_root/data/videoalpha/gizmo.webm rename to test_root/data/video/gizmo.webm