Commit 8624927f by Prem Sichanugrist

Rewritten video module

parent 0b266098
......@@ -43,19 +43,6 @@ class Module(XModule):
'name':self.name,
'annotations':self.annotations})
def get_init_js(self):
'''JavaScript code to be run when problem is shown. Be aware
that this may happen several times on the same page
(e.g. student switching tabs). Common functions should be put
in the main course .js files for now. '''
log.debug(u"INIT POSITION {0}".format(self.position))
return render_to_string('video_init.js',{'streams':self.video_list(),
'id':self.item_id,
'position':self.position})+self.annotations_init
def get_destroy_js(self):
return "videoDestroy(\"{0}\");".format(self.item_id)+self.annotations_destroy
def __init__(self, system, xml, item_id, state=None):
XModule.__init__(self, system, xml, item_id, state)
xmltree=etree.fromstring(xml)
......@@ -69,5 +56,3 @@ class Module(XModule):
self.annotations=[(e.get("name"),self.render_function(e)) \
for e in xmltree]
self.annotations_init="".join([e[1]['init_js'] for e in self.annotations if 'init_js' in e[1]])
self.annotations_destroy="".join([e[1]['destroy_js'] for e in self.annotations if 'destroy_js' in e[1]])
......@@ -13,6 +13,8 @@ class window.Courseware
autoHeight: false
$('#open_close_accordion a').click navigation.toggle
$('#accordion').show()
log: (event, ui) ->
log_event 'accordion',
newheader: ui.newHeader.text()
......
......@@ -2,7 +2,11 @@ $ ->
$.ajaxSetup
headers : { 'X-CSRFToken': $.cookie 'csrftoken' }
window.onTouchBasedDevice = ->
navigator.userAgent.match /iPhone|iPod|iPad/i
Calculator.bind()
Courseware.bind()
FeedbackForm.bind()
$("a[rel*=leanModal]").leanModal()
/**
* jQuery.ScrollTo - Easy element scrolling using jQuery.
* Copyright (c) 2007-2009 Ariel Flesler - aflesler(at)gmail(dot)com | http://flesler.blogspot.com
* Dual licensed under MIT and GPL.
* Date: 5/25/2009
* @author Ariel Flesler
* @version 1.4.2
*
* http://flesler.blogspot.com/2007/10/jqueryscrollto.html
*/
;(function(d){var k=d.scrollTo=function(a,i,e){d(window).scrollTo(a,i,e)};k.defaults={axis:'xy',duration:parseFloat(d.fn.jquery)>=1.3?0:1};k.window=function(a){return d(window)._scrollable()};d.fn._scrollable=function(){return this.map(function(){var a=this,i=!a.nodeName||d.inArray(a.nodeName.toLowerCase(),['iframe','#document','html','body'])!=-1;if(!i)return a;var e=(a.contentWindow||a).document||a.ownerDocument||a;return d.browser.safari||e.compatMode=='BackCompat'?e.body:e.documentElement})};d.fn.scrollTo=function(n,j,b){if(typeof j=='object'){b=j;j=0}if(typeof b=='function')b={onAfter:b};if(n=='max')n=9e9;b=d.extend({},k.defaults,b);j=j||b.speed||b.duration;b.queue=b.queue&&b.axis.length>1;if(b.queue)j/=2;b.offset=p(b.offset);b.over=p(b.over);return this._scrollable().each(function(){var q=this,r=d(q),f=n,s,g={},u=r.is('html,body');switch(typeof f){case'number':case'string':if(/^([+-]=)?\d+(\.\d+)?(px|%)?$/.test(f)){f=p(f);break}f=d(f,this);case'object':if(f.is||f.style)s=(f=d(f)).offset()}d.each(b.axis.split(''),function(a,i){var e=i=='x'?'Left':'Top',h=e.toLowerCase(),c='scroll'+e,l=q[c],m=k.max(q,i);if(s){g[c]=s[h]+(u?0:l-r.offset()[h]);if(b.margin){g[c]-=parseInt(f.css('margin'+e))||0;g[c]-=parseInt(f.css('border'+e+'Width'))||0}g[c]+=b.offset[h]||0;if(b.over[h])g[c]+=f[i=='x'?'width':'height']()*b.over[h]}else{var o=f[h];g[c]=o.slice&&o.slice(-1)=='%'?parseFloat(o)/100*m:o}if(/^\d+$/.test(g[c]))g[c]=g[c]<=0?0:Math.min(g[c],m);if(!a&&b.queue){if(l!=g[c])t(b.onAfterFirst);delete g[c]}});t(b.onAfter);function t(a){r.animate(g,j,b.easing,a&&function(){a.call(this,n,b)})}}).end()};k.max=function(a,i){var e=i=='x'?'Width':'Height',h='scroll'+e;if(!d(a).is('html,body'))return a[h]-d(a)[e.toLowerCase()]();var c='client'+e,l=a.ownerDocument.documentElement,m=a.ownerDocument.body;return Math.max(l[h],m[h])-Math.min(l[c],m[c])};function p(a){return typeof a=='object'?a:{top:a,left:a}}})(jQuery);
\ No newline at end of file
......@@ -14,38 +14,29 @@ section.course-content {
}
}
div.video-subtitles {
div.video {
@include clearfix();
background: #f3f3f3;
border-bottom: 1px solid #e1e1e1;
border-top: 1px solid #e1e1e1;
@include clearfix();
display: block;
margin: 0 (-(lh()));
padding: 6px lh();
div.video-wrapper {
article.video-wrapper {
float: left;
margin-right: flex-gutter(9);
width: flex-grid(6, 9);
div.video-player {
section.video-player {
height: 0;
overflow: hidden;
padding-bottom: 56.25%;
padding-top: 30px;
position: relative;
object {
height: 100%;
left: 0;
position: absolute;
top: 0;
width: 100%;
}
iframe#html5_player {
object, iframe {
border: none;
display: none;
height: 100%;
left: 0;
position: absolute;
......@@ -68,7 +59,7 @@ section.course-content {
}
}
div#slider {
div.slider {
@extend .clearfix;
background: #c2c2c2;
border: none;
......@@ -175,7 +166,8 @@ section.course-content {
}
}
div#vidtime {
div.vidtime {
padding-left: lh(.75);
font-weight: bold;
line-height: 46px; //height of play pause buttons
padding-left: lh(.75);
......@@ -190,6 +182,7 @@ section.course-content {
div.speeds {
float: left;
position: relative;
a {
background: url('../images/closed-arrow.png') 10px center no-repeat;
......@@ -211,7 +204,7 @@ section.course-content {
&.open {
background: url('../images/open-arrow.png') 10px center no-repeat;
ol#video_speeds {
ol.video_speeds {
display: block;
opacity: 1;
}
......@@ -234,47 +227,52 @@ section.course-content {
padding: 0 lh(.5) 0 0;
}
&:hover, &:active, &:focus {
opacity: 1;
background-color: #444;
}
}
// fix for now
ol#video_speeds {
ol.video_speeds {
@include box-shadow(inset 1px 0 0 #555, 0 3px 0 #444);
@include transition();
background-color: #444;
border: 1px solid #000;
@include box-shadow(inset 1px 0 0 #555, 0 3px 0 #444);
bottom: 46px;
display: none;
left: -1px;
opacity: 0;
position: absolute;
top:0;
@include transition();
width: 100%;
width: 125px;
z-index: 10;
li {
border-bottom: 1px solid #000;
@include box-shadow( 0 1px 0 #555);
border-bottom: 1px solid #000;
color: #fff;
cursor: pointer;
padding: 0 lh(.5);
&.active {
font-weight: bold;
}
&:last-child {
border-bottom: 0;
@include box-shadow(none);
margin-top: 0;
}
a {
border: 0;
color: #fff;
display: block;
padding: lh(.5);
&:hover {
background-color: #666;
color: #aaa;
}
}
&.active {
font-weight: bold;
}
&:hover {
background-color: #444;
opacity: 1;
&:last-child {
@include box-shadow(none);
border-bottom: 0;
margin-top: 0;
}
}
}
}
......@@ -334,7 +332,7 @@ section.course-content {
opacity: 1;
}
div#slider {
div.slider {
height: 14px;
margin-top: -7px;
......@@ -352,7 +350,7 @@ section.course-content {
ol.subtitles {
float: left;
max-height: 460px;
overflow: hidden;
overflow: auto;
padding-top: 10px;
width: flex-grid(3, 9);
......@@ -360,7 +358,7 @@ section.course-content {
border: 0;
color: #666;
cursor: pointer;
margin-bottom: 0px;
margin-bottom: 8px;
padding: 0;
@include transition(all, .5s, ease-in);
......@@ -373,11 +371,7 @@ section.course-content {
color: $mit-red;
}
div {
margin-bottom: 8px;
}
div:empty {
&:empty {
margin-bottom: 0px;
}
}
......@@ -386,7 +380,7 @@ section.course-content {
&.closed {
@extend .trans;
div.video-wrapper {
article.video-wrapper {
width: flex-grid(9,9);
}
......@@ -441,11 +435,11 @@ section.course-content {
}
div.tc-wrapper {
div.video-wrapper {
article.video-wrapper {
width: 100%;
}
object#myytplayer, iframe {
object, iframe {
bottom: 0;
height: 100%;
left: 0;
......@@ -487,7 +481,7 @@ section.course-content {
}
}
div.course-wrapper.closed section.course-content div.video-subtitles {
div.course-wrapper.closed section.course-content div.video {
ol.subtitles {
max-height: 577px;
}
......
class window.Video
constructor: (@id, videos) ->
@element = $("#video_#{@id}")
@parseVideos videos
@fetchMetadata()
@parseSpeed()
$("#video_#{@id}").data('video', this)
window.onYouTubePlayerAPIReady = =>
$('.course-content .video').each ->
$(this).data('video').embed()
youtubeId: (speed)->
@videos[speed || @speed]
parseVideos: (videos) ->
@videos = {}
$.each videos, (speed, url) =>
speed = parseFloat(speed).toFixed(2).replace /\.00$/, '.0'
@videos[speed] = url
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(this)
fetchMetadata: (url) ->
@metadata = {}
$.each @videos, (speed, url) =>
$.get "http://gdata.youtube.com/feeds/api/videos/#{url}?v=2&alt=jsonc", ((data) => @metadata[data.data.id] = data.data) , 'jsonp'
getDuration: ->
@metadata[@youtubeId()].duration
class VideoCaption
constructor: (@player, @youtubeId) ->
@index = []
@fetchCaption()
@bind()
$: (selector) ->
@player.$(selector)
bind: ->
$(window).bind('resize', @onWindowResize)
$(@player).bind('resize', @onWindowResize)
$(@player).bind('updatePlayTime', @onUpdatePlayTime)
@$('.hide-subtitles').click @toggle
fetchCaption: ->
$.getJSON @captionURL(), (captions) =>
@captions = captions.text
@start = captions.start
for index in [0...captions.start.length]
for time in [captions.start[index]..captions.end[index]]
@index[time] ||= []
@index[time].push(index)
@render()
captionURL: ->
"/static/subs/#{@youtubeId}.srt.sjson"
render: ->
container = $('<ol class="subtitles">')
container.css maxHeight: @$('.video-wrapper').height() - 5
$.each @captions, (index, text) =>
container.append $('<li>').html(text).attr
'data-index': index
'data-start': @start[index]
@$('.subtitles').replaceWith(container)
@$('.subtitles').mouseenter(@onMouseEnter).mouseleave(@onMouseLeave)
.mousemove(@onMovement).bind('mousewheel', @onMovement)
.bind('DOMMouseScroll', @onMovement)
@$('.subtitles li[data-index]').click @seekPlayer
# prepend and append an empty <li> for cosmatic reason
@$('.subtitles').prepend($('<li class="spacing">').height(@topSpacingHeight()))
.append($('<li class="spacing">').height(@bottomSpacingHeight()))
onUpdatePlayTime: (event, time) =>
# This 250ms offset is required to match the video speed
time = Math.round(Time.convert(time, @player.currentSpeed(), '1.0') * 1000 + 250)
newIndex = @index[time]
if newIndex != undefined && @currentIndex != newIndex
if @currentIndex
for index in @currentIndex
@$(".subtitles li[data-index='#{index}']").removeClass('current')
for index in newIndex
@$(".subtitles li[data-index='#{newIndex}']").addClass('current')
@currentIndex = newIndex
@scrollCaption()
onWindowResize: =>
@$('.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: (event) =>
@onMouseEnter()
onMouseLeave: =>
clearTimeout @frozen if @frozen
@frozen = null
@scrollCaption() if @player.isPlaying()
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', @player.currentSpeed()) / 1000)
$(@player).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 @player.element.hasClass('closed')
@$('.hide-subtitles').attr('title', 'Turn off captions')
@player.element.removeClass('closed')
else
@$('.hide-subtitles').attr('title', 'Turn on captions')
@player.element.addClass('closed')
@scrollCaption()
captionHeight: ->
if @player.element.hasClass('fullscreen')
$(window).height() - @$('.video-controls').height()
else
@$('.video-wrapper').height()
class VideoPlayer
constructor: (@video) ->
@currentTime = 0
@element = $("#video_#{@video.id}")
@buildPlayer()
@bind()
$: (selector) ->
$(selector, @element)
bind: ->
$(@).bind('seek', @onSeek)
$(@).bind('updatePlayTime', @onUpdatePlayTime)
$(@).bind('speedChange', @onSpeedChange)
$(document).keyup @bindExitFullScreen
@$('.video_control').click @togglePlayback
@$('.add-fullscreen').click @toggleFullScreen
@addToolTip unless onTouchBasedDevice()
bindExitFullScreen: (event) =>
if @element.hasClass('fullscreen') && event.keyCode == 27
@toggleFullScreen(event)
buildPlayer: ->
new VideoCaption(this, @video.youtubeId('1.0'))
new VideoSpeedControl(this, @video.speeds)
new VideoProgressSlider(this)
@player = new YT.Player @video.id,
playerVars:
controls: 0
wmode: 'transparent'
rel: 0
showinfo: 0
enablejsapi: 1
videoId: @video.youtubeId()
events:
onReady: @onReady
onStateChange: @onStateChange
addToolTip: ->
@$('.add-fullscreen, .hide-subtitles').qtip
position:
my: 'top right'
at: 'top center'
onReady: =>
@setProgress(0, @duration())
$(@).trigger('ready')
unless true || onTouchBasedDevice()
$('.course-content .video:first').data('video').player.play()
onStateChange: (event) =>
switch event.data
when YT.PlayerState.PLAYING
if window.player && window.player != @player
window.player.pauseVideo()
window.player = @player
@onPlay()
when YT.PlayerState.PAUSED
if window.player == @player
window.player = null
@onPause()
when YT.PlayerState.ENDED
if window.player == @player
window.player = null
@onPause()
onPlay: ->
@$('.video_control').removeClass('play').addClass('pause').html('Pause')
unless @player.interval
@player.interval = setInterval(@update, 200)
onPause: ->
@$('.video_control').removeClass('pause').addClass('play').html('Play')
clearInterval(@player.interval)
@player.interval = null
onSeek: (event, time) ->
@player.seekTo(time, true)
if @isPlaying()
clearInterval(@player.interval)
@player.interval = setInterval(@update, 200)
else
@currentTime = time
$(@).trigger('updatePlayTime', time)
onSpeedChange: (event, newSpeed) =>
@currentTime = Time.convert(@currentTime, parseFloat(@currentSpeed()), newSpeed)
@video.setSpeed(parseFloat(newSpeed).toFixed(2).replace /\.00$/, '.0')
if @isPlaying()
@player.loadVideoById(@video.youtubeId(), @currentTime)
else
@player.cueVideoById(@video.youtubeId(), @currentTime)
@setProgress(@currentTime, @duration())
$(@).trigger('updatePlayTime', @currentTime)
update: =>
if @currentTime = @player.getCurrentTime()
$(@).trigger('updatePlayTime', @currentTime)
onUpdatePlayTime: (event, time) =>
@setProgress(@currentTime) if time
setProgress: (time) =>
progress = Time.format(time) + ' / ' + Time.format(@duration())
if @progress != progress
@$(".vidtime").html(progress)
@progress = progress
togglePlayback: (event) =>
event.preventDefault()
if $(event.target).hasClass('play')
@play()
else
@pause()
toggleFullScreen: (event) =>
event.preventDefault()
if @element.hasClass('fullscreen')
@$('.exit').remove()
@$('.add-fullscreen').attr('title', 'Fill browser')
@element.removeClass('fullscreen')
else
@element.append('<a href="#" class="exit">Exit</a>').addClass('fullscreen')
@$('.add-fullscreen').attr('title', 'Exit fill browser')
@$('.exit').click @toggleFullScreen
$(@).trigger('resize')
# Delegates
play: ->
@player.playVideo() if @player.playVideo
isPlaying: ->
@player.getPlayerState() == YT.PlayerState.PLAYING
pause: ->
@player.pauseVideo()
duration: ->
@video.getDuration()
currentSpeed: ->
@video.speed
class VideoProgressSlider
constructor: (@player) ->
@buildSlider()
@buildHandle()
$(@player).bind('updatePlayTime', @onUpdatePlayTime)
$(@player).bind('ready', @onReady)
$: (selector) ->
@player.$(selector)
buildSlider: ->
@slider = @$('.slider').slider
range: 'min'
change: @onChange
slide: @onSlide
stop: @onStop
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
onReady: =>
@slider.slider('option', 'max', @player.duration())
onUpdatePlayTime: (event, currentTime) =>
if !@frozen
@slider.slider('option', 'max', @player.duration())
@slider.slider('value', currentTime)
onSlide: (event, ui) =>
@frozen = true
@updateTooltip(ui.value)
$(@player).trigger('seek', ui.value)
onChange: (event, ui) =>
@updateTooltip(ui.value)
onStop: (event, ui) =>
@frozen = true
$(@player).trigger('seek', ui.value)
setTimeout (=> @frozen = false), 200
updateTooltip: (value)->
@handle.qtip('option', 'content.text', "#{Time.format(value)}")
class VideoSpeedControl
constructor: (@player, @speeds) ->
@build()
@bind()
$: (selector) ->
@player.$(selector)
bind: ->
$(@player).bind('speedChange', @onSpeedChange)
@$('.video_speeds a').click @changeVideoSpeed
if onTouchBasedDevice()
@$('.speeds').click -> $(this).toggleClass('open')
else
@$('.speeds').mouseover -> $(this).addClass('open')
.mouseout -> $(this).removeClass('open')
.click (event) ->
event.preventDefault()
$(this).removeClass('open')
build: ->
$.each @speeds, (index, speed) =>
link = $('<a>').attr(href: "#").html("#{speed}x")
@$('.video_speeds').prepend($('<li>').attr('data-speed', speed).html(link))
@setSpeed(@player.currentSpeed())
changeVideoSpeed: (event) =>
event.preventDefault()
unless $(event.target).parent().hasClass('active')
$(@player).trigger 'speedChange', $(event.target).parent().data('speed')
onSpeedChange: (event, speed) =>
@setSpeed(parseFloat(speed).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 @Time
@format: (time) ->
seconds = Math.floor time
minutes = Math.floor seconds / 60
hours = Math.floor minutes / 60
seconds = seconds % 60
minutes = minutes % 60
if hours
"#{hours}:#{@pad(minutes)}:#{@pad(seconds % 60)}"
else
"#{minutes}:#{@pad(seconds % 60)}"
@pad: (number) ->
if number < 10
"0#{number}"
else
number
@convert: (time, oldSpeed, newSpeed) ->
(time * oldSpeed / newSpeed).toFixed(3)
......@@ -26,7 +26,7 @@
<a href="#">close</a>
</header>
<div id="accordion">
<div id="accordion" style="display: none">
<nav>
${accordion}
</nav>
......
......@@ -116,6 +116,11 @@
<script type="text/javascript" src="${static.url('js/video_player.js')}"></script>
<script type="text/javascript" src="${static.url('js/schematic.js')}"></script>
<script type="text/javascript" src="${static.url('js/cktsim.js')}"></script>
<script type="text/javascript" src="${static.url('js/jquery.scrollTo-1.4.2-min.js')}"></script>
<script type="text/javascript">
document.write('\x3Cscript type="text/javascript" src="' +
document.location.protocol + '//www.youtube.com/player_api">\x3C/script>');
</script>
<%block name="js_extra"/>
</body>
......
......@@ -2,123 +2,49 @@
<h1> ${name} </h1>
% endif
<div class="video-subtitles">
<div class="tc-wrapper">
<div class="video-wrapper">
<div class="video-player">
<div id="ytapiplayer">
</div>
<iframe id="html5_player" type="text/html" frameborder="0">
</iframe>
</div>
<div id="video_${id}" class="video">
<div class="tc-wrapper">
<article class="video-wrapper">
<section class="video-player">
<div id="${id}"></div>
</section>
<section class="video-controls">
<div id="slider"></div>
<section>
<div class="slider"></div>
<div>
<ul class="vcr">
<li><a id="video_control" class="pause">Pause</a></li>
<li><a class="video_control play">Play</a></li>
<li>
<div id="vidtime">0:00 / 0:00</div>
<div class="vidtime">0:00 / 0:00</div>
</li>
</ul>
<div class="secondary-controls">
<div class="speeds">
<a href="#">
<h3>Speed</h3>
<p class="active"></p>
<ol id="video_speeds"></ol>
</a>
<ol class="video_speeds"></ol>
</div>
<a href="#" class="add-fullscreen" title="Fill browser">Fill Browser</a>
<a href="#" class="hide-subtitles" title="Turn off captions">Captions</a>
</div>
</section>
</section>
</div>
</section>
</article>
<ol class="subtitles">
<!-- <li id="stt_n5"><div id="std_n7" onclick="title_seek(-7);"></div></li> -->
<li id="stt_n4"><div id="std_n6" onclick="title_seek(-6);"></div></li>
<li id="stt_n4"><div id="std_n5" onclick="title_seek(-5);"></div></li>
<li id="stt_n4"><div id="std_n4" onclick="title_seek(-4);"></div></li>
<li id="stt_n3"><div id="std_n3" onclick="title_seek(-3);"></div></li>
<li id="stt_n2"><div id="std_n2" onclick="title_seek(-2);"></div></li>
<li id="stt_n1"><div id="std_n1" onclick="title_seek(-1);"></div></li>
<li id="stt_0 "class="current"><div id="std_0" onclick="title_seek(0);"></div></li>
<li id="stt_p1"><div id="std_p1" onclick="title_seek( 1);"></div></li>
<li id="stt_p2"><div id="std_p2" onclick="title_seek( 2);"></div></li>
<li id="stt_p3"><div id="std_p3" onclick="title_seek( 3);"></div></li>
<li id="stt_p4"><div id="std_p4" onclick="title_seek( 4);"></div></li>
<li id="stt_p5"><div id="std_p5" onclick="title_seek( 5);"></div></li>
<li id="stt_p6"><div id="std_p7" onclick="title_seek( 6);"></div></li>
<li id="stt_p6"><div id="std_p7" onclick="title_seek( 7);"></div></li>
<li id="stt_p6"><div id="std_p7" onclick="title_seek( 8);"></div></li>
<li>Attempting to load captions...</li>
</ol>
</div>
</div>
</div>
<%block name="js_extra">
<script src="/static/js/jquery.ui.touch-punch.min.js"></script>
<script type="text/javascript" charset="utf-8">
$(function() {
// tooltips for full browser and closed caption
$('.add-fullscreen, .hide-subtitles ').qtip({
position: {
my: 'top right',
at: 'top center'
}
});
//full browser
$('.add-fullscreen').click(function() {
$('div.video-subtitles').toggleClass('fullscreen');
if ($('div.video-subtitles').hasClass('fullscreen')) {
$('div.video-subtitles').append('<a href="#" class="exit">Exit</a>');
} else {
$('a.exit').remove();
}
$('.exit').click(function() {
$('div.video-subtitles').removeClass('fullscreen');
$(this).remove();
return false;
});
var link_title = $(this).attr('title');
$(this).attr('title', (link_title == 'Exit fill browser') ? 'Fill browser' : 'Exit fill browser');
return false;
});
//hide subtitles
$('.hide-subtitles').click(function() {
$('div.video-subtitles').toggleClass('closed');
var link_title = $(this).attr('title');
$(this).attr('title', (link_title == 'Turn on captions') ? 'Turn off captions' : 'Turn on captions');
return false;
});
$("div.speeds a").hover(function() {
$(this).toggleClass("open");
});
$("div.speeds a").click(function() {
return false;
});
<script type="text/javascript">
$(function(){
new Video('${id}', ${streams});
});
</script>
</%block>
......
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