Fett, kursiv, unterstrichen, durchgestrichen -- ueberall

Filipe, 21.09.2026: "dan will ich dass die leute auch immer die art
von text aussuchen können, fettgedrückt, unterstrichen und so alles.
das überall sei es im chat jeder für sich oder sei es wenn die modis
oder rechte hand oder dogfather eine aufgabe oder sachen posten."

VORHER GEMESSEN: Es gab genau EINE Auszeichnung im ganzen Haus --
fett, und nur auf den Brettern (`mitFett` in bereich.js). Im Chat
konnte niemand etwas hervorheben.

EINE QUELLE FUER DAS GANZE HAUS: workspace/assets/js/textform.js.
Chat, Bretter und Aufgaben zeichnen ihren Text jetzt durch denselben
Zerleger. Drei Fassungen derselben Regel waeren drei Fassungen, die
verschieden altern.

  **fett**   _kursiv_   __unterstrichen__   ~~durchgestrichen~~

Dazu eine Leiste ueber jedem Schreibfeld: F K U S, 44 px am Finger,
Strg+B/I/U, und ein zweiter Druck nimmt die Zeichen wieder weg.

DIE WORTGRENZEN SIND DER EIGENTLICHE BAU. Ein Zerleger, der alles
auszeichnet, ist schlimmer als keiner: `datei_name_hier` hiesse
plotzlich anders, als es heisst, und `@max_muster` ebenso. Deshalb
stehen bei den Unterstrichen Wortgrenzen -- bei Sternchen und Tilden
nicht, die kommen in Text nicht versehentlich paarweise vor.

GEBAUT MIT createTextNode, NIE innerHTML. Wer Text zu Auszeichnung
macht, ist einen Tippfehler von einer Luecke entfernt. Das ist heute
sicher; pruef-textform misst es, damit es das morgen auch ist.

EIN ECHTER FEHLER DABEI GEFUNDEN -- in meinem eigenen Einbau von
vorhin: Auf dem Aufgabenbrett stand `$('f-text')` in einem Block, der
`$` gar nicht kennt (die Datei hat drei getrennte Bloecke).
`ReferenceError: $ is not defined`, die Leiste kam dort nie an, und
die Seite sah dabei vollkommen normal aus. Derselbe Block beginnt
ausserdem mit `if (!feld) return;` auf ein Aufwand-Feld, das mit
Textgestaltung nichts zu tun hat -- die Leiste haette an einer
voellig fremden Bedingung gehangen. Jetzt ein eigener Block, ohne
fremden Helfer und ohne fremde Bedingung.

Gefunden hat es die Pruefung, weil sie die Leiste AM FELD sucht,
statt den Aufruf im Quelltext zu zaehlen. Sie sammelt seitdem auch
Skriptfehler ein -- ein ReferenceError ist immer ein Befund, auch
wenn man noch nicht weiss, was er anrichtet.

pruef-textform.mjs, 50 Aussagen:
  - welche Seite das Modul braucht, wird ABGELEITET (beide
    Richtungen: keine ohne, keine umsonst) -- 3 brauchen, 32 nicht
  - 13 Regelfaelle im echten Browser an der echten Datei, davon
    sechs, die NICHT gestaltet werden duerfen
  - eine echte Nachricht wird zu <strong>/<em>/<u>/<s>
  - Sicherheitsprobe: <b> und <img onerror> bleiben Text, nichts
    wird ausgefuehrt -- und die echte Auszeichnung daneben wirkt
    trotzdem (sonst waere nur bewiesen, dass gar nichts passiert)
  - die Leiste legt Zeichen wirklich um und wieder ab
  - Gegenproben fuer beide Richtungen

Nachbarn unveraendert gruen: pruef-chat-optik 45/0 (war 39 -- die
Antwortleiste kam dazu), pruef-aufgabenbrett 49/0, pruef-nachfrage
49/0, pruef-css-klassen 30/0, pruef-tippziele 11/0, pruef-meldungen
8/0.
This commit is contained in:
2026-09-21 16:42:43 +02:00
parent 7305f694d5
commit bfbe6feafe
44 changed files with 1503 additions and 528 deletions
+58 -8
View File
@@ -737,6 +737,14 @@
Runden; siehe die Route dazu im Server. */
$('kanal-leute').hidden = !(darfKanal && offen.art === 'kanal');
$('schreiben').hidden = false;
/* DIE LEISTE FUER DIE TEXTGESTALTUNG (21.09.2026).
Hier und nicht beim Laden der Seite: Das Formular ist bis zum
Oeffnen eines Raumes versteckt, und eine Leiste ueber einem
versteckten Feld baut man zweimal, wenn man nicht aufpasst.
`Textform.leiste` merkt sich am Feld selbst, dass sie schon
da ist -- zweimal aufrufen schadet also nichts. */
if (window.Textform) window.Textform.leiste($('text'));
/* JEDES MAL BEIM OEFFNEN. Der Stand haengt am RAUM (nur der Treff
hat eine Nachtruhe) -- wer aus einem Teamraum in den Treff
wechselt, muss das Band sehen, ohne die Seite neu zu laden. */
@@ -1237,7 +1245,8 @@
z.type = 'button';
z.append(el('span', 'chat-zitat__von', n.antwort.von));
z.append(el('span', 'chat-zitat__text', n.antwort.zurueckgenommen
? 'Nachricht zurückgenommen' : n.antwort.text));
? 'Nachricht zurückgenommen'
: (window.Textform ? window.Textform.nurText(n.antwort.text) : n.antwort.text)));
z.title = 'Zur zitierten Nachricht springen';
/* Ein Zitat, das nicht zur Stelle fuehrt, ist ein Bild von
einer Nachricht. Der Klick springt hin und hebt sie kurz
@@ -1758,9 +1767,45 @@
Grund, warum hier Knoten gebaut und nicht Zeichenketten
zusammengeklebt werden. Eine Nachricht darf keine Auszeichnung
einschleusen, auch keinen eigenen Namen in spitzen Klammern. */
/* DIE GESTALTUNG LIEGT AUSSEN, LINKS UND ERWAEHNUNGEN INNEN
(21.09.2026).
Filipe: "ich will dass die leute auch immer die art von text
aussuchen können, fettgedrückt, unterstrichen und so alles ...
das überall sei es im chat jeder für sich."
WARUM NICHT EINFACH EINE FUENFTE SORTE STELLE: Links und
Erwaehnungen sind PUNKTE im Text -- sie haben Anfang und Ende und
liegen nebeneinander. Gestaltung ist etwas anderes: Sie UMSCHLIESST
etwas, und sie kann sich verschachteln ("**fett und _auch
kursiv_**"). Beides in dieselbe Liste zu werfen haette bei jeder
Ueberlappung geraten.
Deshalb zwei Schichten: Erst wird der Text in Stuecke mit Stilen
zerlegt, dann bekommt JEDES Stueck die vorhandene Suche nach
Links und Erwaehnungen -- und zum Schluss legt sich die Gestaltung
aussen herum. Ein Link in einem fetten Satz bleibt damit ein Link.
Ohne textform.js (aeltere Fassung im Zwischenspeicher) faellt es
auf den alten Zustand zurueck: ein Stueck, keine Stile. Dann sieht
man Sternchen statt Fettschrift -- aber nichts ist kaputt. */
function textAbsatz(text) {
const p = el('p', 'chat-nachricht__text');
const roh = String(text);
const teilchen = window.Textform
? window.Textform.teile(text)
: [{ text: String(text), stile: {} }];
for (const t of teilchen) {
const innen = stellenBauen(t.text);
p.append(window.Textform ? window.Textform.huelle(innen, t.stile) : innen);
}
return p;
}
/** Die vorhandene Suche nach Links und Erwaehnungen -- unveraendert,
* nur arbeitet sie jetzt auf einem STUECK statt auf dem ganzen Text
* und gibt einen Baustein zurueck statt einen Absatz. */
function stellenBauen(roh) {
const stueck = document.createDocumentFragment();
const stellen = [];
for (const treffer of roh.matchAll(LINKMUSTER)) {
@@ -1781,13 +1826,13 @@
let letzte = 0;
for (const st of stellen) {
if (st.von < letzte) continue; // liegt in einer frueheren Stelle
if (st.von > letzte) p.append(document.createTextNode(roh.slice(letzte, st.von)));
if (st.von > letzte) stueck.append(document.createTextNode(roh.slice(letzte, st.von)));
if (st.art === 'link') {
const a = el('a', 'chat-nachricht__link', st.wort);
a.href = st.wort.startsWith('www.') ? 'https://' + st.wort : st.wort;
a.target = '_blank';
a.rel = 'noopener noreferrer';
p.append(a);
stueck.append(a);
} else {
/* KEIN KNOPF, SONDERN EINE MARKE. Ein Klick darauf muesste
irgendwohin fuehren -- zum Steckbrief? in ein Zweiergespraech?
@@ -1800,12 +1845,12 @@
Zweck: In einem Raum mit acht Leuten soll der eigene Name
aus dem Absatz herausspringen. */
if (ich && st.id === ich.id) m.dataset.ich = 'ja';
p.append(m);
stueck.append(m);
}
letzte = st.bis;
}
if (letzte < roh.length) p.append(document.createTextNode(roh.slice(letzte)));
return p;
if (letzte < roh.length) stueck.append(document.createTextNode(roh.slice(letzte)));
return stueck;
}
/* ---------- Antworten und Springen (09.09.2026, Punkt 15) ---------------- */
@@ -1816,7 +1861,12 @@
if (!leiste) return;
leiste.hidden = false;
$('antwort-von').textContent = n.von;
$('antwort-text').textContent = n.text;
/* IN DER VORSCHAU STEHEN KEINE ZEICHEN (21.09.2026). Hier ist
keine Gestaltung moeglich -- eine Zeile, in der "**super**"
steht, sieht nach kaputt aus. `nurText` nimmt die Zeichen weg
und laesst den Satz stehen. */
$('antwort-text').textContent = window.Textform
? window.Textform.nurText(n.text) : n.text;
$('text').focus();
}