import { Component, Attributes } from "armature"; import { $html, $each, $if } from "ekma"; import * as moment from "moment"; import GeckoCalendar, { DayEvent } from "./"; import * as API from "./API"; import CalendarDay from "./CalendarDay"; import EventStore from "./EventStore"; /** * Takes a list and produces a list of lists of a size no greater than `size` */ function takes(source: T[], size: number): T[][] { const output: T[][] = []; let last: T[] = []; for (const val of source) { last.push(val); if (last.length >= size) { output.push(last); last = []; } } if (last.length > 0) { output.push(last); } return output; } const template = (month: Month) => $html` ${ $each(month.rows, row => $html`
${ $each(row, day => $html` ${ $if(day, () => day, () => $html`
`) } `) }
`) } `; interface State { month: number; calendar: GeckoCalendar } @Attributes({ tag: "gecko-calendar-month", template }) export default class Month extends Component { selectedDay: CalendarDay; days: CalendarDay[]; rows: CalendarDay[][]; /** * Maps the day's date to the day component */ dayMap = new Map(); constructor(state: State) { super(state); EventStore.listen("showOnlyEvents", (ids: number[]) => { this.reify(); }); const thisMonth = API.monthNumberToMoment(this.state.month); const daysThisMonth = thisMonth.daysInMonth(); const firstThisMonth = thisMonth.weekday(); const nextMonth = thisMonth.clone().add(1, "month"); const firstNextMonth = nextMonth.weekday(); const lastMonth = thisMonth.clone().add(-1, "month"); this.days = []; for (let i = firstThisMonth; i > 0; i--) { this.days.push(null); } for (let i = 1; i <= daysThisMonth; i++) { const day = new CalendarDay({ month: this.state.month, date: i }); day .setLabel(i.toString()) .setParent(this); this.days.push(day); this.dayMap.set(i, day); } if (firstNextMonth > 0) { for (let i = 0; i < 7 - firstNextMonth; i++) { this.days.push(null); } } this.rows = takes(this.days, 7); if (this.rows.length < 6) { this.rows.push([null, null, null, null, null, null, null]); } } addEvents(events: DayEvent[]) { for (const event of events) { const now = moment.unix(event.date).utc(); const date = now.date(); const day = this.dayMap.get(date); if (!day) { console.warn(`Couldn't find date ${ date } on the calendar!`); continue; } day.addEvent(event); } } remove() { this.parent.children = this.parent.children.filter(v => v !== this); if (this.element.parentElement) { this.element.parentElement.removeChild(this.element); } } selectDay(day: CalendarDay) { if (this.selectedDay) { this.selectedDay.markDeselected(); } day.markSelected(); this.selectedDay = day; this.state.calendar.showEvents(day.state.events); } }