UNPKG

@kalender/core

Version:
642 lines (626 loc) 20.8 kB
'use strict'; 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