refactor: extract date.js, event-factory.js, split.js; use shared date helpers in recur/organize

- date.js: single source of truth for ISO date formatting/arithmetic
  (toISODate, parseISODate, addDays, daysBetween, todayISO, nowCompactTimestamp)
- event-factory.js: createEvent/cloneEvent (structuredClone with JSON fallback)
- split.js: splitRecurringEvent pure function using intervalDays from recur.js
- recur.js: replaced local toISO() and inline Date math with date.js helpers
- organize.js: replaced inline date formatting and gap math with date.js helpers,
  extracted buildGrid() helper and byDate comparator
This commit is contained in:
timeTable2 dev
2026-07-13 20:01:10 +08:00
parent e4f549f848
commit 02cfdda900
5 changed files with 186 additions and 43 deletions

View File

@@ -2,6 +2,7 @@
* Recurrence grid expansion - port of ical_editor.py's occurrence generation.
* occurrences are computed on-demand from exdates, never stored on the model.
*/
import { toISODate, toDate, addDays } from './date.js'
/** Interval in days for a recurring event. */
export function intervalDays(ev) {
@@ -11,12 +12,7 @@ export function intervalDays(ev) {
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}`
}
const MAX_OCCURRENCES = 500
/**
* Expand a recurring event into an occurrence grid.
@@ -33,20 +29,18 @@ export function expandOccurrences(ev) {
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
? toDate(ev.rrule.untilDate)
: new Date(toDate(ev.dtstartDate).getTime() + 365 * 24 * 3600 * 1000)
const exdateSet = new Set(ev.exdates || [])
const occs = []
const cur = new Date(start)
let cur = ev.dtstartDate
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)
while (cur <= toISODate(until) && count < MAX_OCCURRENCES) {
occs.push({ date: cur, skipped: exdateSet.has(cur) })
cur = addDays(cur, step)
count++
}