attentive/lib/assets/javascripts/attentive.js.coffee

213 lines
4.6 KiB
CoffeeScript
Raw Normal View History

2012-02-20 21:53:48 +00:00
#= require underscore
#
2012-02-15 16:34:08 +00:00
class PresentationTimer
constructor: ->
@time = 0
@el = document.createElement('div')
@el.classList.add('timer')
this.render()
render: ->
@el.innerHTML = this.formattedTime()
start: ->
@_runner = this.runner()
2012-02-20 21:53:48 +00:00
@el.classList.add('running')
2012-02-15 16:34:08 +00:00
runner: ->
setTimeout(
=>
this.render()
@time += 1
this.runner() if @_runner?
, 1000
)
stop: ->
clearTimeout(@_runner)
2012-02-20 21:53:48 +00:00
@el.classList.remove('running')
2012-02-15 16:34:08 +00:00
@_runner = null
reset: ->
this.stop()
@time = 0
this.render()
toggle: ->
if @_runner?
this.stop()
else
this.start()
toggleVisible: ->
@el.classList.toggle('hide')
isVisible: ->
!@el.classList.contains('hide')
hide: ->
@el.classList.add('hide')
formattedTime: ->
minute = "00#{Math.floor(@time / 60)}".slice(-2)
second = "00#{@time % 60}".slice(-2)
"#{minute}:#{second}"
2012-02-20 21:53:48 +00:00
class Slide
@fromList: (list) ->
result = (new Slide(slide) for slide in list)
constructor: (@dom) ->
recalculate: =>
@dom.style['width'] = "#{window.innerWidth}px"
currentMarginTop = Number(@dom.style['marginTop'].replace(/[^\d\.]/g, ''))
height = (window.innerHeight - @dom.querySelector('.content').clientHeight) / 2
if height != currentMarginTop
@dom.style['marginTop'] = "#{height}px"
true
activate: =>
@dom.classList.add('active')
deactivate: =>
@dom.classList.remove('active')
2012-02-14 21:32:35 +00:00
class this.Attentive
@setup: (identifier) ->
starter = ->
setTimeout(
->
(new Attentive(identifier)).start()
, 250
)
2012-02-14 21:32:35 +00:00
window.addEventListener('DOMContentLoaded', starter, false)
constructor: (@identifier) ->
@length = @allSlides().length
@priorSlide = null
@initialRender = true
2012-02-15 16:34:08 +00:00
@timer = new PresentationTimer()
@timer.hide()
2012-02-20 21:53:48 +00:00
@currentWindowHeight = null
2012-02-15 16:34:08 +00:00
document.querySelector('body').appendChild(@timer.el)
2012-02-14 21:32:35 +00:00
bodyClassList: ->
@_bodyClassList ||= document.querySelector('body').classList
allSlides: ->
2012-02-20 21:53:48 +00:00
@_allSlides ||= Slide.fromList(@slidesViewer().querySelectorAll('.slide'))
2012-02-14 21:32:35 +00:00
slidesViewer: ->
@_slidesViewer ||= document.querySelector(@identifier)
start: ->
if !this.isFile()
window.addEventListener('popstate', @handlePopState, false)
document.addEventListener('click', @handleClick, false)
document.addEventListener('keydown', @handleKeyDown, false)
2012-02-20 21:53:48 +00:00
window.addEventListener('resize', _.throttle(@calculate, 500), false)
2012-02-14 21:32:35 +00:00
2012-02-27 14:08:27 +00:00
imageWait = null
imageWait = =>
wait = false
for slide in @allSlides()
for img in slide.dom.getElementsByTagName('img')
wait = true if !img.complete
if wait
setTimeout(imageWait, 100)
else
this.advanceTo(this.slideFromLocation())
imageWait()
2012-02-14 21:32:35 +00:00
slideFromLocation: ->
value = if this.isFile()
location.hash
else
location.pathname
Number(value.substr(1))
handlePopState: (e) =>
this.advanceTo(if e.state then e.state.index else this.slideFromLocation())
handleClick: (e) =>
this.advance() if e.target.tagName != 'A'
handleKeyDown: (e) =>
switch e.keyCode
2012-02-15 16:34:08 +00:00
when 72
this.advanceTo(0)
2012-02-14 21:32:35 +00:00
when 37
this.advance(-1)
when 39, 32
this.advance()
2012-02-15 16:34:08 +00:00
when 220
@timer.reset()
when 84
if e.shiftKey
@timer.toggleVisible()
else
@timer.toggle() if @timer.isVisible()
2012-02-14 21:32:35 +00:00
advance: (offset = 1) =>
this.advanceTo(Math.max(Math.min(@currentSlide + offset, @length - 1), 0))
isFile: => location.href.slice(0, 4) == 'file'
advanceTo: (index) =>
@priorSlide = @currentSlide
@currentSlide = index || 0
this.calculate()
if this.isFile()
location.hash = @currentSlide
else
history.pushState({ index: @currentSlide }, '', @currentSlide)
calculate: =>
2012-02-20 21:53:48 +00:00
if @currentWindowHeight != window.innerHeight
recalculate = true
times = 3
while recalculate and times > 0
recalculate = false
times -= 1
2012-02-14 21:32:35 +00:00
2012-02-20 21:53:48 +00:00
for slide in @allSlides()
recalculate = true if slide.recalculate()
2012-02-14 21:32:35 +00:00
2012-02-20 21:53:48 +00:00
@currentWindowHeight = window.innerHeight
@slidesViewer().style['width'] = "#{window.innerWidth * @allSlides().length}px"
2012-02-14 21:32:35 +00:00
this.align()
2012-02-20 21:53:48 +00:00
getCurrentSlide: =>
@allSlides()[@currentSlide]
2012-02-14 21:32:35 +00:00
align: =>
2012-02-20 21:53:48 +00:00
@allSlides()[@priorSlide].deactivate() if @priorSlide
this.getCurrentSlide().activate()
2012-02-14 21:32:35 +00:00
@slidesViewer().style['left'] = "-#{@currentSlide * window.innerWidth}px"
if @initialRender
@bodyClassList().remove('loading')
@initialRender = false
2012-02-27 14:08:27 +00:00
@currentWindowHeight = null
this.calculate()