feat: add recurrence grid expansion

This commit is contained in:
timeTable2 dev
2026-07-13 18:32:46 +08:00
parent 7e708932b1
commit e187337127
2 changed files with 123 additions and 0 deletions

54
src/lib/recur.js Normal file
View 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
}