calendar
All repositories: gitoria
5.0 KB
// lib/events-helpers.hl — what lib/events.hl looks up (calendar mission 001, code order): the size limits, what the// page sends → a WorldAPI Event record (build), a stored event → what the page shows (viewOf), the temporary ids of// events made offline, the window check of the faces and the order by start.import { isText, isDate, isTime, isZone, nextDay, prevDay, before } from '../components/month-view/dates.hl'import { toReminders, toRows } from '../components/month-view/reminders.hl'static maxTitle = 200static maxPlace = 200static maxNotes = 5000// what the page sends: { id?, custom, reminders (rows), title, allDay, startDate, startTime, endDate, endTime, place, notes, zone }// → { error } or { record } (a WorldAPI Event without owner/id). endDate/endTime may be empty (no end); all-day: the// last day, inclusive ('' = one day).static build = (b) => {if (b == null || hlTypeName(b) != 'Hybrid') { return { error = 'the event must be an object' } }if (!isText(b.title) || b.title.trim() == '') { return { error = 'the event needs a title' } }if (b.title.length > maxTitle) { return { error = 'the title is too long (at most ' + maxTitle + ' characters)' } }if (!isText(b.place) || b.place.length > maxPlace) { return { error = 'the place is too long (at most ' + maxPlace + ' characters)' } }if (!isText(b.notes) || b.notes.length > maxNotes) { return { error = 'the notes are too long (at most ' + maxNotes + ' characters)' } }if (b.allDay != true && b.allDay != false) { return { error = 'allDay must be true or false' } }if (!isDate(b.startDate)) { return { error = 'the start date is not a date' } }if (!isZone(b.zone)) { return { error = 'the time zone is missing' } }let r = {}r['$type'] = 'event'r['$version'] = 1r['$title'] = b.title.trim()if (b.notes.trim() != '') { r['$description'] = b.notes }if (b.place.trim() != '') { r['$location'] = b.place.trim() }r['$status'] = 'confirmed'r['$visibility'] = 'private'// no own reminders: `$reminders` stays out and the calendar's apply; own ones (also none at all) are writtenif (b.custom == true) {let rem = toReminders(b.reminders)if (rem.error != null) { return { error = rem.error } }r['$reminders'] = rem.reminders}if (b.allDay) {r['$kind'] = 'allday'r['$start'] = b.startDateif (isText(b.endDate) && b.endDate != '') {if (!isDate(b.endDate)) { return { error = 'the end date is not a date' } }if (before(b.endDate, b.startDate)) { return { error = 'the end is before the start' } }if (b.endDate != b.startDate) { r['$end'] = nextDay(b.endDate) }}return { record = r }}if (!isTime(b.startTime)) { return { error = 'the start time is not a time' } }r['$kind'] = 'appointment'r['$timezone'] = b.zoner['$start'] = b.startDate + 'T' + b.startTime + ':00'let hasEnd = (isText(b.endDate) && b.endDate != '') || (isText(b.endTime) && b.endTime != '')if (hasEnd) {let ed = isText(b.endDate) && b.endDate != '' ? b.endDate : b.startDateif (!isDate(ed)) { return { error = 'the end date is not a date' } }if (!isTime(b.endTime)) { return { error = 'the end time is not a time' } }let end = ed + 'T' + b.endTime + ':00'if (before(end, r['$start'])) { return { error = 'the end is before the start' } }r['$end'] = end}return { record = r }}// what the page shows of a stored event: first / last day (inclusive), times, textsstatic viewOf = (e) => {let allDay = e['$kind'] == 'allday'let start = e['$start']let end = e['$end']let first = start.slice(0, 10)let last = firstif (allDay) {if (end != null) { last = prevDay(end) }} else if (end != null) {last = end.slice(0, 10)}let v = { id = e.id title = e['$title'] allDay = allDay first = first last = laststartDate = first startTime = allDay ? '' : start.slice(11, 16)endDate = end == null ? '' : last endTime = allDay || end == null ? '' : end.slice(11, 16)place = e['$location'] == null ? '' : e['$location'] notes = e['$description'] == null ? '' : e['$description']start = start zone = e['$timezone'] == null ? '' : e['$timezone']custom = e['$reminders'] != null rows = e['$reminders'] == null ? [] : toRows(e['$reminders']) }return v}// an event made offline carries a temporary id `local-…` until the page reloads; the server keeps it as `ref`, so an edit// (or delete) sent with that id reaches the same event instead of making a second onestatic isLocalId = (id) => { return isText(id) && id.length > 6 && id.length <= 60 && id.slice(0, 6) == 'local-' }// the window is two dates the page shows; anything else is refusedstatic validWindow = (first, last) => { return isDate(first) && isDate(last) }// the views ordered by start (a hand-written selection sort)static byStart = (views) => {let m = views.lengthlet out = []let used = []let i = 0while (i < m) { used.push(false) i = i + 1 }let round = 0while (round < m) {let best = -1let j = 0while (j < m) {if (!used[j] && (best < 0 || before(views[j].start, views[best].start))) { best = j }j = j + 1}used[best] = trueout.push(views[best])round = round + 1}return out}
Branches
- mainmain branch
Latest commits
- f5ce6b1dcalendar mission 001 (2/4): code order — topics, map, thin faces: lib/util.hl, lib/events(-helpers).hl (+calendarView/settingsView/soonOf), lib/settings.hl, lib/users.hl (+userOfLoginCode, tagOf), lib/api(-helpers).hl; project.hl = map; login route takes &req/&sessions (failed-login reason now kept); gates 78/0 + 18/0mre
- c6fbd011calendar mission 001 (1/4): code order — files moved: lib/events.hl, lib/users.hl, components/styles.hl (imports only); gates 78/0 + 18/0, live-data run identicalmre
- d6c59290calendar: Hybriel master 06617221 (plugin allocators 3a781359 + 413f60e4, mpackdb 2cb7ae5e, http1 773de63e); gates 78/0 + 18/0mre
- 7bd0337ccalendar: Hybriel master 190aa11d (fc838894 GC correctness, #126 closure scopes, #127); gates 78/0 + 18/0mre
- ff41310ccalendar: Hybriel master 8efba065 (#126 memory, #48 lambda copy; audit: no & needed)mre
- 14ba08c7antcolony#40: mission references point to the moved missionsmre
- 99c73346antcolony#40: history (LOG.md), worker briefs (missions/) and reports moved here from antcolony, numbered per project; old numbers in antcolony docs/mission-map.mdmre
- 76edaa62calendar: Hybriel master ff51cf46 (re-vendor round, static workaround removed)mre
- 90a3fc2cdeploy.sh: back up live storage/.sessions/.env before every deploy (newest 5 kept)mre
- 6722b72ddeploy.sh: never send .git or .gitignore to Byrodinmre
- be099807State of 2026-09-27, before the move to gitoriamre