UNPKG

ember-assembly

Version:

A collection of beautiful UI components built by Goods

199 lines (178 loc) 5.5 kB
import Component from '@ember/component'; // @ts-ignore: Ignore import of compiled template import template from './template'; import moment, { Moment } from 'moment'; import { action, computed, set } from '@ember/object'; import { isNone } from '@ember/utils'; interface Day { id: string; number: string; date: Moment; isCurrentMonth: boolean; isPreviousMonth: boolean; isNextMonth: boolean; isToday: boolean; isSelected: boolean; isRangeStart: boolean; isRangeFinish: boolean; } export default class UiCalendar extends Component { layout = template; tagName: string = ''; selected: Moment[] = []; mode?: 'single' | 'multiple' | 'range' = 'multiple'; center?: Moment = moment.utc(); rangeStart?: Moment | undefined = undefined; rangeFinish?: Moment | undefined = undefined; onChangeSelection?: Function | null = null; onChangeRange?: Function | null = null; onChangeCenter?: Function | null = null; /* A local copy of the range start and finish is needed to handle the problem where the range is only actually selected once a start and finish have been chosen. */ localRangeStart: Moment | undefined = undefined; localRangeFinish: Moment | undefined = undefined; @computed('center') get startDate(): Moment { return moment.utc(this.center).startOf('month').startOf('week'); } @computed('center') get finishDate(): Moment { return moment.utc(this.center).endOf('month').endOf('week'); } @computed( 'center', 'startDate', 'finishDate', 'selected.[]', 'localRangeStart', 'localRangeFinish' ) get days(): Day[] { let days: any = []; let date = this.startDate.clone(); let currentMonth = moment.utc().format('M'); if (!isNone(this.center)) { currentMonth = this.center.format('M'); } let formattedSelected = this.selected.map((selected) => moment(selected).format('YYYY-MM-DD') ); while (date.isBefore(this.finishDate)) { let id = date.format('YYYY-MM-DD'); let isSelected = false; let isRangeStart = false; let isRangeFinish = false; if (this.mode == 'range') { let localRangeFinish = this.localRangeFinish; if (isNone(localRangeFinish)) { localRangeFinish = this.localRangeStart; } isRangeStart = !isNone(this.localRangeStart) && this.localRangeStart.isSame(date, 'day'); isRangeFinish = !isNone(this.localRangeFinish) && this.localRangeFinish.isSame(date, 'day'); isSelected = date.isSameOrAfter(this.localRangeStart, 'day') && date.isSameOrBefore(localRangeFinish, 'day'); } else { isSelected = formattedSelected.find((selected) => selected == id) !== undefined; } days.push({ id: id, number: date.format('D'), date: date.clone(), isCurrentMonth: date.format('M') == currentMonth, isPreviousMonth: date.isBefore(this.center, 'month'), isNextMonth: date.isAfter(this.center, 'month'), isToday: date.isSame(moment.utc(), 'day'), isSelected, isRangeStart, isRangeFinish, }); date.add(1, 'day'); } return days; } @computed('days.[]') get weeks() { let { days } = this; let weeks: any = []; let i = 0; while (days[i]) { let daysOfWeek = days.slice(i, i + 7); let id = ''; if (!isNone(daysOfWeek[0])) { id = daysOfWeek[0].id; } weeks.push({ id: `week-of-${id}`, days: daysOfWeek, missingDays: 7 - daysOfWeek.length, }); i += 7; } return weeks; } @action onMoveCenter(quantity: number, unit: 'day' | 'month' | 'year') { let center = moment.utc(this.center).add(quantity, unit); if (!isNone(this.onChangeCenter)) { this.onChangeCenter(center); } else { set(this, 'center', center); } } @action onSelectDate(day: Day) { let selected: Moment[] = []; if (this.mode == 'single') { selected = [day.date]; if (!isNone(this.onChangeSelection)) { this.onChangeSelection(selected); } } else if (this.mode == 'multiple') { selected = this.selected.map((date) => date.clone()); if (day.isSelected) { let date = selected.find((date) => date.format() == day.date.format()); if (!isNone(date)) { //@ts-ignore selected.removeObject(date); } } else { //@ts-ignore selected.pushObject(day.date); } if (!isNone(this.onChangeSelection)) { this.onChangeSelection(selected); } } else if (this.mode == 'range') { let isChangingStart = isNone(this.localRangeStart) || !isNone(this.localRangeFinish); if (isChangingStart) { set(this, 'localRangeStart', day.date); set(this, 'localRangeFinish', undefined); } else { if (day.date.isBefore(this.localRangeStart)) { set(this, 'localRangeFinish', this.localRangeStart); set(this, 'localRangeStart', day.date); } else { set(this, 'localRangeFinish', day.date); } if (!isNone(this.onChangeRange)) { this.onChangeRange(this.localRangeStart, this.localRangeFinish); } } } } init() { super.init(); set(this, 'localRangeStart', this.rangeStart); set(this, 'localRangeFinish', this.rangeFinish); } }