guide.coffee 7.4 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263
  1. #
  2. # Config
  3. #
  4. FETCH_URL = 'programs.php'
  5. HOUR_WIDTH = 200
  6. CHANNEL_LABEL_WIDTH = 180
  7. STORAGE_CHANNELS = 'tvgids-channels'
  8. STORAGE_PROGRAMS = 'tvgids-programs'
  9. #SCROLL_MULTIPLIER = HOUR_WIDTH
  10. #
  11. # Utils
  12. #
  13. seconds_today = (time) -> (time - (new Date()).setHours(0, 0, 0, 0)) / 1000
  14. time2px = (seconds) -> HOUR_WIDTH / 3600 * seconds
  15. zeropad = (digit) -> if digit < 10 then '0' + digit else String(digit)
  16. format_time = (time) ->
  17. date = new Date(time)
  18. zeropad(date.getHours()) + ':' + zeropad(date.getMinutes())
  19. store_list = (name, values) -> localStorage.setItem(name, values.join(';'))
  20. load_stored_list = (name, def) ->
  21. store_list(name, def) if not localStorage.hasOwnProperty(name)
  22. value = localStorage.getItem(name)
  23. if value.length > 0 then value.split(';') else []
  24. #
  25. # Models & collections
  26. #
  27. Channel = Backbone.Model.extend(
  28. defaults:
  29. id: null
  30. name: 'Some channel'
  31. visible: true
  32. programs: []
  33. )
  34. Program = Backbone.Model.extend(
  35. defaults:
  36. title: 'Some program'
  37. genre: ''
  38. sort: ''
  39. start: 0
  40. end: 0
  41. article_id: null
  42. article_title: null
  43. )
  44. ChannelList = Backbone.Collection.extend(
  45. model: Channel
  46. #comparator: (a, b) -> parseInt(a.get('id')) - parseInt(b.get('id'))
  47. initialize: ->
  48. @listenTo(Settings, 'change:favourite_channels', @propagateVisible)
  49. fetch: ->
  50. @reset(CHANNELS)
  51. #$.getJSON('channels.php', (data) => @reset(data))
  52. @propagateVisible()
  53. propagateVisible: ->
  54. visible = Settings.get('favourite_channels')
  55. for id in visible
  56. @findWhere(id: id)?.set(visible: true)
  57. for id in _.difference(@pluck('id'), visible)
  58. @findWhere(id: id)?.set(visible: false)
  59. fetchPrograms: (day) ->
  60. $.getJSON(
  61. FETCH_URL
  62. channels: @pluck('id').join(','), day: day
  63. (channels) ->
  64. _.each channels, (programs, id) ->
  65. channel = Channels.findWhere(id: id)
  66. channel.set(programs: (
  67. new Program(
  68. title: p.titel
  69. genre: p.genre
  70. sort: p.soort
  71. start: Date.parse(p.datum_start)
  72. end: Date.parse(p.datum_end)
  73. article_id: p.artikel_id
  74. article_title: p.artikel_titel
  75. ) for p in programs
  76. ))
  77. )
  78. )
  79. #
  80. # Views
  81. #
  82. ChannelView = Backbone.View.extend(
  83. tagName: 'div'
  84. className: 'channel'
  85. initialize: ->
  86. @listenTo(@model, 'change:programs', @render)
  87. @listenTo(@model, 'change:visible', @toggleVisible)
  88. #@$el.text(@model.get('title'))
  89. render: ->
  90. @$el.empty()
  91. _.each @model.get('programs'), (program) =>
  92. view = new ProgramView(model: program)
  93. view.render()
  94. @$el.append(view.el)
  95. toggleVisible: ->
  96. @$el.toggle(@model.get('visible'))
  97. )
  98. ProgramView = Backbone.View.extend(
  99. tagName: 'div'
  100. className: 'program'
  101. events:
  102. 'click .favlink': 'toggleFavourite'
  103. initialize: ->
  104. $('<span class="title"/>').text(@model.get('title')).appendTo(@el)
  105. from = format_time(@model.get('start'))
  106. to = format_time(@model.get('end'))
  107. @$el.attr('title', @model.get('title') + " (#{from} - #{to})")
  108. @$fav = $('<a class="favlink icon-heart"/>').appendTo(@el)
  109. @$fav.attr('title', 'Als favoriet instellen')
  110. @updateFavlink()
  111. left = time2px(Math.max(0, seconds_today(@model.get('start'))))
  112. width = time2px(seconds_today(@model.get('end'))) - left
  113. @$el.css(
  114. left: left + 'px'
  115. width: (width - 10) + 'px'
  116. )
  117. @listenTo(Settings, 'change:favourite_programs', @updateFavlink)
  118. toggleFavourite: ->
  119. Settings.toggleFavouriteProgram(@model.get('title'))
  120. updateFavlink: ->
  121. isfav = Settings.isFavouriteProgram(@model.get('title'))
  122. @$fav.toggleClass('favourite', isfav)
  123. render: ->
  124. if @model.get('start') <= Date.now()
  125. if @model.get('end') < Date.now()
  126. @$el.removeClass('current').addClass('past')
  127. else
  128. @$el.addClass('current')
  129. )
  130. ChannelLabelView = Backbone.View.extend(
  131. el: $('.channel-labels')
  132. initialize: (options) ->
  133. @listenTo(Channels, 'reset', @addChannels)
  134. @listenTo(options.app, 'scroll', @moveTop)
  135. addChannels: ->
  136. @$el.empty()
  137. Channels.each((channel) ->
  138. elem = $('<div id="label-' + channel.get('id') + '" class="label"/>')
  139. elem.html(channel.get('name')).toggle(channel.get('visible')).appendTo(@el)
  140. @listenTo(channel, 'change:visible', -> @toggleVisible(channel))
  141. , @)
  142. moveTop: (delta) ->
  143. @$el.css('top', (@$el.position().top - delta) + 'px')
  144. toggleVisible: (channel) ->
  145. @$('#label-' + channel.get('id')).toggle(channel.get('visible'))
  146. )
  147. AppView = Backbone.View.extend(
  148. el: $('#guide')
  149. events:
  150. # TODO: move to initialize
  151. 'click #yesterday': -> @loadDay(-1)
  152. 'click #today': -> @loadDay(0)
  153. 'click #tomorrow': -> @loadDay(1)
  154. 'scroll': 'moveTimeline'
  155. moveTimeline: ->
  156. if @$el.scrollTop() != @prevScrollTop
  157. @trigger('scroll', @$el.scrollTop() - @prevScrollTop)
  158. @prevScrollTop = @$el.scrollTop()
  159. @$('.timeline').css('top', (@$el.scrollTop() + 37) + 'px')
  160. initialize: ->
  161. @prevScrollTop = null
  162. @listenTo(Channels, 'reset', @addChannels)
  163. @listenTo(Settings, 'change:day', @fetchPrograms)
  164. @labelview = new ChannelLabelView(app: @)
  165. @updateIndicator()
  166. @centerIndicator()
  167. Channels.fetch()
  168. setInterval((=> @updateIndicator()), 3600000 / HOUR_WIDTH)
  169. addChannels: ->
  170. @$('.channels > .channel').remove()
  171. Channels.each((channel) ->
  172. view = new ChannelView(model: channel)
  173. view.render()
  174. @$('.channels').append(view.el)
  175. , @)
  176. @$('.indicator').height(@$('.channels').height())
  177. @fetchPrograms()
  178. loadDay: (day) ->
  179. Settings.set(day: day)
  180. @$('.navbar .active').removeClass('active')
  181. $(@$('.navbar .navitem')[day + 1]).addClass('active')
  182. updateIndicator: ->
  183. left = time2px(seconds_today(Date.now())) + CHANNEL_LABEL_WIDTH - 1
  184. @$('.indicator').css('left', left + 'px')
  185. centerIndicator: ->
  186. @$el.scrollLeft(@$('.indicator').position().left - @$el.width() / 2)
  187. fetchPrograms: ->
  188. Channels.fetchPrograms(Settings.get('day'))
  189. )
  190. #
  191. # Main
  192. #
  193. Settings = new (Backbone.Model.extend(
  194. defaults:
  195. day: 0
  196. favourite_channels: load_stored_list(STORAGE_CHANNELS,
  197. _.pluck(CHANNELS, 'id'))
  198. favourite_programs: load_stored_list(STORAGE_PROGRAMS, [])
  199. toggleFavouriteProgram: (title) ->
  200. list = @get('favourite_programs')
  201. if @isFavouriteProgram(title)
  202. list.splice(list.indexOf(title), 1)
  203. else
  204. list.push(title)
  205. @attributes.favourite_programs = list
  206. @trigger('change:favourite_programs')
  207. store_list(STORAGE_PROGRAMS, list)
  208. isFavouriteProgram: (title) ->
  209. _.contains(@get('favourite_programs'), title)
  210. ))()
  211. Channels = new ChannelList()
  212. App = new AppView()