src/datepicker/engine/flag-days-calendar.ts
import {
DaysCalendarViewModel,
DayViewModel,
WeekViewModel
} from '../models/index';
import { isSameDay, isSameMonth } from '../../chronos/utils/date-getters';
import { isAfter, isBefore } from '../../chronos/utils/date-compare';
import { isMonthDisabled } from '../utils/bs-calendar-utils';
import { shiftDate } from '../../chronos/utils/date-setters';
import { endOf, startOf } from '../../chronos/utils/start-end-of';
export interface FlagDaysCalendarOptions {
isDisabled: boolean;
minDate: Date;
maxDate: Date;
hoveredDate: Date;
selectedDate: Date;
selectedRange: Date[];
displayMonths: number;
monthIndex: number;
}
export function flagDaysCalendar(
formattedMonth: DaysCalendarViewModel,
options: FlagDaysCalendarOptions
): DaysCalendarViewModel {
formattedMonth.weeks.forEach((week: WeekViewModel, weekIndex: number) => {
week.days.forEach((day: DayViewModel, dayIndex: number) => {
// datepicker
const isOtherMonth = !isSameMonth(day.date, formattedMonth.month);
const isHovered =
!isOtherMonth && isSameDay(day.date, options.hoveredDate);
// date range picker
const isSelectionStart =
!isOtherMonth &&
options.selectedRange &&
isSameDay(day.date, options.selectedRange[0]);
const isSelectionEnd =
!isOtherMonth &&
options.selectedRange &&
isSameDay(day.date, options.selectedRange[1]);
const isSelected =
(!isOtherMonth && isSameDay(day.date, options.selectedDate)) ||
isSelectionStart ||
isSelectionEnd;
const isInRange =
!isOtherMonth &&
options.selectedRange &&
isDateInRange(day.date, options.selectedRange, options.hoveredDate);
const isDisabled =
options.isDisabled ||
isBefore(day.date, options.minDate, 'day') ||
isAfter(day.date, options.maxDate, 'day');
// decide update or not
const newDay = Object.assign({}, day, {
isOtherMonth,
isHovered,
isSelected,
isSelectionStart,
isSelectionEnd,
isInRange,
isDisabled
});
if (
day.isOtherMonth !== newDay.isOtherMonth ||
day.isHovered !== newDay.isHovered ||
day.isSelected !== newDay.isSelected ||
day.isSelectionStart !== newDay.isSelectionStart ||
day.isSelectionEnd !== newDay.isSelectionEnd ||
day.isDisabled !== newDay.isDisabled ||
day.isInRange !== newDay.isInRange
) {
week.days[dayIndex] = newDay;
}
});
});
// todo: add check for linked calendars
formattedMonth.hideLeftArrow =
options.isDisabled ||
(options.monthIndex > 0 && options.monthIndex !== options.displayMonths);
formattedMonth.hideRightArrow =
options.isDisabled ||
(options.monthIndex < options.displayMonths &&
options.monthIndex + 1 !== options.displayMonths);
formattedMonth.disableLeftArrow = isMonthDisabled(
shiftDate(formattedMonth.month, { month: -1 }),
options.minDate,
options.maxDate
);
formattedMonth.disableRightArrow = isMonthDisabled(
shiftDate(formattedMonth.month, { month: 1 }),
options.minDate,
options.maxDate
);
return formattedMonth;
}
function isDateInRange(
date: Date,
selectedRange: Date[],
hoveredDate: Date
): boolean {
if (!date || !selectedRange[0]) {
return false;
}
if (selectedRange[1]) {
return date > selectedRange[0] && date <= selectedRange[1];
}
if (hoveredDate) {
return date > selectedRange[0] && date <= hoveredDate;
}
return false;
}