app/assets/javascripts/announcer.js.coffee
class window.Announcer
constructor: (options) ->
@admin = options.admin
@callbacks = [@renderDashboard]
@renderFunction = switch options.type
when 'dashboard' then @render
else @renderNotice
@renderFunction(options.stats) if options.stats
@connect()
@initializeDomEvents()
initializeDomEvents: ->
@initializeButtonClickWithRender
selector: '#start-race'
url: '/races/new'
method: 'get'
replacementText: 'Starting…'
@initializeButtonClickWithRender
selector: '#redo'
url: '/races/redo'
method: 'put'
replacementText: 'redoing…'
@initializeButtonClickWithRender
selector: '.cancel-heat'
url: '/heats/cancel_current'
method: 'post'
click: (event) -> $(event.target).css(opacity: 0)
@initializeHoverEventsForCancelHeat()
initializeButtonClickWithRender: (options) ->
button = $(options.selector)
button.click (event) =>
event.preventDefault()
return if options.click?(event) == false
@ajaxLoadingButton button, options.replacementText, (doneLoadingCallback) =>
$.ajax
url: options.url
method: options.method || 'POST'
dataType: 'json'
success: (json) =>
@renderFunction(json)
doneLoadingCallback()
ajaxLoadingButton: (button, replacementText, clickHandler) ->
button = $(button)
return console.log 'Ignored click while loading' if button.data 'loading'
button.data 'loading', true
button.data 'originalText', button.text() unless button.data 'originalText'
doneLoadingCallback = ->
button.text button.data 'originalText'
button.data 'loading', false
clickHandler(doneLoadingCallback)
button.text(replacementText) if replacementText
initializeHoverEventsForCancelHeat: ->
hoverTargets = '.current-race,.cancel-heat'
cancelHeatButton = $('.cancel-heat')
$(document).on 'mouseenter', hoverTargets, ->
cancelHeatButton.css(opacity: 1, cursor: 'pointer') if $('.current-race').length
$(document).on 'mouseleave', hoverTargets, ->
cancelHeatButton.css(opacity: 0, cursor: 'default')
connect: ->
@faye = window.faye = new Faye.Client '/faye', timeout: 30
@faye.subscribe '/announce', (stats) =>
console.log '/announce: ', stats
@renderFunction JSON.parse(stats)
render: (stats) ->
callback.call(@, stats) for callback in @callbacks
renderDashboard: (stats) ->
return if @renderEquivalent(stats, @lastRenderedStats)
@lastRenderedStats = stats
@notifyOfChange() if @alreadyRendered
@alreadyRendered = true
@dashboard = $('#dashboard')
return unless @dashboard.length
@renderStandings stats.contestant_times
@renderMostRecentHeat stats.most_recent_heat
@renderUpcomingHeats stats.upcoming_heats
@renderNotice stats
renderEquivalent: (stats1, stats2) ->
stats1 = $.extend({}, stats1)
stats2 = $.extend({}, stats2)
for stats in [stats1, stats2]
stats.device_status = null
for heat in stats.upcoming_heats || []
for contestant in heat.contestants || []
contestant.run_id = null
console.log('checking', window.s1=stats1, window.s2=stats2, _.isEqual(stats1, stats2))
_.isEqual(stats1, stats2)
renderStandings: (contestantTimes = []) ->
container = @dashboard.find('#standings')
standings = for contestant in contestantTimes
"<div class='contestant'>" +
" <div class='name span2'>#{contestant.rank}</div>" +
" <div class='name span7'>#{contestant.name}</div>" +
" <div class='time span3'>#{contestant.average_time}</div>" +
"</div>"
if standings.length
container.show().find('.contestants').html standings.join('\n')
else
container.hide()
renderMostRecentHeat: (mostRecentHeat = []) ->
container = @dashboard.find('#most-recent-heat')
container.find('.name, .time').html('')
for run in mostRecentHeat
lane = container.find(".lane#{run.lane}")
lane.find('.name').html(run.name)
lane.find('.time').html(run.time)
if mostRecentHeat.length
container.show()
else
container.hide()
renderUpcomingHeats: (upcomingHeats = []) ->
container = @dashboard.find('#upcoming-heats')
if upcomingHeats.length
container.show()
else
container.hide()
container.find('.name').html('')
upcomingCounter = 0
for heat in upcomingHeats
upcomingCounter++
heatContainer = container.find(".next#{upcomingCounter}")
if heat.current
heatContainer.addClass('current-race btn-success')
else
heatContainer.removeClass('current-race btn-success')
for contestant in heat.contestants
slot = heatContainer.find(".lane#{contestant.lane}")
if contestant.postponable and @admin
contestantLink = "<a href='/runs/#{contestant.run_id}/postpone' class='postponable' title='postpone'>#{contestant.name}</a>"
slot.html contestantLink
else
slot.html contestant.name
renderNotice: (stats) ->
{notice, device_status} = stats
if notice
$('#faye-notification').show().html notice
else
$('#faye-notification').hide()
if device_status == 'idle'
$('#start-race,#redo').show()
else
$('#start-race,#redo').hide()
if stats.derby_status == 'begin' && window.location.pathname == '/'
window.location.href = '/board'
else if stats.derby_status == 'complete'
setTimeout ->
window.location.href = '/contestants'
, 5000
notifyOfChange: ->
$("body").stop().css("background-color", "#FFFF7C").animate({ backgroundColor: "#FFFFFF"}, 500)