Brett und Kalender kennen einander jetzt in beide Richtungen

Der Kalender zeigt seit heute, was auf den Brettern steht und einen
Termin hat. Die Verbindung war aber EINSEITIG, und beide Halften
fehlten:

  Beim SCHREIBEN konnte niemand wissen, dass ein Tag in der Zukunft den
  Zettel in den Kalender bringt. Das Feld heisst "Datum" und ist mit
  HEUTE vorbelegt -- die Funktion war vorhanden und unauffindbar. Eine
  Funktion, die niemand findet, ist keine.

  Beim LESEN sagte die Karte nichts. Am Fuss stand bloss ein Datum, und
  "24.09.2026" sieht aus wie "17.09.2026" -- obwohl das eine ein Termin
  ist und das andere der Tag, an dem jemand getippt hat.

EINE REGEL, ZWEI VERWENDER -> server/workspace-termin-regel.js.
Der Kalender fragt "welche gehoeren hinein?" (SQL, ganze Tabelle), die
Brettkarte fragt "stehe ICH drin?" (JavaScript, je Zeile). Beide Fassungen
stehen jetzt nebeneinander in EINER Datei, importfrei wie
treff-tabellen.js.

Das ist kein Vorsichtsprinzip, sondern Erfahrung: Zwei Fassungen
derselben Regel sind im Haus dreimal auseinandergelaufen -- die
abgeschriebene Spaltenliste (11.09., drei Spalten samt Inhalt weg), die
zweite Artenliste neben ARTNAME (ein BigMatch liess sich anlegen und
war unsichtbar) und `.teilen` heute frueh.

server/pruef-terminregel.mjs, 35 Pruefungen. Der Kern ist Abschnitt 2:
Er prueft die beiden Fassungen GEGENEINANDER, nicht jede fuer sich --
zwei Pruefungen, die je eine Seite bestaetigen, finden genau diesen
Fehler nicht. Verglichen wird beides: WELCHE Zettel und WELCHER Tag.
Neun Faelle, davon vier, die zu Recht wegbleiben.

Vier Gegenproben, jede in ihre eigene Richtung:
  JS laesst mehr durch -> "die Karte behauptet einen Termin, den der
                           Kalender nicht kennt"
  JS nennt anderen Tag -> "verschiedene Tage: Kalender 22., Karte 17."
  SQL laesst mehr durch-> "steht im Kalender, aber die Karte sagt nichts"
  Marke ausgebaut      -> 0 statt 1

EIN ECHTER FEHLER DABEI BEHOBEN, und er war aelter als diese Arbeit:
Das Formularraster gibt jedem Feld GENAU ZWEI Zeilen (Schild dehnbar,
Eingabe fest 44 px) -- deshalb sitzen die Eingaben auf einer Linie. Ein
Hinweisabsatz erzeugt eine dritte Zeile, und weil das Raster alle
Felder auf gleiche Hoehe dehnt, rutscht ausgerechnet diese Eingabe nach
oben. Gemessen: 328..372 gegen 351..395. 23 px -- genau das, was man
als "verzogen" sieht.

Mit `git stash` getrennt: aufgaben.html war dadurch SCHON VORHER rot
(ein anderes Feld hat dort ebenfalls einen Hinweis), bereich.html hatte
ich neu verursacht. Der Hinweis haengt jetzt absolut unter dem Feld --
beide sind gruen, und zwar an der Wurzel, nicht symptomatisch.
`pointer-events: none`, sonst faengt der Satz Klicks ab, die dem
Element darunter galten.

Am Handy gemessen statt geschaetzt: 0 Ueberschneidungen mit anderen
Feldern. Gegenprobe (row-gap auf 2 px): 1 Ueberschneidung.

Und noch zwei eigene Pruefungsfehler behoben, beide von derselben Sorte:
ein falscher Selektor samt `.catch(() => {})`, der den Fehlgriff
lautlos verschluckte (danach war das Hinweisfeld leer und die Zeile
darunter trotzdem gruen, weil "" nun einmal nicht "ja" ist) -- und die
Marke wurde ueber `textContent` gezaehlt statt ueber ihre Sichtbarkeit.
Aufgefallen ist das am Bildschirmfoto, auf dem ich sie fuer fehlend
hielt; deshalb macht die Pruefung jetzt zusaetzlich einen AUSSCHNITT
der Karte -- auf einem Vollbild von 2000 px ist eine Pille von 28 px
nicht zu beurteilen.

Gruen: terminregel, kalender, formulare, ueberlappung, countdown,
namen, css-klassen, struktur.

Co-Authored-By: Claude Opus 5 <[email protected]>
This commit is contained in:
2026-09-17 23:53:05 +02:00
co-authored by Claude Opus 5
parent 528ee1ecc7
commit 5e628e0078
40 changed files with 1087 additions and 425 deletions
+90 -2
View File
@@ -281,6 +281,40 @@
/* ---------- Zeichnen --------------------------------------------------- */
/** Sagt unter dem Datumsfeld, ob dieser Tag im Kalender landet.
*
* DIESELBE REGEL WIE AUF DEM SERVER -- aber bewusst nur die eine
* Haelfte, die der Browser ueberhaupt beantworten kann: Liegt der
* Tag in der Zukunft? Ob am Ende `geplant`, `uhrzeit` oder
* `event_ende` gesetzt sind, entscheidet der Server, und die Karte
* zeigt danach sein Ergebnis. Der Hinweis hier ist eine Vorschau,
* keine zweite Wahrheit -- deshalb steht er im Konjunktiv-Ton
* („steht damit im Kalender") und nicht als Zusage. */
function kalenderhinweisSetzen() {
const feld = $('f-datum');
const ziel = $('hinweis-datum');
if (!feld || !ziel) return;
const wert = feld.value;
/* Denselben Rueckfall wie an den zwei Stellen darueber: `heuteLokal`
kommt aus kopf.js, und wenn das noch nicht geladen ist, waere ein
direkter Aufruf ein Absturz mitten im Formularaufbau. */
const heute = window.heuteLokal ? window.heuteLokal()
: new Date().toISOString().slice(0, 10);
if (!wert) { ziel.textContent = ''; return; }
if (wert > heute) {
ziel.textContent = 'Liegt in der Zukunft – steht damit im Kalender.';
ziel.dataset.imkalender = 'ja';
} else if ($('f-uhrzeit') && !$('feld-uhrzeit').hidden && $('f-uhrzeit').value) {
ziel.textContent = 'Mit Uhrzeit – steht damit im Kalender.';
ziel.dataset.imkalender = 'ja';
} else {
ziel.textContent = wert === heute
? 'Heute – das ist der Tag der Notiz, kein Termin.'
: 'Liegt in der Vergangenheit – kein Termin.';
delete ziel.dataset.imkalender;
}
}
function karte(e) {
const k = el('article', 'eintrag-karte');
k.dataset.dringlich = e.dringlichkeit;
@@ -507,10 +541,41 @@
}
}
/* ---- STEHT IM KALENDER (17.09.2026) ------------------------------
Der Kalender zeigt seit heute, was auf den Brettern steht und
einen Termin hat. Die Verbindung war einseitig: vom Kalender
aufs Brett ja, zurueck nicht. Am Kartenfuss stand bloss ein
Datum -- und „24.09.2026" sieht aus wie „17.09.2026", obwohl das
eine ein Termin ist und das andere der Tag, an dem jemand
getippt hat.
OB ER DRINSTEHT, SAGT DER SERVER (`e.termin`). Hier wird es
nicht nachgerechnet: Eine zweite Fassung der Regel behauptet
irgendwann etwas, das der Kalender nicht zeigt -- und eine
Anzeige, die etwas Falsches sagt, ist schlimmer als keine.
ES IST EIN LINK, keine Marke. Wer liest „steht im Kalender",
will als Naechstes nachsehen, was noch an dem Tag ist. */
if (e.termin) {
const zeile = el('a', 'im-kalender');
zeile.dataset.grund = e.termin.grund;
zeile.href = 'kalender.html';
zeile.append(el('span', 'im-kalender__zeichen', '\u{1F5D3}'));
zeile.append(el('span', 'im-kalender__text',
(e.termin.grund === 'zugesagt' ? 'Zugesagt für ' : 'Im Kalender am ')
+ datum(e.termin.tag)
+ (e.uhrzeit ? ' um ' + e.uhrzeit : '')));
k.append(zeile);
}
const fuss = el('div', 'eintrag-fuss');
/* Beim Event steht der Zeitraum schon oben -- das Datum hier waere
dieselbe Zahl ein zweites Mal. */
if (!stand) fuss.append(el('span', null, datum(e.datum)));
dieselbe Zahl ein zweites Mal. Und steht der Zettel im Kalender,
steht der Tag ebenfalls schon da; dann waere das Erfassungsdatum
hier eine ZWEITE Zahl neben einer wichtigeren -- und die
verwirrt mehr, als sie sagt. */
if (!stand && !e.termin) fuss.append(el('span', null, datum(e.datum)));
if (LEITUNG.has(ich.rolle) && e.creator_name) fuss.append(el('span', null, '· ' + e.creator_name));
if (e.erstellt_name) fuss.append(el('span', null, '· von ' + e.erstellt_name));
if (e.status === 'erledigt') fuss.append(el('span', null, '· erledigt'));
@@ -1408,6 +1473,19 @@
if (einstellung?.vertraulich) $('feld-vertraulich').hidden = event;
$('schild-datum').textContent = event ? 'Von' : 'Datum';
/* WAS DAS DATUM BEWIRKT, STEHT DARUNTER (17.09.2026).
Das Feld ist mit HEUTE vorbelegt und heisst schlicht „Datum".
Damit war die Kalenderfunktion zwar vorhanden, aber unauffindbar:
Niemand konnte wissen, dass ein Tag in der Zukunft den Zettel in
den Kalender bringt. Eine Funktion, die niemand findet, ist
keine.
Der Satz aendert sich MIT DER EINGABE, statt allgemein zu
bleiben -- ein fester Hinweis („kann im Kalender erscheinen")
beantwortet die Frage nicht, die man gerade hat: „Steht der
jetzt drin oder nicht?" */
kalenderhinweisSetzen();
$('schild-titel').textContent = event ? 'Titel des Events' : 'Überschrift';
/* textContent wuerde das <span class="leise"> mit erschlagen --
deshalb nur der erste Textknoten, das kleine "(optional)" bleibt
@@ -1439,6 +1517,7 @@
};
$('neu-oeffnen').addEventListener('click', () => {
$('f-datum').value = window.heuteLokal();
kalenderhinweisSetzen();
formularAnpassen();
umschalten(true);
});
@@ -1450,6 +1529,15 @@
am urspruenglichen <select> -- ohne dieses Ereignis merkte das
Formular vom Artwechsel nichts. */
$('f-art').addEventListener('change', formularAnpassen);
/* DER HINWEIS ZIEHT MIT. Ohne diese beiden Zeilen stuende er auf dem
Stand vom Oeffnen des Formulars -- also dauerhaft auf „Heute", auch
nachdem jemand den 24. eingetragen hat. Ein Hinweis, der beim Tippen
stehenbleibt, sagt nach dem ersten Tastendruck etwas Falsches, und
das ist schlechter als gar keiner. */
$('f-datum')?.addEventListener('change', kalenderhinweisSetzen);
$('f-datum')?.addEventListener('input', kalenderhinweisSetzen);
$('f-uhrzeit')?.addEventListener('change', kalenderhinweisSetzen);
$('f-uhrzeit')?.addEventListener('input', kalenderhinweisSetzen);
$('neu').addEventListener('submit', async (e) => {
e.preventDefault();