class TimeTable constructor: (@element, @modal) -> events = @element.querySelectorAll 'tbody td > ul > li' for event in events # JS scoping hell… event.addEventListener 'click', ((_this, _event) -> -> _this.modal.open _event )(this, event) parse_time: (time) -> time = time.split ':' hour = parseInt time[0] min = parseInt time[1] 60 * hour + min find_including: (times, time) -> previous = null for current in times if previous? if previous.time <= time < current.time return [previous, current] else previous = current null prorate: (ref, time) -> from = ref[0] to = ref[1] ratio = (time - from.time) / (to.time - from.time) top = from.top + (to.top - from.top) * ratio top position: (times, element) -> from = @parse_time element.dataset.from to = @parse_time element.dataset.to including_from = @find_including times, from including_to = @find_including times, to top = @prorate including_from, from bottom = @prorate including_to, to root = element.parentElement width = root.offsetWidth element.style.top = "#{top + window.pageYOffset}px" element.style.height = "#{bottom - top}px" element.style.width = "#{width}px" element.style.position = 'absolute' init: -> times = [] hours = @element.querySelectorAll 'tbody th > ul > li' for hour in hours time = @parse_time hour.dataset.time times.push { time: time, top: hour.getBoundingClientRect().top } last = hours[hours.length - 1] time = @parse_time last.dataset.time rect = last.getBoundingClientRect() times.push { time: time + 60 top: rect.top + rect.height } events = @element.querySelectorAll 'tbody td > ul > li' for event in events @position times, event class Modal size: { width: 800, height: 480 } constructor: (@modal) -> @header = @modal.querySelector '.header' @body = @modal.querySelector '.body' @modal.querySelector('.close').addEventListener 'click', @close @modal.querySelector('.cover').addEventListener 'click', @close act: (events) -> wrapper = => next = events.shift() return unless next? [duration, callback] = next setTimeout (=> callback() wrapper() ), duration wrapper() start: -> start = @event.getBoundingClientRect() scroll = { top: window.pageYOffset, left: window.pageXOffset } @modal.style.top = "#{start.top + scroll.top}px" @modal.style.left = "#{start.left + scroll.left}px" @modal.style.width = "#{start.width}px" @modal.style.height = "#{start.height}px" @header.style.width = "#{start.width}px" @header.style.height = "#{start.height}px" @body.style.width = 0 @body.style.height = "#{start.height}px" open: (@event) -> scroll = { top: window.pageYOffset, left: window.pageXOffset } modal = width: Math.round window.innerWidth * .8 height: Math.round window.innerHeight * .8 modal = width: Math.min modal.width, @size.width height: Math.min modal.height, @size.height modal.top = Math.round (window.innerHeight - modal.height) / 2 + scroll.top modal.left = Math.round (window.innerWidth - modal.width) / 2 + scroll.left header_width = Math.round modal.width / 3 time = @event.querySelector('.time').textContent @header.querySelector('.time').textContent = time title = @event.querySelector('.title').textContent @header.querySelector('.title').textContent = title author = @event.querySelector('.author').textContent @header.querySelector('.author').textContent = author description = @event.querySelector('.description').innerHTML @body.innerHTML = '' @modal.classList.remove 'transition' @act [ [20, => @start() @header.classList = @event.classList @header.classList.add 'header' @modal.style.opacity = 1 @modal.classList.remove 'hidden' ], [20, => @transition @modal, null, => @body.innerHTML = description @modal.style.top = "#{modal.top}px" @modal.style.left = "#{modal.left}px" @modal.style.width = "#{modal.width}px" @modal.style.height = "#{modal.height}px" @header.style.width = "#{header_width}px" @header.style.height = "#{modal.height}px" @body.style.width = "#{modal.height - header_width}px" @body.style.height = "#{modal.height}px" ] ] close: => @act [ [20, => @transition @modal, null, => @modal.classList.add 'hidden' @body.innerHTML = '' @start() ] ] transition: (element, events, at_end) -> element.classList.add 'transition' callback = -> element.removeEventListener 'transitionend', callback element.classList.remove 'transition' at_end() if at_end? element.addEventListener 'transitionend', callback @act events if events? init = -> modal = new Modal document.querySelector '.modal' tables = document.querySelectorAll 'table.timetable' for table in tables new TimeTable(table, modal).init() document.addEventListener 'DOMContentLoaded', init window.addEventListener 'resize', init