You can not select more than 25 topics Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.

191 lines
4.9 KiB

4 years ago
4 years ago
4 years ago
4 years ago
4 years ago
4 years ago
4 years ago
4 years ago
4 years ago
4 years ago
4 years ago
4 years ago
4 years ago
4 years ago
4 years ago
4 years ago
4 years ago
4 years ago
4 years ago
  1. class TimeTable
  2. constructor: (@element, @modal) ->
  3. events = @element.querySelectorAll 'tbody td > ul > li'
  4. for event in events
  5. # JS scoping hell…
  6. event.addEventListener 'click', ((_this, _event) ->
  7. -> _this.modal.open _event
  8. )(this, event)
  9. parse_time: (time) ->
  10. time = time.split ':'
  11. hour = parseInt time[0]
  12. min = parseInt time[1]
  13. 60 * hour + min
  14. find_including: (times, time) ->
  15. previous = null
  16. for current in times
  17. if previous?
  18. if previous.time <= time < current.time
  19. return [previous, current]
  20. else
  21. previous = current
  22. null
  23. prorate: (ref, time) ->
  24. from = ref[0]
  25. to = ref[1]
  26. ratio = (time - from.time) / (to.time - from.time)
  27. top = from.top + (to.top - from.top) * ratio
  28. top
  29. position: (times, element) ->
  30. from = @parse_time element.dataset.from
  31. to = @parse_time element.dataset.to
  32. including_from = @find_including times, from
  33. including_to = @find_including times, to
  34. top = @prorate including_from, from
  35. bottom = @prorate including_to, to
  36. root = element.parentElement
  37. width = root.offsetWidth
  38. element.style.top = "#{top + window.pageYOffset}px"
  39. element.style.height = "#{bottom - top}px"
  40. element.style.width = "#{width}px"
  41. element.style.position = 'absolute'
  42. init: ->
  43. times = []
  44. hours = @element.querySelectorAll 'tbody th > ul > li'
  45. for hour in hours
  46. time = @parse_time hour.dataset.time
  47. times.push {
  48. time: time,
  49. top: hour.getBoundingClientRect().top
  50. }
  51. last = hours[hours.length - 1]
  52. time = @parse_time last.dataset.time
  53. rect = last.getBoundingClientRect()
  54. times.push {
  55. time: time + 60
  56. top: rect.top + rect.height
  57. }
  58. events = @element.querySelectorAll 'tbody td > ul > li'
  59. for event in events
  60. @position times, event
  61. class Modal
  62. size: { width: 800, height: 480 }
  63. constructor: (@modal) ->
  64. @header = @modal.querySelector '.header'
  65. @body = @modal.querySelector '.body'
  66. @modal.querySelector('.close').addEventListener 'click', @close
  67. @modal.querySelector('.cover').addEventListener 'click', @close
  68. act: (events) ->
  69. wrapper = =>
  70. next = events.shift()
  71. return unless next?
  72. [duration, callback] = next
  73. setTimeout (=>
  74. callback()
  75. wrapper()
  76. ), duration
  77. wrapper()
  78. start: ->
  79. start = @event.getBoundingClientRect()
  80. scroll = {
  81. top: window.pageYOffset,
  82. left: window.pageXOffset
  83. }
  84. @modal.style.top = "#{start.top + scroll.top}px"
  85. @modal.style.left = "#{start.left + scroll.left}px"
  86. @modal.style.width = "#{start.width}px"
  87. @modal.style.height = "#{start.height}px"
  88. @header.style.width = "#{start.width}px"
  89. @header.style.height = "#{start.height}px"
  90. @body.style.width = 0
  91. @body.style.height = "#{start.height}px"
  92. open: (@event) ->
  93. scroll = {
  94. top: window.pageYOffset,
  95. left: window.pageXOffset
  96. }
  97. modal =
  98. width: Math.round window.innerWidth * .8
  99. height: Math.round window.innerHeight * .8
  100. modal =
  101. width: Math.min modal.width, @size.width
  102. height: Math.min modal.height, @size.height
  103. modal.top = Math.round (window.innerHeight - modal.height) / 2 + scroll.top
  104. modal.left = Math.round (window.innerWidth - modal.width) / 2 + scroll.left
  105. header_width = Math.round modal.width / 3
  106. time = @event.querySelector('.time').textContent
  107. @header.querySelector('.time').textContent = time
  108. title = @event.querySelector('.title').textContent
  109. @header.querySelector('.title').textContent = title
  110. author = @event.querySelector('.author').textContent
  111. @header.querySelector('.author').textContent = author
  112. description = @event.querySelector('.description').innerHTML
  113. @body.innerHTML = ''
  114. @modal.classList.remove 'transition'
  115. @act [
  116. [20, =>
  117. @start()
  118. @header.classList = @event.classList
  119. @header.classList.add 'header'
  120. @modal.style.opacity = 1
  121. @modal.classList.remove 'hidden'
  122. ],
  123. [20, =>
  124. @transition @modal, null, =>
  125. @body.innerHTML = description
  126. @modal.style.top = "#{modal.top}px"
  127. @modal.style.left = "#{modal.left}px"
  128. @modal.style.width = "#{modal.width}px"
  129. @modal.style.height = "#{modal.height}px"
  130. @header.style.width = "#{header_width}px"
  131. @header.style.height = "#{modal.height}px"
  132. @body.style.width = "#{modal.height - header_width}px"
  133. @body.style.height = "#{modal.height}px"
  134. ]
  135. ]
  136. close: =>
  137. @act [
  138. [20, =>
  139. @transition @modal, null, =>
  140. @modal.classList.add 'hidden'
  141. @body.innerHTML = ''
  142. @start()
  143. ]
  144. ]
  145. transition: (element, events, at_end) ->
  146. element.classList.add 'transition'
  147. callback = ->
  148. element.removeEventListener 'transitionend', callback
  149. element.classList.remove 'transition'
  150. at_end() if at_end?
  151. element.addEventListener 'transitionend', callback
  152. @act events if events?
  153. init = ->
  154. modal = new Modal document.querySelector '.modal'
  155. tables = document.querySelectorAll 'table.timetable'
  156. for table in tables
  157. new TimeTable(table, modal).init()
  158. document.addEventListener 'DOMContentLoaded', init
  159. window.addEventListener 'resize', init