Commit graph www/static
Author SHA1 Message Date
4545852327 Report errors while loading the calendar
The response of the fetch went to the parser without ever looking at it. When
the calendar could not be loaded the error page of the web server was parsed as
a calendar, which threw inside a promise nobody was waiting on. The result was
an empty table, an unhandled rejection in the console and an error message
about broken calendar syntax that says nothing about the actual problem, a
calendar that is not there.

Refuse a response that is not ok, naming the status, and log failures in the
chain, like the calendar page already does.

  before: Uncaught (in promise) Error: invalid line (no token ";" or ":")
                                       "<html>404 Not Found</html>"
  after:  Fehler beim Laden der Termine:
          Error: /calendars/all.ics: 404 Not Found

The table stays empty either way, there is nothing to show without a calendar.

Fixes: c28f04c6e8 ("switch to ics files; make calendars work; fix some minor issues")
Assisted-by: Claude:claude-opus-5
Signed-off-by: Hauke Mehrtens <hauke@hauke-m.de>
2026-08-23 01:07:25 +02:00
cd39842ac0 Show event times in Berlin time
`toLocaleString()` was given the German locale but no time zone, so it printed
the time in whatever zone the browser of the visitor is set to. The events
happen in Berlin, so this is only correct for visitors who are in Berlin.
Somebody reading the start page from Sydney was told the Plenum of Tuesday
20:00 takes place on Wednesday at 04:00.

Format in Europe/Berlin explicitly. For an event that names a point in time
only the printing was wrong, picking and sorting work on absolute points in
time and were not affected.

An all day event carries a date, and a date has neither a time nor a zone: its
digits are the day itself. `toJSDate()` reads them as midnight in the zone of
the browser, so the point in time that is then printed in Berlin time is off by
the offset between the two, which puts a bogus time of day on the entry and,
far enough east or west, the wrong day. An event on 30.08. was announced as:

  Berlin       Sonntag, 30.08., 00:00 Uhr
  Los Angeles  Sonntag, 30.08., 09:00 Uhr
  Tokio        Samstag, 29.08., 17:00 Uhr

Keep the digits of the date and read them as UTC, which no browser setting
moves, and print an all day event in UTC and without a time of day. Berlin,
Tokyo, Los Angeles and Kiritimati all say "Sonntag, 30.08." now, while a timed
event keeps saying "Sonntag, 30.08., 19:00 Uhr" everywhere. Sorting improves
with it, an all day event no longer changes its place in the list depending on
where the visitor sits.

The published calendar has no all day events today, they can be created in the
CalDAV calendar the export comes from.

Drop the two replacements around the formatted date while touching it. The
first removes the comma after the weekday and the second puts it back, so they
cancel each other out:

  "Samstag, 22.08., 17:00" -> "Samstag 22.08., 17:00" -> "Samstag, 22.08., 17:00"

Fixes: c28f04c6e8 ("switch to ics files; make calendars work; fix some minor issues")
Assisted-by: Claude:claude-opus-5
Signed-off-by: Hauke Mehrtens <hauke@hauke-m.de>
2026-08-23 01:07:25 +02:00
6d99a39190 Do not list a moved event occurrence twice
An occurrence of a recurring event that was changed on its own carries a
RECURRENCE-ID and is stored as an additional VEVENT next to the event it
belongs to. `getAllSubcomponents("vevent")` returns those components as well,
and since they have no RRULE of their own they were handled as separate single
events. The occurrence therefore ended up in the list twice: once from
expanding the recurring event, which resolves the modified time through the
exception, and once more from the extra VEVENT.

To make it worse the two rows disagreed, because name and URL were taken from
the recurring event while the time came from the modification, so the first row
showed the new time under the old name.

Skip components that are a recurrence exception, they are already covered by
the event they modify, and take name and URL from the occurrence details, which
point at the modification where there is one and at the event itself otherwise.
Events whose RECURRENCE-ID refers to an event that is not in the file are
dropped by this, which cannot happen in a full calendar export.

With a recurring Plenum whose 25.08. occurrence is moved two hours earlier and
renamed:

  before: 25.08. 18:00  CCCB Plenum
          25.08. 18:00  CCCB Plenum (verschoben)
  after:  25.08. 18:00  CCCB Plenum (verschoben)

Leaning on the resolution ical.js does here needs two more things to be right.

The first is which modifications an event is asked to resolve. Unless it is
told, `ICAL.Event` relates every VEVENT with a RECURRENCE-ID in the file to
every recurring event and keys them by the recurrence id alone; the UID is only
compared with `strictExceptions`, which then throws instead of skipping. A
modification would therefore also override the occurrence another series holds
at the same instant, so the wrong entry is shown and the modified one twice
over. Group the modifications by the UID of the event they belong to and hand
each event its own, which also turns the relating off for events that have
none. Recognise a modification on the component instead of on the event,
because relating exceptions to an exception throws. With two unrelated weekly
series that both meet on Thursday at 19:00, of which only A has its occurrence
of 03.09. moved to 17:00:

  before: 27.08. 19:00 Serie A          after: 27.08. 19:00 Serie A
          27.08. 19:00 Serie B                 27.08. 19:00 Serie B
          03.09. 17:00 Serie A (versch.)       03.09. 17:00 Serie A (versch.)
          03.09. 17:00 Serie A (versch.)       03.09. 19:00 Serie B

The second is how far the expansion has to run. It walks the unmodified
recurrence times and stopped at the end of the window, but the occurrence
handed to `getOccurrenceDetails()` may have been moved somewhere else entirely.
Both directions were wrong: an occurrence pulled forward from beyond the window
was never reached, because the walk had already stopped at its original time,
and one pushed out of the window was still listed, because only its original
time was ever compared against the window. Iterate far enough that the largest
move towards the past can still reach the window, and decide by the time the
occurrence really takes place at. The stop condition keeps using the raw
recurrence time, which stays monotonic, so the iteration still terminates. With
a weekly series whose occurrence of 05.10. is pulled forward to 25.08. and
whose occurrence of 31.08. is pushed to 02.11., seen from 23.08. through the 20
day window:

  before: 24.08. Serie                 after: 24.08. Serie
          31.08. Serie                        25.08. Serie (vorgezogen)
          07.09. Serie                        07.09. Serie

Reading the URL becomes a function of its own while name and URL move to the
occurrence details, and it now looks at what it reads. The calendar is exported
from a CalDAV server, so whoever may write to it decides what ends up in the
href of the link, and `URL:javascript:alert(1)` on an event would run that
script when a visitor clicks the entry. Pass on nothing but http and https; a
value that is not a URL at all no longer reaches the href either.

The published calendar contains no RECURRENCE-ID at all today, so nothing about
the modifications changes for it. It is exported from a CalDAV server though,
and moving a single Club Discordia or Plenum out of the way of a holiday is
exactly what creates such a modification. Checked against
https://berlin.ccc.de/calendars/all.ics: the list and the links of the 30
events that carry a URL are unchanged.

Fixes: c28f04c6e8 ("switch to ics files; make calendars work; fix some minor issues")
Assisted-by: Claude:claude-opus-5
Signed-off-by: Hauke Mehrtens <hauke@hauke-m.de>
2026-08-23 01:07:25 +02:00
8b692a2e88 Keep running events in the upcoming list until they end
The "Nächste Veranstaltungen" table selected events with `start > now`, so an
event disappeared from the list the moment it began. Someone looking at the
start page at 20:30 no longer saw the Plenum that had started at 20:00 and ran
until 22:00, which is exactly when that information is most useful.

Select on the end of the event instead, so an event stays listed for as long as
it is still running. A currently running event sorts first, because the list is
ordered by start time.

For recurring events the end of the individual occurrence is needed, not the
end of the series, so go through `getOccurrenceDetails()`. That also resolves
occurrences overridden via RECURRENCE-ID. The chronological break out of the
iteration keeps using the raw occurrence time, which stays monotonic even when
an override moves a single occurrence. `ICAL.Event.endDate` falls back to
DURATION and, for all-day events, to the following day, so events without an
explicit DTEND keep working.

The `maxDays` window still applies to the start of an event, so a long running
event does not extend the window.

This is not a regression from the commit below, the Python generator it
replaced filtered on `dtstart >= start` in the same way.

Checked against https://berlin.ccc.de/calendars/all.ics: the Plenum (20:00 to
22:00) is now listed at 20:30 and 21:59 and gone at 22:01, and the multi-day
Amateurfunk trip (30.10. 12:00 to 01.11. 18:00) stays listed throughout.

Fixes: c28f04c6e8 ("switch to ics files; make calendars work; fix some minor issues")
Assisted-by: Claude:claude-opus-5
Signed-off-by: Hauke Mehrtens <hauke@hauke-m.de>
2026-08-23 01:07:25 +02:00
b8ec457818 Link upcoming events to their ICS URL
The "Nächste Veranstaltungen" table read the event URL via `ICAL.Event.url`,
but ical.js does not expose a `url` getter on `ICAL.Event` (it only has uid,
summary, description, color, location, sequence, the dates, organizer and
attendees). `event.url` was therefore always `undefined` and the `?? ""`
fallback turned it into an empty string, so every row rendered as
`<a href="">`, a dead link that just reloads the start page.

Read the URL from the VEVENT component instead. This also picks up the
`URL;VALUE=URI:` form used by most events in the published calendar, which is
exported from a CalDAV client and does not use a bare `URL:` property.

Not every event has a URL, so only wrap the name in a link when one is
present and emit plain text otherwise.

Checked against https://berlin.ccc.de/calendars/all.ics (31 events, 1 of them
without a URL):

  before: <td><a href="">CCCB Plenum</a></td>
  after:  <td><a href="https://wiki.berlin.ccc.de/Plenum">CCCB Plenum</a></td>
  after:  <td>Aktionstag gegen Überwachung im Chaos Computer Club Berlin</td>

Fixes: c28f04c6e8 ("switch to ics files; make calendars work; fix some minor issues")
Assisted-by: Claude:claude-opus-5
Signed-off-by: Hauke Mehrtens <hauke@hauke-m.de>
2026-08-23 01:07:25 +02:00
c28f04c6e8
switch to ics files; make calendars work; fix some minor issues 2026-08-12 02:01:58 +02:00
Marek Krug
1055074233 update tdoh post 2025-03-11 23:10:10 +01:00
Vinzenz Schroeter
fabc5ff0ea fix naming conflict to restore old gallery with thumbnails 2025-03-10 17:40:10 +01:00
Marek Krug
03af7ae63a tdoh image, calendar improvements, minor changes to a few articles 2025-03-10 04:31:53 +01:00
Vinzenz Schroeter
2178fe4504 add missing image 2025-03-09 20:58:04 +01:00
Marek Krug
91de4b20f2 neue Ordnerstruktur + richtige editurl + kein kochen auf clubdiscordia seite
Some checks failed
Release website / build-and-deploy (push) Has been cancelled
2025-03-02 18:24:11 +01:00
Marek Krug
55a2411613 even better favicons 2025-02-28 00:08:41 +01:00
Marek Krug
1cd3099e37 favicons 2025-02-27 23:27:39 +01:00
Marek Krug
ba414b0015 new images, new content, new theme almost finished 2025-02-27 00:21:42 +01:00
Marek Krug
b62b53674f new theme (work in progress) 2025-02-26 19:47:07 +01:00
Marek Krug
8c2d5c037b new anfahrt picture, different pictures in clubdiscordia and mastodon 2025-02-26 14:31:09 +01:00
Marek Krug
4950d2602b big updates to the website: bastel+spieleabend, beitragsordnung, küche, mastodon, plenum, subbotnik 2025-02-26 12:10:01 +01:00
a9bd7f6e7b
fix images and theme 2023-06-13 22:44:57 +02:00
73871a7b83 Delete coderdojo.png 2019-03-17 18:57:43 +01:00
c45854a0cc Chaosradio image update 2019-03-15 00:07:05 +01:00
Sebastian Pflieger
ea4f18e364 remove ungutes foto 2018-12-02 18:47:50 +01:00
b547c0fd23 Bildergallerie 2018-07-09 00:04:25 +02:00
619f2904ee Logo für Amatuerfunker 2018-06-11 21:22:22 +02:00
Sebastian Breuer
925055c09a modified links, fixed image 2018-05-21 02:05:17 +02:00
vidister
0e2335404d change logo file 2018-05-20 23:43:49 +02:00
e6f908ac6d Amateuerfunk und Datengarten hinzugefuegt 2018-05-18 13:33:20 +02:00
f556273928 Initial commit 2018-05-18 01:30:59 +02:00