@kalender/core
Version:
calendar core library
642 lines (626 loc) • 20.8 kB
JavaScript
;
Object.defineProperty(exports, '__esModule', { value: true });
(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";
})(exports.TimeUnits || (exports.TimeUnits = {}));
(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";
})(exports.WeekDay || (exports.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 = exports.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 = {
[exports.WeekDay.Monday]: [],
[exports.WeekDay.Tuesday]: [],
[exports.WeekDay.Wednesday]: [],
[exports.WeekDay.Thursday]: [],
[exports.WeekDay.Friday]: [],
[exports.WeekDay.Saturday]: [],
[exports.WeekDay.Sunday]: [],
[exports.WeekDay.WorkDay]: [],
[exports.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[exports.WeekDay.WorkDay].push(date);
}
else {
result[exports.WeekDay.Weekend].push(date);
}
}
return result;
}
function theFirstWeekDay(year, month, weekDay) {
let date = normalDate(year, month, 1);
if (weekDay === exports.WeekDay.WorkDay) {
while (!isWorkDay(date)) {
date = addDays(date, 1);
}
}
else if (weekDay === exports.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 === exports.WeekDay.WorkDay) {
while (!isWorkDay(date)) {
date = addDays(date, -1);
}
}
else if (weekDay === exports.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 = exports.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);
}
(function (RepeatTypes) {
RepeatTypes["Interval"] = "Interval";
RepeatTypes["DayOfWeek"] = "DayOfWeek";
RepeatTypes["DayOfMonth"] = "DayOfMonth";
RepeatTypes["DayOfYear"] = "DayOfYear";
RepeatTypes["MonthDay"] = "MonthDay";
RepeatTypes["NthWeekDayOfIntervalMonth"] = "NthWeekDayOfIntervalMonth";
RepeatTypes["NthWeekDayOfSpecifiedMonth"] = "NthWeekDayOfSpecifiedMonth";
})(exports.RepeatTypes || (exports.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(exports.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(exports.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(exports.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(exports.RepeatTypes.DayOfYear, () => {
throw new Error('Handler not implemented');
});
registerHandler(exports.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(exports.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(exports.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 = exports.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 = exports.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();
exports.WeekDays = WeekDays;
exports.WeekendDays = WeekendDays;
exports.WorkDays = WorkDays;
exports.addDays = addDays;
exports.addMonths = addMonths;
exports.addWeekDays = addWeekDays;
exports.addWeeks = addWeeks;
exports.createEvent = createEvent;
exports.createEvents = createEvents;
exports.dayOfYear = dayOfYear;
exports.daysBetween = daysBetween;
exports.daysOf = daysOf;
exports.daysOfMonth = daysOfMonth;
exports.daysOfYear = daysOfYear;
exports.daysRemainOfMonth = daysRemainOfMonth;
exports.diff = diff;
exports.diffTime = diffTime;
exports.eraseTime = eraseTime;
exports.extract = extract;
exports.extractDate = extractDate;
exports.getCalendarDay = getCalendarDay;
exports.getCalendarMonth = getCalendarMonth;
exports.getCalendarMonthDates = getCalendarMonthDates;
exports.getCalendarWeek = getCalendarWeek;
exports.getCalendarWeekDates = getCalendarWeekDates;
exports.getDefault = getDefault;
exports.getMonth = getMonth;
exports.getMonthDates = getMonthDates;
exports.getWeekDay = getWeekDay;
exports.increaseSign = increaseSign;
exports.isDefined = isDefined;
exports.isEventMatch = isEventMatch;
exports.isInt = isInt;
exports.isNthWeekDay = isNthWeekDay;
exports.isNum = isNum;
exports.isPositiveInt = isPositiveInt;
exports.isWeekDay = isWeekDay;
exports.isWeekend = isWeekend;
exports.isWorkDay = isWorkDay;
exports.lastOf = lastOf;
exports.normalDate = normalDate;
exports.now = now;
exports.nthWeekDay = nthWeekDay;
exports.parseEvents = parseEvents;
exports.perfectDate = perfectDate;
exports.range = range;
exports.registerHandler = registerHandler;
exports.setupHandlers = setupHandlers;
exports.theFirstWeekDay = theFirstWeekDay;
exports.theLastWeekDay = theLastWeekDay;
exports.theNthWeekDay = theNthWeekDay;
exports.toPositiveInt = toPositiveInt;
exports.weekDayFilter = weekDayFilter;
exports.weekDaysBetween = weekDaysBetween;
exports.weekendDaysBetween = weekendDaysBetween;
exports.weeksBetween = weeksBetween;
exports.weeksOf = weeksOf;
exports.workDaysBetween = workDaysBetween;
//# sourceMappingURL=index.common.js.map