Das Suchfeld nimmt wieder Eingaben, eigene Kanalnamen, Community in Kanälen
screen1, drei Teile. === 1. „bei suchen kann man nichts reinschreiben" === MEIN FEHLER VOM SELBEN TAG. Beim Popover-Umbau heute frueh hing die Liste am <body>, damit sie nicht hinter dem modalen Dialog verschwindet. Gemessen: Das Suchfeld war da, der Fokus landete nicht darin, ein getipptes Zeichen kam nicht an. DER GRUND IST DER FOKUS-KAEFIG. Ein Dialog aus showModal() sperrt den Fokus auf seinen eigenen DOM-Baum ein. Die Liste lag im Top Layer -- sichtbar und anklickbar, aber ausserhalb des Kaefigs. Klicken braucht keinen Fokus, Tippen schon. Deshalb fiel es niemandem auf: Die Liste stand da, sie filterte auf Knopfdruck, nur eine Eingabe kam nicht an. DIE LOESUNG WAR EINE KOMBINATION, die ich vorher fuer unmoeglich hielt. Im Dialog wurde die Liste vom clip-path der abgeschraegten Ecke abgeschnitten, draussen war sie nicht bedienbar. Ein POPOVER wird aber in die Top Layer gehoben und dort gezeichnet -- der Beschnitt des Elternteils erreicht es nicht mehr, waehrend der DOM-Baum (und damit der Fokus) der des Dialogs bleibt. Jetzt haengt sie wieder im Dialog UND ist ein Popover: bedienbar und unbeschnitten. Gemessen beides gegeneinander: „comm" getippt -> kommt an, filtert auf 1 Treffer; und die LETZTE Zeile der vollen Liste ist wirklich anklickbar (elementFromPoint trifft sie selbst, nicht den Dialog). Daraus ist pruef-suchfeld geworden -- der Fehler war von aussen nicht zu sehen, und gefunden hat ihn Filipe, nicht ich. === 2. „einen neuen namen erstellen den es noch nicht gibt" === `data-frei="ja"` war in wahl.js seit langem gebaut und wurde NIE GESETZT -- dieselbe Sorte Lueue wie `grund_min` heute Morgen. Jetzt gesetzt; der getippte Text erscheint als eigener Eintrag ganz oben. Der Server nahm bisher nur die neun festen Zustaendigkeiten. Jetzt auch einen eigenen Namen: Der SCHLUESSEL wird daraus abgeleitet („Technik & Ton" -> "eigen-technik-ton"), der ANGEZEIGTE Name bleibt wie geschrieben. Das Praefix ist kein Schmuck -- ohne es entstuende aus dem Namen „Community" derselbe Schluessel wie beim festen Thema, und der eindeutige Index lehnte ihn ab, obwohl der Kanal nicht existiert. Gemessen: genau dieser Fall antwortet jetzt mit 201. Der alte Kommentar sprach sich gegen freie Namen aus („der sichere Weg zu Clipping neben Clipping-Team"). Das Risiko bleibt und wird begrenzt: Derselbe Name zweimal ergibt denselben Schluessel und damit 409. === 3. „kanäle mit den leuten mit der community rolle" === Seit dem 19.09. nimmt `ohneAussen()` die Community aus den Listen aller anderen. Die Begruendung dort ist ausdruecklich: „Ein Zweier-Gespraech ist kein Kanal. Es hat keine Nachtruhe, kein Modi liest mit, und niemand koennte moderieren." Genau diese Begruendung laesst den Kanal offen. Die Sperre bleibt fuer GESPRAECHE und faellt fuer KANAELE -- `?fuer=kanal` an der Partnerliste, und nur fuer den, der Kanaele ueberhaupt aufmachen darf. Sonst waere der Parameter ein Weg, an `ohneAussen` vorbei Namen zu erfahren. Gemessen: DogFather sieht im Gespraech VanVan und Miss, im Kanal zusaetzlich Kessi und Tom (beide Community). Ein Modi bekommt die erweiterte Liste auch mit dem Parameter nicht. Gruen: pruef-suchfeld (8, neu), pruef-chat-kanaele (81), pruef-treffchat, pruef-chat-neu, pruef-freie-namen (32), pruef-nachfrage (53), pruef-css-klassen. Co-Authored-By: Claude Opus 5 <[email protected]>
This commit is contained in:
@@ -764,7 +764,11 @@ function kanalName(kategorie) {
|
||||
Teams, sondern ein eigener Raum mit eigenen Regeln. Ohne diese
|
||||
Zeile hiesse er schlicht "Kanal". */
|
||||
if (kategorie === TREFF_KATEGORIE) return TREFF_NAME;
|
||||
return MODI_KATEGORIEN.find((k) => k.wert === kategorie)?.name || "Kanal";
|
||||
/* EIN EIGENER KANAL TRAEGT SEINEN NAMEN IN DER ZEILE (24.09.2026).
|
||||
MODI_KATEGORIEN kennt ihn nicht -- fuer ihn steht der Name in
|
||||
der Spalte "name" des Raums. Ohne diesen Weg hiesse jeder eigene
|
||||
Kanal schlicht „Kanal". */
|
||||
return MODI_KATEGORIEN.find((k) => k.wert === kategorie)?.name || null;
|
||||
}
|
||||
|
||||
/** Wer darf hier etwas anheften?
|
||||
@@ -918,7 +922,11 @@ function gehoertInKanal(id) {
|
||||
}
|
||||
|
||||
function raumName(raum, teilnehmer, ichId) {
|
||||
if (raum.art === "kanal") return raum.name || kanalName(raum.kategorie);
|
||||
/* Der gespeicherte Name zuerst -- bei einem eigenen Kanal ist er
|
||||
die einzige Quelle. Der Rueckfall auf "Kanal" gilt Raeumen aus
|
||||
der Zeit vor der Namensspalte; ohne ihn stuende dort seit dem
|
||||
24.09. gar nichts, weil kanalName() jetzt null liefert. */
|
||||
if (raum.art === "kanal") return raum.name || kanalName(raum.kategorie) || "Kanal";
|
||||
if (raum.art === "gruppe") return raum.name || "Gruppe";
|
||||
const andere = teilnehmer.filter((t) => t.id !== ichId);
|
||||
return andere.map((t) => t.name).join(", ") || "Gespräch";
|
||||
@@ -931,7 +939,24 @@ function raumName(raum, teilnehmer, ichId) {
|
||||
/** Mit wem kann ich ein Gespräch anfangen? */
|
||||
chatRouter.get("/workspace/api/chat/partner", (req, res) => {
|
||||
try {
|
||||
const ids = schreibbareIds(req.person);
|
||||
/* ==== FUER EINEN KANAL GILT EINE ANDERE LISTE (24.09.2026) ====
|
||||
|
||||
Filipe: „ich will auch die option kanäle mit den leuten mit der
|
||||
community rolle."
|
||||
|
||||
Seit dem 19.09. nimmt "ohneAussen()" die Community aus den
|
||||
Listen aller anderen -- weil ein Zweier-Gespraech mit einem
|
||||
Zuschauer eine Standleitung ohne Moderation waere. Diese
|
||||
Begruendung gilt fuer ein Gespraech und NICHT fuer einen Kanal:
|
||||
Dort sitzt die ganze Teamfuehrung drin, und er ist moderierbar.
|
||||
|
||||
"?fuer=kanal" fragt also eine andere Frage, nicht dieselbe mit
|
||||
weniger Sorgfalt. Wer Kanaele gar nicht aufmachen darf, bekommt
|
||||
die erweiterte Liste auch nicht -- sonst waere der Parameter
|
||||
ein Weg, an "ohneAussen" vorbei Namen zu erfahren. */
|
||||
const fuerKanal = String(req.query?.fuer || "") === "kanal"
|
||||
&& darfKanalAufmachen(req.person);
|
||||
const ids = fuerKanal ? null : schreibbareIds(req.person);
|
||||
const wo = ids === null
|
||||
? "id <> ?" : `id IN (${ids.map(() => "?").join(",")})`;
|
||||
const werte = ids === null ? [req.person.id] : ids;
|
||||
@@ -1296,9 +1321,54 @@ chatRouter.post("/workspace/api/chat/kanal", gleicheHerkunft, express.json({ lim
|
||||
nicht erfahren, dass es die Moeglichkeit gibt. */
|
||||
if (!darfKanalAufmachen(req.person)) return res.status(404).json({ fehler: "nicht_gefunden" });
|
||||
|
||||
/* ==== EIN EIGENER NAME IST ERLAUBT (24.09.2026) ===============
|
||||
|
||||
Filipe: „ich will dass man die option hat einen neuen namen zu
|
||||
erstellen den es noch nicht da in der liste gibt."
|
||||
|
||||
Bis heute musste die Zustaendigkeit aus MODI_KATEGORIEN
|
||||
stammen -- neun feste Themen. Jetzt geht auch ein eigener
|
||||
Name, und die Liste bleibt als Vorschlag.
|
||||
|
||||
DER SCHLUESSEL WIRD ABGELEITET, NICHT GETIPPT. Er landet in
|
||||
der Datenbank und in Adressen; Leerzeichen, Umlaute und
|
||||
Satzzeichen haetten dort nichts verloren. Aus „Technik & Ton"
|
||||
wird "technik-ton". Der ANGEZEIGTE Name bleibt, wie er
|
||||
geschrieben wurde -- er steht in "name".
|
||||
|
||||
WARUM EIN PRAEFIX: Ein eigener Schluessel darf nie mit einem
|
||||
festen zusammenfallen. Schriebe jemand „Community", entstuende
|
||||
"community" -- derselbe Schluessel wie das feste Thema, und
|
||||
der eindeutige Index in der Datenbank wuerde ihn ablehnen,
|
||||
obwohl der Kanal noch gar nicht existiert. Mit "eigen-" davor
|
||||
kann das nicht passieren.
|
||||
|
||||
DER NAME WIRD MITGESPEICHERT. Bei den festen Themen kommt er
|
||||
aus MODI_KATEGORIEN (siehe kanalName weiter oben); ein eigener
|
||||
hat dort keinen Eintrag, deshalb steht er in der Spalte
|
||||
"name". */
|
||||
const kategorie = String(req.body?.kategorie ?? "").trim();
|
||||
if (!MODI_KATEGORIEN.some((k) => k.wert === kategorie)) {
|
||||
return res.status(400).json({ fehler: "Unbekannte Kategorie." });
|
||||
const eigenerName = String(req.body?.eigener_name ?? "").trim()
|
||||
.replace(/\s+/g, " ").slice(0, 60);
|
||||
const fest = MODI_KATEGORIEN.some((k) => k.wert === kategorie);
|
||||
let schluessel = kategorie;
|
||||
let anzeigeName = null;
|
||||
if (!fest) {
|
||||
if (eigenerName.length < 2) {
|
||||
return res.status(400).json({
|
||||
fehler: "Für einen eigenen Kanal brauchst du einen Namen (mindestens zwei Zeichen).",
|
||||
});
|
||||
}
|
||||
const rein = eigenerName.toLowerCase()
|
||||
.replace(/ä/g, "ae").replace(/ö/g, "oe").replace(/ü/g, "ue").replace(/ß/g, "ss")
|
||||
.replace(/[^a-z0-9]+/g, "-").replace(/^-+|-+$/g, "").slice(0, 40);
|
||||
if (!rein) {
|
||||
return res.status(400).json({
|
||||
fehler: "Der Name braucht mindestens einen Buchstaben oder eine Ziffer.",
|
||||
});
|
||||
}
|
||||
schluessel = "eigen-" + rein;
|
||||
anzeigeName = eigenerName;
|
||||
}
|
||||
|
||||
const d = db();
|
||||
@@ -1307,7 +1377,7 @@ chatRouter.post("/workspace/api/chat/kanal", gleicheHerkunft, express.json({ lim
|
||||
jemand lesen kann, und dort eine Zusage, die auch dann gilt, wenn
|
||||
einmal zwei Anfragen im selben Augenblick ankommen. */
|
||||
const schon = d.prepare("SELECT id FROM chat_raeume WHERE art = 'kanal' AND kategorie = ?")
|
||||
.get(kategorie);
|
||||
.get(schluessel);
|
||||
if (schon) {
|
||||
return res.status(409).json({ fehler: "Diesen Kanal gibt es schon.", raum_id: schon.id });
|
||||
}
|
||||
@@ -1335,7 +1405,10 @@ chatRouter.post("/workspace/api/chat/kanal", gleicheHerkunft, express.json({ lim
|
||||
const n = jetzt();
|
||||
d.prepare(`INSERT INTO chat_raeume (art, name, kategorie, erstellt, erstellt_von)
|
||||
VALUES ('kanal',?,?,?,?)`)
|
||||
.run(kanalName(kategorie), kategorie, n, req.person.id);
|
||||
/* Der eigene Name geht in die Spalte, der feste kommt aus
|
||||
MODI_KATEGORIEN. Beides landet in derselben Spalte -- die
|
||||
Zeile im Chat liest nur noch dort nach. */
|
||||
.run(anzeigeName || kanalName(schluessel), schluessel, n, req.person.id);
|
||||
const raumId = d.prepare("SELECT last_insert_rowid() AS id").get().id;
|
||||
|
||||
/* DIE GANZE TEAMFUEHRUNG KOMMT HINEIN, nicht nur der Anlegende.
|
||||
@@ -1363,7 +1436,7 @@ chatRouter.post("/workspace/api/chat/kanal", gleicheHerkunft, express.json({ lim
|
||||
personId: req.person.id, rolle: req.person.rolle, ip: echteIp(req),
|
||||
detail: `#${raumId} ${kategorie} (${drin})`.slice(0, 120),
|
||||
});
|
||||
res.status(201).json({ raum_id: raumId, name: kanalName(kategorie) });
|
||||
res.status(201).json({ raum_id: raumId, name: anzeigeName || kanalName(schluessel) });
|
||||
} catch (fehler) {
|
||||
console.error("[chat] Kanal:", fehler?.message);
|
||||
res.status(503).json({ fehler: "nicht_verfuegbar" });
|
||||
|
||||
Reference in New Issue
Block a user