Mailspring/internal_packages/calendar-bar/lib/calendar-bar.cjsx
Ben Gotow 91edef9f7a fix(naming): Move atom/inbox/nilas refs to Nylas
Conflicts:
	internal_packages/inbox-activity-bar/lib/activity-bar-long-poll-item.cjsx
2015-05-15 11:07:28 -07:00

127 lines
4 KiB
CoffeeScript

React = require 'react'
{Actions} = require("nylas-exports")
CalendarBarItem = require("./calendar-bar-item")
CalendarBarEventStore = require ("./calendar-bar-event-store")
class CalendarBarRow
constructor: (initialItem = null) ->
@items = []
@last = 0
if initialItem
@last = initialItem.event.end
@items.push(initialItem)
canHoldItem: (item) =>
item.event.start > @last
addItem: (item) =>
@last = item.event.end
@items.push(item)
class CalendarBarMarker extends React.Component
@displayName: "CalendarBarMarker"
render: =>
classname = "marker"
classname += " now" if @props.marker.now
<div className={classname} style={left: @props.marker.xPercent} id={@props.marker.xPercent}/>
class CalendarBar extends React.Component
@displayName: "CalendarBar"
constructor: (@props) ->
@state = @_getStateFromStores()
componentDidMount: =>
@unsubscribe = CalendarBarEventStore.listen @_onStoreChange
# It's important that every React class explicitly stops listening to
# atom events before it unmounts. Thank you event-kit
# This can be fixed via a Reflux mixin
componentWillUnmount: =>
@unsubscribe() if @unsubscribe
render: =>
markers = @_getMarkers().map (marker) ->
<CalendarBarMarker marker={marker}/>
items = @_getItemsForEvents(@state.events)
items = items.map (item) ->
<CalendarBarItem item={item}/>
<div className="calendar-bar-inner">
{markers}
{items}
</div>
_onStoreChange: =>
@setState @_getStateFromStores()
_getStateFromStores: =>
events: CalendarBarEventStore.events()
range: CalendarBarEventStore.range()
_getMarkers: =>
range = @state.range
now = (new Date).getTime()/1000 - range.start
markers = []
for hour in [0..24]
time = 60*60*hour
markers.push
xPercent: (time * 100) / (range.end - range.start) + "%"
markers.push
now: true
xPercent: (now * 100) / (range.end - range.start) + "%"
markers
_getItemsForEvents: (events) =>
# Create an array of items with additional metadata needed for our view.
# We compute the X and width of elements using their durations as a fraction
# of the displayed range
range = @state.range
items = events.map (event) ->
{
event: event,
z: event.start - range.start
xPercent: (event.start - range.start) * 100 / (range.end - range.start) + "%",
wPercent: (event.end - event.start) * 100 / (range.end - range.start) + "%"
}
# Compute the number of rows we need by assigning events to rows. This works by
# creating virtual "row" objects which hold a series of non-overlapping events and
# have a "last" timestamp. For each item, we iterate through the rows:
#
# - If the event fits in more than one row, we delete all but one of the rows.
# This ensures that if we have two overlapping events, the next event that
# does not overlap goes back to taking all of the available height. (Rows no
# longer necessary)
#
# - If the event does not fit in any rows, we create a new row, and tell all of
# the items in existing rows that they're now sharing space with a new row.
rows = [new CalendarBarRow]
for item in items
for x in [rows.length-1..0] by -1
if rows[x].canHoldItem(item)
rows.splice(item.rowIndex, 1) unless item.rowIndex is undefined
rows[x].addItem(item)
item.rowIndex = x
if item.rowIndex is undefined
rows.push(new CalendarBarRow(item))
item.rowIndex = rows.length - 1
for row in rows
for item in row.items
item.rowCount += 1
item.rowCount = rows.length
# Now that each item knows what row it's in and how many rows are being displayed
# alongside it, we can assign fractional positions to them.
for item in items
item.yPercent = (item.rowIndex / item.rowCount) * 100 + "%"
item.hPercent = (100.0 / item.rowCount) + "%"
items
module.exports = CalendarBar