@kalender/core
Version:
calendar core library
585 lines (571 loc) • 19.3 kB
JavaScript
var TimeUnits;
(function (TimeUnits) {
TimeUnits["Year"] = "Year";
TimeUnits["Month"] = "Month";
TimeUnits["Week"] = "Week";
TimeUnits["WorkDay"] = "WorkDay";
TimeUnits["Weekend"] = "Weekend";
TimeUnits["Day"] = "Day";
TimeUnits["Hour"] = "Hour";
TimeUnits["Minute"] = "Minute";
TimeUnits["Second"] = "Second";
})(TimeUnits || (TimeUnits = {}));
// 0 is weekend and -1 is weekday
var WeekDay;
(function (WeekDay) {
WeekDay[WeekDay["WorkDay"] = -1] = "WorkDay";
WeekDay[WeekDay["Weekend"] = 0] = "Weekend";
WeekDay[WeekDay["Monday"] = 1] = "Monday";
WeekDay[WeekDay["Tuesday"] = 2] = "Tuesday";
WeekDay[WeekDay["Wednesday"] = 3] = "Wednesday";
WeekDay[WeekDay["Thursday"] = 4] = "Thursday";
WeekDay[WeekDay["Friday"] = 5] = "Friday";
WeekDay[WeekDay["Saturday"] = 6] = "Saturday";
WeekDay[WeekDay["Sunday"] = 7] = "Sunday";
})(WeekDay || (WeekDay = {}));
const WeekDays = [1, 2, 3, 4, 5, 6, 7];
const WorkDays = [1, 2, 3, 4, 5];
const WeekendDays = [6, 7];
function diff(a, b) {
const result = {};
if (isDefined(a) && isDefined(b)) {
Object.keys(a).forEach((p) => {
Object.defineProperty(result, p, {
value: b[p] - a[p],
});
});
}
return result;
}
function isNum(number) {
return typeof number === 'number' && !isNaN(number);
}
function isInt(number) {
return Number.isInteger(number);
}
function isPositiveInt(number) {
return isInt(number) && number > 0;
}
function increaseSign(a, b) {
if (a === b) {
return 0;
}
return (b - a) / Math.abs(b - a);
}
function range(a, b) {
if (isNum(a) && isNum(b)) {
return Array(Math.abs(b - a) + 1)
.fill(0)
.map((_, i) => a + i * increaseSign(a, b));
}
else {
return Array(a)
.fill(0)
.map((_, i) => i);
}
}
function isDefined(val) {
return val !== undefined && val !== null;
}
function lastOf(list) {
return list[list.length - 1];
}
function getDefault(val, defaultVal) {
if (isDefined(val)) {
return val;
}
return defaultVal;
}
function toPositiveInt(number) {
return number >= 1 ? Math.round(number) : 1;
}
function diffTime(d1, d2) {
return diff(extract(d1), extract(d2));
}
function daysOf(ms) {
return Math.floor(ms / 1000 / 3600 / 24);
}
function weeksOf(ms) {
return Math.floor(ms / 1000 / 3600 / 24 / 7);
}
function daysBetween(start, end) {
return daysOf(end.valueOf() - start.valueOf()) + 1;
}
function weeksBetween(start, end) {
while (getWeekDay(start) !== 1) {
start = addDays(start, -1);
}
while (getWeekDay(end) !== 7) {
end = addDays(end, 1);
}
return Math.floor(daysBetween(start, end) / 7);
}
function weekDaysBetween(start, end, days) {
let count = 0;
while (getWeekDay(start) !== 1) {
if (days.includes(getWeekDay(start)))
count++;
start = addDays(start, 1);
}
while (getWeekDay(end) !== 7) {
if (days.includes(getWeekDay(end)))
count++;
end = addDays(end, -1);
}
count += (daysBetween(start, end) / 7) * weekDayFilter(days).length;
return count;
}
function workDaysBetween(start, end) {
return weekDaysBetween(start, end, WorkDays);
}
function weekendDaysBetween(start, end) {
return weekDaysBetween(start, end, WeekendDays);
}
function addDays(date, count) {
const newDate = new Date(date.valueOf());
newDate.setDate(newDate.getDate() + count);
return newDate;
}
function isWeekDay(number) {
return WeekDays.includes(number);
}
function weekDayFilter(days) {
const set = new Set();
for (const day of days) {
if (isWeekDay(day)) {
set.add(day);
}
}
return Array.from(set);
}
function daysOfMonth(year, month) {
return new Date(year, month, 0).getDate();
}
function getMonthDates(year, month) {
const days = [];
for (let i = 0; i < daysOfMonth(year, month); i++) {
days.push(normalDate(year, month, i + 1));
}
return days;
}
function getCalendarMonthDates(year, month, startOfWeek = WeekDay.Monday) {
const days = getMonthDates(year, month);
while (getWeekDay(days[0]) !== startOfWeek) {
const day = extract(days[0]);
days.unshift(normalDate(day.year, day.month, day.day - 1));
}
while (getWeekDay(lastOf(days)) !== addWeekDays(startOfWeek, -1)) {
const day = extract(lastOf(days));
days.push(normalDate(day.year, day.month, day.day + 1));
}
return days;
}
function addMonths({ year, month, }, count) {
const { year: y, month: m } = extract(new Date(year, month + count - 1));
return {
year: y,
month: m,
};
}
function isNthWeekDay(date, weekDay, rank = 0) {
const { year, month } = extract(date);
const diff = diffTime(date, theNthWeekDay(year, month, weekDay, rank));
return diff.year === 0 && diff.month === 0 && diff.day === 0;
}
function nthWeekDay(year, month) {
const result = {
[WeekDay.Monday]: [],
[WeekDay.Tuesday]: [],
[WeekDay.Wednesday]: [],
[WeekDay.Thursday]: [],
[WeekDay.Friday]: [],
[WeekDay.Saturday]: [],
[WeekDay.Sunday]: [],
[WeekDay.WorkDay]: [],
[WeekDay.Weekend]: [],
};
const days = daysOfMonth(year, month);
for (let day = 1; day <= days; day++) {
let date = normalDate(year, month, day);
result[getWeekDay(date)].push(date);
if (isWorkDay(date)) {
result[WeekDay.WorkDay].push(date);
}
else {
result[WeekDay.Weekend].push(date);
}
}
return result;
}
function theFirstWeekDay(year, month, weekDay) {
let date = normalDate(year, month, 1);
if (weekDay === WeekDay.WorkDay) {
while (!isWorkDay(date)) {
date = addDays(date, 1);
}
}
else if (weekDay === WeekDay.Weekend) {
while (!isWeekend(date)) {
date = addDays(date, 1);
}
}
else {
while (getWeekDay(date) !== weekDay) {
date = addDays(date, 1);
}
}
return date;
}
function theLastWeekDay(year, month, weekDay) {
let date = normalDate(year, month + 1, 0);
if (weekDay === WeekDay.WorkDay) {
while (!isWorkDay(date)) {
date = addDays(date, -1);
}
}
else if (weekDay === WeekDay.Weekend) {
while (!isWeekend(date)) {
date = addDays(date, -1);
}
}
else {
while (getWeekDay(date) !== weekDay) {
date = addDays(date, -1);
}
}
return date;
}
function theNthWeekDay(year, month, weekDay, rank = 0) {
if (rank === -1) {
return theLastWeekDay(year, month, weekDay);
}
const weekDays = nthWeekDay(year, month);
return weekDays[weekDay][rank];
}
function isWorkDay(date) {
const day = date.getDay();
return day >= 1 && day <= 5;
}
function isWeekend(date) {
const day = date.getDay();
return day === 6 || day === 0;
}
function getWeekDay(date) {
const day = date.getDay();
return day === 0 ? 7 : day;
}
function getMonth(date) {
return date.getMonth() + 1;
}
function eraseTime(date) {
const { year, month, day } = extract(date);
return normalDate(year, month, day);
}
function extract(date) {
return {
year: date.getFullYear(),
month: getMonth(date),
day: date.getDate(),
weekDay: getWeekDay(date),
dayOfYear: dayOfYear(date),
hour: date.getHours(),
minute: date.getMinutes(),
second: date.getSeconds(),
};
}
function extractDate(date) {
return {
year: date.getFullYear(),
month: getMonth(date),
day: date.getDate(),
weekDay: getWeekDay(date),
};
}
function normalDate(year, month, day = 1) {
return new Date(year, month - 1, day);
}
function perfectDate(year, month, day = 1) {
if (day > 0) {
return normalDate(year, month, day);
}
const maxDay = daysOfMonth(year, month);
if (day === 0)
day = -1;
return normalDate(year, month, day + maxDay + 1);
}
function dayOfYear(date) {
const firstDay = normalDate(date.getFullYear(), 1, 1);
return (date.valueOf() - firstDay.valueOf()) / 1000 / 3600 / 24 + 1;
}
function addWeekDays(day, count) {
count = count % 7;
day = day + count;
if (day < 0) {
day += 7;
}
if (day > 7) {
day -= 7;
}
return day;
}
function now() {
return new Date();
}
function daysRemainOfMonth(date) {
const { year, month, day } = extract(date);
const days = daysOfMonth(year, month);
return days - day;
}
function daysOfYear(year) {
const start = normalDate(year, 1, 1);
const end = normalDate(year + 1, 1, 1);
return (end.valueOf() - start.valueOf()) / 1000 / 3600 / 24;
}
function getCalendarWeekDates(date, startOfWeek = WeekDay.Monday) {
const days = [date];
while (getWeekDay(days[0]) !== startOfWeek) {
const day = extract(days[0]);
days.unshift(normalDate(day.year, day.month, day.day - 1));
}
while (getWeekDay(lastOf(days)) !== addWeekDays(startOfWeek, -1)) {
const day = extract(lastOf(days));
days.push(normalDate(day.year, day.month, day.day + 1));
}
return days;
}
function addWeeks(date, count) {
const day = extract(date);
return normalDate(day.year, day.month, day.day + count);
}
var RepeatTypes;
(function (RepeatTypes) {
RepeatTypes["Interval"] = "Interval";
RepeatTypes["DayOfWeek"] = "DayOfWeek";
RepeatTypes["DayOfMonth"] = "DayOfMonth";
RepeatTypes["DayOfYear"] = "DayOfYear";
RepeatTypes["MonthDay"] = "MonthDay";
RepeatTypes["NthWeekDayOfIntervalMonth"] = "NthWeekDayOfIntervalMonth";
RepeatTypes["NthWeekDayOfSpecifiedMonth"] = "NthWeekDayOfSpecifiedMonth";
})(RepeatTypes || (RepeatTypes = {}));
const handlers = new Map();
function isEventMatch(date, event) {
date = eraseTime(date);
const { repeat } = event;
const start = eraseTime(repeat.start);
if (date < start) {
return false;
}
if (isDefined(repeat.end)) {
const end = eraseTime(repeat.end);
if (date > end) {
return false;
}
}
const handler = handlers.get(repeat.type);
if (handler && handler(date, repeat))
return true;
return false;
}
function registerHandler(type, handler) {
handlers.set(type, handler);
}
function setupHandlers() {
registerHandler(RepeatTypes.Interval, (date, option) => {
const interval = toPositiveInt(getDefault(option.interval, 1));
const days = daysBetween(eraseTime(option.start), eraseTime(date));
if ((days - 1) % interval !== 0) {
return false;
}
if (isDefined(option.times)) {
return days <= interval * option.times;
}
return true;
});
registerHandler(RepeatTypes.DayOfWeek, (date, option) => {
const interval = toPositiveInt(getDefault(option.interval, 1));
const days = getDefault(option.days, WeekDays);
if (!days.includes(getWeekDay(date))) {
return false;
}
const weeks = weeksBetween(option.start, date);
if ((weeks - 1) % interval !== 0)
return false;
if (isDefined(option.weeks) && weeks > option.weeks * interval)
return false;
if (isDefined(option.times)) {
let weekDays = weekDaysBetween(eraseTime(option.start), eraseTime(date), days);
weekDays -= ((weeks - 1) / interval) * (interval - 1) * days.length;
return weekDays <= option.times;
}
return true;
});
registerHandler(RepeatTypes.DayOfMonth, (date, option) => {
const { day, month, year } = extract(date);
// support days counting from end of month:
const maxDay = daysOfMonth(year, month);
const endDays = option.days
.filter((x) => x < 0)
.map((x) => x + maxDay + 1);
if (!option.days.includes(day) && !endDays.includes(day))
return false;
if (isDefined(option.months) && !option.months.includes(month))
return false;
if (isDefined(option.times)) {
console.log('times option for [DayOfMonth] is not supported now');
}
return true;
});
registerHandler(RepeatTypes.DayOfYear, () => {
throw new Error('Handler not implemented');
});
registerHandler(RepeatTypes.MonthDay, (date, option) => {
// support days counting from end of month:
const daysRemain = daysRemainOfMonth(date);
if (option.day < 0) {
if (Math.abs(option.day + 1) !== daysRemain)
return false;
}
else {
if (option.day !== date.getDate()) {
return false;
}
}
const thatDay = perfectDate(option.start.getFullYear(), option.month, option.day);
const { year, month } = diffTime(thatDay, eraseTime(date));
if (month !== 0)
return false;
if (isDefined(option.interval) &&
(year - (thatDay < eraseTime(option.start) ? 1 : 0)) %
option.interval !==
0)
return false;
if (isDefined(option.times) &&
year + (thatDay < eraseTime(option.start) ? 0 : 1) >
getDefault(option.interval, 1) * option.times)
return false;
return true;
});
registerHandler(RepeatTypes.NthWeekDayOfIntervalMonth, (date, option) => {
if (isDefined(option.times)) {
console.log('times option for [NthWeekDayOfIntervalMonth] is not supported now');
}
if (isDefined(option.rank) && option.rank > 3) {
console.log('rank should be [0-3] or -1');
return false;
}
const { year, month } = extract(option.start);
const nth = theNthWeekDay(year, month, option.weekDay, getDefault(option.rank, 0));
let start;
if (nth >= option.start) {
start = nth;
}
else {
start = theNthWeekDay(year, month + 1, option.weekDay, getDefault(option.rank, 0));
}
const diff = diffTime(start, eraseTime(date));
if (isDefined(option.interval) &&
(diff.year * 12 + diff.month) % option.interval !== 0)
return false;
return isNthWeekDay(date, option.weekDay, getDefault(option.rank, 0));
});
registerHandler(RepeatTypes.NthWeekDayOfSpecifiedMonth, (date, option) => {
if (isDefined(option.times)) {
console.log('times option for [NthWeekDayOfIntervalMonth] is not supported now');
}
if (isDefined(option.rank) && option.rank > 3) {
console.log('rank should be [0-3] or -1');
return false;
}
if (!isNthWeekDay(date, option.weekDay, getDefault(option.rank, 0))) {
return false;
}
const { year } = extract(option.start);
let start = theNthWeekDay(year, option.month, option.weekDay, getDefault(option.rank, 0));
if (start.valueOf() < eraseTime(option.start).valueOf()) {
start = theNthWeekDay(year + 1, option.month, option.weekDay, getDefault(option.rank, 0));
}
const diff = diffTime(start, date);
return (diff.month === 0 && diff.year % getDefault(option.interval, 1) === 0);
});
}
function createEvent(option, repeat) {
repeat.start = eraseTime(repeat.start);
return {
id: Symbol(),
title: option.title,
description: option.description,
start: option.start,
end: option.end,
repeat: repeat,
customData: option.customData || null,
};
}
function createEvents(options) {
return options.map((x) => {
x.repeat.start = new Date(x.repeat.start);
if (x.repeat.end) {
x.repeat.end = new Date(x.repeat.end);
}
x.id = Symbol();
return x;
});
}
function parseEvents(events) {
try {
return createEvents(JSON.parse(events));
}
catch (error) {
return [];
}
}
function getCalendarMonth(year, month, events = [], startOfWeek = WeekDay.Monday) {
const days = getCalendarMonthDates(year, month, startOfWeek);
return days.map((day) => {
return {
date: day,
...extractDate(day),
events: events
.filter((e) => isEventMatch(day, e))
.sort((a, b) => {
return (a.start.hour * 3600 +
a.start.minute * 60 +
a.start.second -
(b.start.hour * 3600 + b.start.minute * 60 + b.start.second));
}),
};
});
}
function getCalendarWeek(date, events = [], startOfWeek = WeekDay.Monday) {
const days = getCalendarWeekDates(date, startOfWeek);
return days.map((day) => {
return {
date: day,
...extractDate(day),
events: events
.filter((e) => isEventMatch(day, e))
.sort((a, b) => {
return (a.start.hour * 3600 +
a.start.minute * 60 +
a.start.second -
(b.start.hour * 3600 + b.start.minute * 60 + b.start.second));
}),
};
});
}
function getCalendarDay(date, events = []) {
return {
date: date,
...extractDate(date),
events: events
.filter((e) => isEventMatch(date, e))
.sort((a, b) => {
return (a.start.hour * 3600 +
a.start.minute * 60 +
a.start.second -
(b.start.hour * 3600 + b.start.minute * 60 + b.start.second));
}),
};
}
setupHandlers();
export { RepeatTypes, TimeUnits, WeekDay, WeekDays, WeekendDays, WorkDays, addDays, addMonths, addWeekDays, addWeeks, createEvent, createEvents, dayOfYear, daysBetween, daysOf, daysOfMonth, daysOfYear, daysRemainOfMonth, diff, diffTime, eraseTime, extract, extractDate, getCalendarDay, getCalendarMonth, getCalendarMonthDates, getCalendarWeek, getCalendarWeekDates, getDefault, getMonth, getMonthDates, getWeekDay, increaseSign, isDefined, isEventMatch, isInt, isNthWeekDay, isNum, isPositiveInt, isWeekDay, isWeekend, isWorkDay, lastOf, normalDate, now, nthWeekDay, parseEvents, perfectDate, range, registerHandler, setupHandlers, theFirstWeekDay, theLastWeekDay, theNthWeekDay, toPositiveInt, weekDayFilter, weekDaysBetween, weekendDaysBetween, weeksBetween, weeksOf, workDaysBetween };
//# sourceMappingURL=index.esm.js.map