Chat: sechs Ergaenzungen -- und ein Absturz, den nie jemand gesehen hat

Filipe: "die kategorie chat, boah ich will dass du die wirklich ueberall
perfektionierst. wirklich alles was gratis ist und hinzugefuegt werden
kann ohne problem will ich drin haben bitte. ich will das es hoch
profissionel und ultra krass geil ist."

Zuerst Bestand aufgenommen, nicht gebaut: Suche, Ungelesen-Zahlen, die
"ab hier neu"-Linie, Lesestand, Live-Strom, Antworten mit Zitat,
Zuruecknehmen und Enter-zum-Senden gab es schon. Dazugekommen ist, was
gefehlt hat und ohne fremde Bibliothek geht:

1. ADRESSEN SIND ANKLICKBAR. Gebaut als echte Knoten, nie ueber
   innerHTML -- ein Chat ist die eine Stelle, an der jeder schreiben
   darf. Erkannt wird bewusst wenig (http, https, www.): Wer mehr
   erkennt, macht irgendwann aus "z.b." einen Link ins Nichts.
   Satzzeichen am Ende bleiben beim Satz. rel="noopener noreferrer".
2. KOPIEREN je Nachricht, mit Rueckfall auf "Text markieren", wenn der
   Browser die Zwischenablage nicht hergibt.
3. DER VERLAUF REISST NIEMANDEN MEHR WEG. Vorher sprang er bei JEDEM
   Neuzeichnen ans Ende -- wer weiter oben nachlas und dabei eine
   Nachricht bekam, verlor die Stelle. Jetzt bleibt er stehen, und ein
   Knopf sagt, WIE VIEL unten wartet, nicht nur DASS etwas da ist.
4. ENTWUERFE JE GESPRAECH. Wer mitten im Satz wechselt, findet ihn
   wieder. Im localStorage, nicht auf dem Server: Ein Entwurf ist
   nichts, was jemand anders sehen soll. Abgeschickt heisst geloescht.
5. EMOJI-AUSWAHL, dreissig feste Zeichen, eingefuegt an der
   Cursorstelle. Am Handy hat die Tastatur sie ohnehin -- am Rechner
   nicht, und dort sitzt die Betreuung.
6. ZEICHENZAEHLER, sichtbar ab 400 Rest. Die Grenze steht NICHT im
   Skript, sondern kommt aus dem maxlength des Feldes -- zwei Stellen
   fuer dieselbe Zahl laufen auseinander.

--- DER FUND, um den es eigentlich geht ---

Die neue Pruefung hoert auf "pageerror". Damit kam sofort neun Mal
dieselbe Meldung: "Cannot set properties of null (setting 'hidden')",
raumOeffnen, Zeile 278.

Ursache: verlaufZeichnen() leerte den Verlaufskasten mit
`textContent = ''`. Darin liegt aber #verlauf-leer, der Absatz "Links
ein Gespraech auswaehlen". Nach dem ersten Zeichnen gab es ihn nicht
mehr, und raumOeffnen faellt sechs Zeilen weiter darueber.

Die Folge ist nicht die Fehlermeldung, sondern der Abbruch: Beim ZWEITEN
Aufruf liefen history.replaceState, gelesenMelden() und raeumeZeichnen()
nie. Der zweite Aufruf ist der Normalfall -- der Ereignisstrom ruft nach
jedem Verbindungsaufbau genau das, um nachzuholen, was waehrend der
Pause geschrieben wurde. Dieses Nachholen hat nie funktioniert. Von
aussen sah alles normal aus; nur die Konsole wusste Bescheid.

Behoben, indem nur noch die Nachrichten entfernt werden und der Absatz
stehenbleibt. Abschnitt 8 der Pruefung wechselt jetzt dreimal zwischen
zwei Gespraechen OHNE Neuladen und verlangt null Abstuerze.

--- UND EIN ZWEITER, der schon laenger drin war ---

Abschnitt 9 misst den Kontrast an der wirklichen Flaeche (Text kurz
unsichtbar, Flaeche fotografiert). Die Fusszeile jeder Nachricht stand
auf --text-still: auf der eigenen Blase 3,68:1, unter den 4,5:1 fuer
Text dieser Groesse. Aufgefallen ist es nie, weil niemand nachgemessen
hat. Jetzt traegt .chat-nachricht__fuss EINE Farbe (--text-leise,
4,81:1) und Uhrzeit, antworten, zuruecknehmen und kopieren erben sie --
statt vier eigener Angaben, die beim naechsten Mal auseinanderlaufen.

--- Pruefung ---

server/pruef-chat-ausbau.mjs, neu, 64 Pruefungen, alle gruen. Zu jedem
Punkt eine Gegenprobe: kein Link ohne Adresse, keine Auszeichnung aus
<b>/<img onerror>, kein Kopier-Knopf an zurueckgenommenen Nachrichten,
kein Sprungknopf fuer den, der schon unten steht, kein Entwurf nach dem
Abschicken, ein absichtlich zu dunkler Text faellt durch, und ein
absichtlich geworfener Fehler wird bemerkt (sonst waere Abschnitt 10
auch gruen, wenn niemand zuhoert).

Ausserdem gruen: pruef-css-klassen, pruef-chat, pruef-chat-optik.
Angesehen bei 1440 px und bei 390 px.

Co-Authored-By: Claude Opus 5 <[email protected]>
This commit is contained in:
2026-09-09 12:13:24 +02:00
co-authored by Claude Opus 5
parent 7c00e76d63
commit e28724564a
22 changed files with 1220 additions and 199 deletions
+137 -4
View File
@@ -321,12 +321,28 @@
border-style: dashed;
}
/* EINE FARBE FÜR DIE GANZE FUSSZEILE — und zwar hier, an einer Stelle.
---------------------------------------------------------------------
Uhrzeit, "antworten", "zurücknehmen" und "kopieren" standen alle auf
var(--text-still) (#7f8fa6). Gemessen (pruef-chat-ausbau, Abschnitt 9)
ergibt das auf der eigenen Blase 3,68:1 -- unter den 4,5:1, die für
Text dieser Größe gelten. Es ist nie aufgefallen, weil niemand
nachgemessen hat; die Blase ist heller als der übrige Grund, und
genau dort wird eine leise Farbe zu leise.
var(--text-leise) (#94a5bb) bringt dieselbe Stelle auf 4,80:1 und
bleibt trotzdem deutlich ruhiger als der Nachrichtentext.
Die Kinder erben sie (color: inherit). Vier eigene Farbangaben wären
vier Stellen, die beim nächsten Mal auseinanderlaufen -- der Fehler,
der in diesem Haus am häufigsten vorkommt. */
.chat-nachricht__fuss {
display: flex; align-items: center; gap: 9px;
margin-top: 4px;
color: var(--text-leise);
}
.chat-nachricht__zeit {
font-size: .75rem; color: var(--text-still);
font-size: .75rem; color: inherit;
font-variant-numeric: tabular-nums;
}
/* Der Zurücknehmen-Knopf erscheint erst beim Darüberfahren -- er ist
@@ -335,7 +351,7 @@
.chat-nachricht__weg-knopf {
padding: 0; border: 0; background: none;
font: inherit; font-size: .75rem;
color: var(--text-still); cursor: pointer;
color: inherit; cursor: pointer;
opacity: 0; transition: opacity .16s ease, color .16s ease;
}
.chat-nachricht:hover .chat-nachricht__weg-knopf,
@@ -790,7 +806,124 @@
.chat-nachricht__antwort-knopf {
border: 0; background: none; padding: 0;
font: inherit; font-size: .72rem;
color: var(--text-still); cursor: pointer;
color: inherit; cursor: pointer;
text-decoration: underline; text-underline-offset: 2px;
}
.chat-nachricht__antwort-knopf:hover { color: var(--text-leise); }
.chat-nachricht__antwort-knopf:hover { color: var(--text); }
/* =====================================================================
CHAT: SECHS ERGÄNZUNGEN (09.09.2026)
Filipe: "die kategorie chat, boah ich will dass du die wirklich
überall perfektionierst. wirklich alles was gratis ist und
hinzugefügt werden kann ohne problem will ich drin haben."
Alle sechs kommen ohne fremde Bibliothek aus und laden nichts nach:
Links, Kopieren, Emoji-Auswahl, Zeichenzähler, ein Bildlauf der nicht
mehr wegreisst, und Entwürfe je Gespräch (dafür braucht es kein CSS).
===================================================================== */
/* Ein Link in einer Nachricht ist unterstrichen, nicht farbig -- eine
Blase hat schon eine Farbe, und zwei Farben in einer Blase lesen sich
wie zwei Sachen. */
.chat-nachricht__link {
color: inherit;
text-decoration: underline;
text-underline-offset: 3px;
text-decoration-color: color-mix(in srgb, currentColor 55%, transparent);
word-break: break-word;
}
.chat-nachricht__link:hover { text-decoration-color: currentColor; }
.chat-nachricht__link:focus-visible {
outline: 2px solid var(--akzent); outline-offset: 2px; border-radius: 3px;
}
/* Der Kopier-Knopf sieht aus wie "antworten" -- es ist dieselbe Sorte
Handgriff an derselben Stelle. Ein anders gestalteter Knopf daneben
waere eine zweite Sprache in derselben Zeile. */
.chat-nachricht__kopie-knopf {
appearance: none; border: 0; background: none; padding: 0;
font: inherit; font-size: .72rem; font-weight: 600;
color: inherit; cursor: pointer;
text-decoration: underline; text-underline-offset: 2px;
}
.chat-nachricht__kopie-knopf:hover { color: var(--text); }
.chat-nachricht__kopie-knopf:focus-visible {
outline: 2px solid var(--akzent); outline-offset: 2px; border-radius: 4px;
}
/* ---- Emoji ---------------------------------------------------------- */
.chat__emoji {
flex: none;
width: 40px; height: 40px;
display: flex; align-items: center; justify-content: center;
appearance: none; border: 1px solid rgba(150, 186, 220, .18);
border-radius: 11px;
background: rgba(255, 255, 255, .04);
color: var(--text-leise);
font-size: 1.15rem; line-height: 1; cursor: pointer;
transition: color var(--tempo), border-color var(--tempo);
}
.chat__emoji:hover { color: var(--text); border-color: rgba(150, 186, 220, .34); }
.chat__emoji:focus-visible { outline: 2px solid var(--akzent); outline-offset: 2px; }
/* Die Tafel steht ÜBER der Eingabe, nicht darunter: Darunter läge sie
auf dem Handy hinter der Bildschirmtastatur. */
.emoji-tafel {
position: absolute;
right: 14px; bottom: calc(100% - 6px);
z-index: 5;
display: grid; grid-template-columns: repeat(10, 1fr); gap: 2px;
padding: 10px;
border-radius: 14px;
background: rgba(8, 12, 20, .97);
border: 1px solid rgba(150, 186, 220, .2);
box-shadow: 0 18px 40px -18px rgba(0, 0, 0, .9);
}
.emoji-tafel__knopf {
appearance: none; border: 0; background: none;
width: 34px; height: 34px; border-radius: 8px;
font-size: 1.15rem; line-height: 1; cursor: pointer;
transition: background var(--tempo);
}
.emoji-tafel__knopf:hover { background: rgba(255, 255, 255, .1); }
.emoji-tafel__knopf:focus-visible { outline: 2px solid var(--akzent); outline-offset: -2px; }
@media (max-width: 620px) {
.emoji-tafel { left: 14px; right: 14px; grid-template-columns: repeat(8, 1fr); }
}
/* ---- Zeichenzähler --------------------------------------------------- */
.chat__zeichen {
flex: none; align-self: center;
font-size: .72rem; font-weight: 700; letter-spacing: .04em;
color: var(--text-still);
font-variant-numeric: tabular-nums;
}
/* Eng heisst rot -- aber erst dann. Ein dauerhaft roter Zähler ist eine
Warnung, die niemand mehr liest. */
.chat__zeichen[data-eng="ja"] { color: var(--warn, #ff9aa2); }
/* ---- Zum neuesten ---------------------------------------------------- */
.chat__zum-neuesten {
position: absolute; left: 50%; bottom: 96px;
transform: translateX(-50%);
z-index: 4;
padding: 9px 18px;
border-radius: 999px;
border: 1px solid color-mix(in srgb, var(--akzent) 40%, transparent);
background: rgba(8, 12, 20, .95);
color: var(--text);
font: inherit; font-size: .8rem; font-weight: 700;
cursor: pointer;
box-shadow: 0 10px 26px -12px rgba(0, 0, 0, .9);
}
.chat__zum-neuesten:hover { border-color: var(--akzent); }
.chat__zum-neuesten:focus-visible { outline: 2px solid var(--akzent); outline-offset: 2px; }
@media (prefers-reduced-motion: reduce) {
.chat__emoji, .emoji-tafel__knopf { transition: none; }
}
@media (forced-colors: active) {
.emoji-tafel, .chat__zum-neuesten { border: 1px solid CanvasText; background: Canvas; }
}
+255 -4
View File
@@ -278,7 +278,14 @@
$('verlauf-leer').hidden = true;
$('chat').dataset.ansicht = 'verlauf';
/* Ein frisch geoeffnetes Gespraech steht immer am Ende -- man will
das Letzte sehen, nicht das Erste. */
unten = true; neuUnten = 0;
verlaufZeichnen();
/* Der Entwurf von vorhin, falls einer da ist. */
$('text').value = entwurfHolen(id);
hoeheAnpassen();
zaehlerZeigen();
if (!sanft) $('text').focus();
/* Die Adresszeile merkt sich das Gespräch -- so führt die
Benachrichtigung direkt hierher, und ein Neuladen bleibt am
@@ -290,7 +297,28 @@
function verlaufZeichnen() {
const ziel = $('verlauf');
ziel.textContent = '';
/* NUR DIE NACHRICHTEN WEG — NICHT DER GANZE KASTEN.
------------------------------------------------------------------
Hier stand `ziel.textContent = ''`. Das loeschte auch
`#verlauf-leer`, den Absatz "Links ein Gespraech auswaehlen", denn
der liegt IN diesem Kasten. Nach dem ersten Zeichnen gab es ihn
also nicht mehr — und `raumOeffnen` faellt sechs Zeilen weiter
genau darueber:
$('verlauf-leer').hidden = true; -> null
Folge, und die ist die eigentliche: `raumOeffnen` bricht an dieser
Stelle ab. Damit laufen `history.replaceState`, `gelesenMelden()`
und `raeumeZeichnen()` beim ZWEITEN Aufruf nie. Der zweite Aufruf
ist aber der Normalfall — der Ereignisstrom ruft nach jedem
Verbindungsaufbau genau das (`{ sanft: true }`), um nachzuholen,
was waehrend der Pause geschrieben wurde. Dieses Nachholen hat
nie funktioniert; der Absturz stand still in der Konsole.
Gefunden hat das nicht das Auge, sondern der Lauscher auf
`pageerror` in pruef-chat-ausbau.mjs. Ohne ihn waere es geblieben:
Die Seite sieht danach voellig normal aus. */
for (const alt of [...ziel.children]) if (alt.id !== 'verlauf-leer') alt.remove();
if (!nachrichten.length) {
ziel.append(el('p', 'chat__leer', 'Noch nichts geschrieben. Fang an.'));
return;
@@ -386,7 +414,7 @@
/* textContent, nie innerHTML: Eine Nachricht darf keine
Auszeichnung einschleusen. Zeilenumbrüche macht das CSS
(white-space: pre-wrap). */
blase.append(el('p', 'chat-nachricht__text', n.text));
blase.append(mitLinks(n.text));
}
const fuss = el('div', 'chat-nachricht__fuss');
@@ -410,11 +438,95 @@
weg.addEventListener('click', () => zuruecknehmen(n.id));
fuss.append(weg);
}
/* KOPIEREN. Eine Adresse, ein Code, eine Uhrzeit -- man will sie
weitergeben, nicht abtippen. Der Knopf bestaetigt sich selbst
und faellt danach zurueck; eine Meldung anderswo waere ein
zweiter Ort, an dem man nachsehen muesste. */
if (!n.zurueckgenommen && n.text) {
const kopie = el('button', 'chat-nachricht__kopie-knopf', 'kopieren');
kopie.type = 'button';
kopie.addEventListener('click', async () => {
try {
await navigator.clipboard.writeText(n.text);
kopie.textContent = 'kopiert';
} catch {
/* Ohne Zwischenablage-Recht (aeltere Browser, kein HTTPS)
den Text wenigstens auswaehlen -- dann geht Strg+C. */
const p = kopie.closest('.chat-nachricht')?.querySelector('.chat-nachricht__text');
if (p) { const r = document.createRange(); r.selectNodeContents(p);
const sel = getSelection(); sel.removeAllRanges(); sel.addRange(r); }
kopie.textContent = 'markiert';
}
setTimeout(() => { kopie.textContent = 'kopieren'; }, 1600);
});
fuss.append(kopie);
}
blase.append(fuss);
zeile.append(blase);
ziel.append(zeile);
}
ziel.scrollTop = ziel.scrollHeight;
/* NUR NACH UNTEN SPRINGEN, WENN MAN SCHON UNTEN WAR.
Vorher sprang der Verlauf bei JEDEM Neuzeichnen ans Ende. Wer
weiter oben etwas nachlas und dabei eine neue Nachricht bekam,
wurde mitten im Satz weggerissen -- und das passiert im Live-
Strom staendig. Jetzt gilt: Wer unten steht, bleibt unten
(das ist der Normalfall). Wer liest, bleibt stehen und bekommt
einen Knopf, der sagt, wie viel unten wartet. */
if (unten) {
ziel.scrollTop = ziel.scrollHeight;
neuUnten = 0;
}
springKnopfZeigen();
}
/* Steht der Verlauf am Ende? 40 Pixel Nachsicht -- ein Bildlauf trifft
die letzte Zeile selten auf den Punkt, und ein Knopf, der bei einem
Pixel Abstand erscheint, ist ein Flackern. */
let unten = true;
let neuUnten = 0;
function amEnde(e) { return e.scrollHeight - e.scrollTop - e.clientHeight < 40; }
function springKnopfZeigen() {
const k = $('zum-neuesten');
if (!k) return;
k.hidden = unten || !nachrichten.length;
k.textContent = neuUnten
? (neuUnten === 1 ? '1 neue Nachricht' : `${neuUnten} neue Nachrichten`)
: 'Zum neuesten';
}
/* ---------- Links in Nachrichten (09.09.2026) ---------------------------
Eine Adresse im Text soll anklickbar sein. Gebaut wird sie als
ECHTER Knoten, nie ueber innerHTML: Sonst koennte ein Absender
Auszeichnung einschleusen, und in einem Chat schreibt jeder.
Erkannt wird bewusst wenig -- http, https und www. Wer mehr
erkennt (Mailadressen, nackte Domains), erwischt irgendwann
"3.stelle" oder "z.b." und macht daraus einen Link ins Nichts.
`rel="noopener noreferrer"` ist Pflicht: Ohne `noopener` kann die
geoeffnete Seite auf das Fenster zurueckgreifen, aus dem sie kam. */
const LINKMUSTER = /(https?:\/\/[^\s<>"']+|www\.[^\s<>"']+)/g;
function mitLinks(text) {
const p = el('p', 'chat-nachricht__text');
let letzte = 0;
for (const treffer of String(text).matchAll(LINKMUSTER)) {
const roh = treffer[0];
/* Satzzeichen am Ende gehoeren zum Satz, nicht zur Adresse. */
const sauber = roh.replace(/[.,;:!?)\]]+$/, '');
if (treffer.index > letzte) p.append(document.createTextNode(text.slice(letzte, treffer.index)));
const a = el('a', 'chat-nachricht__link', sauber);
a.href = sauber.startsWith('www.') ? 'https://' + sauber : sauber;
a.target = '_blank';
a.rel = 'noopener noreferrer';
p.append(a);
if (sauber.length < roh.length) p.append(document.createTextNode(roh.slice(sauber.length)));
letzte = treffer.index + roh.length;
}
if (letzte < text.length) p.append(document.createTextNode(text.slice(letzte)));
return p;
}
/* ---------- Antworten und Springen (09.09.2026, Punkt 15) ---------------- */
@@ -482,8 +594,13 @@
: null,
};
nachrichten.push(vorlaeufig);
/* Wer selbst schreibt, will das Ergebnis sehen -- auch wenn er
vorher weiter oben gelesen hat. */
unten = true; neuUnten = 0;
verlaufZeichnen();
feld.value = '';
entwurfWeg(offen.id);
zaehlerZeigen();
antwortLoeschen();
hoeheAnpassen();
melde('');
@@ -608,6 +725,9 @@
}
nachrichten.push({ ...n, selbst: n.von_id === ich.id });
/* Wer gerade weiter oben liest, soll sehen, WIE VIEL unten
dazugekommen ist -- nicht nur, DASS etwas da ist. */
if (!unten && n.von_id !== ich.id) neuUnten++;
verlaufZeichnen();
gelesenMelden();
}
@@ -789,7 +909,138 @@
$('schreiben').addEventListener('submit', abschicken);
$('text').addEventListener('input', hoeheAnpassen);
$('text').addEventListener('input', () => {
hoeheAnpassen();
entwurfMerken();
zaehlerZeigen();
});
/* ---------- Entwurf je Gespraech (09.09.2026) ----------------------------
Wer mitten im Satz das Gespraech wechselt, findet den Satz beim
Zurueckkommen wieder. Ohne das ist jeder Wechsel eine Entscheidung:
"wegwerfen oder erst fertig schreiben?"
Im localStorage und nicht auf dem Server: Ein Entwurf ist nichts,
was jemand anders sehen soll, und er gehoert an dieses Geraet.
Abgeschickte oder geleerte Entwuerfe werden geloescht -- eine
Ablage, die nur waechst, ist ein Leck. */
const ENTWURF = (id) => `dfw-chat-entwurf-${id}`;
function entwurfMerken() {
if (!offen) return;
const t = $('text').value;
try {
if (t.trim()) localStorage.setItem(ENTWURF(offen.id), t);
else localStorage.removeItem(ENTWURF(offen.id));
} catch { /* privater Modus: dann eben nicht */ }
}
function entwurfHolen(raumId) {
try { return localStorage.getItem(ENTWURF(raumId)) || ''; } catch { return ''; }
}
function entwurfWeg(raumId) {
try { localStorage.removeItem(ENTWURF(raumId)); } catch { /* egal */ }
}
/* ---------- Zeichenzaehler ------------------------------------------------
Er erscheint erst, wenn es eng wird. Ein Zaehler, der von Anfang an
mitlaeuft, zaehlt die meiste Zeit etwas, das niemanden interessiert --
und wird dann auch dann uebersehen, wenn er zaehlt. */
/* Die Zahl steht NICHT hier. Sie steht im maxlength des Feldes, und
dort steht sie, weil der Server sie so haben will (TEXT_MAX = 4000
in workspace-chat.js). Zwei Stellen fuer dieselbe Zahl laufen
auseinander -- dann zaehlt der Zaehler bis 4000 herunter, waehrend
das Feld schon bei 2000 dichtmacht, und niemand versteht warum. */
const GRENZE = Number($('text').getAttribute('maxlength')) || 4000;
function zaehlerZeigen() {
const z = $('zeichen');
if (!z) return;
const n = $('text').value.length;
const rest = GRENZE - n;
z.hidden = rest > 400;
z.textContent = `noch ${rest}`;
z.dataset.eng = rest <= 100 ? 'ja' : 'nein';
}
/* ---------- Emoji-Auswahl -------------------------------------------------
Eine kleine, feste Auswahl statt einer vollstaendigen Tafel: Diese
dreissig decken den Alltag ab, und sie laden nichts nach. Eine
Emoji-Bibliothek waere ein Megabyte fuer etwas, das die
Bildschirmtastatur ohnehin kann -- am Rechner aber nicht.
Eingefuegt wird an der CURSORSTELLE, nicht am Ende: Wer mitten im
Satz eines setzen will, soll nicht erst umsortieren. */
const EMOJIS = ['😀','😂','🥹','😍','😎','🤔','😅','🙃','😴','🤝',
'👍','👏','🙌','💪','🙏','🔥','✨','⭐','💯','🎉',
'❤️','💙','💚','🖤','👀','🎮','🎧','📈','⏰','✅'];
function emojiTafelBauen() {
const tafel = $('emoji-tafel');
if (!tafel || tafel.childElementCount) return;
for (const e of EMOJIS) {
const b = el('button', 'emoji-tafel__knopf', e);
b.type = 'button';
b.setAttribute('aria-label', `Emoji ${e} einfügen`);
b.addEventListener('click', () => {
const f = $('text');
const a = f.selectionStart ?? f.value.length;
const b2 = f.selectionEnd ?? a;
f.value = f.value.slice(0, a) + e + f.value.slice(b2);
f.focus();
f.selectionStart = f.selectionEnd = a + e.length;
hoeheAnpassen(); entwurfMerken(); zaehlerZeigen();
});
tafel.append(b);
}
}
$('emoji-auf')?.addEventListener('click', () => {
const tafel = $('emoji-tafel');
emojiTafelBauen();
const auf = tafel.hidden;
tafel.hidden = !auf;
$('emoji-auf').setAttribute('aria-expanded', String(auf));
if (auf) tafel.querySelector('button')?.focus();
});
/* Ein Klick daneben schliesst die Tafel -- sonst steht sie im Weg,
und man sucht den Knopf, mit dem man sie aufgemacht hat. */
document.addEventListener('click', (e) => {
const tafel = $('emoji-tafel');
if (!tafel || tafel.hidden) return;
if (tafel.contains(e.target) || e.target.closest('#emoji-auf')) return;
tafel.hidden = true;
$('emoji-auf')?.setAttribute('aria-expanded', 'false');
});
/* Escape schliesst sie -- und zwar von ueberall her, nicht nur wenn
die Schreibmarke zufaellig noch in der Tafel steht.
Erster Anlauf hing der Zuhoerer an der Tafel selbst. Das geht gut,
solange man sie gerade aufgemacht hat (dann liegt der Fokus auf dem
ersten Zeichen). Wer danach ins Schreibfeld zurueckklickt, drueckt
Escape aber ins Leere -- und die Tafel steht weiter im Weg. Am
Dokument gilt es immer; ist die Tafel zu, tut die Zeile nichts. */
document.addEventListener('keydown', (e) => {
if (e.key !== 'Escape') return;
const tafel = $('emoji-tafel');
if (!tafel || tafel.hidden) return;
tafel.hidden = true;
$('emoji-auf')?.setAttribute('aria-expanded', 'false');
$('text').focus();
});
/* ---------- Zum neuesten springen ---------------------------------------- */
$('verlauf')?.addEventListener('scroll', () => {
const v = $('verlauf');
const jetztUnten = amEnde(v);
if (jetztUnten !== unten) {
unten = jetztUnten;
if (unten) neuUnten = 0;
springKnopfZeigen();
}
});
$('zum-neuesten')?.addEventListener('click', () => {
const v = $('verlauf');
v.scrollTop = v.scrollHeight;
unten = true; neuUnten = 0;
springKnopfZeigen();
});
/* Enter schickt, Umschalt+Enter macht eine neue Zeile. Am Handy
NICHT -- dort ist Enter die Zeilenschaltung der Bildschirmtastatur,
und wer eine zweite Zeile will, käme sonst nie dazu. */
+9 -9
View File
@@ -14,10 +14,10 @@
<meta name="theme-color" content="#06090f" />
<link rel="icon" type="image/png" href="/assets/img/app-symbole/workspace-32.png" />
<link rel="apple-touch-icon" href="/assets/img/app-symbole/workspace-180.png" />
<link rel="stylesheet" href="assets/css/gate.css?v=202609090318" />
<link rel="stylesheet" href="assets/css/start.css?v=202609090318" />
<link rel="stylesheet" href="assets/css/aufgaben.css?v=202609090318" />
<link rel="stylesheet" href="assets/css/module.css?v=202609090318" />
<link rel="stylesheet" href="assets/css/gate.css?v=202609091211" />
<link rel="stylesheet" href="assets/css/start.css?v=202609091211" />
<link rel="stylesheet" href="assets/css/aufgaben.css?v=202609091211" />
<link rel="stylesheet" href="assets/css/module.css?v=202609091211" />
</head>
<body class="start">
@@ -231,10 +231,10 @@
</form>
</dialog>
<script src="assets/js/wahl.js?v=202609090318" defer></script>
<script src="assets/js/bereiche.js?v=202609090318" defer></script>
<script src="assets/js/kopf.js?v=202609090318" defer></script>
<script src="assets/js/glocke.js?v=202609090318" defer></script>
<script src="assets/js/aufgaben.js?v=202609090318" defer></script>
<script src="assets/js/wahl.js?v=202609091211" defer></script>
<script src="assets/js/bereiche.js?v=202609091211" defer></script>
<script src="assets/js/kopf.js?v=202609091211" defer></script>
<script src="assets/js/glocke.js?v=202609091211" defer></script>
<script src="assets/js/aufgaben.js?v=202609091211" defer></script>
</body>
</html>
+10 -10
View File
@@ -14,11 +14,11 @@
<meta name="theme-color" content="#06090f" />
<link rel="icon" type="image/png" href="/assets/img/app-symbole/workspace-32.png" />
<link rel="apple-touch-icon" href="/assets/img/app-symbole/workspace-180.png" />
<link rel="stylesheet" href="assets/css/gate.css?v=202609090318" />
<link rel="stylesheet" href="assets/css/start.css?v=202609090318" />
<link rel="stylesheet" href="assets/css/aufgaben.css?v=202609090318" />
<link rel="stylesheet" href="assets/css/automation.css?v=202609090318" />
<link rel="stylesheet" href="assets/css/module.css?v=202609090318" />
<link rel="stylesheet" href="assets/css/gate.css?v=202609091211" />
<link rel="stylesheet" href="assets/css/start.css?v=202609091211" />
<link rel="stylesheet" href="assets/css/aufgaben.css?v=202609091211" />
<link rel="stylesheet" href="assets/css/automation.css?v=202609091211" />
<link rel="stylesheet" href="assets/css/module.css?v=202609091211" />
</head>
<body class="start">
@@ -140,10 +140,10 @@
</main>
<script src="assets/js/wahl.js?v=202609090318" defer></script>
<script src="assets/js/bereiche.js?v=202609090318" defer></script>
<script src="assets/js/kopf.js?v=202609090318" defer></script>
<script src="assets/js/glocke.js?v=202609090318" defer></script>
<script src="assets/js/automation.js?v=202609090318" defer></script>
<script src="assets/js/wahl.js?v=202609091211" defer></script>
<script src="assets/js/bereiche.js?v=202609091211" defer></script>
<script src="assets/js/kopf.js?v=202609091211" defer></script>
<script src="assets/js/glocke.js?v=202609091211" defer></script>
<script src="assets/js/automation.js?v=202609091211" defer></script>
</body>
</html>
+14 -14
View File
@@ -14,11 +14,11 @@
<meta name="theme-color" content="#06090f" />
<link rel="icon" type="image/png" href="/assets/img/app-symbole/workspace-32.png" />
<link rel="apple-touch-icon" href="/assets/img/app-symbole/workspace-180.png" />
<link rel="stylesheet" href="assets/css/gate.css?v=202609090318" />
<link rel="stylesheet" href="assets/css/start.css?v=202609090318" />
<link rel="stylesheet" href="assets/css/aufgaben.css?v=202609090318" />
<link rel="stylesheet" href="assets/css/bereich.css?v=202609090318" />
<link rel="stylesheet" href="assets/css/module.css?v=202609090318" />
<link rel="stylesheet" href="assets/css/gate.css?v=202609091211" />
<link rel="stylesheet" href="assets/css/start.css?v=202609091211" />
<link rel="stylesheet" href="assets/css/aufgaben.css?v=202609091211" />
<link rel="stylesheet" href="assets/css/bereich.css?v=202609091211" />
<link rel="stylesheet" href="assets/css/module.css?v=202609091211" />
</head>
<body class="start">
@@ -149,14 +149,14 @@
</main>
<script src="assets/js/wahl.js?v=202609090318" defer></script>
<script src="assets/js/bereiche.js?v=202609090318" defer></script>
<script src="assets/js/kopf.js?v=202609090318" defer></script>
<script src="assets/js/glocke.js?v=202609090318" defer></script>
<script src="assets/js/checkliste.js?v=202609090318" defer></script>
<script src="assets/js/ampel.js?v=202609090318" defer></script>
<script src="assets/js/schulung.js?v=202609090318" defer></script>
<script src="assets/js/vorlagen.js?v=202609090318" defer></script>
<script src="assets/js/bereich.js?v=202609090318" defer></script>
<script src="assets/js/wahl.js?v=202609091211" defer></script>
<script src="assets/js/bereiche.js?v=202609091211" defer></script>
<script src="assets/js/kopf.js?v=202609091211" defer></script>
<script src="assets/js/glocke.js?v=202609091211" defer></script>
<script src="assets/js/checkliste.js?v=202609091211" defer></script>
<script src="assets/js/ampel.js?v=202609091211" defer></script>
<script src="assets/js/schulung.js?v=202609091211" defer></script>
<script src="assets/js/vorlagen.js?v=202609091211" defer></script>
<script src="assets/js/bereich.js?v=202609091211" defer></script>
</body>
</html>
+11 -11
View File
@@ -14,11 +14,11 @@
<meta name="theme-color" content="#06090f" />
<link rel="icon" type="image/png" href="/assets/img/app-symbole/workspace-32.png" />
<link rel="apple-touch-icon" href="/assets/img/app-symbole/workspace-180.png" />
<link rel="stylesheet" href="assets/css/gate.css?v=202609090318" />
<link rel="stylesheet" href="assets/css/start.css?v=202609090318" />
<link rel="stylesheet" href="assets/css/aufgaben.css?v=202609090318" />
<link rel="stylesheet" href="assets/css/calls.css?v=202609090318" />
<link rel="stylesheet" href="assets/css/module.css?v=202609090318" />
<link rel="stylesheet" href="assets/css/gate.css?v=202609091211" />
<link rel="stylesheet" href="assets/css/start.css?v=202609091211" />
<link rel="stylesheet" href="assets/css/aufgaben.css?v=202609091211" />
<link rel="stylesheet" href="assets/css/calls.css?v=202609091211" />
<link rel="stylesheet" href="assets/css/module.css?v=202609091211" />
</head>
<body class="start">
@@ -82,11 +82,11 @@
</main>
<script src="assets/js/ki.js?v=202609090318" defer></script>
<script src="assets/js/wahl.js?v=202609090318" defer></script>
<script src="assets/js/bereiche.js?v=202609090318" defer></script>
<script src="assets/js/kopf.js?v=202609090318" defer></script>
<script src="assets/js/glocke.js?v=202609090318" defer></script>
<script src="assets/js/calls.js?v=202609090318" defer></script>
<script src="assets/js/ki.js?v=202609091211" defer></script>
<script src="assets/js/wahl.js?v=202609091211" defer></script>
<script src="assets/js/bereiche.js?v=202609091211" defer></script>
<script src="assets/js/kopf.js?v=202609091211" defer></script>
<script src="assets/js/glocke.js?v=202609091211" defer></script>
<script src="assets/js/calls.js?v=202609091211" defer></script>
</body>
</html>
+26 -10
View File
@@ -14,17 +14,17 @@
<meta name="theme-color" content="#06090f" />
<link rel="icon" type="image/png" href="/assets/img/app-symbole/workspace-32.png" />
<link rel="apple-touch-icon" href="/assets/img/app-symbole/workspace-180.png" />
<link rel="stylesheet" href="assets/css/gate.css?v=202609090318" />
<link rel="stylesheet" href="assets/css/start.css?v=202609090318" />
<link rel="stylesheet" href="assets/css/gate.css?v=202609091211" />
<link rel="stylesheet" href="assets/css/start.css?v=202609091211" />
<!-- aufgaben.css bringt die Dialog- und Formularstile mit (.dialog,
.neu__zeile, .dialog__knoepfe). Sie stehen dort seit dem
Aufgabenbrett; sie hierher zu kopieren hiesse, sie an zwei Stellen
zu pflegen. Dieselbe Lösung nutzen kalender.html und content.html.
Gemeldet von pruef-css-klassen.mjs, bevor jemand einen ungestylten
Dialog zu sehen bekam. -->
<link rel="stylesheet" href="assets/css/aufgaben.css?v=202609090318" />
<link rel="stylesheet" href="assets/css/chat.css?v=202609090318" />
<link rel="stylesheet" href="assets/css/module.css?v=202609090318" />
<link rel="stylesheet" href="assets/css/aufgaben.css?v=202609091211" />
<link rel="stylesheet" href="assets/css/chat.css?v=202609091211" />
<link rel="stylesheet" href="assets/css/module.css?v=202609091211" />
</head>
<body class="start">
@@ -116,6 +116,11 @@
<!-- aria-live="polite": Ein Vorleseprogramm sagt neue Nachrichten
an, ohne den Nutzer mitten im Satz zu unterbrechen. -->
<!-- ZUM NEUESTEN (09.09.2026). Vorher sprang der Verlauf bei jeder
neuen Nachricht ans Ende -- wer weiter oben nachlas, wurde
mitten im Satz weggerissen. Jetzt bleibt er stehen, und hier
steht, wie viel unten wartet. -->
<button type="button" class="chat__zum-neuesten" id="zum-neuesten" hidden></button>
<div class="chat__verlauf" id="verlauf" role="log" aria-live="polite" aria-relevant="additions">
<p class="chat__leer" id="verlauf-leer">
Links ein Gespräch auswählen – oder mit <strong>Neu</strong> eines anfangen.
@@ -158,6 +163,17 @@
<textarea id="text" rows="1" maxlength="4000"
placeholder="Nachricht schreiben …"
title="Enter schickt ab, Umschalt+Enter macht eine neue Zeile"></textarea>
<!-- EMOJI-AUSWAHL (09.09.2026). Die Bildschirmtastatur am Handy
hat sie ohnehin -- am Rechner nicht, und dort schreibt die
Betreuung. Dreissig feste Zeichen statt einer nachgeladenen
Tafel: Das deckt den Alltag ab und laedt nichts. -->
<button type="button" class="chat__emoji" id="emoji-auf"
aria-expanded="false" aria-controls="emoji-tafel"
aria-label="Emoji einfügen" title="Emoji einfügen">☺</button>
<div class="emoji-tafel" id="emoji-tafel" role="group"
aria-label="Emoji auswählen" hidden></div>
<!-- Erscheint erst, wenn es eng wird -- siehe chat.js. -->
<span class="chat__zeichen" id="zeichen" aria-live="polite" hidden></span>
<button type="submit" class="chat__senden" id="senden" aria-label="Abschicken">
<svg viewBox="0 0 24 24" aria-hidden="true">
<path d="M4 12l16-7-7 16-2.5-6.5z" />
@@ -199,10 +215,10 @@
</form>
</dialog>
<script src="assets/js/bereiche.js?v=202609090318"></script>
<script src="assets/js/wahl.js?v=202609090318" defer></script>
<script src="assets/js/kopf.js?v=202609090318"></script>
<script src="assets/js/glocke.js?v=202609090318"></script>
<script src="assets/js/chat.js?v=202609090318"></script>
<script src="assets/js/bereiche.js?v=202609091211"></script>
<script src="assets/js/wahl.js?v=202609091211" defer></script>
<script src="assets/js/kopf.js?v=202609091211"></script>
<script src="assets/js/glocke.js?v=202609091211"></script>
<script src="assets/js/chat.js?v=202609091211"></script>
</body>
</html>
+12 -12
View File
@@ -14,11 +14,11 @@
<meta name="theme-color" content="#06090f" />
<link rel="icon" type="image/png" href="/assets/img/app-symbole/workspace-32.png" />
<link rel="apple-touch-icon" href="/assets/img/app-symbole/workspace-180.png" />
<link rel="stylesheet" href="assets/css/gate.css?v=202609090318" />
<link rel="stylesheet" href="assets/css/start.css?v=202609090318" />
<link rel="stylesheet" href="assets/css/aufgaben.css?v=202609090318" />
<link rel="stylesheet" href="assets/css/content.css?v=202609090318" />
<link rel="stylesheet" href="assets/css/module.css?v=202609090318" />
<link rel="stylesheet" href="assets/css/gate.css?v=202609091211" />
<link rel="stylesheet" href="assets/css/start.css?v=202609091211" />
<link rel="stylesheet" href="assets/css/aufgaben.css?v=202609091211" />
<link rel="stylesheet" href="assets/css/content.css?v=202609091211" />
<link rel="stylesheet" href="assets/css/module.css?v=202609091211" />
</head>
<body class="start">
@@ -172,12 +172,12 @@
</main>
<script src="assets/js/wahl.js?v=202609090318" defer></script>
<script src="assets/js/bereiche.js?v=202609090318" defer></script>
<script src="assets/js/kopf.js?v=202609090318" defer></script>
<script src="assets/js/glocke.js?v=202609090318" defer></script>
<script src="assets/js/checkliste.js?v=202609090318" defer></script>
<script src="assets/js/vorlagen.js?v=202609090318" defer></script>
<script src="assets/js/content.js?v=202609090318" defer></script>
<script src="assets/js/wahl.js?v=202609091211" defer></script>
<script src="assets/js/bereiche.js?v=202609091211" defer></script>
<script src="assets/js/kopf.js?v=202609091211" defer></script>
<script src="assets/js/glocke.js?v=202609091211" defer></script>
<script src="assets/js/checkliste.js?v=202609091211" defer></script>
<script src="assets/js/vorlagen.js?v=202609091211" defer></script>
<script src="assets/js/content.js?v=202609091211" defer></script>
</body>
</html>
+10 -10
View File
@@ -14,11 +14,11 @@
<meta name="theme-color" content="#06090f" />
<link rel="icon" type="image/png" href="/assets/img/app-symbole/workspace-32.png" />
<link rel="apple-touch-icon" href="/assets/img/app-symbole/workspace-180.png" />
<link rel="stylesheet" href="assets/css/gate.css?v=202609090318" />
<link rel="stylesheet" href="assets/css/start.css?v=202609090318" />
<link rel="stylesheet" href="assets/css/aufgaben.css?v=202609090318" />
<link rel="stylesheet" href="assets/css/dateien.css?v=202609090318" />
<link rel="stylesheet" href="assets/css/module.css?v=202609090318" />
<link rel="stylesheet" href="assets/css/gate.css?v=202609091211" />
<link rel="stylesheet" href="assets/css/start.css?v=202609091211" />
<link rel="stylesheet" href="assets/css/aufgaben.css?v=202609091211" />
<link rel="stylesheet" href="assets/css/dateien.css?v=202609091211" />
<link rel="stylesheet" href="assets/css/module.css?v=202609091211" />
</head>
<body class="start">
@@ -101,10 +101,10 @@
</main>
<script src="assets/js/wahl.js?v=202609090318" defer></script>
<script src="assets/js/bereiche.js?v=202609090318" defer></script>
<script src="assets/js/kopf.js?v=202609090318" defer></script>
<script src="assets/js/glocke.js?v=202609090318" defer></script>
<script src="assets/js/dateien.js?v=202609090318" defer></script>
<script src="assets/js/wahl.js?v=202609091211" defer></script>
<script src="assets/js/bereiche.js?v=202609091211" defer></script>
<script src="assets/js/kopf.js?v=202609091211" defer></script>
<script src="assets/js/glocke.js?v=202609091211" defer></script>
<script src="assets/js/dateien.js?v=202609091211" defer></script>
</body>
</html>
+2 -2
View File
@@ -32,7 +32,7 @@
<link rel="icon" type="image/png" href="/assets/img/app-symbole/workspace-32.png" />
<link rel="apple-touch-icon" href="/assets/img/app-symbole/workspace-180.png" />
<link rel="stylesheet" href="assets/css/gate.css?v=202609090318" />
<link rel="stylesheet" href="assets/css/gate.css?v=202609091211" />
</head>
<body class="gate">
@@ -401,6 +401,6 @@
</main>
</div>
<script src="assets/js/gate.js?v=202609090318" defer></script>
<script src="assets/js/gate.js?v=202609091211" defer></script>
</body>
</html>
+11 -11
View File
@@ -14,11 +14,11 @@
<meta name="theme-color" content="#06090f" />
<link rel="icon" type="image/png" href="/assets/img/app-symbole/workspace-32.png" />
<link rel="apple-touch-icon" href="/assets/img/app-symbole/workspace-180.png" />
<link rel="stylesheet" href="assets/css/gate.css?v=202609090318" />
<link rel="stylesheet" href="assets/css/start.css?v=202609090318" />
<link rel="stylesheet" href="assets/css/aufgaben.css?v=202609090318" />
<link rel="stylesheet" href="assets/css/kalender.css?v=202609090318" />
<link rel="stylesheet" href="assets/css/module.css?v=202609090318" />
<link rel="stylesheet" href="assets/css/gate.css?v=202609091211" />
<link rel="stylesheet" href="assets/css/start.css?v=202609091211" />
<link rel="stylesheet" href="assets/css/aufgaben.css?v=202609091211" />
<link rel="stylesheet" href="assets/css/kalender.css?v=202609091211" />
<link rel="stylesheet" href="assets/css/module.css?v=202609091211" />
</head>
<body class="start">
@@ -340,11 +340,11 @@
</main>
<script src="assets/js/wahl.js?v=202609090318" defer></script>
<script src="assets/js/bereiche.js?v=202609090318" defer></script>
<script src="assets/js/kopf.js?v=202609090318" defer></script>
<script src="assets/js/glocke.js?v=202609090318" defer></script>
<script src="assets/js/kalender.js?v=202609090318" defer></script>
<script src="assets/js/kalender-abo.js?v=202609090318" defer></script>
<script src="assets/js/wahl.js?v=202609091211" defer></script>
<script src="assets/js/bereiche.js?v=202609091211" defer></script>
<script src="assets/js/kopf.js?v=202609091211" defer></script>
<script src="assets/js/glocke.js?v=202609091211" defer></script>
<script src="assets/js/kalender.js?v=202609091211" defer></script>
<script src="assets/js/kalender-abo.js?v=202609091211" defer></script>
</body>
</html>
+10 -10
View File
@@ -14,11 +14,11 @@
<meta name="theme-color" content="#06090f" />
<link rel="icon" type="image/png" href="/assets/img/app-symbole/workspace-32.png" />
<link rel="apple-touch-icon" href="/assets/img/app-symbole/workspace-180.png" />
<link rel="stylesheet" href="assets/css/gate.css?v=202609090318" />
<link rel="stylesheet" href="assets/css/start.css?v=202609090318" />
<link rel="stylesheet" href="assets/css/aufgaben.css?v=202609090318" />
<link rel="stylesheet" href="assets/css/leistung.css?v=202609090318" />
<link rel="stylesheet" href="assets/css/module.css?v=202609090318" />
<link rel="stylesheet" href="assets/css/gate.css?v=202609091211" />
<link rel="stylesheet" href="assets/css/start.css?v=202609091211" />
<link rel="stylesheet" href="assets/css/aufgaben.css?v=202609091211" />
<link rel="stylesheet" href="assets/css/leistung.css?v=202609091211" />
<link rel="stylesheet" href="assets/css/module.css?v=202609091211" />
</head>
<body class="start">
@@ -217,10 +217,10 @@
</form>
</dialog>
<script src="assets/js/wahl.js?v=202609090318"></script>
<script src="assets/js/bereiche.js?v=202609090318"></script>
<script src="assets/js/kopf.js?v=202609090318"></script>
<script src="assets/js/glocke.js?v=202609090318"></script>
<script src="assets/js/leistung.js?v=202609090318"></script>
<script src="assets/js/wahl.js?v=202609091211"></script>
<script src="assets/js/bereiche.js?v=202609091211"></script>
<script src="assets/js/kopf.js?v=202609091211"></script>
<script src="assets/js/glocke.js?v=202609091211"></script>
<script src="assets/js/leistung.js?v=202609091211"></script>
</body>
</html>
+10 -10
View File
@@ -14,11 +14,11 @@
<meta name="theme-color" content="#06090f" />
<link rel="icon" type="image/png" href="/assets/img/app-symbole/workspace-32.png" />
<link rel="apple-touch-icon" href="/assets/img/app-symbole/workspace-180.png" />
<link rel="stylesheet" href="assets/css/gate.css?v=202609090318" />
<link rel="stylesheet" href="assets/css/start.css?v=202609090318" />
<link rel="stylesheet" href="assets/css/aufgaben.css?v=202609090318" />
<link rel="stylesheet" href="assets/css/personen.css?v=202609090318" />
<link rel="stylesheet" href="assets/css/module.css?v=202609090318" />
<link rel="stylesheet" href="assets/css/gate.css?v=202609091211" />
<link rel="stylesheet" href="assets/css/start.css?v=202609091211" />
<link rel="stylesheet" href="assets/css/aufgaben.css?v=202609091211" />
<link rel="stylesheet" href="assets/css/personen.css?v=202609091211" />
<link rel="stylesheet" href="assets/css/module.css?v=202609091211" />
</head>
<body class="start">
@@ -335,10 +335,10 @@
</main>
<script src="assets/js/wahl.js?v=202609090318" defer></script>
<script src="assets/js/bereiche.js?v=202609090318" defer></script>
<script src="assets/js/kopf.js?v=202609090318" defer></script>
<script src="assets/js/glocke.js?v=202609090318" defer></script>
<script src="assets/js/personen.js?v=202609090318" defer></script>
<script src="assets/js/wahl.js?v=202609091211" defer></script>
<script src="assets/js/bereiche.js?v=202609091211" defer></script>
<script src="assets/js/kopf.js?v=202609091211" defer></script>
<script src="assets/js/glocke.js?v=202609091211" defer></script>
<script src="assets/js/personen.js?v=202609091211" defer></script>
</body>
</html>
+11 -11
View File
@@ -14,11 +14,11 @@
<meta name="theme-color" content="#06090f" />
<link rel="icon" type="image/png" href="/assets/img/app-symbole/workspace-32.png" />
<link rel="apple-touch-icon" href="/assets/img/app-symbole/workspace-180.png" />
<link rel="stylesheet" href="assets/css/gate.css?v=202609090318" />
<link rel="stylesheet" href="assets/css/start.css?v=202609090318" />
<link rel="stylesheet" href="assets/css/aufgaben.css?v=202609090318" />
<link rel="stylesheet" href="assets/css/profil.css?v=202609090318" />
<link rel="stylesheet" href="assets/css/module.css?v=202609090318" />
<link rel="stylesheet" href="assets/css/gate.css?v=202609091211" />
<link rel="stylesheet" href="assets/css/start.css?v=202609091211" />
<link rel="stylesheet" href="assets/css/aufgaben.css?v=202609091211" />
<link rel="stylesheet" href="assets/css/profil.css?v=202609091211" />
<link rel="stylesheet" href="assets/css/module.css?v=202609091211" />
</head>
<body class="start">
@@ -207,11 +207,11 @@
</main>
<script src="assets/js/wahl.js?v=202609090318" defer></script>
<script src="assets/js/bereiche.js?v=202609090318" defer></script>
<script src="assets/js/kopf.js?v=202609090318" defer></script>
<script src="assets/js/glocke.js?v=202609090318" defer></script>
<script src="assets/js/steckbrief.js?v=202609090318" defer></script>
<script src="assets/js/profil.js?v=202609090318" defer></script>
<script src="assets/js/wahl.js?v=202609091211" defer></script>
<script src="assets/js/bereiche.js?v=202609091211" defer></script>
<script src="assets/js/kopf.js?v=202609091211" defer></script>
<script src="assets/js/glocke.js?v=202609091211" defer></script>
<script src="assets/js/steckbrief.js?v=202609091211" defer></script>
<script src="assets/js/profil.js?v=202609091211" defer></script>
</body>
</html>
+11 -11
View File
@@ -14,11 +14,11 @@
<meta name="theme-color" content="#06090f" />
<link rel="icon" type="image/png" href="/assets/img/app-symbole/workspace-32.png" />
<link rel="apple-touch-icon" href="/assets/img/app-symbole/workspace-180.png" />
<link rel="stylesheet" href="assets/css/gate.css?v=202609090318" />
<link rel="stylesheet" href="assets/css/start.css?v=202609090318" />
<link rel="stylesheet" href="assets/css/aufgaben.css?v=202609090318" />
<link rel="stylesheet" href="assets/css/report.css?v=202609090318" />
<link rel="stylesheet" href="assets/css/module.css?v=202609090318" />
<link rel="stylesheet" href="assets/css/gate.css?v=202609091211" />
<link rel="stylesheet" href="assets/css/start.css?v=202609091211" />
<link rel="stylesheet" href="assets/css/aufgaben.css?v=202609091211" />
<link rel="stylesheet" href="assets/css/report.css?v=202609091211" />
<link rel="stylesheet" href="assets/css/module.css?v=202609091211" />
</head>
<body class="start">
@@ -99,11 +99,11 @@
</main>
<script src="assets/js/ki.js?v=202609090318" defer></script>
<script src="assets/js/wahl.js?v=202609090318" defer></script>
<script src="assets/js/bereiche.js?v=202609090318" defer></script>
<script src="assets/js/kopf.js?v=202609090318" defer></script>
<script src="assets/js/glocke.js?v=202609090318" defer></script>
<script src="assets/js/report.js?v=202609090318" defer></script>
<script src="assets/js/ki.js?v=202609091211" defer></script>
<script src="assets/js/wahl.js?v=202609091211" defer></script>
<script src="assets/js/bereiche.js?v=202609091211" defer></script>
<script src="assets/js/kopf.js?v=202609091211" defer></script>
<script src="assets/js/glocke.js?v=202609091211" defer></script>
<script src="assets/js/report.js?v=202609091211" defer></script>
</body>
</html>
+10 -10
View File
@@ -14,11 +14,11 @@
<meta name="theme-color" content="#06090f" />
<link rel="icon" type="image/png" href="/assets/img/app-symbole/workspace-32.png" />
<link rel="apple-touch-icon" href="/assets/img/app-symbole/workspace-180.png" />
<link rel="stylesheet" href="assets/css/gate.css?v=202609090318" />
<link rel="stylesheet" href="assets/css/start.css?v=202609090318" />
<link rel="stylesheet" href="assets/css/aufgaben.css?v=202609090318" />
<link rel="stylesheet" href="assets/css/scouting.css?v=202609090318" />
<link rel="stylesheet" href="assets/css/module.css?v=202609090318" />
<link rel="stylesheet" href="assets/css/gate.css?v=202609091211" />
<link rel="stylesheet" href="assets/css/start.css?v=202609091211" />
<link rel="stylesheet" href="assets/css/aufgaben.css?v=202609091211" />
<link rel="stylesheet" href="assets/css/scouting.css?v=202609091211" />
<link rel="stylesheet" href="assets/css/module.css?v=202609091211" />
</head>
<body class="start">
@@ -132,10 +132,10 @@
</div>
</div>
<script src="assets/js/wahl.js?v=202609090318" defer></script>
<script src="assets/js/bereiche.js?v=202609090318" defer></script>
<script src="assets/js/kopf.js?v=202609090318" defer></script>
<script src="assets/js/glocke.js?v=202609090318" defer></script>
<script src="assets/js/scouting.js?v=202609090318" defer></script>
<script src="assets/js/wahl.js?v=202609091211" defer></script>
<script src="assets/js/bereiche.js?v=202609091211" defer></script>
<script src="assets/js/kopf.js?v=202609091211" defer></script>
<script src="assets/js/glocke.js?v=202609091211" defer></script>
<script src="assets/js/scouting.js?v=202609091211" defer></script>
</body>
</html>
+9 -9
View File
@@ -14,12 +14,12 @@
<meta name="theme-color" content="#06090f" />
<link rel="icon" type="image/png" href="/assets/img/app-symbole/workspace-32.png" />
<link rel="apple-touch-icon" href="/assets/img/app-symbole/workspace-180.png" />
<link rel="stylesheet" href="assets/css/gate.css?v=202609090318" />
<link rel="stylesheet" href="assets/css/start.css?v=202609090318" />
<link rel="stylesheet" href="assets/css/gate.css?v=202609091211" />
<link rel="stylesheet" href="assets/css/start.css?v=202609091211" />
<!-- Nur die Startseite: Begrüßungskachel, Uhr, Glockenmulde. Siehe
den Hinweis in start.css -- dort stand es bis zum 07.09.2026. -->
<link rel="stylesheet" href="assets/css/heim.css?v=202609090318" />
<link rel="stylesheet" href="assets/css/module.css?v=202609090318" />
<link rel="stylesheet" href="assets/css/heim.css?v=202609091211" />
<link rel="stylesheet" href="assets/css/module.css?v=202609091211" />
</head>
<body class="start">
@@ -667,10 +667,10 @@
</p>
</main>
<script src="assets/js/wahl.js?v=202609090318" defer></script>
<script src="assets/js/bereiche.js?v=202609090318" defer></script>
<script src="assets/js/kopf.js?v=202609090318" defer></script>
<script src="assets/js/glocke.js?v=202609090318" defer></script>
<script src="assets/js/start.js?v=202609090318" defer></script>
<script src="assets/js/wahl.js?v=202609091211" defer></script>
<script src="assets/js/bereiche.js?v=202609091211" defer></script>
<script src="assets/js/kopf.js?v=202609091211" defer></script>
<script src="assets/js/glocke.js?v=202609091211" defer></script>
<script src="assets/js/start.js?v=202609091211" defer></script>
</body>
</html>
+11 -11
View File
@@ -14,11 +14,11 @@
<meta name="theme-color" content="#06090f" />
<link rel="icon" type="image/png" href="/assets/img/app-symbole/workspace-32.png" />
<link rel="apple-touch-icon" href="/assets/img/app-symbole/workspace-180.png" />
<link rel="stylesheet" href="assets/css/gate.css?v=202609090318" />
<link rel="stylesheet" href="assets/css/start.css?v=202609090318" />
<link rel="stylesheet" href="assets/css/aufgaben.css?v=202609090318" />
<link rel="stylesheet" href="assets/css/startcheck.css?v=202609090318" />
<link rel="stylesheet" href="assets/css/module.css?v=202609090318" />
<link rel="stylesheet" href="assets/css/gate.css?v=202609091211" />
<link rel="stylesheet" href="assets/css/start.css?v=202609091211" />
<link rel="stylesheet" href="assets/css/aufgaben.css?v=202609091211" />
<link rel="stylesheet" href="assets/css/startcheck.css?v=202609091211" />
<link rel="stylesheet" href="assets/css/module.css?v=202609091211" />
</head>
<body class="start">
@@ -78,11 +78,11 @@
</main>
<script src="assets/js/ki.js?v=202609090318" defer></script>
<script src="assets/js/wahl.js?v=202609090318" defer></script>
<script src="assets/js/bereiche.js?v=202609090318" defer></script>
<script src="assets/js/kopf.js?v=202609090318" defer></script>
<script src="assets/js/glocke.js?v=202609090318" defer></script>
<script src="assets/js/startcheck.js?v=202609090318" defer></script>
<script src="assets/js/ki.js?v=202609091211" defer></script>
<script src="assets/js/wahl.js?v=202609091211" defer></script>
<script src="assets/js/bereiche.js?v=202609091211" defer></script>
<script src="assets/js/kopf.js?v=202609091211" defer></script>
<script src="assets/js/glocke.js?v=202609091211" defer></script>
<script src="assets/js/startcheck.js?v=202609091211" defer></script>
</body>
</html>
+10 -10
View File
@@ -14,11 +14,11 @@
<meta name="theme-color" content="#06090f" />
<link rel="icon" type="image/png" href="/assets/img/app-symbole/workspace-32.png" />
<link rel="apple-touch-icon" href="/assets/img/app-symbole/workspace-180.png" />
<link rel="stylesheet" href="assets/css/gate.css?v=202609090318" />
<link rel="stylesheet" href="assets/css/start.css?v=202609090318" />
<link rel="stylesheet" href="assets/css/aufgaben.css?v=202609090318" />
<link rel="stylesheet" href="assets/css/profil.css?v=202609090318" />
<link rel="stylesheet" href="assets/css/module.css?v=202609090318" />
<link rel="stylesheet" href="assets/css/gate.css?v=202609091211" />
<link rel="stylesheet" href="assets/css/start.css?v=202609091211" />
<link rel="stylesheet" href="assets/css/aufgaben.css?v=202609091211" />
<link rel="stylesheet" href="assets/css/profil.css?v=202609091211" />
<link rel="stylesheet" href="assets/css/module.css?v=202609091211" />
</head>
<body class="start">
@@ -119,10 +119,10 @@
</main>
<script src="assets/js/wahl.js?v=202609090318" defer></script>
<script src="assets/js/bereiche.js?v=202609090318" defer></script>
<script src="assets/js/kopf.js?v=202609090318" defer></script>
<script src="assets/js/glocke.js?v=202609090318" defer></script>
<script src="assets/js/steckbrief.js?v=202609090318" defer></script>
<script src="assets/js/wahl.js?v=202609091211" defer></script>
<script src="assets/js/bereiche.js?v=202609091211" defer></script>
<script src="assets/js/kopf.js?v=202609091211" defer></script>
<script src="assets/js/glocke.js?v=202609091211" defer></script>
<script src="assets/js/steckbrief.js?v=202609091211" defer></script>
</body>
</html>
+10 -10
View File
@@ -14,13 +14,13 @@
<meta name="theme-color" content="#06090f" />
<link rel="icon" type="image/png" href="/assets/img/app-symbole/workspace-32.png" />
<link rel="apple-touch-icon" href="/assets/img/app-symbole/workspace-180.png" />
<link rel="stylesheet" href="assets/css/gate.css?v=202609090318" />
<link rel="stylesheet" href="assets/css/start.css?v=202609090318" />
<link rel="stylesheet" href="assets/css/gate.css?v=202609091211" />
<link rel="stylesheet" href="assets/css/start.css?v=202609091211" />
<!-- Formular- und Dialogstile: seit dem 07.09.2026 steht hier der
Dialog "Creator anlegen". -->
<link rel="stylesheet" href="assets/css/aufgaben.css?v=202609090318" />
<link rel="stylesheet" href="assets/css/uebersicht.css?v=202609090318" />
<link rel="stylesheet" href="assets/css/module.css?v=202609090318" />
<link rel="stylesheet" href="assets/css/aufgaben.css?v=202609091211" />
<link rel="stylesheet" href="assets/css/uebersicht.css?v=202609091211" />
<link rel="stylesheet" href="assets/css/module.css?v=202609091211" />
</head>
<body class="start">
@@ -142,11 +142,11 @@
</main>
<script src="assets/js/bereiche.js?v=202609090318" defer></script>
<script src="assets/js/bereiche.js?v=202609091211" defer></script>
<script src="assets/js/wahl.js?v=202609090318" defer></script>
<script src="assets/js/kopf.js?v=202609090318" defer></script>
<script src="assets/js/glocke.js?v=202609090318" defer></script>
<script src="assets/js/uebersicht.js?v=202609090318" defer></script>
<script src="assets/js/wahl.js?v=202609091211" defer></script>
<script src="assets/js/kopf.js?v=202609091211" defer></script>
<script src="assets/js/glocke.js?v=202609091211" defer></script>
<script src="assets/js/uebersicht.js?v=202609091211" defer></script>
</body>
</html>
+10 -10
View File
@@ -14,11 +14,11 @@
<meta name="theme-color" content="#06090f" />
<link rel="icon" type="image/png" href="/assets/img/app-symbole/workspace-32.png" />
<link rel="apple-touch-icon" href="/assets/img/app-symbole/workspace-180.png" />
<link rel="stylesheet" href="assets/css/gate.css?v=202609090318" />
<link rel="stylesheet" href="assets/css/start.css?v=202609090318" />
<link rel="stylesheet" href="assets/css/aufgaben.css?v=202609090318" />
<link rel="stylesheet" href="assets/css/wissen.css?v=202609090318" />
<link rel="stylesheet" href="assets/css/module.css?v=202609090318" />
<link rel="stylesheet" href="assets/css/gate.css?v=202609091211" />
<link rel="stylesheet" href="assets/css/start.css?v=202609091211" />
<link rel="stylesheet" href="assets/css/aufgaben.css?v=202609091211" />
<link rel="stylesheet" href="assets/css/wissen.css?v=202609091211" />
<link rel="stylesheet" href="assets/css/module.css?v=202609091211" />
</head>
<body class="start">
@@ -183,10 +183,10 @@
</main>
<script src="assets/js/wahl.js?v=202609090318" defer></script>
<script src="assets/js/bereiche.js?v=202609090318" defer></script>
<script src="assets/js/kopf.js?v=202609090318" defer></script>
<script src="assets/js/glocke.js?v=202609090318" defer></script>
<script src="assets/js/wissen.js?v=202609090318" defer></script>
<script src="assets/js/wahl.js?v=202609091211" defer></script>
<script src="assets/js/bereiche.js?v=202609091211" defer></script>
<script src="assets/js/kopf.js?v=202609091211" defer></script>
<script src="assets/js/glocke.js?v=202609091211" defer></script>
<script src="assets/js/wissen.js?v=202609091211" defer></script>
</body>
</html>