2014-07-17 20:20:11 -04:00
CocoView = require ' views/kinds/CocoView '
2014-01-03 13:32:13 -05:00
template = require ' templates/play/level/playback '
{ me } = require ' lib/auth '
2014-11-10 15:47:24 -05:00
LevelOptions = require ' lib/LevelOptions '
2014-01-03 13:32:13 -05:00
2014-07-23 10:02:45 -04:00
module.exports = class LevelPlaybackView extends CocoView
2014-06-30 22:16:26 -04:00
id: ' playback-view '
2014-01-03 13:32:13 -05:00
template: template
subscriptions:
2014-08-27 15:24:03 -04:00
' level:disable-controls ' : ' onDisableControls '
' level:enable-controls ' : ' onEnableControls '
' level:set-playing ' : ' onSetPlaying '
' level:toggle-playing ' : ' onTogglePlay '
' level:scrub-forward ' : ' onScrubForward '
' level:scrub-back ' : ' onScrubBack '
' level:set-volume ' : ' onSetVolume '
2014-01-03 13:32:13 -05:00
' surface:frame-changed ' : ' onFrameChanged '
' god:new-world-created ' : ' onNewWorld '
2014-08-25 00:39:34 -04:00
' god:streaming-world-updated ' : ' onNewWorld '
2014-08-27 15:24:03 -04:00
' level:set-letterbox ' : ' onSetLetterbox '
2014-08-23 16:54:52 -04:00
' tome:cast-spells ' : ' onTomeCast '
2014-08-24 15:33:46 -04:00
' playback:real-time-playback-ended ' : ' onRealTimePlaybackEnded '
2014-08-26 01:05:24 -04:00
' playback:stop-real-time-playback ' : ' onStopRealTimePlayback '
2014-08-29 18:10:04 -04:00
' real-time-multiplayer:manual-cast ' : ' onRealTimeMultiplayerCast '
2014-01-03 13:32:13 -05:00
events:
2014-02-26 13:42:25 -05:00
' click # music-button ' : ' onToggleMusic '
2014-08-27 15:24:03 -04:00
' click # zoom-in-button ' : -> Backbone . Mediator . publish ' camera:zoom-in ' , { } unless @ shouldIgnore ( )
' click # zoom-out-button ' : -> Backbone . Mediator . publish ' camera:zoom-out ' , { } unless @ shouldIgnore ( )
2014-01-03 13:32:13 -05:00
' click # volume-button ' : ' onToggleVolume '
' click # play-button ' : ' onTogglePlay '
2014-08-26 01:05:24 -04:00
' click ' : -> Backbone . Mediator . publish ' tome:focus-editor ' , { } unless @ realTime
2014-03-29 19:38:45 -04:00
' mouseenter # timeProgress ' : ' onProgressEnter '
' mouseleave # timeProgress ' : ' onProgressLeave '
' mousemove # timeProgress ' : ' onProgressHover '
2014-10-27 16:32:25 -04:00
' tapstart # timeProgress ' : ' onProgressTapStart '
' tapend # timeProgress ' : ' onProgressTapEnd '
' tapmove # timeProgress ' : ' onProgressTapMove '
2014-01-29 15:18:37 -05:00
2014-01-03 13:32:13 -05:00
shortcuts:
' ⌘+p, p, ctrl+p ' : ' onTogglePlay '
2014-02-24 12:58:12 -05:00
' ⌘+[, ctrl+[ ' : ' onScrubBack '
2014-05-24 11:31:59 -04:00
' ⌘+⇧+[, ctrl+⇧+[ ' : ' onSingleScrubBack '
2014-02-24 12:58:12 -05:00
' ⌘+], ctrl+] ' : ' onScrubForward '
2014-05-24 11:31:59 -04:00
' ⌘+⇧+], ctrl+⇧+] ' : ' onSingleScrubForward '
2014-01-03 13:32:13 -05:00
constructor: ->
super ( arguments . . . )
2014-03-29 19:38:45 -04:00
me . on ( ' change:music ' , @ updateMusicButton , @ )
2014-01-03 13:32:13 -05:00
2014-02-11 17:24:06 -05:00
afterRender: ->
2014-01-03 13:32:13 -05:00
super ( )
2014-03-29 19:38:45 -04:00
@$progressScrubber = $ ( ' .scrubber .progress ' , @ $el )
2014-01-03 13:32:13 -05:00
@ hookUpScrubber ( )
@ updateMusicButton ( )
2014-03-24 12:07:09 -04:00
$ ( window ) . on ( ' resize ' , @ onWindowResize )
2014-04-11 21:19:52 -04:00
ua = navigator . userAgent . toLowerCase ( )
if /safari/ . test ( ua ) and not /chrome/ . test ( ua )
@ $el . find ( ' .toggle-fullscreen ' ) . hide ( )
2014-08-22 18:32:23 -04:00
@ timePopup ? = new HoverPopup
t = $ . i18n . t
@second = t ' units.second '
@seconds = t ' units.seconds '
@minute = t ' units.minute '
@minutes = t ' units.minutes '
@goto = t ' play_level.time_goto '
@current = t ' play_level.time_current '
@total = t ' play_level.time_total '
2014-11-10 15:47:24 -05:00
@ $el . find ( ' # play-button ' ) . css ( ' visibility ' , ' hidden ' ) if LevelOptions [ @ options . levelID ] ? . hidesPlayButton # Don't show for first few levels, confuses new players.
2014-01-03 13:32:13 -05:00
2014-03-29 19:38:45 -04:00
updatePopupContent: ->
2014-04-22 14:11:08 -04:00
@ timePopup ? . updateContent " <h2> #{ @ timeToString @ newTime } </h2> #{ @ formatTime ( @ current , @ currentTime ) } <br/> #{ @ formatTime ( @ total , @ totalTime ) } "
2014-03-29 19:38:45 -04:00
# These functions could go to some helper class
pad2: (num) ->
2014-06-30 22:16:26 -04:00
if not num ? or num is 0 then ' 00 ' else ( ( if num < 10 then ' 0 ' else ' ' ) + num )
2014-03-29 19:38:45 -04:00
formatTime: (text, time) =>
" #{ text } \t #{ @ timeToString time } "
timeToString: (time=0, withUnits=false) ->
mins = Math . floor ( time / 60 )
2014-03-29 20:30:12 -04:00
secs = ( time - mins * 60 ) . toFixed ( 1 )
2014-03-29 19:38:45 -04:00
if withUnits
2014-06-30 22:16:26 -04:00
ret = ' '
ret = ( mins + ' ' + ( if mins is 1 then @ minute else @ minutes ) ) if ( mins > 0 )
ret = ( ret + ' ' + secs + ' ' + ( if secs is 1 then @ second else @ seconds ) ) if ( secs > 0 or mins is 0 )
2014-03-29 19:38:45 -04:00
else
2014-03-29 20:30:12 -04:00
" #{ mins } : #{ @ pad2 secs } "
2014-03-29 19:38:45 -04:00
2014-01-03 13:32:13 -05:00
# callbacks
updateMusicButton: ->
@ $el . find ( ' # music-button ' ) . toggleClass ( ' music-on ' , me . get ( ' music ' ) )
onSetLetterbox: (e) ->
2014-08-24 01:24:00 -04:00
return if @ realTime
2014-08-23 16:54:52 -04:00
@ togglePlaybackControls ! e . on
2014-01-03 13:32:13 -05:00
@disabled = e . on
2014-08-23 16:54:52 -04:00
togglePlaybackControls: (to) ->
buttons = @ $el . find ' # play-button, .scrubber-handle '
buttons . css ' visibility ' , if to then ' visible ' else ' hidden '
onTomeCast: (e) ->
return unless e . realTime
2014-08-30 00:46:26 -04:00
@realTime = true
@ togglePlaybackControls false
Backbone . Mediator . publish ' playback:real-time-playback-started ' , { }
2014-09-05 15:39:30 -04:00
Backbone . Mediator . publish ' audio-player:play-sound ' , trigger: ' real-time-playback-start ' , volume: 1
2014-10-18 17:51:43 -04:00
Backbone . Mediator . publish ' level:set-letterbox ' , on : true if @ options . level . get ( ' type ' , true ) is [ ' hero ' ] # not with flags...?
Real-time multiplayer initial commit
Simple matchmaking, synchronous multiplayer PVP, flags!
Rough matchmaking is under the game menu multiplayer tab, for ladder
games only. After creating a 2-person game there, you can exit that
modal and real-time cast to play against each other.
If you’re the first person to cast, you’ll sit at the real-time level
playback view waiting until the other player casts. When they do, you
both should start the real-time playback (and start placing flags like
crazy people).
If in a multiplayer session, the real-time simulation runs the players’
code against each other. Your multiplayer opponent’s name should be up
near the level name.
Multiplayer sessions are stored completely in Firebase for now, and
removed if both players leave the game. There’s plenty of bugs,
synchronization issues, and minimal polish to add before we push it to
master.
2014-08-29 02:34:07 -04:00
onRealTimeMultiplayerCast: (e) ->
2014-08-23 16:54:52 -04:00
@realTime = true
@ togglePlaybackControls false
2014-08-30 00:46:26 -04:00
Backbone . Mediator . publish ' playback:real-time-playback-waiting ' , { }
2014-08-23 16:54:52 -04:00
2014-01-03 13:32:13 -05:00
onWindowResize: (s...) =>
@barWidth = $ ( ' .progress ' , @ $el ) . width ( )
2014-02-11 17:24:06 -05:00
onNewWorld: (e) ->
2014-08-22 18:32:23 -04:00
@ updateBarWidth e . world . frames . length , e . world . maxTotalFrames , e . world . dt
updateBarWidth: (loadedFrameCount, maxTotalFrames, dt) ->
2014-09-25 00:01:58 -04:00
@totalTime = ( loadedFrameCount - 1 ) * dt
pct = parseInt ( 100 * loadedFrameCount / ( maxTotalFrames - 1 ) ) + ' % '
2014-02-13 12:26:21 -05:00
@barWidth = $ ( ' .progress ' , @ $el ) . css ( ' width ' , pct ) . show ( ) . width ( )
2014-03-17 00:43:14 -04:00
$ ( ' .scrubber .progress ' , @ $el ) . slider ( ' enable ' , true )
2014-03-29 19:38:45 -04:00
@newTime = 0
@currentTime = 0
2014-08-22 18:32:23 -04:00
@lastLoadedFrameCount = loadedFrameCount
2014-01-03 13:32:13 -05:00
2014-02-11 17:24:06 -05:00
onDisableControls: (e) ->
2014-11-14 21:25:01 -05:00
if not e . controls or ( ' playback ' in e . controls )
2014-01-03 13:32:13 -05:00
@disabled = true
$ ( ' button ' , @ $el ) . addClass ( ' disabled ' )
try
2014-03-29 19:38:45 -04:00
@ $progressScrubber . slider ( ' disable ' , true )
2014-05-15 00:54:36 -04:00
catch error
console . warn ( ' error disabling scrubber ' , error )
2014-04-11 17:03:13 -04:00
@ timePopup ? . disable ( )
2014-11-15 15:46:57 -05:00
$ ( ' # volume-button ' , @ $el ) . removeClass ( ' disabled ' )
@ $el . addClass ' controls-disabled '
2014-01-03 13:32:13 -05:00
2014-02-11 17:24:06 -05:00
onEnableControls: (e) ->
2014-08-24 01:24:00 -04:00
return if @ realTime
2014-11-14 21:25:01 -05:00
if not e . controls or ( ' playback ' in e . controls )
2014-01-03 13:32:13 -05:00
@disabled = false
$ ( ' button ' , @ $el ) . removeClass ( ' disabled ' )
try
2014-03-29 19:38:45 -04:00
@ $progressScrubber . slider ( ' enable ' , true )
2014-05-15 00:54:36 -04:00
catch error
console . warn ( ' error enabling scrubber ' , error )
2014-04-11 17:03:13 -04:00
@ timePopup ? . enable ( )
2014-11-15 15:46:57 -05:00
@ $el . removeClass ' controls-disabled '
2014-01-03 13:32:13 -05:00
2014-02-11 17:24:06 -05:00
onSetPlaying: (e) ->
2014-01-03 13:32:13 -05:00
@playing = ( e ? { } ) . playing ? true
button = @ $el . find ' # play-button '
ended = button . hasClass ' ended '
2014-09-05 15:39:30 -04:00
changed = button . hasClass ( ' playing ' ) isnt @ playing
2014-01-03 13:32:13 -05:00
button . toggleClass ( ' playing ' , @ playing and not ended ) . toggleClass ( ' paused ' , not @ playing and not ended )
2014-09-05 15:39:30 -04:00
Backbone . Mediator . publish ' audio-player:play-sound ' , trigger: ( if @ playing then ' playback-play ' else ' playback-pause ' ) , volume: 1
2014-01-03 13:32:13 -05:00
return # don't stripe the bar
bar = @ $el . find ' .scrubber .progress '
bar . toggleClass ( ' progress-striped ' , @ playing and not ended ) . toggleClass ( ' active ' , @ playing and not ended )
onSetVolume: (e) ->
classes = [ ' vol-off ' , ' vol-down ' , ' vol-up ' ]
button = $ ( ' # volume-button ' , @ $el )
button . removeClass ( c ) for c in classes
button . addClass ( classes [ 0 ] ) if e . volume <= 0.0
button . addClass ( classes [ 1 ] ) if e . volume > 0.0 and e . volume < 1.0
button . addClass ( classes [ 2 ] ) if e . volume >= 1.0
2014-01-29 15:18:37 -05:00
2014-05-24 11:31:59 -04:00
onScrub: (e, options) ->
2014-08-28 20:08:05 -04:00
e ? . preventDefault ? ( )
2014-05-24 11:31:59 -04:00
options.scrubDuration = 500
2014-08-27 15:24:03 -04:00
Backbone . Mediator . publish ( ' level:set-time ' , options )
2014-05-24 11:31:59 -04:00
onScrubForward: (e) ->
@ onScrub e , ratioOffset: 0.05
onSingleScrubForward: (e) ->
@ onScrub e , frameOffset: 1
2014-01-03 13:32:13 -05:00
onScrubBack: (e) ->
2014-05-24 11:31:59 -04:00
@ onScrub e , ratioOffset: - 0.05
onSingleScrubBack: (e) ->
@ onScrub e , frameOffset: - 1
2014-01-03 13:32:13 -05:00
onFrameChanged: (e) ->
if e . progress isnt @ lastProgress
2014-03-29 19:38:45 -04:00
@currentTime = e . frame / e . world . frameRate
2014-04-28 19:31:51 -04:00
@ updatePopupContent ( ) if @ timePopup ? . shown
2014-08-22 18:32:23 -04:00
@ updateProgress ( e . progress , e . world )
2014-01-03 13:32:13 -05:00
@ updatePlayButton ( e . progress )
@lastProgress = e . progress
2014-03-29 19:38:45 -04:00
onProgressEnter: (e) ->
2014-04-11 17:03:13 -04:00
# Why it needs itself as parameter you ask? Ask Twitter instead.
@ timePopup ? . enter @ timePopup
2014-03-29 19:38:45 -04:00
onProgressLeave: (e) ->
2014-04-11 17:03:13 -04:00
@ timePopup ? . leave @ timePopup
2014-03-29 19:38:45 -04:00
2014-10-27 16:32:25 -04:00
onProgressHover: (e, offsetX) ->
2014-03-29 19:38:45 -04:00
timeRatio = @ $progressScrubber . width ( ) / @ totalTime
2014-10-27 16:32:25 -04:00
offsetX ? = e . clientX - $ ( e . target ) . closest ( ' # timeProgress ' ) . offset ( ) . left
2014-07-15 12:35:14 -04:00
@newTime = offsetX / timeRatio
2014-03-29 19:38:45 -04:00
@ updatePopupContent ( )
2014-04-11 17:03:13 -04:00
@ timePopup ? . onHover e
2014-03-29 19:38:45 -04:00
2014-04-11 17:03:13 -04:00
# Show it instantaneously if close enough to current time.
if @ timePopup and Math . abs ( @ currentTime - @ newTime ) < 1 and not @ timePopup . shown
@ timePopup . show ( )
2014-03-29 19:38:45 -04:00
2014-10-27 16:32:25 -04:00
onProgressTapStart: (e, touchData) ->
return unless application . isIPadApp
@ onProgressEnter e
screenOffsetX = e . clientX ? touchData ? . position . x ? 0
offsetX = screenOffsetX - $ ( e . target ) . closest ( ' # timeProgress ' ) . offset ( ) . left
offsetX = Math . max offsetX , 0
@ scrubTo offsetX / @ $progressScrubber . width ( )
@ onTogglePlay ( ) if @ $el . find ( ' # play-button ' ) . hasClass ' playing '
onProgressTapEnd: (e, touchData) ->
return unless application . isIPadApp
@ onProgressLeave e
onProgressTapMove: (e, touchData) ->
return unless application . isIPadApp # Not sure why the tap events would fire when it's not one.
screenOffsetX = e . clientX ? touchData ? . position . x ? 0
offsetX = screenOffsetX - $ ( e . target ) . closest ( ' # timeProgress ' ) . offset ( ) . left
offsetX = Math . max offsetX , 0
@ onProgressHover e , offsetX
@ scrubTo offsetX / @ $progressScrubber . width ( )
2014-08-22 18:32:23 -04:00
updateProgress: (progress, world) ->
if world . frames . length isnt @ lastLoadedFrameCount
@ updateBarWidth world . frames . length , world . maxTotalFrames , world . dt
2014-08-24 15:33:46 -04:00
wasLoaded = @ worldCompletelyLoaded
2014-08-23 16:54:52 -04:00
@worldCompletelyLoaded = world . frames . length is world . totalFrames
2014-08-24 15:33:46 -04:00
if @ realTime and @ worldCompletelyLoaded and not wasLoaded
Backbone . Mediator . publish ' playback:real-time-playback-ended ' , { }
2014-09-25 01:59:13 -04:00
Backbone . Mediator . publish ' level:set-letterbox ' , on : false
2014-08-22 17:59:32 -04:00
$ ( ' .scrubber .progress-bar ' , @ $el ) . css ( ' width ' , " #{ progress * 100 } % " )
2014-01-03 13:32:13 -05:00
updatePlayButton: (progress) ->
2014-11-05 20:47:23 -05:00
playButton = @ $el . find ( ' # play-button ' )
wasEnded = playButton . hasClass ( ' ended ' )
2014-08-23 16:54:52 -04:00
if @ worldCompletelyLoaded and progress >= 0.99 and @ lastProgress < 0.99
2014-11-05 20:47:23 -05:00
playButton . removeClass ( ' playing ' ) . removeClass ( ' paused ' ) . addClass ( ' ended ' )
2014-09-25 01:59:13 -04:00
Backbone . Mediator . publish ' level:set-letterbox ' , on : false if @ realTime
2014-08-24 15:33:46 -04:00
Backbone . Mediator . publish ' playback:real-time-playback-ended ' , { } if @ realTime
2014-05-03 16:26:37 -04:00
if progress < 0.99 and @ lastProgress >= 0.99
2014-11-05 20:47:23 -05:00
playButton . removeClass ( ' ended ' )
playButton . addClass ( if @ playing then ' playing ' else ' paused ' )
isEnded = playButton . hasClass ( ' ended ' )
if wasEnded isnt isEnded
Backbone . Mediator . publish ' playback:ended-changed ' , ended: isEnded
2014-01-03 13:32:13 -05:00
2014-08-24 15:33:46 -04:00
onRealTimePlaybackEnded: (e) ->
return unless @ realTime
@realTime = false
@ togglePlaybackControls true
2014-09-05 15:39:30 -04:00
Backbone . Mediator . publish ' audio-player:play-sound ' , trigger: ' real-time-playback-end ' , volume: 1
2014-08-24 15:33:46 -04:00
2014-08-26 01:05:24 -04:00
onStopRealTimePlayback: (e) ->
2014-09-25 12:48:14 -04:00
Backbone . Mediator . publish ' level:set-letterbox ' , on : false
2014-08-26 01:05:24 -04:00
Backbone . Mediator . publish ' playback:real-time-playback-ended ' , { }
2014-01-03 13:32:13 -05:00
# to refactor
hookUpScrubber: ->
@sliderIncrements = 500 # max slider width before we skip pixels
2014-03-29 19:38:45 -04:00
@ $progressScrubber . slider (
2014-01-03 13:32:13 -05:00
max: @ sliderIncrements
2014-06-30 22:16:26 -04:00
animate: ' slow '
2014-03-17 00:04:36 -04:00
slide: (event, ui) =>
2014-08-23 17:55:58 -04:00
return if @ shouldIgnore ( )
2014-09-05 15:39:30 -04:00
++ @ slideCount
oldRatio = @ getScrubRatio ( )
2014-03-17 00:04:36 -04:00
@ scrubTo ui . value / @ sliderIncrements
2014-09-05 15:39:30 -04:00
if ratioChange = @ getScrubRatio ( ) - oldRatio
sound = " playback-scrub-slide- #{ if ratioChange > 0 then ' forward ' else ' back ' } - #{ @ slideCount % 3 } "
Backbone . Mediator . publish ' audio-player:play-sound ' , trigger: sound , volume: Math . min 1 , Math . abs ratioChange * 50
2014-03-17 00:04:36 -04:00
start: (event, ui) =>
2014-08-23 17:55:58 -04:00
return if @ shouldIgnore ( )
2014-03-17 00:04:36 -04:00
@slideCount = 0
2014-09-25 01:12:00 -04:00
@wasPlaying = @ playing and not $ ( ' # play-button ' ) . hasClass ( ' ended ' )
2014-08-27 15:24:03 -04:00
Backbone . Mediator . publish ' level:set-playing ' , { playing: false }
2014-09-10 22:55:00 -04:00
Backbone . Mediator . publish ' audio-player:play-sound ' , trigger: ' playback-scrub-start ' , volume: 0.5
2014-09-11 14:08:25 -04:00
2014-03-17 00:04:36 -04:00
2014-01-03 13:32:13 -05:00
stop: (event, ui) =>
2014-08-23 17:55:58 -04:00
return if @ shouldIgnore ( )
2014-01-03 13:32:13 -05:00
@actualProgress = ui . value / @ sliderIncrements
2014-08-27 15:24:03 -04:00
Backbone . Mediator . publish ' playback:manually-scrubbed ' , ratio: @ actualProgress # For scripts
Backbone . Mediator . publish ' level:set-playing ' , { playing: @ wasPlaying }
2014-03-17 00:04:36 -04:00
if @ slideCount < 3
2014-01-03 13:32:13 -05:00
@wasPlaying = false
2014-08-27 15:24:03 -04:00
Backbone . Mediator . publish ' level:set-playing ' , { playing: false }
2014-01-03 13:32:13 -05:00
@ $el . find ( ' .scrubber-handle ' ) . effect ( ' bounce ' , { times: 2 } )
2014-09-05 15:39:30 -04:00
else
2014-09-10 22:55:00 -04:00
Backbone . Mediator . publish ' audio-player:play-sound ' , trigger: ' playback-scrub-end ' , volume: 0.5
2014-09-11 14:08:25 -04:00
2014-01-03 13:32:13 -05:00
)
getScrubRatio: ->
2014-03-29 19:38:45 -04:00
@ $progressScrubber . find ( ' .progress-bar ' ) . width ( ) / @ $progressScrubber . width ( )
2014-01-03 13:32:13 -05:00
scrubTo: (ratio, duration=0) ->
2014-03-17 00:43:14 -04:00
return if @ shouldIgnore ( )
2014-08-27 15:24:03 -04:00
Backbone . Mediator . publish ' level:set-time ' , ratio: ratio , scrubDuration: duration
2014-01-03 13:32:13 -05:00
2014-08-23 16:54:52 -04:00
shouldIgnore: -> return @ disabled or @ realTime
2014-01-03 13:32:13 -05:00
onTogglePlay: (e) ->
2014-08-28 20:08:05 -04:00
e ? . preventDefault ? ( )
2014-01-03 13:32:13 -05:00
return if @ shouldIgnore ( )
button = $ ( ' # play-button ' )
willPlay = button . hasClass ( ' paused ' ) or button . hasClass ( ' ended ' )
2014-08-27 15:24:03 -04:00
Backbone . Mediator . publish ' level:set-playing ' , playing: willPlay
2014-01-03 13:32:13 -05:00
$ ( document . activeElement ) . blur ( )
onToggleVolume: (e) ->
button = $ ( e . target ) . closest ( ' # volume-button ' )
classes = [ ' vol-off ' , ' vol-down ' , ' vol-up ' ]
volumes = [ 0 , 0.4 , 1.0 ]
for oldClass , i in classes
if button . hasClass oldClass
newI = ( i + 1 ) % classes . length
break
else if i is classes . length - 1 # no oldClass
newI = 2
2014-08-27 15:24:03 -04:00
Backbone . Mediator . publish ' level:set-volume ' , volume: volumes [ newI ]
2014-01-03 13:32:13 -05:00
$ ( document . activeElement ) . blur ( )
2014-02-26 13:42:25 -05:00
onToggleMusic: (e) ->
e ? . preventDefault ( )
2014-10-02 20:21:06 -04:00
me . set ( ' music ' , not me . get ( ' music ' , true ) )
2014-06-11 17:17:31 -04:00
me . patch ( )
2014-02-26 13:42:25 -05:00
$ ( document . activeElement ) . blur ( )
2014-03-29 19:38:45 -04:00
destroy: ->
me . off ( ' change:music ' , @ updateMusicButton , @ )
$ ( window ) . off ( ' resize ' , @ onWindowResize )
@onWindowResize = null
super ( )
2014-11-04 22:03:35 -05:00
# popover that shows at the current mouse position on the progressbar, using the bootstrap popover.
# Could make this into a jQuery plugins itself theoretically.
class HoverPopup extends $ . fn . popover . Constructor
constructor: () ->
@enabled = true
@shown = false
@type = ' HoverPopup '
@options =
placement: ' top '
container: ' body '
animation: true
html: true
delay:
show: 400
@$element = $ ( ' # timeProgress ' )
@$tip = $ ( ' # timePopover ' )
@content = ' '
getContent: -> @ content
show: ->
unless @ shown
super ( )
@shown = true
updateContent: (@content) ->
@ setContent ( )
@ $tip . addClass ( ' fade top in ' )
onHover: (@e) ->
pos = @ getPosition ( )
actualWidth = @ $tip [ 0 ] . offsetWidth
actualHeight = @ $tip [ 0 ] . offsetHeight
calculatedOffset =
top: pos . top - actualHeight
left: pos . left + pos . width / 2 - actualWidth / 2
this . applyPlacement ( calculatedOffset , ' top ' )
getPosition: ->
top: @ $element . offset ( ) . top
left: if @ e ? then @ e . pageX else @ $element . offset ( ) . left
height: 0
width: 0
hide: ->
super ( )
@shown = false
disable: ->
super ( )
@ hide ( )