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) ->
|
2012-02-26 02:54:41 +00:00
|
|
|
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: ->
|
|
|
|
@bodyClassList().add('loading')
|
|
|
|
|
|
|
|
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
|
|
|
|
|
|
|
this.advanceTo(this.slideFromLocation())
|
|
|
|
|
|
|
|
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
|
|
|
|
|