Kampagnen-Kacheln: gegliederte Texte, Geschenke mit Preis, aufklappbar
Filipe, mit einem Bildschirmfoto des Regelblocks: "man soll die titel
in den texten besser erkennen und sehen was zu was passt. ich will
auch dass man sieht welche geschenke bei dem event zaehlen und so.
ich will alle informationen die moeglich sind wenn man den link
hochlaedt. ... auch wenn man teilt soll es einfach perfekt sein. man
soll alle infos sehen die man braucht. die kacheln von den events
soll auch nicht so lang sein, die soll man aufklappen koennen. genau
wie eine trennung fuer heute, letzte woche letzten monat und so."
DER FEHLER LAG NICHT IM TEXT, SONDERN IN SEINER ANZEIGE. Im Feld
stand die ganze Zeit eine Gliederung -- Hinweise mit "* ", eine
Ueberschrift mit Untertitel hinter einem Gedankenstrich, Absaetze
ohne Zeichen, Aufzaehlungen mit "- ". Die Kachel hat daraus mit
punkteAusText() EINE flache Liste gemacht: jede Zeile derselbe
Strich, alle gleich gross.
gliederung() liest die Gliederung, die schon dasteht, statt
den Text umzuschreiben. Die beiden Kampagnen, die
heute in der Datenbank liegen, sehen dadurch
sofort richtig aus -- ohne Umstellung.
Geschenke kommen aus der gelesenen LISTE, nicht aus dem
Text, und stehen OHNE Aufklappen auf der Kachel.
Aufklappen alles Uebrige hinter einem Druck: gemessen 555 px
weniger je Kachel bei Gipfelstuermer.
Gruppen je Spalte laeuft / kommt / vorbei, Vergangenes
nach diese Woche, dieser Monat, aelter.
NEU GELESEN (stand in allen vier gespeicherten Seiten und wurde nie
angesehen): die Rangliste mit ihren Gruppen ("Superstars" bis
"5. Liga", bei Glow Up "Team Glow"/"Team Shine"), die Beschreibung je
Missionsgruppe, der Steckbrief (Kurznummer, Markt, Sprache, Zone),
der zweite Bildbaustein, und Ueberschriften INNERHALB der Klapptexte
-- "WELCHE LIGA BIN ICH?" hat jetzt sechs eingerueckte Unterpunkte
statt zwoelf gleichrangiger Zeilen.
EVENT_TEXT_MAX 6000 -> 20000. Der Regeltext von Gipfelstuermer ist
7679 Zeichen lang; es fielen bisher jedes Mal rund 1600 Zeichen
echter Inhalt weg. Die Zahl steht jetzt an EINER Stelle.
TEILEN: Was die KAMPAGNE sagt, geht hinaus (Aufgaben, Geschenke,
Regeln) -- wer WIR sind, nicht (Name, Rolle, Haus, Kampagnennummer,
Steckbrief). Und keine Hinweiszeile: "Die Preise konnten nicht
gelesen werden -- bitte nachtragen" ist eine Notiz an DogFather und
hat auf einer Seite, die er in Discord postet, nichts zu suchen.
BERICHTIGT, WEIL NACHGEMESSEN:
- Number(null) ist 0 und 0 ist endlich -- "Feuerwerk" bekam an drei
Stellen "0 Coins" angeschrieben, also eine falsche Preisangabe.
- Ein Kommentar im Leser behauptete, der Wertungszeitraum weiche
vom Kampagnenzeitraum ab. Nachgemessen ist er in allen drei
Seiten mit Rangliste auf die Millisekunde gleich; ich hatte zwei
verschiedene Kampagnen verglichen.
- bild-kampagne.mjs verlangte "jede Kachel traegt den Ton ihrer
Seite" und war damit seit dem 07.10. rot, weil an dem Tag bewusst
das Gegenteil entschieden wurde (Zustandston, Seitenkante). Nicht
aufgefallen, weil nach dem Lauf nur die Zahl der MESSUNGEN notiert
wurde, nicht die der FEHLER.
- .kv-seite > .eintrag-karte wird .kv-seite .eintrag-karte: Die
Karten haengen durch die Gruppen eine Ebene tiefer. Das waere der
fuenfte Direktkind-Selektor gewesen, der nach einem Umbau still
ausfaellt -- diesmal vorher gesehen.
GEPRUEFT: 186 (lesen, +58), 148 (Route/Teilen, +25), 158 (Kachel,
+64), 67 (Agentur, +5), 67 Messungen (Bild, +14), dazu struktur,
css-klassen, zeichen, deutsche-texte, tippziele, lesbarkeit und
haus-trennung (107, unveraendert). Sechs Gegenproben: alle sechs
Sabotagen werden bemerkt, alle Dateien byte-gleich wiederhergestellt.
Co-Authored-By: Claude Opus 5 <[email protected]>
This commit is contained in:
@@ -46,6 +46,11 @@ import { terminVon } from "./workspace-termin-regel.js";
|
||||
-- und dann der Link). Die vierte ist immer die, die etwas
|
||||
durchlaesst. */
|
||||
import { darfSeite } from "./rechte.js";
|
||||
/* Die Gliederung des Regeltextes kommt aus demselben Modul, das
|
||||
ihn schreibt. Sie im Browser zu bauen waere die zweite Fassung
|
||||
derselben Regel -- und die Teilen-Seite (workspace-teilen.js)
|
||||
braeuchte dann eine dritte. */
|
||||
import { gliederung } from "./kampagne-lesen.mjs";
|
||||
|
||||
/* EIN KATALOG AUS ZWEI QUELLEN (17.09.2026)
|
||||
|
||||
@@ -766,6 +771,38 @@ const MIT_ANTWORTEN = new Set(["treff", "wunsch"]);
|
||||
const TITEL_MAX = 160;
|
||||
const TEXT_MAX = 6000;
|
||||
|
||||
/* SO VIEL FASSEN DIE ZWEI EVENT-TEXTFELDER (07.10.2026).
|
||||
|
||||
Filipe: „ich will alle informationen die möglich sind wenn man
|
||||
den link hochlädt." Gemessen stehen dem 6000 Zeichen im Weg:
|
||||
Der Regeltext von „Gipfelstuermer" ist 7605 Zeichen lang --
|
||||
Geschenke, sechs Preisgruppen, Rangliste mit sechs Ligen,
|
||||
Teilnahmebedingungen, Themenideen. Er wurde beim Einlesen an
|
||||
einer Abschnittsgrenze abgeschnitten, und abgeschnitten wurde
|
||||
das Ende: rund 1600 Zeichen echter Inhalt, jedes Mal.
|
||||
|
||||
WARUM NICHT EINFACH TEXT_MAX ERHOEHEN: Weil die 6000 fuer das
|
||||
Beschreibungsfeld eines Aushangs eine sinnvolle Grenze sind --
|
||||
wer dort mehr tippt, schreibt keinen Aushang mehr. Diese zwei
|
||||
Felder sind etwas anderes: Sie halten das Regelwerk einer
|
||||
fremden Kampagne, und wie lang das ist, entscheidet TikTok.
|
||||
Eine Grenze fuer zwei verschiedene Dinge wird immer fuer eines
|
||||
von beiden falsch sein.
|
||||
|
||||
WARUM 20000 UND NICHT UNBEGRENZT: Eine Grenze muss es geben,
|
||||
sonst ist das Feld ein Ablageplatz fuer beliebig viel Text aus
|
||||
dem Netz. 20000 ist das Zweieinhalbfache des laengsten
|
||||
gemessenen Regeltextes -- Platz fuer eine Kampagne, die
|
||||
doppelt so ausfuehrlich ist, und keiner fuer ein Buch.
|
||||
|
||||
DIE ZAHL STEHT NUR HIER. workspace-kampagne.js holt sie sich
|
||||
von hier (`FELD_MAX`), statt sie abzuschreiben: Zwei Fassungen
|
||||
derselben Grenze laufen auseinander, und dann kuerzt der eine
|
||||
Weg auf 6000, waehrend der andere 20000 erlaubt -- eine Kachel,
|
||||
die man speichern kann, aber nicht so, wie sie eingelesen
|
||||
wurde. */
|
||||
export const EVENT_TEXT_MAX = 20000;
|
||||
|
||||
/* =====================================================================
|
||||
DIE PUNKTE EINES AGENTUR-EVENTS (03.10.2026)
|
||||
|
||||
@@ -1485,6 +1522,15 @@ const SPALTEN = `
|
||||
KEINE BACKTICKS IN DIESEM BLOCK: SPALTEN ist selbst ein Template.
|
||||
Ein Backtick im Kommentar beendet es mitten im SQL. */
|
||||
e.kampagne_id, e.kampagne_quelle,
|
||||
/* DAS GELESENE SELBST (07.10.2026, zweite Runde). Daraus baut
|
||||
der Server die Geschenkliste mit Coinpreisen, den Steckbrief
|
||||
und die Beschreibung je Missionsgruppe. Die Spalte selbst
|
||||
geht NICHT an die Oberflaeche -- sie wird unten gelesen und
|
||||
dann aus der Antwort entfernt: ein Auszug ist mehrere
|
||||
Kilobyte gross, und davon braucht die Kachel drei Felder.
|
||||
|
||||
KEINE BACKTICKS IN DIESEM BLOCK, siehe oben. */
|
||||
e.kampagne_daten,
|
||||
/* OB DIESES EVENT GETEILT IST (07.10.2026). Die Oberflaeche baut
|
||||
daraus entweder "Teilen" oder "Link kopieren" plus "nicht mehr
|
||||
teilen". Der Schluessel selbst geht NICHT mit: Er steht in der
|
||||
@@ -1814,9 +1860,90 @@ bereicheRouter.get("/workspace/api/bereich/:bereich", (req, res) => {
|
||||
|
||||
for (const e of events) {
|
||||
const haken = meine.get(e.id) || new Set();
|
||||
|
||||
/* ---- WAS AUS DER KAMPAGNE GELESEN WURDE -------------
|
||||
|
||||
`kampagne_daten` ist der Auszug, den der Leser beim
|
||||
Einlesen abgelegt hat. Drei Dinge daraus stehen auf
|
||||
der Kachel, und alle drei sind GELESENE Daten, nicht
|
||||
aus dem Text zurueckgewonnene:
|
||||
|
||||
geschenke Name, Coinpreis und Hinweis je Geschenk
|
||||
steckbrief Kurznummer, Region, Sprache, Zeitzone
|
||||
gruppen die Beschreibung je Missionsgruppe
|
||||
|
||||
WARUM NICHT AUS DEM TEXT: Im Regeltext steht
|
||||
„· Feuerwerk (Sammle Feuerwerk in deinem LIVE!)" --
|
||||
ohne Preis, weil es ein Kampagnengeschenk ist. Wer
|
||||
daraus den Preis lesen will, muss raten; wer die
|
||||
Liste hat, weiss es. Genau danach hat Filipe
|
||||
gefragt: „ich will auch dass man sieht welche
|
||||
geschenke bei dem event zaehlen und so."
|
||||
|
||||
IN EIN try: Die Spalte ist Text, und ein Eintrag von
|
||||
Hand oder aus einer alten Fassung muss kein JSON
|
||||
sein. Eine Kachel darf daran nicht scheitern -- ohne
|
||||
Auszug fehlen drei Felder, der Regeltext steht
|
||||
trotzdem da. */
|
||||
let auszug = null;
|
||||
if (e.kampagne_daten) {
|
||||
try { auszug = JSON.parse(e.kampagne_daten); } catch { auszug = null; }
|
||||
}
|
||||
delete e.kampagne_daten;
|
||||
|
||||
const gruppen = new Map();
|
||||
for (const g of auszug?.aufgabenGruppen || []) {
|
||||
if (g?.titel) gruppen.set(String(g.titel).trim(), g);
|
||||
}
|
||||
|
||||
e.event_punkte = punkteAusText(e.event_aufgaben)
|
||||
.map((p) => ({ ...p, meiner: haken.has(p.schluessel) }));
|
||||
e.event_regelpunkte = punkteAusText(e.event_regeln);
|
||||
.map((p) => {
|
||||
const g = gruppen.get(p.text.trim());
|
||||
return {
|
||||
...p,
|
||||
meiner: haken.has(p.schluessel),
|
||||
/* Nur wenn es etwas zu sagen gibt. Ein leeres
|
||||
Feld an jeder Aufgabe ist eine Zeile Luft
|
||||
unter jedem Haken. */
|
||||
...(g?.beschreibung ? { beschreibung: g.beschreibung } : {}),
|
||||
...(g?.von_tag && g?.bis_tag
|
||||
? { von_tag: g.von_tag, bis_tag: g.bis_tag } : {}),
|
||||
};
|
||||
});
|
||||
|
||||
/* DIE GLIEDERUNG STATT EINER FLACHEN LISTE (07.10.2026).
|
||||
|
||||
Hier stand `punkteAusText(e.event_regeln)` -- jede
|
||||
Zeile derselbe Strich. Damit sah „INFOS ZUR
|
||||
KAMPAGNE" genauso aus wie der Absatz darunter, und
|
||||
die Hinweise standen zwischen den Regeln, als waeren
|
||||
sie welche. Die Begruendung in Laenge steht bei
|
||||
`gliederung()` in kampagne-lesen.mjs.
|
||||
|
||||
DER DRITTE AUSGANG BLEIBT: `event_regeln` geht
|
||||
weiterhin als Rohtext mit (siehe SPALTEN). Kommt
|
||||
hier nichts heraus, zeigt die Kachel den Text --
|
||||
schlicht, aber vollstaendig. Eine zweite
|
||||
Punkteliste daneben waere eine dritte Abschrift
|
||||
desselben Inhalts in derselben Antwort. */
|
||||
e.event_regelabschnitte = gliederung(e.event_regeln,
|
||||
{ geschenke: auszug?.geschenke || [] });
|
||||
|
||||
if (auszug?.geschenke?.length) {
|
||||
e.event_geschenke = {
|
||||
titel: auszug.geschenkTitel || null,
|
||||
hinweis: auszug.geschenkHinweis || null,
|
||||
liste: auszug.geschenke,
|
||||
};
|
||||
}
|
||||
|
||||
/* Leere Felder fallen weg, statt als „—" zu erscheinen:
|
||||
`union_name` ist in allen gemessenen Kampagnen leer. */
|
||||
if (auszug?.steckbrief) {
|
||||
const s = Object.fromEntries(Object.entries(auszug.steckbrief)
|
||||
.filter(([, v]) => v !== null && v !== undefined && v !== ""));
|
||||
if (Object.keys(s).length) e.event_steckbrief = s;
|
||||
}
|
||||
/* DIE ZAHL KOMMT MIT, statt im Browser gezaehlt zu werden --
|
||||
sie steht sonst an zwei Stellen, und „2 von 3" ist genau
|
||||
die Sorte Angabe, die man nicht zweimal haben will. */
|
||||
@@ -2187,7 +2314,12 @@ function pruefe(bereich, körper, { neu }) {
|
||||
for (const [feld, name] of [["event_aufgaben", "Die Aufgaben"], ["event_regeln", "Die Regeln"]]) {
|
||||
if (körper[feld] === undefined) continue;
|
||||
const t = String(körper[feld] ?? "").trim();
|
||||
if (t.length > TEXT_MAX) fehler.push(`${name} sind zu lang.`);
|
||||
/* EVENT_TEXT_MAX, nicht TEXT_MAX -- Begruendung oben bei der
|
||||
Zahl. Eine Kachel, die der Server beim Speichern ablehnt,
|
||||
laesst den Menschen davor sich selbst fuer den Fehler
|
||||
halten: Er hat ein Wort geaendert und bekommt eine
|
||||
Meldung ueber 1600 Zeichen, die er nie getippt hat. */
|
||||
if (t.length > EVENT_TEXT_MAX) fehler.push(`${name} sind zu lang.`);
|
||||
else aus[feld] = t || null;
|
||||
}
|
||||
/* "Bis" vor "von" ist kein Zeitraum, sondern ein Tippfehler -- und
|
||||
|
||||
Reference in New Issue
Block a user