Commit dad9f26a by Anton Stupak

Make VideoAlpha out of Alpha.

parent e381adbc
......@@ -2,7 +2,7 @@
// ====================
// Video Alpha
.xmodule_VideoAlphaModule {
.xmodule_VideoModule {
// display mode
&.xmodule_display {
......
......@@ -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;
......
......@@ -3,7 +3,7 @@
<div id="example">
<div
id="video_id"
class="videoalpha"
class="video"
data-show-captions="true"
data-start=""
data-end=""
......
......@@ -3,7 +3,7 @@
<div id="example">
<div
id="video_id"
class="videoalpha"
class="video"
data-show-captions="true"
data-start=""
data-end=""
......
......@@ -3,7 +3,7 @@
<div id="example">
<div
id="video_id"
class="videoalpha"
class="video"
data-streams="0.75:7tqY6eQzVhE,1.0:cogebirgzzM"
data-show-captions="false"
data-start=""
......
(function () {
xdescribe('Video', function () {
describe('Video', function () {
var oldOTBD;
beforeEach(function () {
......
(function () {
xdescribe('Video HTML5Video', function () {
describe('Video HTML5Video', function () {
var state, player, oldOTBD, playbackRates = [0.75, 1.0, 1.25, 1.5];
function initialize() {
......
(function() {
xdescribe('VideoCaption', function() {
describe('VideoCaption', function() {
var state, videoPlayer, videoCaption, videoSpeedControl, oldOTBD;
function initialize() {
......
(function() {
xdescribe('VideoControl', function() {
describe('VideoControl', function() {
var state, videoControl, oldOTBD;
function initialize() {
......
(function() {
xdescribe('VideoPlayer', function() {
describe('VideoPlayer', function() {
var state, videoPlayer, player, videoControl, videoCaption, videoProgressSlider, videoSpeedControl, videoVolumeControl, oldOTBD;
function initialize(fixture) {
......
(function() {
xdescribe('VideoProgressSlider', function() {
describe('VideoProgressSlider', function() {
var state, videoPlayer, videoProgressSlider, oldOTBD;
function initialize() {
......
(function() {
xdescribe('VideoQualityControl', function() {
describe('VideoQualityControl', function() {
var state, videoControl, videoQualityControl, oldOTBD;
function initialize() {
......
(function() {
xdescribe('VideoSpeedControl', function() {
describe('VideoSpeedControl', function() {
var state, videoPlayer, videoControl, videoSpeedControl;
function initialize() {
......
(function() {
xdescribe('VideoVolumeControl', function() {
describe('VideoVolumeControl', function() {
var state, videoControl, videoVolumeControl, oldOTBD;
function initialize() {
......
......@@ -4,5 +4,5 @@
*.js
# Videoalpha are written in pure JavaScript.
!videoalpha/*.js
\ No newline at end of file
# Video are written in pure JavaScript.
!video/*.js
\ No newline at end of file
......@@ -88,7 +88,7 @@ class @Sequence
$.postWithPrefix modx_full_url, position: new_position
# On Sequence change, fire custom event "sequence:change" on element.
# Added for aborting video bufferization, see ../videoalpha/10_main.js
# Added for aborting video bufferization, see ../video/10_main.js
@el.trigger "sequence:change"
@mark_active new_position
@$('#seq_content').html @contents.eq(new_position - 1).text()
......
......@@ -12,8 +12,8 @@
(function (requirejs, require, define) {
define(
'videoalpha/01_initialize.js',
['videoalpha/03_video_player.js'],
'video/01_initialize.js',
['video/03_video_player.js'],
function (VideoPlayer) {
if (typeof(window.gettext) == "undefined") {
......@@ -25,8 +25,8 @@ function (VideoPlayer) {
*
* Initialize module exports this function.
*
* @param {Object} state A place for all properties, and methods of Video Alpha.
* @param {DOM element} element Container of the entire Video Alpha DOM element.
* @param {Object} state A place for all properties, and methods of Video.
* @param {DOM element} element Container of the entire Video DOM element.
*/
return function (state, element) {
_makeFunctionsPublic(state);
......@@ -44,7 +44,7 @@ function (VideoPlayer) {
* Functions which will be accessible via 'state' object. When called, these functions will get the 'state'
* object as a context.
*
* @param {Object} state A place for all properties, and methods of Video Alpha.
* @param {Object} state A place for all properties, and methods of Video.
*/
function _makeFunctionsPublic(state) {
state.setSpeed = _.bind(setSpeed, state);
......@@ -70,7 +70,7 @@ function (VideoPlayer) {
state.isFullScreen = false;
// The parent element of the video, and the ID.
state.el = $(element).find('.videoalpha');
state.el = $(element).find('.video');
state.id = state.el.attr('id').replace(/video_/, '');
// We store all settings passed to us by the server in one place. These are "read only", so don't
......
......@@ -14,7 +14,7 @@
(function (requirejs, require, define) {
define(
'videoalpha/02_html5_video.js',
'video/02_html5_video.js',
[],
function () {
var HTML5Video = {};
......
......@@ -2,8 +2,8 @@
// VideoPlayer module.
define(
'videoalpha/03_video_player.js',
['videoalpha/02_html5_video.js'],
'video/03_video_player.js',
['video/02_html5_video.js'],
function (HTML5Video) {
// VideoPlayer() function - what this module "exports".
......@@ -359,7 +359,7 @@ function (HTML5Video) {
this.videoPlayer.player.setPlaybackRate(this.speed);
}
if (!onTouchBasedDevice() && $('.videoalpha:first').data('autoplay') === 'True') {
if (!onTouchBasedDevice() && $('.video:first').data('autoplay') === 'True') {
this.videoPlayer.play();
}
}
......
......@@ -2,7 +2,7 @@
// VideoControl module.
define(
'videoalpha/04_video_control.js',
'video/04_video_control.js',
[],
function () {
......
......@@ -2,7 +2,7 @@
// VideoQualityControl module.
define(
'videoalpha/05_video_quality_control.js',
'video/05_video_quality_control.js',
[],
function () {
......
......@@ -9,7 +9,7 @@ mind, or whether to act, and in acting, to live."
// VideoProgressSlider module.
define(
'videoalpha/06_video_progress_slider.js',
'video/06_video_progress_slider.js',
[],
function () {
......
......@@ -2,7 +2,7 @@
// VideoVolumeControl module.
define(
'videoalpha/07_video_volume_control.js',
'video/07_video_volume_control.js',
[],
function () {
......
......@@ -2,7 +2,7 @@
// VideoSpeedControl module.
define(
'videoalpha/08_video_speed_control.js',
'video/08_video_speed_control.js',
[],
function () {
......
......@@ -2,7 +2,7 @@
// VideoCaption module.
define(
'videoalpha/09_video_caption.js',
'video/09_video_caption.js',
[],
function () {
......
......@@ -3,13 +3,13 @@
// Main module.
require(
[
'videoalpha/01_initialize.js',
'videoalpha/04_video_control.js',
'videoalpha/05_video_quality_control.js',
'videoalpha/06_video_progress_slider.js',
'videoalpha/07_video_volume_control.js',
'videoalpha/08_video_speed_control.js',
'videoalpha/09_video_caption.js'
'video/01_initialize.js',
'video/04_video_control.js',
'video/05_video_quality_control.js',
'video/06_video_progress_slider.js',
'video/07_video_volume_control.js',
'video/08_video_speed_control.js',
'video/09_video_caption.js'
],
function (
Initialize,
......@@ -31,7 +31,7 @@ function (
// afterwards (expecting the DOM elements to be present) must be stopped by hand.
previousState = null;
window.VideoAlpha = function (element) {
window.Video = function (element) {
var state;
// Stop bufferization of previous video on sequence change.
......@@ -64,7 +64,7 @@ function (
// Because the 'state' object is only available inside this closure, we will also make
// it available to the caller by returning it. This is necessary so that we can test
// VideoAlpha with Jasmine.
// Video with Jasmine.
return state;
};
});
......
class @Video
constructor: (element) ->
@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
class @Subview
constructor: (options) ->
$.each options, (key, value) =>
@[key] = value
@initialize()
@render()
@bind()
$: (selector) ->
$(selector, @el)
initialize: ->
render: ->
bind: ->
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 """
# <ol class="subtitles"><li>Attempting to load captions...</li></ol>
# """
@$('.video-wrapper').after """
<ol class="subtitles"></ol>
"""
@$('.video-controls .secondary-controls').append """
<a href="#" class="hide-subtitles" title="Turn off captions">Captions</a>
"""#"
@$('.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 "<li>Caption will be displayed when you start playing the video.</li>"
else
@renderCaption()
renderCaption: ->
container = $('<ol>')
$.each @captions, (index, text) =>
container.append $('<li>').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 <li> for cosmetic reason
@$('.subtitles').prepend($('<li class="spacing">').height(@topSpacingHeight()))
.append($('<li class="spacing">').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()
class @VideoControl extends Subview
bind: ->
@$('.video_control').click @togglePlayback
render: ->
@el.append """
<div class="slider"></div>
<div>
<ul class="vcr">
<li><a class="video_control" href="#"></a></li>
<li>
<div class="vidtime">0:00 / 0:00</div>
</li>
</ul>
<div class="secondary-controls">
<a href="#" class="add-fullscreen" title="Fill browser">Fill Browser</a>
</div>
</div>
"""#"
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')
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()
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)}")
class @VideoQualityControl extends Subview
initialize: ->
@quality = null;
bind: ->
@$('.quality_control').click @toggleQuality
render: ->
@el.append """
<a href="#" class="quality_control" title="HD">HD</a>
"""#"
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
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 """
<div class="speeds">
<a href="#">
<h3>Speed</h3>
<p class="active"></p>
</a>
<ol class="video_speeds"></ol>
</div>
"""
$.each @speeds, (index, speed) =>
link = $('<a>').attr(href: "#").html("#{speed}x")
@$('.video_speeds').prepend($('<li>').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")
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 """
<div class="volume">
<a href="#"></a>
<div class="volume-slider-container">
<div class="volume-slider"></div>
</div>
</div>
"""#"
@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
<%! from django.utils.translation import ugettext as _ %>
% if display_name is not UNDEFINED and display_name is not None:
<h2> ${display_name} </h2>
<h2>${display_name}</h2>
% endif
%if settings.MITX_FEATURES.get('USE_YOUTUBE_OBJECT_API') and normal_speed_video_id:
<object width="640" height="390">
<param name="movie"
<div
id="video_${id}"
class="video"
% 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']:
value="https://www.youtube.com/v/${normal_speed_video_id}?version=3&amp;autoplay=1&amp;rel=0">
${'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
</param>
<param name="allowScriptAccess" value="always"></param>
<embed
% if not settings.MITX_FEATURES['STUB_VIDEO_FOR_TESTING']:
src="https://www.youtube.com/v/${normal_speed_video_id}?version=3&amp;autoplay=1&amp;rel=0"
% endif
type="application/x-shockwave-flash"
allowscriptaccess="always"
width="640" height="390"></embed>
</object>
%else:
<div id="video_${id}"
class="video"
data-youtube-id-0-75="${youtube_id_0_75}"
data-youtube-id-1-0="${youtube_id_1_0}"
data-youtube-id-1-25="${youtube_id_1_25}"
data-youtube-id-1-5="${youtube_id_1_5}"
data-show-captions="${show_captions}"
data-start="${start}"
data-end="${end}"
data-caption-asset-path="${caption_asset_path}"
data-autoplay="${settings.MITX_FEATURES['AUTOPLAY_VIDEOS']}">
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}"
>
<div class="tc-wrapper">
<article class="video-wrapper">
<section class="video-player">
<div id="${id}"></div>
</section>
<section class="video-controls"></section>
</article>
</div>
</div>
%endif
<article class="video-wrapper">
<div class="video-player-pre"></div>
<section class="video-player">
<div id="${id}"></div>
</section>
<div class="video-player-post"></div>
% if source:
<div class="video-sources">
<p>${_('Download video <a href="%s">here</a>.') % source}</p>
<section class="video-controls">
<div class="slider" tabindex="0" title="Video position"></div>
<div>
<ul class="vcr">
<li><a class="video_control" href="#" tabindex="0" title="${_('Play')}"></a></li>
<li><div class="vidtime">0:00 / 0:00</div></li>
</ul>
<div class="secondary-controls">
<div class="speeds">
<a href="#" tabindex="0" title="Speeds">
<h3 tabindex="-1">${_('Speed')}</h3>
<p tabindex="-1" class="active"></p>
</a>
<ol tabindex="-1" class="video_speeds"></ol>
</div>
<div class="volume">
<a href="#" tabindex="0" title="Volume"></a>
<div tabindex="-1" class="volume-slider-container">
<div tabindex="-1" class="volume-slider"></div>
</div>
</div>
<a href="#" class="add-fullscreen" tabindex="0" title="${_('Fill browser')}">${_('Fill browser')}</a>
<a href="#" class="quality_control" tabindex="0" title="${_('HD')}">${_('HD')}</a>
<a href="#" class="hide-subtitles" title="${_('Turn off captions')}">${_('Captions')}</a>
</div>
</div>
</section>
</article>
<ol class="subtitles" tabindex="0" title="Captions"><li></li></ol>
</div>
</div>
% if sources.get('main'):
<div class="video-sources">
<p>${(_('Download video') + ' <a href="%s">' + _('here') + '</a>.') % sources.get('main')}</p>
</div>
% endif
% if track:
<div class="video-tracks">
<p>${_('Download subtitles <a href="%s">here</a>.') % track}</p>
</div>
<div class="video-tracks">
<p>${(_('Download subtitles') + ' <a href="%s">' + _('here') + '</a>.') % track}</p>
</div>
% endif
<%! from django.utils.translation import ugettext as _ %>
% if display_name is not UNDEFINED and display_name is not None:
<h2>${display_name}</h2>
% endif
<div
id="video_${id}"
class="videoalpha"
% 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}"
>
<div class="tc-wrapper">
<article class="video-wrapper">
<div class="video-player-pre"></div>
<section class="video-player">
<div id="${id}"></div>
</section>
<div class="video-player-post"></div>
<section class="video-controls">
<div class="slider" tabindex="0" title="Video position"></div>
<div>
<ul class="vcr">
<li><a class="video_control" href="#" tabindex="0" title="${_('Play')}"></a></li>
<li><div class="vidtime">0:00 / 0:00</div></li>
</ul>
<div class="secondary-controls">
<div class="speeds">
<a href="#" tabindex="0" title="Speeds">
<h3 tabindex="-1">${_('Speed')}</h3>
<p tabindex="-1" class="active"></p>
</a>
<ol tabindex="-1" class="video_speeds"></ol>
</div>
<div class="volume">
<a href="#" tabindex="0" title="Volume"></a>
<div tabindex="-1" class="volume-slider-container">
<div tabindex="-1" class="volume-slider"></div>
</div>
</div>
<a href="#" class="add-fullscreen" tabindex="0" title="${_('Fill browser')}">${_('Fill browser')}</a>
<a href="#" class="quality_control" tabindex="0" title="${_('HD')}">${_('HD')}</a>
<a href="#" class="hide-subtitles" title="${_('Turn off captions')}">${_('Captions')}</a>
</div>
</div>
</section>
</article>
<ol class="subtitles" tabindex="0" title="Captions"><li></li></ol>
</div>
</div>
% if sources.get('main'):
<div class="video-sources">
<p>${(_('Download video') + ' <a href="%s">' + _('here') + '</a>.') % sources.get('main')}</p>
</div>
% endif
% if track:
<div class="video-tracks">
<p>${(_('Download subtitles') + ' <a href="%s">' + _('here') + '</a>.') % track}</p>
</div>
% endif
Markdown is supported
0% or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment