feat: add recurrence grid expansion
This commit is contained in:
54
src/lib/recur.js
Normal file
54
src/lib/recur.js
Normal file
@@ -0,0 +1,54 @@
|
||||
/**
|
||||
* Recurrence grid expansion - port of ical_editor.py's occurrence generation.
|
||||
* occurrences are computed on-demand from exdates, never stored on the model.
|
||||
*/
|
||||
|
||||
/** Interval in days for a recurring event. */
|
||||
export function intervalDays(ev) {
|
||||
if (!ev.rrule) return 0
|
||||
const { freq, interval } = ev.rrule
|
||||
const step = interval || 1
|
||||
return freq === 'WEEKLY' ? 7 * step : step
|
||||
}
|
||||
|
||||
function toISO(date) {
|
||||
const y = date.getFullYear()
|
||||
const m = String(date.getMonth() + 1).padStart(2, '0')
|
||||
const d = String(date.getDate()).padStart(2, '0')
|
||||
return `${y}-${m}-${d}`
|
||||
}
|
||||
|
||||
/**
|
||||
* Expand a recurring event into an occurrence grid.
|
||||
* Returns [{ date: 'YYYY-MM-DD', skipped: boolean }].
|
||||
*/
|
||||
export function expandOccurrences(ev) {
|
||||
// Non-recurring: single occurrence
|
||||
if (!ev.rrule) {
|
||||
return [{ date: ev.dtstartDate, skipped: false }]
|
||||
}
|
||||
|
||||
const step = intervalDays(ev)
|
||||
if (step <= 0) {
|
||||
return [{ date: ev.dtstartDate, skipped: false }]
|
||||
}
|
||||
|
||||
const start = new Date(ev.dtstartDate + 'T00:00:00')
|
||||
const until = ev.rrule.untilDate
|
||||
? new Date(ev.rrule.untilDate + 'T00:00:00')
|
||||
: new Date(start.getTime() + 365 * 24 * 3600 * 1000) // default +1 year
|
||||
|
||||
const exdateSet = new Set(ev.exdates || [])
|
||||
const occs = []
|
||||
const cur = new Date(start)
|
||||
let count = 0
|
||||
|
||||
while (cur <= until && count < 500) {
|
||||
const iso = toISO(cur)
|
||||
occs.push({ date: iso, skipped: exdateSet.has(iso) })
|
||||
cur.setDate(cur.getDate() + step)
|
||||
count++
|
||||
}
|
||||
|
||||
return occs
|
||||
}
|
||||
Reference in New Issue
Block a user