Spenden: Stufen gestaltbar, Bild hochladen, Größe je Stufe
Filipes Wunsch: „mach paar fertige und so dass ich auch hochladen
kann. auch so dass ich das anders gestalten kann oder die größe
verändern kann. ... auch spezielle sachen bei speziellen spenden."
WAS ES SCHON GAB, WAS FEHLTE
Drei Stufen ab Werk, fünf gezeichnete Zeichen, Farbe und Dauer je
Stufe — und sogar schon ein Feld für ein eigenes Bild. Es fehlte der
Weg, das alles zu ÄNDERN: Um eine Stufe umzubenennen, hätte jemand in
die Datenbank greifen müssen.
DIE GRÖSSE IST DAS „SPEZIELLE BEI SPEZIELLEN SPENDEN"
Je Stufe, nicht einmal für alle: Eine Rudel-Legende darf größer
dastehen als ein Danke. Eine einzige Größe für alle wäre wieder eine
Preisliste. Umgesetzt als EINE Schriftgröße, alles darin in `em` —
nicht `transform: scale()`, denn die Karte kommt schon mit
`translateX()` herein, und zwei `transform` an derselben Stelle
schließen einander aus; außerdem wird Text beim Skalieren matschig.
Nur nach oben (1 bis 2,5), und das ist eine ehrliche Grenze: Das
kleinste Wort auf der Karte steht bei 11,52 px, die Hausgrenze ist
11,5. Ein Faktor von 0,8 machte daraus 9,2 px. Kleiner geht an der
richtigen Stelle — die OBS-Tafel hat ihren eigenen Regler in der
Adresse, dort ist es eine Videoeinblendung und kein Text zum Lesen.
AUSPROBIEREN, OHNE EINE SPENDE ANZULEGEN
Der naheliegende Weg wäre gewesen: eine Spende eintragen und danach
löschen. Das ist verboten — in ein laufendes System kommen keine
Testdaten, und „gelöscht" heißt bei Geld nicht „war nie da". Die
Probe schreibt deshalb NICHTS und geht nur an den, der drückt; eine
Probe im ganzen Saal wäre eine Spende, die es nicht gab.
DREI FEHLER, DIE DIE PRÜFUNG GEFUNDEN HAT
1. `protokolliere()` wurde an 17 Stellen falsch herum gerufen —
`(personId, aktion, detail, ip)` statt `(aktion, {…})`. JavaScript
beschwert sich nicht: Das zweite Argument war ein Text, und einen
Text zu zerlegen ergibt lauter `undefined`. Auf dem echten Server
nachgemessen: 39 Protokollzeilen mit Aktionen wie „16.0", alle
ohne Person, ohne Detail, ohne IP. Betroffen waren Material,
Hilfe, Bühne, Reaction und Spenden — also jede Änderung an
Dogi-Media und jede Maßnahme im Live-Chat, ausgerechnet das,
wofür es ein Protokoll gibt. Alle 17 berichtigt, und
pruef-struktur wacht jetzt darüber (mit Gegenprobe).
2. Beim Speichern der Leiter bekam jede Stufe eine NEUE Kennung
(DELETE + INSERT). Ein Bild-Hochladen gegen die eben noch gültige
Kennung antwortete mit 404 — im Alltag trifft das jeden, der einen
zweiten Bildschirm offen hat. Jetzt werden vorhandene Zeilen
geändert statt ersetzt; das Bild bleibt von selbst daran hängen.
3. `ab_cent` ist eindeutig. Zwei Stufen ihre Beträge tauschen zu
lassen scheiterte mit „UNIQUE constraint failed", obwohl das
Ergebnis in Ordnung gewesen wäre: Beim Umschreiben stößt die
Leiter auf sich selbst. Jetzt in drei Schritten — löschen,
geparkte Zwischenwerte, endgültige Werte —, und das ist nach
außen nie sichtbar.
UND DREI, DIE IN MEINER MESSUNG STECKTEN
Die Messung hat eine noch laufende Karte aus dem vorigen Abschnitt
erwischt und daraus drei Fehler gemeldet, die keine waren —
darunter „die Probe läuft im ganzen Saal". Sie zählte außerdem die
versteckten Dateifelder als zu kleine Tippziele. Jetzt räumt sie
vorher auf, wartet auf die Karte MIT DER ERWARTETEN GRÖSSE (die
Karten laufen in einer Schlange — einen Knoten zu entfernen beendet
sie nicht) und lässt die Einblendung zur Ruhe kommen, bevor sie misst.
Ein Bildschirmfoto aus der Einblendphase sah aus, als stünde die
Karte links heraus; nachgemessen: links 18 px, ganz im Bild.
GEMESSEN, NICHT ANGENOMMEN
Karte bei Größe 1: Schrift 16 px, Betrag 25,92 px. Bei Größe 2:
32 px und 51,84 px — Faktor exakt 2,00. Hätte eine einzige Regel noch
in `rem` gestanden, wäre die Karte ungleichmäßig gewachsen, und auf
einem Bild sieht beides nur „größer" aus.
AUCH DAS BILD IST GEPRÜFT
Es liegt am Bühnen-Router und nicht am Spenden-Router: Die
Spendentafel in OBS hat keine Anmeldung, und ein 401 als JSON in
einem `<img>` ergibt ein kaputtes Bild ohne jeden Hinweis. Ohne
Schlüssel, aber mit 128 Bit zufälligem Dateinamen — dieselbe
Größenordnung wie der Bühnenschlüssel, und es ist ein Zierbild, das
ohnehin im Stream steht. Kein Ausbruch aus dem Ordner (vier Wege
geprüft, gemessen wird die Wirkung und nicht der Statuscode).
NACHGETRAGEN AUS BLOCK 4
`reaktion_meldungen` fehlte im Löschkonzept — eine bestehende Prüfung
hat es gefunden. 30 Tage nach dem Erledigen; meistens sind sie
ohnehin früher weg, weil der Live-Chat beim Beenden gelöscht wird und
die Meldungen daran hängen. Wer meldet, muss sich darauf verlassen
können, dass daraus keine dauerhafte Liste wird.
GEPRUEFT
pruef-spenden: 95 Prüfungen (vorher 46), 0 Fehler.
pruef-reaktion 260, pruef-buehne 36, pruef-aufbewahrung 45,
pruef-struktur, pruef-meldungen, pruef-css-klassen, pruef-tippziele,
pruef-deutsche-texte, pruef-auskunft alle grün.
mess-reaktion und mess-buehne: Rückgabewert 0, kein ACHTUNG.
Co-Authored-By: Claude Opus 5 <[email protected]>
This commit is contained in:
@@ -685,6 +685,229 @@ if (zuschauer.konsole.length) console.log(" KONSOLE:", zuschauer.konsole.slice
|
||||
Abzeichen UND ein zweiter Knopf dazugekommen. Genau so ist am
|
||||
28.09. die Regie 197 px uebergelaufen: Die Rechnung ging auf, die
|
||||
Wirklichkeit nicht. */
|
||||
/* ---- Die Gestaltung der Spendenkarten ---------------------------
|
||||
|
||||
Filipe: „mach paar fertige und so dass ich auch hochladen kann.
|
||||
auch so dass ich das anders gestalten kann oder die größe
|
||||
verändern kann."
|
||||
|
||||
GEMESSEN WIRD DIE KARTE, NICHT DIE EINSTELLUNG. Dass in der
|
||||
Datenbank 2.0 steht, sagt nichts darüber, ob die Karte doppelt so
|
||||
groß erscheint -- dazwischen liegen eine Zahl im Stilblatt, eine
|
||||
Umrechnung in `em` und ein Dutzend Regeln, die noch in `rem`
|
||||
stehen könnten. Also: Karte laufen lassen und nachmessen. */
|
||||
console.log("");
|
||||
console.log(" --- Die Gestaltung der Spendenkarten ---");
|
||||
await host.seite.click('#reiter .reiter__knopf[data-tafel="gestaltung"]').catch(() => {});
|
||||
await host.seite.waitForTimeout(700);
|
||||
|
||||
const leiter = await host.seite.evaluate(() => {
|
||||
const zeilen = [...document.querySelectorAll("#stufen .stufe-zeile")];
|
||||
return {
|
||||
zeilen: zeilen.length,
|
||||
ersteName: zeilen[0]?.querySelector(".stufe-name")?.value || "",
|
||||
felder: zeilen[0] ? [...zeilen[0].querySelectorAll("input, select")].length : 0,
|
||||
/* Jedes Bedienelement muss mit dem Finger zu treffen sein --
|
||||
hier wird eingestellt, was vor Publikum im Bild steht. */
|
||||
/* VERSTECKTES ZAEHLT NICHT. Hinter jedem „Bild hochladen" liegt
|
||||
ein `<input type="file" hidden>` -- es ist 0 px hoch, und das
|
||||
ist richtig so: Angefasst wird das Schild davor. Die erste
|
||||
Fassung hat es mitgezaehlt und drei Fehler gemeldet, die
|
||||
keine waren. Eine Messung, die Unsichtbares misst, misst das
|
||||
Falsche. */
|
||||
zuKlein: zeilen.flatMap((z) => [...z.querySelectorAll("input, select, .stufe-tun")])
|
||||
.filter((e) => !e.hidden && e.offsetParent !== null)
|
||||
.filter((e) => e.getBoundingClientRect().height < 40).length,
|
||||
ueber: Math.max(0, document.documentElement.scrollWidth
|
||||
- document.documentElement.clientWidth),
|
||||
};
|
||||
});
|
||||
console.log(` ${leiter.zeilen} Stufen, erste „${leiter.ersteName}", `
|
||||
+ `${leiter.felder} Felder je Zeile, ${leiter.zuKlein} zu kleine Ziele, `
|
||||
+ `seitlich ${leiter.ueber} px`);
|
||||
if (leiter.zeilen < 3 || leiter.felder < 6 || leiter.zuKlein > 0 || leiter.ueber > 0) {
|
||||
console.log(" ACHTUNG: Die Stufenleiter ist unvollstaendig oder laeuft ueber.");
|
||||
ausgang = 1;
|
||||
}
|
||||
await bild(host.seite, "17-stufenleiter");
|
||||
|
||||
/* ---- Eine Stufe umgestalten und nachsehen, ob es ankommt ---- */
|
||||
const vorherKarte = await host.seite.evaluate(async () => {
|
||||
/* Erst einmal bei Größe 1 messen -- ohne Bezugswert sagt die zweite
|
||||
Messung nichts. */
|
||||
const k2 = [...document.querySelectorAll("#stufen .stufe-zeile")][2];
|
||||
k2.querySelector(".stufe-groesse").value = "1";
|
||||
k2.querySelector(".stufe-groesse").dispatchEvent(new Event("input", { bubbles: true }));
|
||||
document.getElementById("stufen-sichern").click();
|
||||
return true;
|
||||
});
|
||||
await host.seite.waitForTimeout(1200);
|
||||
|
||||
/* ==== ERST AUFRAEUMEN, DANN MESSEN ================================
|
||||
|
||||
Die erste Fassung hat einfach `document.querySelector(".spenden-
|
||||
karte")` genommen -- und damit die Karte der echten 10-Euro-Spende
|
||||
erwischt, die aus dem vorigen Messabschnitt noch im Bild stand.
|
||||
Ergebnis: drei gemeldete Fehler, die keine waren, darunter „die
|
||||
Probe laeuft im ganzen Saal". Eine Messung, die nicht weiss, WELCHE
|
||||
Karte sie vor sich hat, misst irgendetwas.
|
||||
|
||||
Also: beide Tafeln leeren, dann druecken, dann auf eine Karte
|
||||
warten, die sich als Probe ausweist. */
|
||||
const tafelnLeeren = async () => {
|
||||
for (const s2 of [host.seite, zuschauer.seite]) {
|
||||
await s2.evaluate(() => {
|
||||
for (const k2 of document.querySelectorAll(".spendenkarte")) k2.remove();
|
||||
});
|
||||
}
|
||||
};
|
||||
|
||||
const messeKarte = async (erwartet) => {
|
||||
await tafelnLeeren();
|
||||
await host.seite.evaluate(() => {
|
||||
const k2 = [...document.querySelectorAll("#stufen .stufe-zeile")][2];
|
||||
[...k2.querySelectorAll(".stufe-tun")].find((x) => x.textContent === "Ausprobieren")?.click();
|
||||
});
|
||||
/* ==== AUF DIE RICHTIGE KARTE WARTEN, NICHT AUF DIE UHR ==========
|
||||
|
||||
Zwei Fallen auf einmal, und die zweite hat die erste Fassung
|
||||
gekostet:
|
||||
|
||||
(1) Die Karten laufen in einer SCHLANGE. Ein Knoten aus dem
|
||||
Dokument zu nehmen beendet nicht, was die Seite gerade
|
||||
zeigt -- die naechste Karte kommt erst, wenn die Dauer der
|
||||
vorigen abgelaufen ist. Bei elf Sekunden Dauer und acht
|
||||
Sekunden Wartezeit kam sie nie, und die Messung meldete
|
||||
einen Fehler, den es nicht gab.
|
||||
|
||||
(2) Gewartet wird auf die Karte MIT DER ERWARTETEN GROESSE.
|
||||
Sonst koennte die vorige Probe die Antwort geben, und die
|
||||
Messung bestaetigte eine Aenderung, die gar nicht
|
||||
angekommen ist. */
|
||||
await host.seite.waitForFunction(
|
||||
(soll) => [...document.querySelectorAll(".spendenkarte")].some((k2) =>
|
||||
k2.querySelector(".spendenkarte__wer")?.textContent === "Probe"
|
||||
&& Math.abs(parseFloat(getComputedStyle(k2).fontSize) - soll) < 0.5),
|
||||
erwartet, { timeout: 16000 },
|
||||
).catch(() => {});
|
||||
/* DIE KARTE KOMMT VON LINKS HEREIN (450 ms). Wer sofort misst,
|
||||
misst einen Zwischenschritt: Waehrend des Hereinkommens steht
|
||||
sie 28 px weiter links und ist halb durchsichtig. Ein
|
||||
Bildschirmfoto aus dieser Phase sieht aus, als waere sie
|
||||
abgeschnitten -- und genau das hat mich beim ersten Ansehen in
|
||||
die Irre gefuehrt. */
|
||||
await host.seite.waitForTimeout(700);
|
||||
return host.seite.evaluate(() => {
|
||||
const k2 = [...document.querySelectorAll(".spendenkarte")]
|
||||
.find((x) => x.querySelector(".spendenkarte__wer")?.textContent === "Probe");
|
||||
if (!k2) return null;
|
||||
const r = k2.getBoundingClientRect();
|
||||
const c = getComputedStyle(k2);
|
||||
const betrag = k2.querySelector(".spendenkarte__betrag");
|
||||
return {
|
||||
schrift: Math.round(parseFloat(c.fontSize) * 100) / 100,
|
||||
breit: Math.round(r.width), hoch: Math.round(r.height),
|
||||
betragText: betrag?.textContent || "",
|
||||
betragSchrift: Math.round(parseFloat(getComputedStyle(betrag).fontSize) * 100) / 100,
|
||||
stufe: k2.querySelector(".spendenkarte__stufe")?.textContent || "",
|
||||
wer: k2.querySelector(".spendenkarte__wer")?.textContent || "",
|
||||
links: Math.round(r.left), oben: Math.round(r.top),
|
||||
/* ALLE VIER SEITEN. Die erste Fassung hat nur rechts und unten
|
||||
geprueft -- eine Karte, die links heraussteht, waere
|
||||
durchgegangen. Im Stream ist links genauso abgeschnitten wie
|
||||
rechts. */
|
||||
imBild: r.left >= -1 && r.top >= -1
|
||||
&& r.right <= window.innerWidth + 1 && r.bottom <= window.innerHeight + 1,
|
||||
};
|
||||
});
|
||||
};
|
||||
|
||||
const kKlein = await messeKarte(16);
|
||||
console.log(` Größe 1: Karte ${kKlein?.breit}x${kKlein?.hoch} px, Schrift ${kKlein?.schrift} px, `
|
||||
+ `Betrag „${kKlein?.betragText}" bei ${kKlein?.betragSchrift} px, Stufe „${kKlein?.stufe}"`);
|
||||
if (!kKlein || kKlein.wer !== "Probe") {
|
||||
console.log(" ACHTUNG: Die Probe zeigt keine Karte -- oder sie ist nicht als Probe erkennbar.");
|
||||
ausgang = 1;
|
||||
}
|
||||
await bild(host.seite, "18-karte-normal");
|
||||
|
||||
/* DIE PROBE DARF NUR BEIM DRUECKENDEN ERSCHEINEN. Eine Probe, die im
|
||||
ganzen Saal laeuft, ist eine Spende, die es nicht gab. */
|
||||
const beimZuschauer = await zuschauer.seite.evaluate(() =>
|
||||
document.querySelectorAll(".spendenkarte").length);
|
||||
console.log(` Karten bei der Zuschauerin waehrend der Probe: ${beimZuschauer} (soll: 0)`);
|
||||
if (beimZuschauer !== 0) {
|
||||
console.log(" ACHTUNG: Die Probe laeuft im ganzen Saal.");
|
||||
ausgang = 1;
|
||||
}
|
||||
|
||||
/* Jetzt auf doppelte Größe -- und nachmessen. */
|
||||
await host.seite.evaluate(() => {
|
||||
const k2 = [...document.querySelectorAll("#stufen .stufe-zeile")][2];
|
||||
k2.querySelector(".stufe-groesse").value = "2";
|
||||
k2.querySelector(".stufe-groesse").dispatchEvent(new Event("input", { bubbles: true }));
|
||||
k2.querySelector(".stufe-farbe").value = "#55d6a0";
|
||||
k2.querySelector(".stufe-farbe").dispatchEvent(new Event("input", { bubbles: true }));
|
||||
document.getElementById("stufen-sichern").click();
|
||||
});
|
||||
await host.seite.waitForTimeout(1400);
|
||||
const kGross = await messeKarte(32);
|
||||
console.log(` Größe 2: Karte ${kGross?.breit}x${kGross?.hoch} px, Schrift ${kGross?.schrift} px, `
|
||||
+ `Betrag bei ${kGross?.betragSchrift} px, links ${kGross?.links} / oben ${kGross?.oben}, `
|
||||
+ `ganz im Bild=${kGross?.imBild}`);
|
||||
await bild(host.seite, "19-karte-doppelt");
|
||||
|
||||
if (!kGross || !kKlein) {
|
||||
console.log(" ACHTUNG: Die Karte liess sich nicht zweimal messen.");
|
||||
ausgang = 1;
|
||||
} else {
|
||||
/* ZWEIFACH HEISST ZWEIFACH. Wenn eine einzige Regel noch in `rem`
|
||||
stünde statt in `em`, wüchse die Karte ungleichmäßig -- und das
|
||||
sieht man auf einem Bildschirmfoto nicht, weil beides „größer"
|
||||
aussieht. */
|
||||
const faktor = kGross.betragSchrift / kKlein.betragSchrift;
|
||||
console.log(` Der Betrag wuchs um das ${faktor.toFixed(2)}-fache (soll: 2,00)`);
|
||||
if (Math.abs(faktor - 2) > 0.05) {
|
||||
console.log(" ACHTUNG: Die Größe wirkt nicht oder nicht gleichmaessig.");
|
||||
ausgang = 1;
|
||||
}
|
||||
if (kGross.hoch <= kKlein.hoch) {
|
||||
console.log(" ACHTUNG: Die Karte wird nicht hoeher.");
|
||||
ausgang = 1;
|
||||
}
|
||||
/* UND SIE MUSS INS BILD PASSEN. Die Obergrenze 2,5 ist daran
|
||||
ausgerichtet -- eine Karte, die rechts heraussteht, ist im
|
||||
Stream abgeschnitten. */
|
||||
if (!kGross.imBild) {
|
||||
console.log(" ACHTUNG: Die doppelt grosse Karte steht aus dem Bild heraus.");
|
||||
ausgang = 1;
|
||||
}
|
||||
}
|
||||
|
||||
/* ---- Und die Farbe? ---- */
|
||||
const farbe = await host.seite.evaluate(() => {
|
||||
const k2 = [...document.querySelectorAll(".spendenkarte")]
|
||||
.find((x) => x.querySelector(".spendenkarte__wer")?.textContent === "Probe");
|
||||
return k2 ? getComputedStyle(k2).getPropertyValue("--sp-farbe").trim() : "";
|
||||
});
|
||||
console.log(` Farbe der Karte: „${farbe}" (gesetzt war #55d6a0)`);
|
||||
if (farbe.toLowerCase() !== "#55d6a0") {
|
||||
console.log(" ACHTUNG: Die Farbe kommt nicht an.");
|
||||
ausgang = 1;
|
||||
}
|
||||
|
||||
/* Wieder auf einen vernuenftigen Wert -- die naechste Messung soll
|
||||
nicht mit einer Karte in doppelter Groesse anfangen. */
|
||||
await host.seite.evaluate(() => {
|
||||
const k2 = [...document.querySelectorAll("#stufen .stufe-zeile")][2];
|
||||
k2.querySelector(".stufe-groesse").value = "1.45";
|
||||
k2.querySelector(".stufe-groesse").dispatchEvent(new Event("input", { bubbles: true }));
|
||||
k2.querySelector(".stufe-farbe").value = "#e0a13a";
|
||||
k2.querySelector(".stufe-farbe").dispatchEvent(new Event("input", { bubbles: true }));
|
||||
document.getElementById("stufen-sichern").click();
|
||||
});
|
||||
await host.seite.waitForTimeout(1000);
|
||||
|
||||
/* ---- Das Video: Tempo, Anordnung, Umschalter --------------------
|
||||
|
||||
Filipe: „auch bei den videos sachen wie pause geschwindigkeit ...
|
||||
|
||||
+265
-4
@@ -16,7 +16,7 @@
|
||||
|
||||
Aufrufen mit: node server/pruef-spenden.mjs
|
||||
===================================================================== */
|
||||
import { mkdtempSync, rmSync } from "node:fs";
|
||||
import { mkdtempSync, rmSync, readFileSync } from "node:fs";
|
||||
import { tmpdir } from "node:os";
|
||||
import { join, dirname } from "node:path";
|
||||
import { fileURLToPath } from "node:url";
|
||||
@@ -83,16 +83,26 @@ for (const [i, [rolle, name]] of ROLLEN.entries()) {
|
||||
d.close();
|
||||
|
||||
/* ---------- Sprechen mit Hausadresse ------------------------------------ */
|
||||
function roh(host, pfad, { method = "GET", keks = "", rumpf = null, origin } = {}) {
|
||||
/** `roher` schickt Bytes statt JSON.
|
||||
*
|
||||
* Gebraucht fuer das Hochladen eines Bildes: Die Route nimmt
|
||||
* `express.raw()` entgegen, und ein als JSON verpacktes Bild waere
|
||||
* etwas anderes als das, was ein Browser schickt -- die Pruefung
|
||||
* wuerde dann einen Weg pruefen, den es gar nicht gibt. */
|
||||
function roh(host, pfad, { method = "GET", keks = "", rumpf = null, roher = null, origin } = {}) {
|
||||
return new Promise((fertig, schief) => {
|
||||
const daten = rumpf === null ? null : Buffer.from(JSON.stringify(rumpf));
|
||||
const daten = roher !== null ? roher
|
||||
: (rumpf === null ? null : Buffer.from(JSON.stringify(rumpf)));
|
||||
const a = request({
|
||||
host: "127.0.0.1", port: PORT, path: pfad, method,
|
||||
headers: {
|
||||
Host: host,
|
||||
Origin: origin === undefined ? `https://${host}` : origin,
|
||||
...(keks ? { Cookie: keks } : {}),
|
||||
...(daten ? { "Content-Type": "application/json", "Content-Length": daten.length } : {}),
|
||||
...(daten ? {
|
||||
"Content-Type": roher !== null ? "application/octet-stream" : "application/json",
|
||||
"Content-Length": daten.length,
|
||||
} : {}),
|
||||
},
|
||||
}, (antwort) => {
|
||||
const teile = [];
|
||||
@@ -355,6 +365,257 @@ melde("=== 7. Keine Spende zweimal ===");
|
||||
d2.close();
|
||||
}
|
||||
|
||||
|
||||
/* =======================================================================
|
||||
8. DIE GESTALTUNG
|
||||
|
||||
Filipe: „mach paar fertige und so dass ich auch hochladen kann.
|
||||
auch so dass ich das anders gestalten kann oder die groesse
|
||||
veraendern kann. ... auch spezielle sachen bei speziellen spenden."
|
||||
======================================================================= */
|
||||
melde("");
|
||||
melde("=== 8. Die Gestaltung der Karten ===");
|
||||
{
|
||||
/* Wie viele Spenden es gibt -- gebraucht fuer den Nachweis, dass
|
||||
die Probe KEINE anlegt. Gezaehlt wird in der Datenbank und nicht
|
||||
in einer Liste der Oberflaeche: Eine Liste zeigt nur, was sie
|
||||
zeigen soll. */
|
||||
const { DatabaseSync: DBZ } = await import("node:sqlite");
|
||||
const dz = new DBZ(process.env.WORKSPACE_DB, { readOnly: true });
|
||||
const zaehle = () => dz.prepare("SELECT COUNT(*) AS n FROM spenden").get().n;
|
||||
|
||||
const { VORLAGEN, STUFEN_MAX, GROESSE_MIN, GROESSE_MAX, DAUER_MS_MIN, DAUER_MS_MAX }
|
||||
= await import("./spenden-tabellen.js");
|
||||
|
||||
/* ---- Die Vorlagen sind an BEIDEN Enden dieselben ----
|
||||
Ein Name, den nur eine Seite kennt, waere eine Vorlage, die sich
|
||||
auswaehlen laesst und dann als Herz erscheint. */
|
||||
{
|
||||
const karte = readFileSync(
|
||||
join(HIER, "..", "workspace", "assets", "js", "spendenkarte.js"), "utf8");
|
||||
const block = karte.match(/const VORLAGEN = \{([\s\S]*?)\n \};/);
|
||||
const inKarte = [...(block ? block[1] : "").matchAll(/^\s{4}([a-z]+):/gm)].map((m) => m[1]);
|
||||
ok(inKarte.length >= 5, `die Karte kennt ${inKarte.length} Zeichnungen`);
|
||||
const fehlt = VORLAGEN.filter((v) => !inKarte.includes(v));
|
||||
const zuviel = inKarte.filter((v) => !VORLAGEN.includes(v));
|
||||
ok(fehlt.length === 0 && zuviel.length === 0,
|
||||
(fehlt.length || zuviel.length)
|
||||
? `UNGLEICH: fehlt ${fehlt.join(",")} / zuviel ${zuviel.join(",")}`
|
||||
: `Server und Karte kennen dieselben ${VORLAGEN.length} Zeichnungen`);
|
||||
ok(!VORLAGEN.includes("wolke"), "Gegenprobe: eine erfundene Zeichnung steht in keiner Liste");
|
||||
}
|
||||
|
||||
/* ---- Wer gestalten darf ---- */
|
||||
const guteLeiter = {
|
||||
stufen: [
|
||||
{ ab_cent: 100, name: "Danke", vorlage: "herz", farbe: "#8ec9ff", dauer_ms: 6000, groesse: 1 },
|
||||
{ ab_cent: 2000, name: "Legende", vorlage: "krone", farbe: "#e0a13a", dauer_ms: 11000, groesse: 1.45 },
|
||||
],
|
||||
};
|
||||
for (const rolle of ["linke", "modi", "gast"]) {
|
||||
const a = await roh(CREW, "/workspace/api/spenden/stufen", {
|
||||
method: "PUT", keks: k[rolle], rumpf: guteLeiter,
|
||||
});
|
||||
ok(a.code === 403, `${rolle}: gestaltet nicht (${a.code})`);
|
||||
}
|
||||
|
||||
/* ---- Was eine Leiter sein muss ---- */
|
||||
const schlecht = [
|
||||
[{ stufen: [] }, 400, "keine_stufe", "eine leere Leiter"],
|
||||
[{ stufen: null }, 400, "stufen_fehlen", "gar keine Leiter"],
|
||||
[{ stufen: Array.from({ length: STUFEN_MAX + 1 }, (x, i) => ({
|
||||
ab_cent: (i + 1) * 100, name: `S${i}`, vorlage: "herz",
|
||||
farbe: "#8ec9ff", dauer_ms: 5000, groesse: 1 })) }, 400, "zu_viele_stufen",
|
||||
`${STUFEN_MAX + 1} Stufen`],
|
||||
[{ stufen: [{ ab_cent: 0, name: "X", vorlage: "herz", farbe: "#8ec9ff", dauer_ms: 5000, groesse: 1 }] },
|
||||
400, "stufe_betrag_unklar", "null Cent"],
|
||||
[{ stufen: [{ ab_cent: 100, name: " ", vorlage: "herz", farbe: "#8ec9ff", dauer_ms: 5000, groesse: 1 }] },
|
||||
400, "stufe_name_fehlt", "ein leerer Name"],
|
||||
[{ stufen: [{ ab_cent: 100, name: "X", vorlage: "wolke", farbe: "#8ec9ff", dauer_ms: 5000, groesse: 1 }] },
|
||||
400, "vorlage_unbekannt", "eine erfundene Zeichnung"],
|
||||
/* DIE FARBE IST DIE HEIKELSTE STELLE: Sie landet als CSS-Wert in
|
||||
der Karte. Ein freier Text waere dort eine Einschleusung. */
|
||||
[{ stufen: [{ ab_cent: 100, name: "X", vorlage: "herz",
|
||||
farbe: "red; background:url(javascript:1)", dauer_ms: 5000, groesse: 1 }] },
|
||||
400, "farbe_unklar", "eine eingeschleuste Farbe"],
|
||||
[{ stufen: [{ ab_cent: 100, name: "X", vorlage: "herz", farbe: "blau", dauer_ms: 5000, groesse: 1 }] },
|
||||
400, "farbe_unklar", "ein Farbwort"],
|
||||
[{ stufen: [{ ab_cent: 100, name: "X", vorlage: "herz", farbe: "#8ec9ff",
|
||||
dauer_ms: DAUER_MS_MAX + 1000, groesse: 1 }] }, 400, "dauer_unklar", "zu lange"],
|
||||
[{ stufen: [{ ab_cent: 100, name: "X", vorlage: "herz", farbe: "#8ec9ff",
|
||||
dauer_ms: DAUER_MS_MIN - 500, groesse: 1 }] }, 400, "dauer_unklar", "zu kurz"],
|
||||
[{ stufen: [{ ab_cent: 100, name: "X", vorlage: "herz", farbe: "#8ec9ff",
|
||||
dauer_ms: 5000, groesse: GROESSE_MAX + 1 }] }, 400, "groesse_unklar", "zu gross"],
|
||||
[{ stufen: [{ ab_cent: 100, name: "X", vorlage: "herz", farbe: "#8ec9ff",
|
||||
dauer_ms: 5000, groesse: GROESSE_MIN - 0.5 }] }, 400, "groesse_unklar", "zu klein"],
|
||||
[{ stufen: [
|
||||
{ ab_cent: 500, name: "A", vorlage: "herz", farbe: "#8ec9ff", dauer_ms: 5000, groesse: 1 },
|
||||
{ ab_cent: 500, name: "B", vorlage: "welle", farbe: "#a98bff", dauer_ms: 5000, groesse: 1 },
|
||||
] }, 409, "stufe_doppelt", "zwei Stufen beim selben Betrag"],
|
||||
];
|
||||
for (const [rumpf, code, wort, was] of schlecht) {
|
||||
const a = await roh(CREW, "/workspace/api/spenden/stufen", {
|
||||
method: "PUT", keks: k.admin, rumpf,
|
||||
});
|
||||
ok(a.code === code && a.j?.fehler === wort,
|
||||
`${was} wird abgelehnt (${a.code}/${a.j?.fehler})`);
|
||||
}
|
||||
|
||||
/* NACH ALL DEN ABLEHNUNGEN MUSS DIE ALTE LEITER NOCH STEHEN.
|
||||
Eine Pruefung, die nur den Fehlercode ansieht, uebersieht genau
|
||||
das: Ein Abbruch mitten im Schreiben haette die Leiter halb
|
||||
geleert zurueckgelassen -- und dann faellt in der naechsten
|
||||
Sendung eine Spende in gar keine Stufe. */
|
||||
const heil = await roh(CREW, "/workspace/api/spenden", { keks: k.admin });
|
||||
ok((heil.j?.stufen || []).length >= 3,
|
||||
`die alte Leiter steht unveraendert (${heil.j?.stufen?.length} Stufen)`);
|
||||
|
||||
/* ---- Und was geht ---- */
|
||||
const gut = await roh(CREW, "/workspace/api/spenden/stufen", {
|
||||
method: "PUT", keks: k.admin, rumpf: guteLeiter,
|
||||
});
|
||||
ok(gut.code === 200 && gut.j?.stufen?.length === 2,
|
||||
`zwei Stufen werden gespeichert (${gut.code})`);
|
||||
ok(gut.j?.stufen?.[0]?.ab_cent === 100 && gut.j?.stufen?.[1]?.ab_cent === 2000,
|
||||
"und stehen aufsteigend");
|
||||
ok(gut.j?.stufen?.[1]?.groesse === 1.45,
|
||||
`die Groesse kommt an (${gut.j?.stufen?.[1]?.groesse})`);
|
||||
|
||||
/* ---- UMSORTIEREN MUSS GEHEN ----
|
||||
`ab_cent` ist eindeutig. Wer zwei vorhandene Stufen ihre Betraege
|
||||
TAUSCHEN laesst, stoesst beim Umschreiben auf sich selbst --
|
||||
obwohl das Ergebnis voellig in Ordnung waere. Gemessen ist genau
|
||||
das passiert („UNIQUE constraint failed"), und der ganze Vorgang
|
||||
brach mit 503 ab. */
|
||||
{
|
||||
const jetzige = gut.j.stufen;
|
||||
const getauscht = await roh(CREW, "/workspace/api/spenden/stufen", {
|
||||
method: "PUT", keks: k.admin,
|
||||
rumpf: { stufen: [
|
||||
{ ...jetzige[0], ab_cent: 2000 },
|
||||
{ ...jetzige[1], ab_cent: 100 },
|
||||
] },
|
||||
});
|
||||
ok(getauscht.code === 200, `zwei Stufen tauschen ihre Betraege (${getauscht.code})`);
|
||||
ok(getauscht.j?.stufen?.[0]?.name === jetzige[1].name,
|
||||
`und die Leiter steht richtig herum (${getauscht.j?.stufen?.[0]?.name})`);
|
||||
/* Und wieder zurueck -- der Rest des Abschnitts rechnet damit. */
|
||||
await roh(CREW, "/workspace/api/spenden/stufen", {
|
||||
method: "PUT", keks: k.admin, rumpf: { stufen: jetzige },
|
||||
});
|
||||
}
|
||||
|
||||
/* SPEZIELLE SACHEN BEI SPEZIELLEN SPENDEN: Die Stufe entscheidet
|
||||
sich am Betrag, und zwar immer die hoechste passende. */
|
||||
const { stufeFuer } = await import("./workspace-spenden.js");
|
||||
ok(stufeFuer(100)?.name === "Danke", "1 EUR -> Danke");
|
||||
ok(stufeFuer(1999)?.name === "Danke", "19,99 EUR -> immer noch Danke");
|
||||
ok(stufeFuer(2000)?.name === "Legende", "20 EUR -> Legende");
|
||||
ok(stufeFuer(50000)?.name === "Legende", "500 EUR -> Legende");
|
||||
ok(stufeFuer(99) === null, "unter der ersten Stufe gibt es keine");
|
||||
|
||||
/* ---- Die Probe legt KEINE Spende an ----
|
||||
Der naheliegende Weg waere gewesen, eine Spende einzutragen und
|
||||
danach zu loeschen. In ein laufendes System kommen keine
|
||||
Testdaten -- und „geloescht" heisst bei Geld nicht „war nie da". */
|
||||
const vorher = zaehle();
|
||||
const probe = await roh(CREW, "/workspace/api/spenden/probe", {
|
||||
method: "POST", keks: k.admin, rumpf: { betrag_cent: 2000 },
|
||||
});
|
||||
ok(probe.code === 200 && probe.j?.karte?.stufe?.name === "Legende",
|
||||
`die Probe zeigt die richtige Stufe (${probe.j?.karte?.stufe?.name})`);
|
||||
ok(probe.j?.karte?.stand === "probe", "und ist als Probe gekennzeichnet");
|
||||
ok(zaehle() === vorher,
|
||||
`und es entsteht KEINE Spende daraus (${vorher} -> ${zaehle()})`);
|
||||
const probeNein = await roh(CREW, "/workspace/api/spenden/probe", {
|
||||
method: "POST", keks: k.modi, rumpf: { betrag_cent: 2000 },
|
||||
});
|
||||
ok(probeNein.code === 403, `ein Modi probiert nicht (${probeNein.code})`);
|
||||
|
||||
/* ---- Das Bild ---- */
|
||||
const id = gut.j.stufen[1].id;
|
||||
const keinBild = await roh(CREW, `/workspace/api/spenden/stufe/${id}/bild`, {
|
||||
method: "POST", keks: k.admin, roher: Buffer.from("das ist kein Bild"),
|
||||
});
|
||||
ok(keinBild.code === 400 && keinBild.j?.fehler === "kein_bild",
|
||||
`Text statt Bild wird abgelehnt (${keinBild.code})`);
|
||||
|
||||
/* EIN ECHTES PNG -- der kleinste gueltige, den es gibt. Ein
|
||||
erfundener Kopf wuerde nur beweisen, dass die Pruefung dieselbe
|
||||
Annahme macht wie der Code. */
|
||||
const png = Buffer.from(
|
||||
"iVBORw0KGgoAAAANSUhEUgAAAAEAAAABCAYAAAAfFcSJAAAADUlEQVR42mP8z8BQDwAEhQGAhKmMIQAAAABJRU5ErkJggg==",
|
||||
"base64");
|
||||
const hoch = await roh(CREW, `/workspace/api/spenden/stufe/${id}/bild`, {
|
||||
method: "POST", keks: k.admin, roher: png,
|
||||
});
|
||||
ok(hoch.code === 200 && /^\/workspace\/api\/buehne\/spendenbild\/[a-f0-9]{32}\.png$/
|
||||
.test(hoch.j?.bild || ""), `ein PNG wird angenommen (${hoch.j?.bild})`);
|
||||
|
||||
/* DAS BILD MUSS OHNE ANMELDUNG ZU HOLEN SEIN. Die Spendentafel in
|
||||
OBS hat keine Sitzung -- ein 401 als JSON in einem <img> ergibt
|
||||
ein kaputtes Bild ohne jeden Hinweis. */
|
||||
const ohne = await roh(CREW, hoch.j.bild, {});
|
||||
ok(ohne.code === 200, `und ohne Anmeldung abrufbar (${ohne.code})`);
|
||||
ok(String(ohne.kopf["content-type"]).startsWith("image/png"),
|
||||
`als Bild und nicht als etwas anderes (${ohne.kopf["content-type"]})`);
|
||||
ok(ohne.kopf["x-content-type-options"] === "nosniff",
|
||||
"der Browser darf den Typ nicht selbst raten");
|
||||
|
||||
/* KEIN AUSBRUCH AUS DEM ORDNER.
|
||||
GEPRUEFT WIRD, WAS HERAUSKOMMT -- nicht, welche Zahl dabeisteht.
|
||||
„../../workspace.db" wird vom Server zu „/workspace/api/workspace.db"
|
||||
zusammengefaltet, bevor diese Route ueberhaupt drankommt; die
|
||||
Antwort ist dann 401 von einer ganz anderen Stelle. Auf 404 zu
|
||||
bestehen hiesse, eine Nebensaechlichkeit zu pruefen und den
|
||||
eigentlichen Punkt zu verfehlen: Es darf keine Datei
|
||||
herauskommen. */
|
||||
for (const boes of ["../../workspace.db", "..%2f..%2fworkspace.db",
|
||||
"%2e%2e%2f%2e%2e%2fworkspace.db", "nicht-vorhanden.png"]) {
|
||||
const a = await roh(CREW, `/workspace/api/buehne/spendenbild/${boes}`, {});
|
||||
ok(a.code !== 200 && !a.text.includes("SQLite format"),
|
||||
`„${boes}" liefert keine Datei (${a.code})`);
|
||||
}
|
||||
/* GEGENPROBE: Die richtige Adresse liefert sehr wohl etwas --
|
||||
sonst waere die Pruefung oben eine, die immer bestaetigt. */
|
||||
{
|
||||
const a = await roh(CREW, hoch.j.bild, {});
|
||||
ok(a.code === 200 && a.text.length > 0,
|
||||
"Gegenprobe: die richtige Adresse liefert das Bild");
|
||||
}
|
||||
|
||||
/* DAS BILD UEBERLEBT DAS NAECHSTE SPEICHERN. Wer nur den Namen
|
||||
aendert, soll sein Bild nicht verlieren. */
|
||||
const nochmal = await roh(CREW, "/workspace/api/spenden/stufen", {
|
||||
method: "PUT", keks: k.admin,
|
||||
rumpf: { stufen: gut.j.stufen.map((z) => ({ ...z, name: z.name + "!" })) },
|
||||
});
|
||||
const jetztBild = (nochmal.j?.stufen || []).find((z) => z.ab_cent === 2000)?.bild;
|
||||
ok(jetztBild === hoch.j.bild,
|
||||
`nach dem Umbenennen haengt das Bild noch dran (${jetztBild ? "ja" : "nein"})`);
|
||||
|
||||
/* DIE KENNUNG MUSS DAS SPEICHERN UEBERLEBT HABEN. Vorher wurde
|
||||
beim Speichern geloescht und neu eingefuegt -- jede Stufe bekam
|
||||
dabei eine neue Kennung, und ein Bild-Hochladen gegen die eben
|
||||
noch gueltige antwortete mit 404. Im Alltag trifft das jeden,
|
||||
der einen zweiten Bildschirm offen hat. */
|
||||
const nachId = (nochmal.j?.stufen || []).find((z) => z.ab_cent === 2000)?.id;
|
||||
ok(nachId === id, `die Kennung bleibt ueber das Speichern hinweg (${id} -> ${nachId})`);
|
||||
|
||||
const weg = await roh(CREW, `/workspace/api/spenden/stufe/${id}/bild`,
|
||||
{ method: "DELETE", keks: k.admin });
|
||||
ok(weg.code === 200, `das Bild laesst sich wegnehmen (${weg.code})`);
|
||||
const fort = await roh(CREW, hoch.j.bild, {});
|
||||
ok(fort.code === 404, `und die Datei ist danach wirklich fort (${fort.code})`);
|
||||
|
||||
/* ---- Was die Oberflaeche braucht, kommt vom Server ---- */
|
||||
const lage2 = await roh(CREW, "/workspace/api/spenden", { keks: k.admin });
|
||||
const g2 = lage2.j?.gestaltung;
|
||||
ok(!!g2 && Array.isArray(g2.vorlagen) && g2.stufen_max === STUFEN_MAX
|
||||
&& g2.groesse_min === GROESSE_MIN && g2.groesse_max === GROESSE_MAX,
|
||||
"die Grenzen stehen im Stand und nicht nur in der Oberflaeche");
|
||||
}
|
||||
|
||||
melde("");
|
||||
melde(`${geprueft} Pruefungen, ${fehler} Fehler`);
|
||||
melde(fehler === 0 ? "ALLES IN ORDNUNG" : "NICHT IN ORDNUNG");
|
||||
|
||||
@@ -830,6 +830,68 @@ console.log(`\n=== Rechnen die Pruefungen mit Ortszeit? ===`);
|
||||
ok(!harmlos, "Gegenprobe: ein voller Zeitstempel (ohne Schnitt) schlägt nicht an");
|
||||
}
|
||||
|
||||
/* =======================================================================
|
||||
WIRD DAS PROTOKOLL RICHTIG HERUM GERUFEN?
|
||||
|
||||
`protokolliere(aktion, { personId, rolle, detail, ip })` -- die
|
||||
Aktion zuerst, alles Weitere benannt.
|
||||
|
||||
Aufgerufen wurde es an 17 Stellen andersherum:
|
||||
`protokolliere(req.person.id, "aktion", detail, ip)`. JavaScript
|
||||
beschwert sich darueber NICHT. Das zweite Argument ist ein Text,
|
||||
und einen Text zu zerlegen ergibt lauter `undefined`. Der Eintrag
|
||||
entsteht also -- nur steht die Personen-Kennung im Feld `aktion`,
|
||||
und Person, Detail und IP sind leer.
|
||||
|
||||
AUF DEM ECHTEN SERVER NACHGEMESSEN: 39 Zeilen mit Aktionen wie
|
||||
„16.0" und „4.0". Betroffen war unter anderem jede Aenderung an
|
||||
Dogi-Media und jede Massnahme im Live-Chat -- also ausgerechnet
|
||||
das, wofuer es ein Protokoll gibt.
|
||||
|
||||
Ein Kommentar haette das nicht verhindert (11.09.2026: „Ein
|
||||
Kommentar, der vor einem Fehler warnt, verhindert ihn nicht").
|
||||
Eine Pruefung schon.
|
||||
======================================================================= */
|
||||
console.log(`\n=== Wird das Protokoll richtig herum gerufen? ===`);
|
||||
{
|
||||
/* Das erste Argument muss etwas sein, das eine Aktion SEIN KANN:
|
||||
eine Zeichenkette oder ein Ausdruck, der eine liefert (`a ? "x" :
|
||||
"y"`). Was es nicht sein darf, ist eine Kennung -- und die
|
||||
erkennt man daran, dass sie auf `.id` endet oder schlicht
|
||||
`personId` heisst. */
|
||||
const schlecht = [];
|
||||
let gesehen = 0;
|
||||
for (const datei of readdirSync(SERVER).filter((n) => n.endsWith(".js"))) {
|
||||
const text = readFileSync(join(SERVER, datei), "utf8");
|
||||
for (const m of text.matchAll(/\bprotokolliere\(\s*([^,)]{1,60})/g)) {
|
||||
const erstes = m[1].trim();
|
||||
if (erstes.startsWith("aktion")) continue; // die Erklaerung selbst
|
||||
gesehen++;
|
||||
if (/\.id\s*$/.test(erstes) || /^personId$/.test(erstes)
|
||||
|| /^\d/.test(erstes)) {
|
||||
const zeile = text.slice(0, m.index).split("\n").length;
|
||||
schlecht.push(`${datei}:${zeile} -> ${erstes}`);
|
||||
}
|
||||
}
|
||||
}
|
||||
ok(gesehen > 60, `${gesehen} Protokollaufrufe im Haus gefunden`);
|
||||
ok(schlecht.length === 0,
|
||||
schlecht.length
|
||||
? `FALSCH HERUM: ${schlecht.slice(0, 6).join(" | ")}`
|
||||
: "alle rufen die Aktion zuerst");
|
||||
|
||||
/* GEGENPROBE: Kann die Pruefung „nein" sagen? Ohne sie waere sie
|
||||
eine, die immer bestaetigt -- und die bestaetigt nichts. */
|
||||
const probe = 'protokolliere(req.person.id, "test", "x");';
|
||||
const trifft = [...probe.matchAll(/\bprotokolliere\(\s*([^,)]{1,60})/g)]
|
||||
.some((m) => /\.id\s*$/.test(m[1].trim()));
|
||||
ok(trifft, "Gegenprobe: ein falsch herum gebauter Aufruf wird erkannt");
|
||||
const gut = 'protokolliere("test", { personId: req.person.id });';
|
||||
const trifftNicht = [...gut.matchAll(/\bprotokolliere\(\s*([^,)]{1,60})/g)]
|
||||
.some((m) => /\.id\s*$/.test(m[1].trim()));
|
||||
ok(!trifftNicht, "Gegenprobe: ein richtiger Aufruf schlaegt nicht an");
|
||||
}
|
||||
|
||||
/* ---------- Gegenprobe --------------------------------------------------- */
|
||||
|
||||
console.log(`\n=== Gegenprobe (muss anschlagen) ===`);
|
||||
|
||||
@@ -114,6 +114,21 @@ export const TEMPI = [0.5, 0.75, 1, 1.25, 1.5, 2];
|
||||
* waere eine Sperre ohne all das. */
|
||||
export const STUMM_MAX_MINUTEN = 60;
|
||||
|
||||
/** So lange bleibt eine erledigte Meldung stehen.
|
||||
*
|
||||
* DREISSIG TAGE, UND NICHT LAENGER. Eine Meldung enthaelt drei
|
||||
* Dinge, die zusammen empfindlich sind: was jemand geschrieben hat,
|
||||
* wer es war und wer ihn gemeldet hat. Solange dieselbe Sendung
|
||||
* laeuft, ist das die Arbeitsgrundlage der Moderation; danach ist es
|
||||
* eine Liste darueber, wer sich mal danebenbenommen hat -- und wer
|
||||
* das gemeldet hat.
|
||||
*
|
||||
* Meistens sind sie ohnehin frueher weg: Der Live-Chat wird beim
|
||||
* Beenden der Sendung geloescht, und die Meldungen haengen mit
|
||||
* `ON DELETE CASCADE` daran. Diese Frist greift nur fuer den Fall,
|
||||
* dass eine Sendung nie ordentlich beendet wurde. */
|
||||
export const MELDUNG_TAGE = 30;
|
||||
|
||||
/** Die zwei kurzen Massnahmen der Sendung. */
|
||||
export const MASSNAHMEN = ["stumm", "raus"];
|
||||
|
||||
|
||||
@@ -64,6 +64,55 @@ export const BETRAG_MAX_CENT = 500000;
|
||||
export const NAME_MAX = 40;
|
||||
export const GRUSS_MAX = 200;
|
||||
|
||||
/** Die mitgelieferten Zeichnungen.
|
||||
*
|
||||
* DIESE LISTE IST DIE WAHRHEIT -- `spendenkarte.js` hat dieselben
|
||||
* Namen, und eine Pruefung haelt beide aneinander. Ein Name, den
|
||||
* nur eine Seite kennt, waere eine Vorlage, die sich auswaehlen
|
||||
* laesst und dann als Herz erscheint. */
|
||||
export const VORLAGEN = ["herz", "welle", "krone", "stern", "pfote"];
|
||||
|
||||
/** So viele Stufen hoechstens.
|
||||
*
|
||||
* Sechs. Bei sieben merkt sich niemand mehr, was welche bedeutet --
|
||||
* und eine Stufenleiter, die man nicht im Kopf hat, ist keine
|
||||
* Belohnung, sondern eine Preisliste. */
|
||||
export const STUFEN_MAX = 6;
|
||||
|
||||
/** Wie lange eine Karte stehen darf. */
|
||||
export const DAUER_MS_MIN = 2000;
|
||||
export const DAUER_MS_MAX = 30000;
|
||||
|
||||
/** Wie gross eine Karte werden darf (Faktor auf die Grundgroesse).
|
||||
*
|
||||
* Filipe: „auch so dass ich das anders gestalten kann oder die
|
||||
* groesse veraendern kann."
|
||||
*
|
||||
* JE STUFE UND NICHT EINMAL FUER ALLE. Genau darin steckt „spezielle
|
||||
* sachen bei speziellen spenden": Eine Rudel-Legende darf GROESSER
|
||||
* dastehen als ein Danke. Eine einzige Groesse fuer alle waere
|
||||
* wieder die Preisliste.
|
||||
*
|
||||
* WARUM ES NUR NACH OBEN GEHT. Die Karte ist bereits auf die
|
||||
* Untergrenze des Hauses gebaut: Das kleinste Wort darauf steht bei
|
||||
* 0,72rem, also 11,52 Pixel, und 11,5 ist die Grenze, unter die
|
||||
* nichts in diesem Haus faellt (pruef-css-klassen misst das). Ein
|
||||
* Faktor von 0,8 machte daraus 9,2 Pixel -- ein Dank, den man nicht
|
||||
* mehr lesen kann, ist keiner.
|
||||
*
|
||||
* KLEINER GEHT TROTZDEM -- aber an der richtigen Stelle: Die
|
||||
* OBS-Tafel hat ihren eigenen Regler in der Adresse (`&g=`, 0,5 bis
|
||||
* 4). Dort ist es eine Videoeinblendung und kein Text zum Lesen,
|
||||
* und dort entscheidet ohnehin die Groesse des Streams.
|
||||
*
|
||||
* Die Obergrenze ist gemessen: Ueber 2,5 passt die Karte auf 1080
|
||||
* Pixel Hoehe nicht mehr neben den Chat. */
|
||||
export const GROESSE_MIN = 1;
|
||||
export const GROESSE_MAX = 2.5;
|
||||
|
||||
/** Wie gross ein hochgeladenes Bild sein darf. */
|
||||
export const BILD_MAX_BYTES = 3 * 1024 * 1024;
|
||||
|
||||
/** Die Stufen, die es ab Werk gibt — „paar fertige" aus Filipes
|
||||
* Ansage. Sie stehen hier und nicht in der Datenbank, damit ein
|
||||
* frisches Haus sofort etwas anzuzeigen hat; geaendert werden sie
|
||||
@@ -74,9 +123,9 @@ export const GRUSS_MAX = 200;
|
||||
* richtig grosse Danke. Drei Stufen, nicht sieben — bei sieben
|
||||
* merkt sich niemand mehr, was welche bedeutet. */
|
||||
export const STUFEN_START = [
|
||||
{ ab_cent: 100, name: "Danke", vorlage: "herz", farbe: "#8ec9ff", dauer_ms: 6000 },
|
||||
{ ab_cent: 500, name: "Starke Runde", vorlage: "welle", farbe: "#a98bff", dauer_ms: 8000 },
|
||||
{ ab_cent: 2000, name: "Rudel-Legende", vorlage: "krone", farbe: "#e0a13a", dauer_ms: 11000 },
|
||||
{ ab_cent: 100, name: "Danke", vorlage: "herz", farbe: "#8ec9ff", dauer_ms: 6000, groesse: 1 },
|
||||
{ ab_cent: 500, name: "Starke Runde", vorlage: "welle", farbe: "#a98bff", dauer_ms: 8000, groesse: 1.15 },
|
||||
{ ab_cent: 2000, name: "Rudel-Legende", vorlage: "krone", farbe: "#e0a13a", dauer_ms: 11000, groesse: 1.45 },
|
||||
];
|
||||
|
||||
/** Die Betraege, die als Knopf angeboten werden (in Cent).
|
||||
@@ -147,6 +196,16 @@ export function spendenTabellen(d) {
|
||||
);
|
||||
`);
|
||||
|
||||
/* ==== NACHGEWACHSEN: DIE GROESSE ================================
|
||||
`ALTER TABLE ... ADD COLUMN` und nicht „Tabelle neu bauen": Am
|
||||
11.09.2026 hat genau dieses Umkopieren an anderer Stelle drei
|
||||
Spalten mit Inhalt verschluckt, ohne Fehlermeldung. */
|
||||
const da = new Set(d.prepare("PRAGMA table_info(spenden_stufen)").all().map((z) => z.name));
|
||||
if (!da.has("groesse")) {
|
||||
d.exec("ALTER TABLE spenden_stufen ADD COLUMN groesse REAL NOT NULL DEFAULT 1");
|
||||
console.log("[spenden] Spalte groesse angelegt.");
|
||||
}
|
||||
|
||||
/* DIE DREI STUFEN ANLEGEN, WENN ES NOCH KEINE GIBT.
|
||||
|
||||
`INSERT OR IGNORE` je Zeile und nicht „erst zaehlen, dann
|
||||
@@ -155,8 +214,8 @@ export function spendenTabellen(d) {
|
||||
const nun = new Date().toISOString();
|
||||
for (const s of STUFEN_START) {
|
||||
d.prepare(`INSERT OR IGNORE INTO spenden_stufen
|
||||
(ab_cent, name, vorlage, farbe, dauer_ms, geaendert)
|
||||
VALUES (?,?,?,?,?,?)`)
|
||||
.run(s.ab_cent, s.name, s.vorlage, s.farbe, s.dauer_ms, nun);
|
||||
(ab_cent, name, vorlage, farbe, dauer_ms, groesse, geaendert)
|
||||
VALUES (?,?,?,?,?,?,?)`)
|
||||
.run(s.ab_cent, s.name, s.vorlage, s.farbe, s.dauer_ms, s.groesse, nun);
|
||||
}
|
||||
}
|
||||
|
||||
@@ -48,7 +48,7 @@ import { supportAufraeumen } from "./workspace-support.js";
|
||||
import { notizenAufraeumen } from "./workspace-notizen.js";
|
||||
import { reaktionAufraeumen } from "./workspace-reaktion.js";
|
||||
import { spendenAufraeumen } from "./workspace-spenden.js";
|
||||
import { VERLAUF_TAGE } from "./reaktion-tabellen.js";
|
||||
import { VERLAUF_TAGE, MELDUNG_TAGE } from "./reaktion-tabellen.js";
|
||||
import { SPENDEN_TAGE } from "./spenden-tabellen.js";
|
||||
import { PAPIERKORB_TAGE as NOTIZ_TAGE } from "./notiz-tabellen.js";
|
||||
import { ZAEHLUNG_TAGE } from "./unterstuetzung-tabellen.js";
|
||||
@@ -344,6 +344,26 @@ export const FRISTEN = [
|
||||
vorTagen(VERLAUF_TAGE)),
|
||||
raeumen: () => reaktionAufraeumen(),
|
||||
},
|
||||
{
|
||||
schluessel: "reaktion_meldungen",
|
||||
was: "Gemeldete Chat-Beiträge einer Sendung",
|
||||
art: "raeumen",
|
||||
frist: `${MELDUNG_TAGE} Tage nach dem Erledigen`,
|
||||
zweck: "Die Moderation muss während einer Sendung sehen, was gemeldet "
|
||||
+ "wurde – und hinterher nachvollziehen können, was sie entschieden hat.",
|
||||
grundlage: "Art. 6 Abs. 1 lit. f DSGVO – berechtigtes Interesse "
|
||||
+ "(ein Chat, in dem sich alle benehmen)",
|
||||
wirkung: "Die Zeile verschwindet: der gemeldete Beitrag, wer gemeldet hat "
|
||||
+ "und wer es erledigt hat. Meistens ist sie ohnehin früher weg – der "
|
||||
+ "Live-Chat wird beim Beenden der Sendung gelöscht, und die Meldungen "
|
||||
+ "hängen daran. Wer gemeldet hat, muss sich darauf verlassen können, "
|
||||
+ "dass daraus keine dauerhafte Liste wird.",
|
||||
offen: (d) => zaehle(d,
|
||||
"SELECT COUNT(*) AS n FROM reaktion_meldungen WHERE erledigt_am IS NOT NULL"
|
||||
+ " AND erledigt_am < ?",
|
||||
vorTagen(MELDUNG_TAGE)),
|
||||
raeumen: () => reaktionAufraeumen(),
|
||||
},
|
||||
{
|
||||
schluessel: "spenden",
|
||||
was: "Spenden und ihre Karten",
|
||||
|
||||
@@ -54,7 +54,11 @@
|
||||
===================================================================== */
|
||||
import express from "express";
|
||||
import { randomBytes, timingSafeEqual } from "node:crypto";
|
||||
import { db, sitzungLesen, einstellung, einstellungSetzen, protokolliere, echteIp } from "./workspace.js";
|
||||
import { join } from "node:path";
|
||||
import { existsSync, createReadStream } from "node:fs";
|
||||
import {
|
||||
db, sitzungLesen, einstellung, einstellungSetzen, protokolliere, echteIp, DATEN_ORDNER,
|
||||
} from "./workspace.js";
|
||||
|
||||
export const buehneRouter = express.Router();
|
||||
|
||||
@@ -127,6 +131,51 @@ export function buehneQuellen() {
|
||||
DIE WEGE
|
||||
====================================================================== */
|
||||
|
||||
/* ==== DAS BILD EINER SPENDENSTUFE ==================================
|
||||
|
||||
Es haengt HIER und nicht am Spenden-Router, und dafuer gibt es
|
||||
genau einen Grund: Die Spendentafel in OBS hat KEINE Anmeldung.
|
||||
Am Spenden-Router steht eine Schranke ueber allem, und ein 401 als
|
||||
JSON in einem `<img>` ergibt ein kaputtes Bild ohne jeden Hinweis.
|
||||
Dieselbe Ueberlegung wie beim Profilbild, das deshalb auch vor dem
|
||||
Aufgaben-Router haengt.
|
||||
|
||||
OHNE SCHLUESSEL -- UND WARUM DAS VERTRETBAR IST. Der Dateiname
|
||||
sind 32 zufaellige Zeichen aus `randomBytes(16)`, also 128 Bit. Das
|
||||
ist dieselbe Groessenordnung wie der Buehnenschluessel selbst. Und
|
||||
der Gegenstand ist ein Zierbild, das Filipe fuer seinen Stream
|
||||
hochlaedt -- es steht ohnehin oeffentlich im Bild. Eine Schranke
|
||||
davor waere eine, die nur den eigenen Saal aussperrt: Der kennt
|
||||
den Buehnenschluessel naemlich nicht, den bekommt nur die Leitung.
|
||||
|
||||
DER NAME MUSS GENAU DEM MUSTER ENTSPRECHEN. Damit laesst sich kein
|
||||
Pfad verlassen, auch nicht ueber kodierte Zeichen. */
|
||||
buehneRouter.get("/workspace/api/buehne/spendenbild/:datei", (req, res) => {
|
||||
try {
|
||||
const name = String(req.params.datei);
|
||||
if (!/^[a-f0-9]{32}\.(jpg|png|webp)$/.test(name)) return res.status(404).end();
|
||||
const pfad = join(DATEN_ORDNER, "spendenbilder", name);
|
||||
if (!existsSync(pfad)) return res.status(404).end();
|
||||
res.setHeader("Content-Type", name.endsWith(".jpg") ? "image/jpeg"
|
||||
: name.endsWith(".png") ? "image/png" : "image/webp");
|
||||
res.setHeader("X-Content-Type-Options", "nosniff");
|
||||
/* Alles verbietende Inhaltsregel: Selbst wenn eine Datei jemals
|
||||
durchkaeme, die der Browser als etwas anderes liest, darf sie
|
||||
nichts nachladen und nichts ausfuehren. */
|
||||
res.setHeader("Content-Security-Policy", "default-src 'none'; sandbox");
|
||||
/* Der Name ist zufaellig und aendert sich bei jedem neuen Bild --
|
||||
er darf lange zwischengespeichert werden. Das ist hier mehr als
|
||||
Sparsamkeit: Eine OBS-Quelle laeuft stundenlang, und ein Bild,
|
||||
das bei jeder Karte neu geladen wird, erscheint beim ersten Mal
|
||||
mit einer Verzoegerung mitten in der Einblendung. */
|
||||
res.setHeader("Cache-Control", "public, max-age=604800, immutable");
|
||||
createReadStream(pfad).pipe(res);
|
||||
} catch (fehler) {
|
||||
console.error("[buehne] Spendenbild:", fehler?.message);
|
||||
res.status(404).end();
|
||||
}
|
||||
});
|
||||
|
||||
/** Was gerade laeuft. Ein einziger Aufruf beim Start der Quelle. */
|
||||
buehneRouter.get("/workspace/api/buehne/lage", mitSchluessel, (req, res) => {
|
||||
try {
|
||||
@@ -215,7 +264,11 @@ buehneRouter.post("/workspace/api/buehne/schluessel", nurLeitung, (req, res) =>
|
||||
try {
|
||||
const neu = randomBytes(32).toString("hex");
|
||||
einstellungSetzen(SCHLUESSEL_NAME, neu, req.person);
|
||||
protokolliere(req.person.id, "buehne_schluessel", "neu erzeugt", echteIp(req));
|
||||
protokolliere("buehne_schluessel", {
|
||||
personId: req.person.id,
|
||||
detail: "neu erzeugt",
|
||||
ip: echteIp(req),
|
||||
});
|
||||
/* DIE ALTEN QUELLEN WERDEN GESCHLOSSEN. Sonst liefe eine Quelle
|
||||
mit dem alten Schluessel weiter, obwohl er zurueckgezogen ist
|
||||
-- und man haelt sich fuer sicher, ohne es zu sein. */
|
||||
|
||||
@@ -221,7 +221,7 @@ hilfeRouter.post("/workspace/api/hilfe", express.json(), (req, res) => {
|
||||
|
||||
/* IM PROTOKOLL STEHT NUR, DASS ES EINEN FALL GIBT -- nicht, worum
|
||||
es geht. Das Protokoll lesen mehr Leute als den Fall. */
|
||||
protokolliere(req.person.id, "hilfe_fall_neu", `Fall ${id}`);
|
||||
protokolliere("hilfe_fall_neu", { personId: req.person.id, detail: `Fall ${id}` });
|
||||
leitungBenachrichtigen(id, betreff).catch(() => { /* Push ist Zugabe */ });
|
||||
|
||||
res.status(201).json({ id });
|
||||
@@ -297,7 +297,7 @@ hilfeRouter.post("/workspace/api/hilfe/:id(\\d+)/schliessen", express.json(), (r
|
||||
+ " geschlossen_am = ?, geschlossen_von = ? WHERE id = ?")
|
||||
.run(FALL_STAND.zu, t, t, req.person.id, fall.id);
|
||||
|
||||
protokolliere(req.person.id, "hilfe_fall_zu", `Fall ${fall.id}`);
|
||||
protokolliere("hilfe_fall_zu", { personId: req.person.id, detail: `Fall ${fall.id}` });
|
||||
schlussBenachrichtigen(fall).catch(() => { /* Zugabe */ });
|
||||
res.json({ ok: true });
|
||||
} catch (fehler) {
|
||||
|
||||
@@ -395,8 +395,11 @@ materialRouter.post(
|
||||
sonst keinen Beleg. Genau deshalb steht das Haus hier. */
|
||||
req.person.haus || null);
|
||||
|
||||
protokolliere(req.person.id, "material_eingestellt",
|
||||
`${art} "${name}" (${req.body.length} Bytes)`, echteIp(req));
|
||||
protokolliere("material_eingestellt", {
|
||||
personId: req.person.id,
|
||||
detail: `${art} "${name}" (${req.body.length} Bytes)`,
|
||||
ip: echteIp(req),
|
||||
});
|
||||
res.status(201).json({ id: Number(lastInsertRowid) });
|
||||
} catch (f) {
|
||||
console.error("[material] Einstellen:", f?.message);
|
||||
@@ -437,7 +440,11 @@ materialRouter.post("/workspace/api/material/:id/nehmen", (req, res) => {
|
||||
});
|
||||
}
|
||||
|
||||
protokolliere(req.person.id, "material_genommen", `Dogi-Media ${id}`, echteIp(req));
|
||||
protokolliere("material_genommen", {
|
||||
personId: req.person.id,
|
||||
detail: `Dogi-Media ${id}`,
|
||||
ip: echteIp(req),
|
||||
});
|
||||
res.json({ ok: true, weg: `/workspace/api/material/${id}/datei` });
|
||||
} catch (f) {
|
||||
console.error("[material] Nehmen:", f?.message);
|
||||
@@ -566,7 +573,11 @@ materialRouter.patch("/workspace/api/material/:id", express.json({ limit: "32kb"
|
||||
|
||||
db().prepare("UPDATE material SET text = ?, gilt_ab = ?, gilt_bis = ? WHERE id = ?")
|
||||
.run(text, ab, bis, id);
|
||||
protokolliere(req.person.id, "material_geaendert", `Dogi-Media ${id}`, echteIp(req));
|
||||
protokolliere("material_geaendert", {
|
||||
personId: req.person.id,
|
||||
detail: `Dogi-Media ${id}`,
|
||||
ip: echteIp(req),
|
||||
});
|
||||
res.json({ ok: true, id, text, gilt_ab: ab, gilt_bis: bis,
|
||||
zustand: zustandVon({ ...z, gilt_ab: ab, gilt_bis: bis }, tagLokal(0)) });
|
||||
} catch (f) {
|
||||
@@ -589,7 +600,11 @@ materialRouter.delete("/workspace/api/material/:id", (req, res) => {
|
||||
}
|
||||
db().prepare("DELETE FROM material WHERE id = ?").run(id);
|
||||
try { unlinkSync(join(ORDNER, z.datei)); } catch { /* schon weg */ }
|
||||
protokolliere(req.person.id, "material_entfernt", `Dogi-Media ${id}`, echteIp(req));
|
||||
protokolliere("material_entfernt", {
|
||||
personId: req.person.id,
|
||||
detail: `Dogi-Media ${id}`,
|
||||
ip: echteIp(req),
|
||||
});
|
||||
res.json({ ok: true });
|
||||
} catch (f) {
|
||||
console.error("[material] Entfernen:", f?.message);
|
||||
|
||||
@@ -48,6 +48,7 @@ import { einstellung } from "./workspace.js";
|
||||
import { mitZugangsdaten, wegeAusfaechern } from "./workspace-turn.js";
|
||||
import {
|
||||
SICHT_PLAETZE, GAESTE_MAX, TEXT_MAX, SCHREIB_BREMSE, STAENDE, LAYOUTS, TEMPI,
|
||||
MELDUNG_TAGE,
|
||||
VERLAUF_TAGE, LISTE_MAX, CHAT_MODI, STUMM_MAX_MINUTEN, MASSNAHMEN,
|
||||
} from "./reaktion-tabellen.js";
|
||||
/* DIE SPERREN DES TREFFS GELTEN AUCH HIER. Ein zweites System
|
||||
@@ -189,7 +190,7 @@ function weiterZu(zeile, personId) {
|
||||
+ " sekunde = 0, geaendert = ? WHERE id = 1")
|
||||
.run(zeile.video, zeile.titel, jetzt());
|
||||
db().prepare("DELETE FROM reaktion_liste WHERE id = ?").run(zeile.id);
|
||||
protokolliere(personId, "reaktion_weiter", zeile.video, "");
|
||||
protokolliere("reaktion_weiter", { personId, detail: zeile.video });
|
||||
const s = sendung();
|
||||
/* ZWEI MELDUNGEN, UND BEIDE WERDEN GEBRAUCHT.
|
||||
|
||||
@@ -552,7 +553,11 @@ reaktionRouter.post("/workspace/api/reaktion/stand", nurHost, express.json({ lim
|
||||
db().prepare(`UPDATE reaktion SET ${spalten} WHERE id = 1`)
|
||||
.run(...Object.values(felder));
|
||||
|
||||
protokolliere(req.person.id, "reaktion_stand", `${s.stand} -> ${neu}`, echteIp(req));
|
||||
protokolliere("reaktion_stand", {
|
||||
personId: req.person.id,
|
||||
detail: `${s.stand} -> ${neu}`,
|
||||
ip: echteIp(req),
|
||||
});
|
||||
const l = lage(req.person);
|
||||
melden("reaktion", { was: "stand", lage: oeffentlich(l) });
|
||||
res.json(l);
|
||||
@@ -686,7 +691,11 @@ reaktionRouter.post("/workspace/api/reaktion/gast", nurHost, express.json({ limi
|
||||
|
||||
db().prepare("INSERT OR REPLACE INTO reaktion_gaeste (person_id, seit, stumm, platz) VALUES (?,?,0,?)")
|
||||
.run(id, jetzt(), platz);
|
||||
protokolliere(req.person.id, "reaktion_gast_dazu", `${p.name} (Platz ${platz})`, echteIp(req));
|
||||
protokolliere("reaktion_gast_dazu", {
|
||||
personId: req.person.id,
|
||||
detail: `${p.name} (Platz ${platz})`,
|
||||
ip: echteIp(req),
|
||||
});
|
||||
const l = lage(req.person);
|
||||
melden("reaktion", { was: "gaeste", lage: oeffentlich(l) });
|
||||
stromAn([id], "reaktion", { was: "du_bist_gast", lage: oeffentlich(l) });
|
||||
@@ -1096,8 +1105,11 @@ reaktionRouter.post("/workspace/api/reaktion/massnahme", express.json({ limit: "
|
||||
db().prepare("DELETE FROM reaktion_gaeste WHERE person_id = ?").run(ziel.id);
|
||||
}
|
||||
|
||||
protokolliere(req.person.id, "reaktion_massnahme",
|
||||
`${art} gegen ${ziel.name}${bis ? ` bis ${bis.slice(11, 16)}` : ""}`, echteIp(req));
|
||||
protokolliere("reaktion_massnahme", {
|
||||
personId: req.person.id,
|
||||
detail: `${art} gegen ${ziel.name}${bis ? ` bis ${bis.slice(11, 16)}` : ""}`,
|
||||
ip: echteIp(req),
|
||||
});
|
||||
|
||||
/* DIE PERSON ERFAEHRT ES SELBST -- und zwar sofort. Wer nicht
|
||||
mehr schreiben kann und nicht weiss warum, sucht den Fehler
|
||||
@@ -1236,7 +1248,11 @@ reaktionRouter.post("/workspace/api/reaktion/chatmodus", nurHost, express.json({
|
||||
const modus = String(req.body?.modus ?? "");
|
||||
if (!CHAT_MODI.includes(modus)) return res.status(400).json({ fehler: "chatmodus_unbekannt" });
|
||||
db().prepare("UPDATE reaktion SET chat_modus = ? WHERE id = 1").run(modus);
|
||||
protokolliere(req.person.id, "reaktion_chatmodus", modus, echteIp(req));
|
||||
protokolliere("reaktion_chatmodus", {
|
||||
personId: req.person.id,
|
||||
detail: modus,
|
||||
ip: echteIp(req),
|
||||
});
|
||||
const l = lage(req.person);
|
||||
melden("reaktion", { was: "chatmodus", lage: oeffentlich(l) });
|
||||
res.json(l);
|
||||
@@ -1320,7 +1336,11 @@ reaktionRouter.delete("/workspace/api/reaktion/chat/:id", (req, res) => {
|
||||
db().prepare("UPDATE reaktion_chat SET weg_am = ?, weg_von = ? WHERE id = ?")
|
||||
.run(jetzt(), req.person.id, id);
|
||||
if (!eigen) {
|
||||
protokolliere(req.person.id, "reaktion_chat_weg", `Beitrag ${id} von ${b.name}`, echteIp(req));
|
||||
protokolliere("reaktion_chat_weg", {
|
||||
personId: req.person.id,
|
||||
detail: `Beitrag ${id} von ${b.name}`,
|
||||
ip: echteIp(req),
|
||||
});
|
||||
}
|
||||
melden("reaktion_chat", { was: "weg", id });
|
||||
res.json({ ok: true });
|
||||
@@ -1424,8 +1444,20 @@ export function reaktionAufraeumen() {
|
||||
const a = db().prepare("DELETE FROM reaktion_verlauf WHERE beendet < ?").run(grenze);
|
||||
const b = db().prepare("DELETE FROM reaktion_dabei WHERE gesehen < ?")
|
||||
.run(new Date(Date.now() - 600_000).toISOString());
|
||||
if (a.changes || b.changes) {
|
||||
console.log(`[reaktion] Aufgeraeumt: ${a.changes} Verlauf, ${b.changes} Zusehende.`);
|
||||
/* ERLEDIGTE MELDUNGEN. Meistens sind sie schon mit dem Chat
|
||||
verschwunden (CASCADE); das hier greift, wenn eine Sendung nie
|
||||
ordentlich beendet wurde. */
|
||||
const c = db().prepare("DELETE FROM reaktion_meldungen WHERE erledigt_am IS NOT NULL"
|
||||
+ " AND erledigt_am < ?")
|
||||
.run(new Date(Date.now() - MELDUNG_TAGE * 86400_000).toISOString());
|
||||
/* Und abgelaufene Massnahmen -- sie enden ohnehin mit der
|
||||
Sendung, aber eine Zeile, die niemand mehr wegraeumt, bleibt
|
||||
sonst fuer immer stehen. */
|
||||
const e = db().prepare("DELETE FROM reaktion_massnahmen WHERE bis IS NOT NULL AND bis < ?")
|
||||
.run(jetzt());
|
||||
if (a.changes || b.changes || c.changes || e.changes) {
|
||||
console.log(`[reaktion] Aufgeraeumt: ${a.changes} Verlauf, ${b.changes} Zusehende, `
|
||||
+ `${c.changes} Meldungen, ${e.changes} Massnahmen.`);
|
||||
}
|
||||
} catch (fehler) {
|
||||
console.error("[reaktion] Aufraeumen:", fehler?.message);
|
||||
|
||||
+327
-5
@@ -34,10 +34,18 @@ import express from "express";
|
||||
import { db, sitzungLesen, protokolliere, echteIp } from "./workspace.js";
|
||||
import { stromAn } from "./workspace-chat.js";
|
||||
import { buehneMelden } from "./workspace-buehne.js";
|
||||
import { join } from "node:path";
|
||||
import { mkdirSync, writeFileSync, unlinkSync } from "node:fs";
|
||||
import { randomBytes } from "node:crypto";
|
||||
import { DATEN_ORDNER } from "./workspace.js";
|
||||
import {
|
||||
BETRAG_MAX_CENT, NAME_MAX, GRUSS_MAX, BETRAG_KNOEPFE, SPENDEN_TAGE,
|
||||
VORLAGEN, STUFEN_MAX, DAUER_MS_MIN, DAUER_MS_MAX,
|
||||
GROESSE_MIN, GROESSE_MAX, BILD_MAX_BYTES,
|
||||
} from "./spenden-tabellen.js";
|
||||
|
||||
const BILDER = join(DATEN_ORDNER, "spendenbilder");
|
||||
|
||||
export const spendenRouter = express.Router();
|
||||
|
||||
/** Wer eine Spende bestaetigen, eintragen oder ablehnen darf.
|
||||
@@ -152,12 +160,22 @@ function alsKarte(z) {
|
||||
stand: z.stand,
|
||||
erstellt: z.erstellt,
|
||||
stufe: st ? {
|
||||
name: st.name, vorlage: st.vorlage, bild: st.bild,
|
||||
name: st.name, vorlage: st.vorlage, bild: bildAdresse(st.bild),
|
||||
farbe: st.farbe, dauer_ms: st.dauer_ms,
|
||||
groesse: Number(st.groesse) || 1,
|
||||
} : null,
|
||||
};
|
||||
}
|
||||
|
||||
/** Aus dem Dateinamen wird eine Adresse -- oder nichts.
|
||||
*
|
||||
* Die Adresse zeigt auf den Buehnen-Router und NICHT hierher: Die
|
||||
* Spendentafel in OBS hat keine Anmeldung, und an diesem Router
|
||||
* steht eine Schranke ueber allem. */
|
||||
function bildAdresse(datei) {
|
||||
return datei ? `/workspace/api/buehne/spendenbild/${datei}` : "";
|
||||
}
|
||||
|
||||
/** Eine bestaetigte Spende ins Bild schicken. */
|
||||
function zeigen(z) {
|
||||
db().prepare("UPDATE spenden SET gezeigt_am = ? WHERE id = ?").run(jetzt(), z.id);
|
||||
@@ -185,8 +203,20 @@ spendenRouter.get("/workspace/api/spenden", (req, res) => {
|
||||
res.json({
|
||||
paypal: pp ? { ziel: pp.ziel, knopf: pp.knopf } : null,
|
||||
knoepfe,
|
||||
stufen: db().prepare("SELECT ab_cent, name, vorlage, bild, farbe, dauer_ms"
|
||||
+ " FROM spenden_stufen ORDER BY ab_cent").all(),
|
||||
stufen: db().prepare("SELECT id, ab_cent, name, vorlage, bild, farbe, dauer_ms,"
|
||||
+ " groesse FROM spenden_stufen ORDER BY ab_cent").all()
|
||||
.map((z) => ({ ...z, bild: bildAdresse(z.bild), groesse: Number(z.groesse) || 1 })),
|
||||
/* WAS SICH EINSTELLEN LAESST, KOMMT VOM SERVER. Stuenden die
|
||||
Vorlagennamen und die Grenzen auch in der Oberflaeche, waeren
|
||||
es zwei Listen -- und die eine liefe irgendwann von der
|
||||
anderen weg. Dann steht dort ein Knopf, den der Server
|
||||
ablehnt. */
|
||||
gestaltung: {
|
||||
vorlagen: VORLAGEN, stufen_max: STUFEN_MAX,
|
||||
dauer_min: DAUER_MS_MIN, dauer_max: DAUER_MS_MAX,
|
||||
groesse_min: GROESSE_MIN, groesse_max: GROESSE_MAX,
|
||||
bild_max_mb: Math.round(BILD_MAX_BYTES / 1024 / 1024),
|
||||
},
|
||||
betrag_max_cent: BETRAG_MAX_CENT,
|
||||
ich: { darf },
|
||||
/* Die offenen Meldungen sieht nur, wer sie bestaetigen kann.
|
||||
@@ -267,7 +297,11 @@ spendenRouter.post("/workspace/api/spenden", nurGeld, express.json({ limit: "4kb
|
||||
.run(cent, "EUR", name, gruss, jetzt(), jetzt(), req.person.id);
|
||||
|
||||
const z = db().prepare("SELECT * FROM spenden WHERE id = ?").get(Number(lastInsertRowid));
|
||||
protokolliere(req.person.id, "spende_hand", `${cent} Cent von ${name}`, echteIp(req));
|
||||
protokolliere("spende_hand", {
|
||||
personId: req.person.id,
|
||||
detail: `${cent} Cent von ${name}`,
|
||||
ip: echteIp(req),
|
||||
});
|
||||
zeigen(z);
|
||||
res.status(201).json(alsKarte(z));
|
||||
} catch (fehler) {
|
||||
@@ -300,7 +334,11 @@ spendenRouter.post("/workspace/api/spenden/:id(\\d+)/bestaetigen", nurGeld,
|
||||
bestaetigt_am = ?, bestaetigt_von = ? WHERE id = ?`)
|
||||
.run(cent, jetzt(), req.person.id, z.id);
|
||||
const neu = db().prepare("SELECT * FROM spenden WHERE id = ?").get(z.id);
|
||||
protokolliere(req.person.id, "spende_bestaetigt", `#${z.id}, ${cent} Cent`, echteIp(req));
|
||||
protokolliere("spende_bestaetigt", {
|
||||
personId: req.person.id,
|
||||
detail: `#${z.id}, ${cent} Cent`,
|
||||
ip: echteIp(req),
|
||||
});
|
||||
zeigen(neu);
|
||||
res.json(alsKarte(neu));
|
||||
} catch (fehler) {
|
||||
@@ -324,6 +362,290 @@ spendenRouter.post("/workspace/api/spenden/:id(\\d+)/ablehnen", nurGeld, (req, r
|
||||
|
||||
/** Dieselbe Karte noch einmal zeigen — fuer den Fall, dass sie
|
||||
* jemand verpasst hat oder die Technik im falschen Moment hakte. */
|
||||
/* ======================================================================
|
||||
DIE GESTALTUNG
|
||||
|
||||
Filipe: „mach paar fertige und so dass ich auch hochladen kann.
|
||||
auch so dass ich das anders gestalten kann oder die groesse
|
||||
veraendern kann. ... auch spezielle sachen bei speziellen spenden."
|
||||
|
||||
DIE GANZE LEITER AUF EINMAL UND NICHT ZEILE FUER ZEILE. Eine
|
||||
Stufenleiter ist keine Liste unabhaengiger Zeilen -- sie muss als
|
||||
Ganzes stimmen: aufsteigende Grenzen, keine zwei mit demselben
|
||||
Betrag, mindestens eine. Wer einzeln speichert, geht durch
|
||||
Zwischenzustaende, in denen sie das nicht tut, und waehrend einer
|
||||
Sendung faellt dann eine Spende in die falsche Stufe.
|
||||
====================================================================== */
|
||||
spendenRouter.put("/workspace/api/spenden/stufen", nurGeld,
|
||||
express.json({ limit: "16kb" }), (req, res) => {
|
||||
try {
|
||||
const roh = Array.isArray(req.body?.stufen) ? req.body.stufen : null;
|
||||
if (!roh) return res.status(400).json({ fehler: "stufen_fehlen" });
|
||||
if (!roh.length) return res.status(400).json({ fehler: "keine_stufe" });
|
||||
if (roh.length > STUFEN_MAX) return res.status(400).json({ fehler: "zu_viele_stufen" });
|
||||
|
||||
const sauber = [];
|
||||
for (const z of roh) {
|
||||
const ab = Math.round(Number(z?.ab_cent));
|
||||
if (!Number.isFinite(ab) || ab <= 0 || ab > BETRAG_MAX_CENT) {
|
||||
return res.status(400).json({ fehler: "stufe_betrag_unklar" });
|
||||
}
|
||||
const name = String(z?.name ?? "").trim().slice(0, NAME_MAX);
|
||||
if (!name) return res.status(400).json({ fehler: "stufe_name_fehlt" });
|
||||
|
||||
const vorlage = String(z?.vorlage ?? "herz");
|
||||
if (!VORLAGEN.includes(vorlage)) {
|
||||
return res.status(400).json({ fehler: "vorlage_unbekannt" });
|
||||
}
|
||||
/* NUR ECHTE FARBWERTE. Ein freier Text landete als CSS-Wert
|
||||
in der Karte -- das ist genau die Stelle, an der aus einer
|
||||
Einstellung eine Einschleusung wird. */
|
||||
const farbe = String(z?.farbe ?? "").trim();
|
||||
if (!/^#[0-9a-fA-F]{6}$/.test(farbe)) {
|
||||
return res.status(400).json({ fehler: "farbe_unklar" });
|
||||
}
|
||||
const dauer = Math.round(Number(z?.dauer_ms));
|
||||
if (!Number.isFinite(dauer) || dauer < DAUER_MS_MIN || dauer > DAUER_MS_MAX) {
|
||||
return res.status(400).json({ fehler: "dauer_unklar" });
|
||||
}
|
||||
const groesse = Number(z?.groesse);
|
||||
if (!Number.isFinite(groesse) || groesse < GROESSE_MIN || groesse > GROESSE_MAX) {
|
||||
return res.status(400).json({ fehler: "groesse_unklar" });
|
||||
}
|
||||
sauber.push({ ab, name, vorlage, farbe, dauer, groesse, id: Number(z?.id) || 0 });
|
||||
}
|
||||
|
||||
sauber.sort((a, b2) => a.ab - b2.ab);
|
||||
for (let i = 1; i < sauber.length; i++) {
|
||||
if (sauber[i].ab === sauber[i - 1].ab) {
|
||||
return res.status(409).json({ fehler: "stufe_doppelt" });
|
||||
}
|
||||
}
|
||||
|
||||
/* ==== DIE KENNUNGEN MUESSEN DAS SPEICHERN UEBERLEBEN =======
|
||||
|
||||
Der erste Bau hat hier `DELETE` und dann `INSERT` gemacht.
|
||||
Das Ergebnis war richtig -- und trotzdem falsch: Jede Stufe
|
||||
bekam dabei eine NEUE Kennung. Gemessen ist das in der
|
||||
Pruefung aufgefallen, als ein Bild-Hochladen gegen die eben
|
||||
noch gueltige Kennung mit 404 antwortete.
|
||||
|
||||
Im Alltag heisst das: Wer die Leiter speichert und dann auf
|
||||
„Bild hochladen" drueckt, ohne dass die Seite dazwischen neu
|
||||
gezeichnet wurde, greift ins Leere. Und ein zweiter offener
|
||||
Bildschirm greift IMMER ins Leere.
|
||||
|
||||
Also: vorhandene Zeilen AENDERN, neue anlegen, entfernte
|
||||
loeschen. Dann bleibt die Kennung, und das Bild bleibt von
|
||||
selbst daran haengen -- ohne eine Landkarte, die man pflegen
|
||||
muesste. */
|
||||
const vorhanden = db().prepare("SELECT id, bild FROM spenden_stufen").all();
|
||||
const kenneIch = new Set(vorhanden.map((z) => z.id));
|
||||
const behalten = new Set();
|
||||
|
||||
/* EIN SCHREIBVORGANG. `node:sqlite` kennt kein `.transaction()`,
|
||||
also von Hand -- ein Abbruch mittendrin haette eine Leiter
|
||||
zurueckgelassen, die halb die alte und halb die neue ist. */
|
||||
db().exec("BEGIN IMMEDIATE");
|
||||
try {
|
||||
/* ==== DREI SCHRITTE, UND DIE REIHENFOLGE IST DER PUNKT ====
|
||||
|
||||
`ab_cent` ist EINDEUTIG. Wer die Zeilen einfach der Reihe
|
||||
nach umschreibt, stoesst mitten im Vorgang auf sich
|
||||
selbst: Die 500er-Stufe auf 100 zu setzen scheitert,
|
||||
solange die alte 100er noch dasteht -- obwohl das ERGEBNIS
|
||||
voellig in Ordnung waere. Gemessen ist genau das passiert:
|
||||
„UNIQUE constraint failed: spenden_stufen.ab_cent", und
|
||||
der ganze Vorgang brach ab.
|
||||
|
||||
Also erst alles aus dem Weg raeumen: Was weg soll, wird
|
||||
geloescht; was bleibt, wandert kurz auf einen Betrag, den
|
||||
niemand sonst hat (eine Milliarde plus die eigene
|
||||
Kennung). Danach kann jede Zeile ihren endgueltigen Wert
|
||||
bekommen, ohne einer anderen in die Quere zu kommen.
|
||||
|
||||
Das ist nur INNERHALB des Schreibvorgangs sichtbar -- nach
|
||||
aussen gibt es diesen Zwischenzustand nie. */
|
||||
for (const z of vorhanden) {
|
||||
const bleibt = sauber.some((n) => n.id === z.id);
|
||||
if (!bleibt) db().prepare("DELETE FROM spenden_stufen WHERE id = ?").run(z.id);
|
||||
else {
|
||||
db().prepare("UPDATE spenden_stufen SET ab_cent = ? WHERE id = ?")
|
||||
.run(1000000000 + z.id, z.id);
|
||||
}
|
||||
}
|
||||
|
||||
const aendern = db().prepare(`UPDATE spenden_stufen SET
|
||||
ab_cent = ?, name = ?, vorlage = ?, farbe = ?, dauer_ms = ?,
|
||||
groesse = ?, geaendert = ? WHERE id = ?`);
|
||||
const ein = db().prepare(`INSERT INTO spenden_stufen
|
||||
(ab_cent, name, vorlage, bild, farbe, dauer_ms, groesse, geaendert)
|
||||
VALUES (?,?,?,'',?,?,?,?)`);
|
||||
for (const z of sauber) {
|
||||
if (z.id && kenneIch.has(z.id)) {
|
||||
aendern.run(z.ab, z.name, z.vorlage, z.farbe, z.dauer, z.groesse, jetzt(), z.id);
|
||||
behalten.add(z.id);
|
||||
} else {
|
||||
const { lastInsertRowid } = ein.run(
|
||||
z.ab, z.name, z.vorlage, z.farbe, z.dauer, z.groesse, jetzt());
|
||||
behalten.add(Number(lastInsertRowid));
|
||||
}
|
||||
}
|
||||
db().exec("COMMIT");
|
||||
} catch (f) {
|
||||
db().exec("ROLLBACK");
|
||||
throw f;
|
||||
}
|
||||
|
||||
/* WAS AN BILDERN UEBRIG BLEIBT, WIRD WEGGERAEUMT. Sonst
|
||||
sammelt sich bei jeder geloeschten Stufe eine Datei an, die
|
||||
niemand mehr findet und niemand mehr loescht. */
|
||||
for (const z of vorhanden) {
|
||||
if (z.bild && !behalten.has(z.id)) {
|
||||
try { unlinkSync(join(BILDER, z.bild)); } catch { /* war schon weg */ }
|
||||
}
|
||||
}
|
||||
|
||||
protokolliere("spenden_stufen", {
|
||||
personId: req.person.id,
|
||||
detail: `${sauber.length} Stufen gespeichert`,
|
||||
ip: echteIp(req),
|
||||
});
|
||||
res.json({ ok: true, stufen: stufenLesen() });
|
||||
} catch (fehler) {
|
||||
console.error("[spenden] Stufen:", fehler?.message);
|
||||
res.status(503).json({ fehler: "nicht_verfuegbar" });
|
||||
}
|
||||
});
|
||||
|
||||
function stufenLesen() {
|
||||
return db().prepare("SELECT id, ab_cent, name, vorlage, bild, farbe, dauer_ms,"
|
||||
+ " groesse FROM spenden_stufen ORDER BY ab_cent").all()
|
||||
.map((z) => ({ ...z, bild: bildAdresse(z.bild), groesse: Number(z.groesse) || 1 }));
|
||||
}
|
||||
|
||||
/** Woran man ein Bild erkennt -- an seinem Inhalt und nicht an seinem
|
||||
* Namen. Eine Datei „katze.png", die etwas anderes enthaelt, waere
|
||||
* sonst ein Bild, das der Browser als etwas anderes liest. */
|
||||
function bildart(puffer) {
|
||||
if (!puffer || puffer.length < 12) return null;
|
||||
if (puffer[0] === 0xff && puffer[1] === 0xd8 && puffer[2] === 0xff) return "jpg";
|
||||
if (puffer[0] === 0x89 && puffer[1] === 0x50 && puffer[2] === 0x4e && puffer[3] === 0x47) {
|
||||
return "png";
|
||||
}
|
||||
if (puffer.toString("ascii", 0, 4) === "RIFF" && puffer.toString("ascii", 8, 12) === "WEBP") {
|
||||
return "webp";
|
||||
}
|
||||
return null;
|
||||
}
|
||||
|
||||
/* Ein zu grosses Bild ist kein Serverfehler, sondern eine ganz
|
||||
normale Eingabe -- und der Absender soll erfahren, WAS zu tun ist.
|
||||
Ohne diese Stelle laeuft der Fehler von express.raw() bis in die
|
||||
allgemeine Behandlung durch und kommt als „500 Serverfehler" an. */
|
||||
function zuGross(fehler, req, res, next) {
|
||||
if (fehler?.type === "entity.too.large") {
|
||||
return res.status(413).json({ fehler: "bild_zu_gross" });
|
||||
}
|
||||
return next(fehler);
|
||||
}
|
||||
|
||||
spendenRouter.post("/workspace/api/spenden/stufe/:id(\\d+)/bild", nurGeld,
|
||||
express.raw({ type: "*/*", limit: BILD_MAX_BYTES }), zuGross, (req, res) => {
|
||||
try {
|
||||
const id = Number(req.params.id);
|
||||
const stufe = db().prepare("SELECT id, bild FROM spenden_stufen WHERE id = ?").get(id);
|
||||
if (!stufe) return res.status(404).json({ fehler: "nicht_gefunden" });
|
||||
|
||||
const endung = bildart(req.body);
|
||||
if (!endung) return res.status(400).json({ fehler: "kein_bild" });
|
||||
|
||||
mkdirSync(BILDER, { recursive: true });
|
||||
const name = `${randomBytes(16).toString("hex")}.${endung}`;
|
||||
writeFileSync(join(BILDER, name), req.body);
|
||||
|
||||
db().prepare("UPDATE spenden_stufen SET bild = ?, geaendert = ? WHERE id = ?")
|
||||
.run(name, jetzt(), id);
|
||||
/* Das alte wegraeumen -- sonst bleibt bei jedem Wechsel eine
|
||||
Datei liegen, die niemand mehr findet. */
|
||||
if (stufe.bild && stufe.bild !== name) {
|
||||
try { unlinkSync(join(BILDER, stufe.bild)); } catch { /* war schon weg */ }
|
||||
}
|
||||
protokolliere("spenden_bild", {
|
||||
personId: req.person.id,
|
||||
detail: `Stufe ${id}, ${Math.round(req.body.length / 1024)} KB`,
|
||||
ip: echteIp(req),
|
||||
});
|
||||
res.json({ ok: true, bild: bildAdresse(name), stufen: stufenLesen() });
|
||||
} catch (fehler) {
|
||||
console.error("[spenden] Bild:", fehler?.message);
|
||||
res.status(503).json({ fehler: "nicht_verfuegbar" });
|
||||
}
|
||||
});
|
||||
|
||||
spendenRouter.delete("/workspace/api/spenden/stufe/:id(\\d+)/bild", nurGeld, (req, res) => {
|
||||
try {
|
||||
const id = Number(req.params.id);
|
||||
const stufe = db().prepare("SELECT id, bild FROM spenden_stufen WHERE id = ?").get(id);
|
||||
if (!stufe) return res.status(404).json({ fehler: "nicht_gefunden" });
|
||||
db().prepare("UPDATE spenden_stufen SET bild = '', geaendert = ? WHERE id = ?")
|
||||
.run(jetzt(), id);
|
||||
if (stufe.bild) { try { unlinkSync(join(BILDER, stufe.bild)); } catch { /* war weg */ } }
|
||||
res.json({ ok: true, stufen: stufenLesen() });
|
||||
} catch (fehler) {
|
||||
console.error("[spenden] Bild loeschen:", fehler?.message);
|
||||
res.status(503).json({ fehler: "nicht_verfuegbar" });
|
||||
}
|
||||
});
|
||||
|
||||
/** Einmal ansehen, wie es aussieht -- OHNE eine Spende anzulegen.
|
||||
*
|
||||
* ==== DAS IST DER GANZE PUNKT DIESER ROUTE ==========================
|
||||
*
|
||||
* Wer eine Stufe gestaltet, will sehen, was herauskommt. Der
|
||||
* naheliegende Weg waere, eine Spende von Hand einzutragen und
|
||||
* danach zu loeschen -- und genau das ist verboten: In ein laufendes
|
||||
* System kommen keine Testdaten. „Storniert heisst nicht weg"; der
|
||||
* Eintrag stuende trotzdem im Verlauf, in der Summe und in der
|
||||
* Aufbewahrung, und bei Geld ist das nicht nur unordentlich.
|
||||
*
|
||||
* Diese Route schreibt deshalb NICHTS. Sie baut eine Karte aus den
|
||||
* aktuellen Stufen und schickt sie los. Und sie geht NUR an den,
|
||||
* der drueckt -- eine Probe, die im ganzen Saal erscheint, waere
|
||||
* eine Spende, die es nicht gab. */
|
||||
spendenRouter.post("/workspace/api/spenden/probe", nurGeld,
|
||||
express.json({ limit: "2kb" }), (req, res) => {
|
||||
try {
|
||||
const cent = Math.round(Number(req.body?.betrag_cent));
|
||||
if (!Number.isFinite(cent) || cent <= 0 || cent > BETRAG_MAX_CENT) {
|
||||
return res.status(400).json({ fehler: "betrag_unklar" });
|
||||
}
|
||||
const st = stufeFuer(cent);
|
||||
const karte = {
|
||||
id: 0,
|
||||
betrag_cent: cent,
|
||||
waehrung: "EUR",
|
||||
/* KENNTLICH ALS PROBE. Stuende hier ein Name, waere auf dem
|
||||
Bildschirmfoto nicht mehr zu unterscheiden, ob jemand
|
||||
gespendet hat. */
|
||||
name: "Probe",
|
||||
gruss: "So sieht es aus",
|
||||
herkunft: "hand",
|
||||
stand: "probe",
|
||||
erstellt: jetzt(),
|
||||
stufe: st ? {
|
||||
name: st.name, vorlage: st.vorlage, bild: bildAdresse(st.bild),
|
||||
farbe: st.farbe, dauer_ms: st.dauer_ms, groesse: Number(st.groesse) || 1,
|
||||
} : null,
|
||||
};
|
||||
stromAn([req.person.id], "spende", { was: "zeigen", karte });
|
||||
res.json({ ok: true, karte });
|
||||
} catch (fehler) {
|
||||
console.error("[spenden] Probe:", fehler?.message);
|
||||
res.status(503).json({ fehler: "nicht_verfuegbar" });
|
||||
}
|
||||
});
|
||||
|
||||
spendenRouter.post("/workspace/api/spenden/:id(\\d+)/nochmal", nurGeld, (req, res) => {
|
||||
try {
|
||||
const z = db().prepare("SELECT * FROM spenden WHERE id = ? AND stand = 'bestaetigt'")
|
||||
|
||||
@@ -16,8 +16,8 @@
|
||||
verdeckt. Gefunden hat es pruef-struktur.
|
||||
|
||||
Richtig sind `gate.css` (die Farbwerte des Hauses) und `haus.css`. -->
|
||||
<link rel="stylesheet" href="assets/css/gate.css?v=202609280947" />
|
||||
<link rel="stylesheet" href="assets/css/haus.css?v=202609280947" />
|
||||
<link rel="stylesheet" href="assets/css/gate.css?v=202609281013" />
|
||||
<link rel="stylesheet" href="assets/css/haus.css?v=202609281013" />
|
||||
<!-- Ohne diese drei nimmt ein iPhone einen Bildschirmausschnitt als
|
||||
Symbol, Android zeichnet die Leiste weiss, und die Seite oeffnet
|
||||
ausserhalb der App -- auf einer Seite, die genau erklaeren soll,
|
||||
@@ -33,7 +33,7 @@
|
||||
schreibt jede Seite app.webmanifest -- auch die hier. -->
|
||||
<link rel="manifest" href="/workspace/app.webmanifest" />
|
||||
<meta name="theme-color" content="#06090f" />
|
||||
<link rel="apple-touch-icon" href="/assets/img/app-symbole/workspace-180.png?v=202609280947" />
|
||||
<link rel="apple-touch-icon" href="/assets/img/app-symbole/workspace-180.png?v=202609281013" />
|
||||
<style>
|
||||
/* Bewusst in der Seite und nicht in einer eigenen Datei: Diese Seite
|
||||
soll auch dann noch etwas anzeigen, wenn genau das schiefgeht,
|
||||
@@ -135,7 +135,7 @@
|
||||
|
||||
|
||||
|
||||
<script src="assets/js/anruf-probe.js?v=202609280947" defer></script>
|
||||
<script src="assets/js/installieren.js?v=202609280947" defer></script>
|
||||
<script src="assets/js/anruf-probe.js?v=202609281013" defer></script>
|
||||
<script src="assets/js/installieren.js?v=202609281013" defer></script>
|
||||
</body>
|
||||
</html>
|
||||
|
||||
@@ -23,25 +23,25 @@
|
||||
},
|
||||
"icons": [
|
||||
{
|
||||
"src": "/assets/img/app-symbole/workspace-192.png?v=202609280947",
|
||||
"src": "/assets/img/app-symbole/workspace-192.png?v=202609281013",
|
||||
"sizes": "192x192",
|
||||
"type": "image/png",
|
||||
"purpose": "any"
|
||||
},
|
||||
{
|
||||
"src": "/assets/img/app-symbole/workspace-512.png?v=202609280947",
|
||||
"src": "/assets/img/app-symbole/workspace-512.png?v=202609281013",
|
||||
"sizes": "512x512",
|
||||
"type": "image/png",
|
||||
"purpose": "any"
|
||||
},
|
||||
{
|
||||
"src": "/assets/img/app-symbole/workspace-192-maskable.png?v=202609280947",
|
||||
"src": "/assets/img/app-symbole/workspace-192-maskable.png?v=202609281013",
|
||||
"sizes": "192x192",
|
||||
"type": "image/png",
|
||||
"purpose": "maskable"
|
||||
},
|
||||
{
|
||||
"src": "/assets/img/app-symbole/workspace-512-maskable.png?v=202609280947",
|
||||
"src": "/assets/img/app-symbole/workspace-512-maskable.png?v=202609281013",
|
||||
"sizes": "512x512",
|
||||
"type": "image/png",
|
||||
"purpose": "maskable"
|
||||
|
||||
@@ -1438,6 +1438,68 @@
|
||||
.gast-leer { font-size: .8rem; color: var(--schrift-leise); margin: 0; }
|
||||
|
||||
/* ---- Anordnung ------------------------------------------------------- */
|
||||
/* ==== DIE STUFENLEITER =============================================
|
||||
Eine Zeile je Stufe, alle Felder nebeneinander. Umbrechen statt
|
||||
rollen: Am Handy wird aus der Zeile ein Block, und die Regie
|
||||
bleibt bedienbar, ohne dass man seitwaerts schieben muss. */
|
||||
.stufen { display: grid; gap: 9px; }
|
||||
.stufe-zeile {
|
||||
display: flex; flex-wrap: wrap; align-items: flex-end; gap: 9px;
|
||||
padding: 11px 12px 12px;
|
||||
border-radius: 13px;
|
||||
background: rgba(255, 255, 255, .035);
|
||||
border: 1px solid var(--rand);
|
||||
}
|
||||
.stufe-feld { display: grid; gap: 3px; min-width: 0; }
|
||||
.stufe-feld > span {
|
||||
font-size: .72rem; font-weight: 700;
|
||||
letter-spacing: .06em; text-transform: uppercase;
|
||||
color: var(--schrift-leise);
|
||||
}
|
||||
.stufe-feld input, .stufe-feld select {
|
||||
appearance: none;
|
||||
min-height: 44px; padding: 9px 11px;
|
||||
border-radius: 10px;
|
||||
border: 1px solid var(--rand);
|
||||
background: rgba(255, 255, 255, .05);
|
||||
color: var(--schrift);
|
||||
font: inherit; font-size: .84rem;
|
||||
min-width: 0;
|
||||
}
|
||||
.stufe-feld input[type="color"] { width: 56px; padding: 4px; }
|
||||
.stufe-ab, .stufe-dauer, .stufe-groesse { width: 5.5rem; }
|
||||
.stufe-name { width: 10rem; }
|
||||
.stufe-vorlage { width: 7.5rem; }
|
||||
|
||||
.stufe-bild { display: flex; align-items: center; gap: 7px; }
|
||||
.stufe-bild img {
|
||||
width: 44px; height: 44px;
|
||||
object-fit: contain;
|
||||
border-radius: 9px;
|
||||
background: rgba(255, 255, 255, .05);
|
||||
border: 1px solid var(--rand);
|
||||
}
|
||||
.stufe-tun {
|
||||
appearance: none; cursor: pointer;
|
||||
display: inline-flex; align-items: center; justify-content: center;
|
||||
min-height: 44px; padding: 9px 13px;
|
||||
border-radius: 10px;
|
||||
border: 1px solid var(--rand);
|
||||
background: rgba(255, 255, 255, .05);
|
||||
color: var(--schrift);
|
||||
font: inherit; font-size: .8rem; font-weight: 700;
|
||||
white-space: nowrap;
|
||||
}
|
||||
.stufe-tun:hover { background: rgba(255, 255, 255, .09); }
|
||||
.stufe-tun--weg { color: var(--schrift-leise); font-weight: 500; }
|
||||
.stufe-tun--weg:hover { color: var(--an-hell); background: rgba(216, 64, 74, .12); }
|
||||
.stufe-tun--aus { opacity: .45; cursor: default; }
|
||||
|
||||
/* „Noch nicht übernommen" in Gold: Es ist keine Störung, sondern
|
||||
eine Erinnerung -- Rot gehört in diesem Haus dem Senden. */
|
||||
#stufen-stand[data-offen="ja"] { color: var(--gleich); font-weight: 700; }
|
||||
#stufen-stand[data-offen="nein"] { color: var(--schrift-leise); }
|
||||
|
||||
.layout-reihe { display: flex; gap: 9px; flex-wrap: wrap; }
|
||||
.layout-knopf {
|
||||
appearance: none; cursor: pointer;
|
||||
|
||||
@@ -22,12 +22,30 @@
|
||||
pointer-events: none;
|
||||
}
|
||||
|
||||
/* ==== DIE GROESSE ==================================================
|
||||
|
||||
Filipe: „auch so dass ich das anders gestalten kann oder die
|
||||
größe verändern kann."
|
||||
|
||||
EINE SCHRIFTGRÖSSE UND NICHT ZEHN EINZELWERTE. Die Karte setzt
|
||||
ihre eigene Grundgröße aus `--sp-gross`, und alles darin rechnet
|
||||
in `em` — Abstände, Rundungen, das Zeichen, jede Schrift. Ein
|
||||
Faktor, und die ganze Karte wächst gleichmäßig mit.
|
||||
|
||||
Der naheliegende Weg wäre `transform: scale()` gewesen. Der geht
|
||||
hier nicht: Die Karte kommt mit `transform: translateX()` herein,
|
||||
und zwei `transform` an derselben Stelle schließen einander aus —
|
||||
entweder die Größe oder die Bewegung. Außerdem skaliert `scale()`
|
||||
auch die Schriftglättung mit, und Text wird dabei sichtbar
|
||||
matschig. Eine Schriftgröße tut das nicht. */
|
||||
.spendenkarte {
|
||||
--sp-farbe: #8ec9ff;
|
||||
display: flex; align-items: center; gap: 14px;
|
||||
max-width: min(30rem, 78%);
|
||||
padding: 13px 20px 13px 14px;
|
||||
border-radius: 18px;
|
||||
--sp-gross: 1;
|
||||
font-size: calc(1rem * var(--sp-gross));
|
||||
display: flex; align-items: center; gap: .875em;
|
||||
max-width: min(30em, 78%);
|
||||
padding: .8125em 1.25em .8125em .875em;
|
||||
border-radius: 1.125em;
|
||||
background:
|
||||
linear-gradient(90deg,
|
||||
color-mix(in srgb, var(--sp-farbe) 26%, rgba(10, 8, 16, .92)),
|
||||
@@ -51,25 +69,28 @@
|
||||
|
||||
.spendenkarte__bild {
|
||||
flex: none;
|
||||
width: 54px; height: 54px;
|
||||
width: 3.375em; height: 3.375em;
|
||||
display: grid; place-items: center;
|
||||
}
|
||||
.spendenkarte__bild svg { width: 100%; height: 100%; }
|
||||
.spendenkarte__bild img {
|
||||
width: 100%; height: 100%;
|
||||
/* `contain` und nicht `cover`: Ein hochgeladenes Zeichen soll ganz
|
||||
zu sehen sein. Wer sein Logo hochlädt, will es nicht beschnitten
|
||||
wiederfinden. */
|
||||
object-fit: contain;
|
||||
border-radius: 10px;
|
||||
border-radius: .625em;
|
||||
}
|
||||
|
||||
.spendenkarte__text { display: grid; gap: 1px; min-width: 0; }
|
||||
.spendenkarte__wer {
|
||||
font-size: .8rem; font-weight: 700;
|
||||
font-size: .8em; font-weight: 700;
|
||||
letter-spacing: .03em;
|
||||
color: color-mix(in srgb, var(--sp-farbe) 30%, #ffffff);
|
||||
overflow: hidden; text-overflow: ellipsis; white-space: nowrap;
|
||||
}
|
||||
.spendenkarte__betrag {
|
||||
font-size: 1.62rem; font-weight: 900;
|
||||
font-size: 1.62em; font-weight: 900;
|
||||
letter-spacing: -.02em; line-height: 1.05;
|
||||
color: #ffffff;
|
||||
/* Der Betrag ist das, worum es geht -- er bekommt als Einziges
|
||||
@@ -77,13 +98,13 @@
|
||||
text-shadow: 0 0 22px color-mix(in srgb, var(--sp-farbe) 60%, transparent);
|
||||
}
|
||||
.spendenkarte__stufe {
|
||||
font-size: .72rem; font-weight: 800;
|
||||
font-size: .72em; font-weight: 800;
|
||||
letter-spacing: .12em; text-transform: uppercase;
|
||||
color: color-mix(in srgb, var(--sp-farbe) 22%, #ffffff);
|
||||
}
|
||||
.spendenkarte__gruss {
|
||||
margin: 5px 0 0;
|
||||
font-size: .86rem; line-height: 1.4;
|
||||
margin: .3125em 0 0;
|
||||
font-size: .86em; line-height: 1.4;
|
||||
color: #e9e6f2;
|
||||
/* Hoechstens drei Zeilen. Ein langer Gruss darf das Bild nicht
|
||||
zuwachsen -- und wer mehr schreiben will, schreibt in den Chat. */
|
||||
@@ -101,8 +122,8 @@
|
||||
.spendentafel { bottom: 12px; padding: 0 10px; }
|
||||
.spendenkarte {
|
||||
max-width: 92%;
|
||||
gap: 10px; padding: 10px 14px 10px 10px;
|
||||
gap: .625em; padding: .625em .875em .625em .625em;
|
||||
}
|
||||
.spendenkarte__bild { width: 42px; height: 42px; }
|
||||
.spendenkarte__betrag { font-size: 1.3rem; }
|
||||
.spendenkarte__bild { width: 2.625em; height: 2.625em; }
|
||||
.spendenkarte__betrag { font-size: 1.3em; }
|
||||
}
|
||||
|
||||
@@ -217,6 +217,31 @@
|
||||
schon_im_bild:
|
||||
'Das läuft gerade schon. Ein Umschalter braucht zwei verschiedene Videos – '
|
||||
+ 'sonst passiert beim Drücken nichts.',
|
||||
/* ---- Die Gestaltung der Spendenkarten --------------------- */
|
||||
stufen_fehlen:
|
||||
'Da ist keine Stufenleiter angekommen. Lade die Seite neu und versuch es noch einmal.',
|
||||
keine_stufe:
|
||||
'Mindestens eine Stufe muss es geben – sonst erscheint bei einer Spende gar nichts.',
|
||||
zu_viele_stufen:
|
||||
'Mehr als sechs Stufen werden unübersichtlich. Nimm eine weg, dann geht es.',
|
||||
stufe_betrag_unklar:
|
||||
'Bei einer Stufe ergibt der Betrag keinen Sinn. Schreib ihn in Euro, zum Beispiel 5 oder 7,50.',
|
||||
stufe_name_fehlt:
|
||||
'Jede Stufe braucht einen Namen – er steht auf der Karte.',
|
||||
stufe_doppelt:
|
||||
'Zwei Stufen fangen beim selben Betrag an. Dann wäre nicht entschieden, welche gilt.',
|
||||
vorlage_unbekannt:
|
||||
'Dieses Zeichen gibt es nicht. Wähl eines aus der Liste.',
|
||||
farbe_unklar:
|
||||
'Diese Farbe verstehe ich nicht. Nimm den Farbwähler.',
|
||||
groesse_unklar:
|
||||
'Diese Größe geht nicht. Möglich ist 1 bis 2,5 – kleiner wäre auf der Karte nicht mehr zu lesen. '
|
||||
+ 'Für den Stream kannst du die Tafel über ihre Adresse kleiner stellen.',
|
||||
kein_bild:
|
||||
'Das ist kein Bild. Erlaubt sind JPG, PNG und WebP.',
|
||||
bild_zu_gross:
|
||||
'Das Bild ist zu groß. Erlaubt sind 3 MB.',
|
||||
|
||||
kein_zweites:
|
||||
'Es liegt kein zweites Video bereit. Trag eins unter „Sendung" ein, '
|
||||
+ 'dann kannst du hin und her wechseln.',
|
||||
|
||||
@@ -1607,6 +1607,10 @@
|
||||
$('obs-neu').addEventListener('click', buehneNeu);
|
||||
buehneHolen();
|
||||
|
||||
/* ---- Gestaltung ---- */
|
||||
$('stufe-neu').addEventListener('click', stufeDazu);
|
||||
$('stufen-sichern').addEventListener('click', stufenSichern);
|
||||
|
||||
/* ---- Spenden ---- */
|
||||
$('sp-zeigen').addEventListener('click', spendeEintragen);
|
||||
$('sp-betrag').addEventListener('keydown', (e) => {
|
||||
@@ -2542,6 +2546,213 @@
|
||||
let spendenLage = null;
|
||||
let gemeldeterBetrag = 0;
|
||||
|
||||
/* =================================================================
|
||||
DIE STUFENLEITER
|
||||
|
||||
Filipe: „mach paar fertige und so dass ich auch hochladen kann.
|
||||
auch so dass ich das anders gestalten kann oder die größe
|
||||
verändern kann. ... auch spezielle sachen bei speziellen spenden."
|
||||
|
||||
ALLES AUF EINMAL SPEICHERN UND NICHT ZEILE FÜR ZEILE. Eine
|
||||
Stufenleiter ist keine Liste unabhängiger Zeilen — sie muss als
|
||||
GANZES stimmen: aufsteigende Grenzen, keine zwei mit demselben
|
||||
Betrag, mindestens eine. Wer einzeln speichert, geht durch
|
||||
Zwischenzustände, in denen sie das nicht tut, und mitten in einer
|
||||
Sendung fiele dann eine Spende in die falsche Stufe.
|
||||
|
||||
Das Bild ist die Ausnahme: Es wird sofort hochgeladen. Eine
|
||||
Datei in einem Formular zwischenzuhalten, bis jemand
|
||||
„Übernehmen" drückt, heißt, sie bei jedem Versehen wieder zu
|
||||
verlieren. */
|
||||
let stufen = null;
|
||||
|
||||
function stufenZeichnen() {
|
||||
const kasten = $('stufen');
|
||||
if (!kasten || !stufen) return;
|
||||
const g = stufen.gestaltung;
|
||||
kasten.textContent = '';
|
||||
|
||||
stufen.liste.forEach((st, i) => {
|
||||
const zeile = el('div', 'stufe-zeile');
|
||||
zeile.dataset.platz = String(i);
|
||||
|
||||
const feld = (wort, knoten) => {
|
||||
const l = el('label', 'stufe-feld');
|
||||
l.append(el('span', null, wort));
|
||||
l.append(knoten);
|
||||
return l;
|
||||
};
|
||||
const eingabe = (art, wert, wie) => {
|
||||
const e = document.createElement('input');
|
||||
e.type = art;
|
||||
e.value = wert;
|
||||
Object.assign(e, wie || {});
|
||||
e.addEventListener('input', () => { stufenGeaendert(); });
|
||||
return e;
|
||||
};
|
||||
|
||||
/* Der Betrag steht in EURO im Feld und in CENT in der Leitung.
|
||||
Gerechnet wird nie mit dem, was hier steht. */
|
||||
zeile.append(feld('Ab', eingabe('text', (st.ab_cent / 100)
|
||||
.toString().replace('.', ','), { inputMode: 'decimal', className: 'stufe-ab' })));
|
||||
zeile.append(feld('Name', eingabe('text', st.name,
|
||||
{ maxLength: 40, className: 'stufe-name' })));
|
||||
|
||||
const wahl = document.createElement('select');
|
||||
wahl.className = 'stufe-vorlage';
|
||||
for (const v of g.vorlagen) {
|
||||
const o = document.createElement('option');
|
||||
o.value = v;
|
||||
o.textContent = v.charAt(0).toUpperCase() + v.slice(1);
|
||||
wahl.append(o);
|
||||
}
|
||||
wahl.value = st.vorlage;
|
||||
wahl.addEventListener('change', stufenGeaendert);
|
||||
zeile.append(feld('Zeichen', wahl));
|
||||
|
||||
zeile.append(feld('Farbe', eingabe('color', st.farbe, { className: 'stufe-farbe' })));
|
||||
zeile.append(feld('Sekunden', eingabe('number', String(Math.round(st.dauer_ms / 1000)), {
|
||||
min: String(Math.round(g.dauer_min / 1000)),
|
||||
max: String(Math.round(g.dauer_max / 1000)),
|
||||
step: '1', className: 'stufe-dauer',
|
||||
})));
|
||||
zeile.append(feld('Größe', eingabe('number', String(st.groesse), {
|
||||
min: String(g.groesse_min), max: String(g.groesse_max),
|
||||
step: '0.05', className: 'stufe-groesse',
|
||||
})));
|
||||
|
||||
/* ---- Das eigene Bild ---- */
|
||||
const bildTeil = el('div', 'stufe-bild');
|
||||
if (st.bild) {
|
||||
const b = document.createElement('img');
|
||||
b.src = st.bild;
|
||||
b.alt = '';
|
||||
bildTeil.append(b);
|
||||
}
|
||||
const hoch = el('label', 'stufe-tun', st.bild ? 'Anderes Bild' : 'Bild hochladen');
|
||||
const wahlfeld = document.createElement('input');
|
||||
wahlfeld.type = 'file';
|
||||
wahlfeld.accept = 'image/jpeg,image/png,image/webp';
|
||||
wahlfeld.hidden = true;
|
||||
wahlfeld.addEventListener('change', () => bildHoch(st, wahlfeld));
|
||||
hoch.append(wahlfeld);
|
||||
/* NUR WER SCHON GESPEICHERT IST, KANN EIN BILD BEKOMMEN. Eine
|
||||
frische Zeile hat noch keine Kennung, an der es hängen
|
||||
könnte -- der Knopf sagt das, statt ins Leere zu greifen. */
|
||||
if (!st.id) {
|
||||
hoch.classList.add('stufe-tun--aus');
|
||||
hoch.textContent = 'Erst übernehmen';
|
||||
wahlfeld.disabled = true;
|
||||
}
|
||||
bildTeil.append(hoch);
|
||||
if (st.bild) {
|
||||
const weg = el('button', 'stufe-tun stufe-tun--weg', 'Bild weg');
|
||||
weg.type = 'button';
|
||||
weg.addEventListener('click', () => bildWeg(st));
|
||||
bildTeil.append(weg);
|
||||
}
|
||||
zeile.append(bildTeil);
|
||||
|
||||
const probe = el('button', 'stufe-tun', 'Ausprobieren');
|
||||
probe.type = 'button';
|
||||
probe.title = 'Zeigt dir eine Karte — es wird keine Spende daraus';
|
||||
probe.addEventListener('click', () => stufeProbe(st));
|
||||
zeile.append(probe);
|
||||
|
||||
const weg = el('button', 'stufe-tun stufe-tun--weg', 'Stufe weg');
|
||||
weg.type = 'button';
|
||||
weg.addEventListener('click', () => { stufen.liste.splice(i, 1); stufenZeichnen(); stufenGeaendert(); });
|
||||
zeile.append(weg);
|
||||
|
||||
kasten.append(zeile);
|
||||
});
|
||||
|
||||
$('stufe-neu').disabled = stufen.liste.length >= stufen.gestaltung.stufen_max;
|
||||
}
|
||||
|
||||
function stufenGeaendert() {
|
||||
const st = $('stufen-stand');
|
||||
if (st) { st.textContent = 'Noch nicht übernommen'; st.dataset.offen = 'ja'; }
|
||||
}
|
||||
|
||||
function stufeDazu() {
|
||||
if (!stufen || stufen.liste.length >= stufen.gestaltung.stufen_max) return;
|
||||
const hoechste = stufen.liste.reduce((a, b) => Math.max(a, b.ab_cent), 0);
|
||||
stufen.liste.push({
|
||||
id: 0, ab_cent: hoechste ? hoechste * 2 : 100, name: 'Neue Stufe',
|
||||
vorlage: 'stern', bild: '', farbe: '#8ec9ff', dauer_ms: 7000, groesse: 1,
|
||||
});
|
||||
stufenZeichnen();
|
||||
stufenGeaendert();
|
||||
}
|
||||
|
||||
/** Was in den Feldern steht, zurück in Zahlen. */
|
||||
function stufenAusFeldern() {
|
||||
return [...$('stufen').children].map((zeile, i) => ({
|
||||
id: stufen.liste[i]?.id || 0,
|
||||
ab_cent: eurosInCent(zeile.querySelector('.stufe-ab').value),
|
||||
name: zeile.querySelector('.stufe-name').value.trim(),
|
||||
vorlage: zeile.querySelector('.stufe-vorlage').value,
|
||||
farbe: zeile.querySelector('.stufe-farbe').value,
|
||||
dauer_ms: Math.round(Number(zeile.querySelector('.stufe-dauer').value) * 1000),
|
||||
groesse: Number(zeile.querySelector('.stufe-groesse').value),
|
||||
}));
|
||||
}
|
||||
|
||||
async function stufenSichern() {
|
||||
const liste = stufenAusFeldern();
|
||||
const a = await hole('/workspace/api/spenden/stufen', {
|
||||
method: 'PUT',
|
||||
headers: { 'Content-Type': 'application/json' },
|
||||
body: JSON.stringify({ stufen: liste }),
|
||||
});
|
||||
if (!a.ok) { melde(await a.json().catch(() => null), 'Das ging nicht.'); return; }
|
||||
const d = await a.json();
|
||||
stufen.liste = d.stufen;
|
||||
stufenZeichnen();
|
||||
const st = $('stufen-stand');
|
||||
st.textContent = 'Übernommen';
|
||||
st.dataset.offen = 'nein';
|
||||
}
|
||||
|
||||
async function bildHoch(stufe, feld) {
|
||||
const datei = feld.files && feld.files[0];
|
||||
if (!datei) return;
|
||||
feld.value = '';
|
||||
const a = await hole(`/workspace/api/spenden/stufe/${stufe.id}/bild`, {
|
||||
method: 'POST',
|
||||
headers: { 'Content-Type': datei.type || 'application/octet-stream' },
|
||||
body: datei,
|
||||
});
|
||||
if (!a.ok) { melde(await a.json().catch(() => null), 'Das Bild ging nicht.'); return; }
|
||||
const d = await a.json();
|
||||
stufen.liste = d.stufen;
|
||||
stufenZeichnen();
|
||||
}
|
||||
|
||||
async function bildWeg(stufe) {
|
||||
const a = await hole(`/workspace/api/spenden/stufe/${stufe.id}/bild`, { method: 'DELETE' });
|
||||
if (!a.ok) { melde(await a.json().catch(() => null), 'Das ging nicht.'); return; }
|
||||
const d = await a.json();
|
||||
stufen.liste = d.stufen;
|
||||
stufenZeichnen();
|
||||
}
|
||||
|
||||
/** Einmal ansehen -- ohne dass eine Spende daraus wird.
|
||||
*
|
||||
* DER NAHELIEGENDE WEG WÄRE FALSCH GEWESEN: eine Spende von Hand
|
||||
* eintragen und danach löschen. In ein laufendes System kommen
|
||||
* keine Testdaten, und „gelöscht" heißt bei Geld nicht „war nie
|
||||
* da" -- der Eintrag stünde im Verlauf und in der Aufbewahrung. */
|
||||
async function stufeProbe(stufe) {
|
||||
const a = await hole('/workspace/api/spenden/probe', {
|
||||
method: 'POST',
|
||||
headers: { 'Content-Type': 'application/json' },
|
||||
body: JSON.stringify({ betrag_cent: stufe.ab_cent }),
|
||||
});
|
||||
if (!a.ok) melde(await a.json().catch(() => null), 'Das ging nicht.');
|
||||
}
|
||||
|
||||
async function spendenHolen() {
|
||||
try {
|
||||
const a = await hole('/workspace/api/spenden');
|
||||
@@ -2549,6 +2760,15 @@
|
||||
spendenLage = await a.json();
|
||||
gebenZeichnen();
|
||||
if (lage && lage.ich.host) spendenPultZeichnen();
|
||||
/* DIE STUFENLEITER NUR BEIM ERSTEN MAL AUS DER LEITUNG NEHMEN.
|
||||
Wer gerade an den Feldern tippt und dabei eine Spende
|
||||
hereinbekommt, verlöre sonst mitten im Satz, was er
|
||||
eingetragen hat -- `spendenHolen()` läuft bei jeder
|
||||
Meldung. */
|
||||
if (lage && lage.ich.host && spendenLage.gestaltung && !stufen) {
|
||||
stufen = { liste: spendenLage.stufen, gestaltung: spendenLage.gestaltung };
|
||||
stufenZeichnen();
|
||||
}
|
||||
} catch { /* ohne Feld ist die Seite vollständig */ }
|
||||
}
|
||||
|
||||
|
||||
@@ -115,6 +115,16 @@
|
||||
const farbe = karte.stufe?.farbe || '#8ec9ff';
|
||||
const tafel = el('div', 'spendenkarte');
|
||||
tafel.style.setProperty('--sp-farbe', farbe);
|
||||
/* DIE GROESSE KOMMT VON DER STUFE. Genau das ist „spezielle
|
||||
sachen bei speziellen spenden": Eine Rudel-Legende darf
|
||||
größer dastehen als ein Danke.
|
||||
BEGRENZT, obwohl der Server schon prüft -- diese Datei läuft
|
||||
auch auf der OBS-Tafel, und dort kommt der Wert über den
|
||||
Bühnenstrom. Eine Zahl, die aus der Leitung kommt, wird nicht
|
||||
ungeprüft in ein Stilblatt geschrieben. */
|
||||
const g = Number(karte.stufe?.groesse);
|
||||
tafel.style.setProperty('--sp-gross',
|
||||
String(Number.isFinite(g) && g >= 1 && g <= 2.5 ? g : 1));
|
||||
tafel.dataset.stufe = karte.stufe?.name || '';
|
||||
tafel.setAttribute('role', 'status');
|
||||
|
||||
|
||||
+19
-19
@@ -12,19 +12,19 @@
|
||||
Ton wie die Kopfleiste darunter (#06090f), damit Leiste und Seite
|
||||
eine Flaeche sind statt zweier. -->
|
||||
<meta name="theme-color" content="#06090f" />
|
||||
<link rel="icon" type="image/png" href="/assets/img/app-symbole/workspace-32.png?v=202609280947" />
|
||||
<link rel="apple-touch-icon" href="/assets/img/app-symbole/workspace-180.png?v=202609280947" />
|
||||
<link rel="stylesheet" href="assets/css/gate.css?v=202609280947" />
|
||||
<link rel="stylesheet" href="assets/css/start.css?v=202609280947" />
|
||||
<link rel="stylesheet" href="assets/css/aufgaben.css?v=202609280947" />
|
||||
<link rel="stylesheet" href="assets/css/module.css?v=202609280947" />
|
||||
<link rel="icon" type="image/png" href="/assets/img/app-symbole/workspace-32.png?v=202609281013" />
|
||||
<link rel="apple-touch-icon" href="/assets/img/app-symbole/workspace-180.png?v=202609281013" />
|
||||
<link rel="stylesheet" href="assets/css/gate.css?v=202609281013" />
|
||||
<link rel="stylesheet" href="assets/css/start.css?v=202609281013" />
|
||||
<link rel="stylesheet" href="assets/css/aufgaben.css?v=202609281013" />
|
||||
<link rel="stylesheet" href="assets/css/module.css?v=202609281013" />
|
||||
<!-- haus.css MUSS die letzte Stilvorlage sein (10.09.2026).
|
||||
Auf der Agenturadresse ist sie leer -- das Haus hier IST der
|
||||
Grundzustand. Auf der Adresse von Team Dogi biegt der Server
|
||||
genau diesen Dateinamen auf crew-haus.css um, und die Seite
|
||||
kommt schon beim ERSTEN Abruf in Lila und Babyblau an --
|
||||
ohne Umfaerben im Browser, ohne Flackern. -->
|
||||
<link rel="stylesheet" href="assets/css/haus.css?v=202609280947" />
|
||||
<link rel="stylesheet" href="assets/css/haus.css?v=202609281013" />
|
||||
</head>
|
||||
|
||||
<body class="start">
|
||||
@@ -391,22 +391,22 @@
|
||||
<!-- TEXTFORM ZUERST (21.09.2026): Die Seite fragt beim Zeichnen nach
|
||||
`window.Textform`. Kaeme sie spaeter, waere der erste Eintrag ohne
|
||||
Gestaltung. Kein `defer`, damit sie wirklich vorher dasteht. -->
|
||||
<script src="assets/js/textform.js?v=202609280947"></script>
|
||||
<script src="assets/js/meldung.js?v=202609280947" defer></script>
|
||||
<script src="assets/js/hochladen.js?v=202609280947" defer></script>
|
||||
<script src="assets/js/nachfrage.js?v=202609280947" defer></script>
|
||||
<script src="assets/js/textform.js?v=202609281013"></script>
|
||||
<script src="assets/js/meldung.js?v=202609281013" defer></script>
|
||||
<script src="assets/js/hochladen.js?v=202609281013" defer></script>
|
||||
<script src="assets/js/nachfrage.js?v=202609281013" defer></script>
|
||||
|
||||
<script src="assets/js/wahl.js?v=202609280947" defer></script>
|
||||
<script src="assets/js/bereiche.js?v=202609280947" defer></script>
|
||||
<script src="assets/js/installieren.js?v=202609280947" defer></script>
|
||||
<script src="assets/js/kopf.js?v=202609280947" defer></script>
|
||||
<script src="assets/js/glocke.js?v=202609280947" defer></script>
|
||||
<script src="assets/js/zuteilung.js?v=202609280947" defer></script>
|
||||
<script src="assets/js/wahl.js?v=202609281013" defer></script>
|
||||
<script src="assets/js/bereiche.js?v=202609281013" defer></script>
|
||||
<script src="assets/js/installieren.js?v=202609281013" defer></script>
|
||||
<script src="assets/js/kopf.js?v=202609281013" defer></script>
|
||||
<script src="assets/js/glocke.js?v=202609281013" defer></script>
|
||||
<script src="assets/js/zuteilung.js?v=202609281013" defer></script>
|
||||
<!-- Der Vorlagenkatalog stand bis zum 23.09.2026 mitten in
|
||||
aufgaben.js. Er bedient jetzt zwei Seiten und hat deshalb eine
|
||||
eigene Datei; hier zeigt er den Creator-Katalog.
|
||||
Vor aufgaben.js, weil die Seite ihn beim Start einrichtet. -->
|
||||
<script src="assets/js/vorlagenbrett.js?v=202609280947" defer></script>
|
||||
<script src="assets/js/aufgaben.js?v=202609280947" defer></script>
|
||||
<script src="assets/js/vorlagenbrett.js?v=202609281013" defer></script>
|
||||
<script src="assets/js/aufgaben.js?v=202609281013" defer></script>
|
||||
</body>
|
||||
</html>
|
||||
|
||||
+16
-16
@@ -12,20 +12,20 @@
|
||||
Ton wie die Kopfleiste darunter (#06090f), damit Leiste und Seite
|
||||
eine Flaeche sind statt zweier. -->
|
||||
<meta name="theme-color" content="#06090f" />
|
||||
<link rel="icon" type="image/png" href="/assets/img/app-symbole/workspace-32.png?v=202609280947" />
|
||||
<link rel="apple-touch-icon" href="/assets/img/app-symbole/workspace-180.png?v=202609280947" />
|
||||
<link rel="stylesheet" href="assets/css/gate.css?v=202609280947" />
|
||||
<link rel="stylesheet" href="assets/css/start.css?v=202609280947" />
|
||||
<link rel="stylesheet" href="assets/css/aufgaben.css?v=202609280947" />
|
||||
<link rel="stylesheet" href="assets/css/automation.css?v=202609280947" />
|
||||
<link rel="stylesheet" href="assets/css/module.css?v=202609280947" />
|
||||
<link rel="icon" type="image/png" href="/assets/img/app-symbole/workspace-32.png?v=202609281013" />
|
||||
<link rel="apple-touch-icon" href="/assets/img/app-symbole/workspace-180.png?v=202609281013" />
|
||||
<link rel="stylesheet" href="assets/css/gate.css?v=202609281013" />
|
||||
<link rel="stylesheet" href="assets/css/start.css?v=202609281013" />
|
||||
<link rel="stylesheet" href="assets/css/aufgaben.css?v=202609281013" />
|
||||
<link rel="stylesheet" href="assets/css/automation.css?v=202609281013" />
|
||||
<link rel="stylesheet" href="assets/css/module.css?v=202609281013" />
|
||||
<!-- haus.css MUSS die letzte Stilvorlage sein (10.09.2026).
|
||||
Auf der Agenturadresse ist sie leer -- das Haus hier IST der
|
||||
Grundzustand. Auf der Adresse von Team Dogi biegt der Server
|
||||
genau diesen Dateinamen auf crew-haus.css um, und die Seite
|
||||
kommt schon beim ERSTEN Abruf in Lila und Babyblau an --
|
||||
ohne Umfaerben im Browser, ohne Flackern. -->
|
||||
<link rel="stylesheet" href="assets/css/haus.css?v=202609280947" />
|
||||
<link rel="stylesheet" href="assets/css/haus.css?v=202609281013" />
|
||||
</head>
|
||||
|
||||
<body class="start">
|
||||
@@ -168,15 +168,15 @@
|
||||
|
||||
</main>
|
||||
|
||||
<script src="assets/js/meldung.js?v=202609280947" defer></script>
|
||||
<script src="assets/js/nachfrage.js?v=202609280947" defer></script>
|
||||
<script src="assets/js/meldung.js?v=202609281013" defer></script>
|
||||
<script src="assets/js/nachfrage.js?v=202609281013" defer></script>
|
||||
|
||||
|
||||
<script src="assets/js/wahl.js?v=202609280947" defer></script>
|
||||
<script src="assets/js/bereiche.js?v=202609280947" defer></script>
|
||||
<script src="assets/js/installieren.js?v=202609280947" defer></script>
|
||||
<script src="assets/js/kopf.js?v=202609280947" defer></script>
|
||||
<script src="assets/js/glocke.js?v=202609280947" defer></script>
|
||||
<script src="assets/js/automation.js?v=202609280947" defer></script>
|
||||
<script src="assets/js/wahl.js?v=202609281013" defer></script>
|
||||
<script src="assets/js/bereiche.js?v=202609281013" defer></script>
|
||||
<script src="assets/js/installieren.js?v=202609281013" defer></script>
|
||||
<script src="assets/js/kopf.js?v=202609281013" defer></script>
|
||||
<script src="assets/js/glocke.js?v=202609281013" defer></script>
|
||||
<script src="assets/js/automation.js?v=202609281013" defer></script>
|
||||
</body>
|
||||
</html>
|
||||
|
||||
+17
-17
@@ -7,14 +7,14 @@
|
||||
<meta name="robots" content="noindex, nofollow" />
|
||||
<link rel="manifest" href="/workspace/app.webmanifest" />
|
||||
<meta name="theme-color" content="#06090f" />
|
||||
<link rel="icon" type="image/png" href="/assets/img/app-symbole/workspace-32.png?v=202609280947" />
|
||||
<link rel="apple-touch-icon" href="/assets/img/app-symbole/workspace-180.png?v=202609280947" />
|
||||
<link rel="stylesheet" href="assets/css/gate.css?v=202609280947" />
|
||||
<link rel="stylesheet" href="assets/css/start.css?v=202609280947" />
|
||||
<link rel="stylesheet" href="assets/css/aufgaben.css?v=202609280947" />
|
||||
<link rel="stylesheet" href="assets/css/entwicklung.css?v=202609280947" />
|
||||
<link rel="stylesheet" href="assets/css/module.css?v=202609280947" />
|
||||
<link rel="stylesheet" href="assets/css/haus.css?v=202609280947" />
|
||||
<link rel="icon" type="image/png" href="/assets/img/app-symbole/workspace-32.png?v=202609281013" />
|
||||
<link rel="apple-touch-icon" href="/assets/img/app-symbole/workspace-180.png?v=202609281013" />
|
||||
<link rel="stylesheet" href="assets/css/gate.css?v=202609281013" />
|
||||
<link rel="stylesheet" href="assets/css/start.css?v=202609281013" />
|
||||
<link rel="stylesheet" href="assets/css/aufgaben.css?v=202609281013" />
|
||||
<link rel="stylesheet" href="assets/css/entwicklung.css?v=202609281013" />
|
||||
<link rel="stylesheet" href="assets/css/module.css?v=202609281013" />
|
||||
<link rel="stylesheet" href="assets/css/haus.css?v=202609281013" />
|
||||
</head>
|
||||
|
||||
<body class="start">
|
||||
@@ -197,16 +197,16 @@
|
||||
|
||||
</main>
|
||||
|
||||
<script src="assets/js/meldung.js?v=202609280947" defer></script>
|
||||
<script src="assets/js/nachfrage.js?v=202609280947" defer></script>
|
||||
<script src="assets/js/meldung.js?v=202609281013" defer></script>
|
||||
<script src="assets/js/nachfrage.js?v=202609281013" defer></script>
|
||||
|
||||
|
||||
<script src="assets/js/wahl.js?v=202609280947" defer></script>
|
||||
<script src="assets/js/bereiche.js?v=202609280947" defer></script>
|
||||
<script src="assets/js/installieren.js?v=202609280947" defer></script>
|
||||
<script src="assets/js/kopf.js?v=202609280947" defer></script>
|
||||
<script src="assets/js/glocke.js?v=202609280947" defer></script>
|
||||
<script src="assets/js/holen.js?v=202609280947" defer></script>
|
||||
<script src="assets/js/befinden.js?v=202609280947" defer></script>
|
||||
<script src="assets/js/wahl.js?v=202609281013" defer></script>
|
||||
<script src="assets/js/bereiche.js?v=202609281013" defer></script>
|
||||
<script src="assets/js/installieren.js?v=202609281013" defer></script>
|
||||
<script src="assets/js/kopf.js?v=202609281013" defer></script>
|
||||
<script src="assets/js/glocke.js?v=202609281013" defer></script>
|
||||
<script src="assets/js/holen.js?v=202609281013" defer></script>
|
||||
<script src="assets/js/befinden.js?v=202609281013" defer></script>
|
||||
</body>
|
||||
</html>
|
||||
|
||||
+22
-22
@@ -12,24 +12,24 @@
|
||||
Ton wie die Kopfleiste darunter (#06090f), damit Leiste und Seite
|
||||
eine Flaeche sind statt zweier. -->
|
||||
<meta name="theme-color" content="#06090f" />
|
||||
<link rel="icon" type="image/png" href="/assets/img/app-symbole/workspace-32.png?v=202609280947" />
|
||||
<link rel="apple-touch-icon" href="/assets/img/app-symbole/workspace-180.png?v=202609280947" />
|
||||
<link rel="stylesheet" href="assets/css/gate.css?v=202609280947" />
|
||||
<link rel="stylesheet" href="assets/css/start.css?v=202609280947" />
|
||||
<link rel="stylesheet" href="assets/css/aufgaben.css?v=202609280947" />
|
||||
<link rel="stylesheet" href="assets/css/bereich.css?v=202609280947" />
|
||||
<link rel="icon" type="image/png" href="/assets/img/app-symbole/workspace-32.png?v=202609281013" />
|
||||
<link rel="apple-touch-icon" href="/assets/img/app-symbole/workspace-180.png?v=202609281013" />
|
||||
<link rel="stylesheet" href="assets/css/gate.css?v=202609281013" />
|
||||
<link rel="stylesheet" href="assets/css/start.css?v=202609281013" />
|
||||
<link rel="stylesheet" href="assets/css/aufgaben.css?v=202609281013" />
|
||||
<link rel="stylesheet" href="assets/css/bereich.css?v=202609281013" />
|
||||
<!-- Wegen des Blocks „Willst du dazugehoeren?" auf dem Brett
|
||||
„Mitmachen". Eine eigene Kopie der Regel hier waere die zweite
|
||||
Stelle, an der dieselbe Sache anders aussieht. -->
|
||||
<link rel="stylesheet" href="assets/css/bewerbung.css?v=202609280947" />
|
||||
<link rel="stylesheet" href="assets/css/module.css?v=202609280947" />
|
||||
<link rel="stylesheet" href="assets/css/bewerbung.css?v=202609281013" />
|
||||
<link rel="stylesheet" href="assets/css/module.css?v=202609281013" />
|
||||
<!-- haus.css MUSS die letzte Stilvorlage sein (10.09.2026).
|
||||
Auf der Agenturadresse ist sie leer -- das Haus hier IST der
|
||||
Grundzustand. Auf der Adresse von Team Dogi biegt der Server
|
||||
genau diesen Dateinamen auf crew-haus.css um, und die Seite
|
||||
kommt schon beim ERSTEN Abruf in Lila und Babyblau an --
|
||||
ohne Umfaerben im Browser, ohne Flackern. -->
|
||||
<link rel="stylesheet" href="assets/css/haus.css?v=202609280947" />
|
||||
<link rel="stylesheet" href="assets/css/haus.css?v=202609281013" />
|
||||
</head>
|
||||
|
||||
<body class="start">
|
||||
@@ -304,19 +304,19 @@
|
||||
<!-- TEXTFORM ZUERST (21.09.2026): Die Seite fragt beim Zeichnen nach
|
||||
`window.Textform`. Kaeme sie spaeter, waere der erste Eintrag ohne
|
||||
Gestaltung. Kein `defer`, damit sie wirklich vorher dasteht. -->
|
||||
<script src="assets/js/textform.js?v=202609280947"></script>
|
||||
<script src="assets/js/meldung.js?v=202609280947" defer></script>
|
||||
<script src="assets/js/nachfrage.js?v=202609280947" defer></script>
|
||||
<script src="assets/js/textform.js?v=202609281013"></script>
|
||||
<script src="assets/js/meldung.js?v=202609281013" defer></script>
|
||||
<script src="assets/js/nachfrage.js?v=202609281013" defer></script>
|
||||
|
||||
<script src="assets/js/wahl.js?v=202609280947" defer></script>
|
||||
<script src="assets/js/bereiche.js?v=202609280947" defer></script>
|
||||
<script src="assets/js/installieren.js?v=202609280947" defer></script>
|
||||
<script src="assets/js/kopf.js?v=202609280947" defer></script>
|
||||
<script src="assets/js/glocke.js?v=202609280947" defer></script>
|
||||
<script src="assets/js/checkliste.js?v=202609280947" defer></script>
|
||||
<script src="assets/js/ampel.js?v=202609280947" defer></script>
|
||||
<script src="assets/js/schulung.js?v=202609280947" defer></script>
|
||||
<script src="assets/js/holen.js?v=202609280947" defer></script>
|
||||
<script src="assets/js/bereich.js?v=202609280947" defer></script>
|
||||
<script src="assets/js/wahl.js?v=202609281013" defer></script>
|
||||
<script src="assets/js/bereiche.js?v=202609281013" defer></script>
|
||||
<script src="assets/js/installieren.js?v=202609281013" defer></script>
|
||||
<script src="assets/js/kopf.js?v=202609281013" defer></script>
|
||||
<script src="assets/js/glocke.js?v=202609281013" defer></script>
|
||||
<script src="assets/js/checkliste.js?v=202609281013" defer></script>
|
||||
<script src="assets/js/ampel.js?v=202609281013" defer></script>
|
||||
<script src="assets/js/schulung.js?v=202609281013" defer></script>
|
||||
<script src="assets/js/holen.js?v=202609281013" defer></script>
|
||||
<script src="assets/js/bereich.js?v=202609281013" defer></script>
|
||||
</body>
|
||||
</html>
|
||||
|
||||
+19
-19
@@ -7,17 +7,17 @@
|
||||
<meta name="robots" content="noindex, nofollow" />
|
||||
<link rel="manifest" href="/workspace/app.webmanifest" />
|
||||
<meta name="theme-color" content="#06090f" />
|
||||
<link rel="icon" type="image/png" href="/assets/img/app-symbole/workspace-32.png?v=202609280947" />
|
||||
<link rel="apple-touch-icon" href="/assets/img/app-symbole/workspace-180.png?v=202609280947" />
|
||||
<link rel="stylesheet" href="assets/css/gate.css?v=202609280947" />
|
||||
<link rel="stylesheet" href="assets/css/start.css?v=202609280947" />
|
||||
<link rel="stylesheet" href="assets/css/aufgaben.css?v=202609280947" />
|
||||
<link rel="stylesheet" href="assets/css/bereich.css?v=202609280947" />
|
||||
<link rel="stylesheet" href="assets/css/treff.css?v=202609280947" />
|
||||
<link rel="stylesheet" href="assets/css/bewerbung.css?v=202609280947" />
|
||||
<link rel="stylesheet" href="assets/css/module.css?v=202609280947" />
|
||||
<link rel="icon" type="image/png" href="/assets/img/app-symbole/workspace-32.png?v=202609281013" />
|
||||
<link rel="apple-touch-icon" href="/assets/img/app-symbole/workspace-180.png?v=202609281013" />
|
||||
<link rel="stylesheet" href="assets/css/gate.css?v=202609281013" />
|
||||
<link rel="stylesheet" href="assets/css/start.css?v=202609281013" />
|
||||
<link rel="stylesheet" href="assets/css/aufgaben.css?v=202609281013" />
|
||||
<link rel="stylesheet" href="assets/css/bereich.css?v=202609281013" />
|
||||
<link rel="stylesheet" href="assets/css/treff.css?v=202609281013" />
|
||||
<link rel="stylesheet" href="assets/css/bewerbung.css?v=202609281013" />
|
||||
<link rel="stylesheet" href="assets/css/module.css?v=202609281013" />
|
||||
<!-- haus.css MUSS die letzte Stilvorlage sein - siehe treff-regeln.html. -->
|
||||
<link rel="stylesheet" href="assets/css/haus.css?v=202609280947" />
|
||||
<link rel="stylesheet" href="assets/css/haus.css?v=202609281013" />
|
||||
</head>
|
||||
|
||||
<body class="start">
|
||||
@@ -108,15 +108,15 @@
|
||||
</main>
|
||||
|
||||
<!-- Der Fuß gehört zu jeder Seite - siehe pruef-css-klassen. -->
|
||||
<script src="assets/js/meldung.js?v=202609280947" defer></script>
|
||||
<script src="assets/js/nachfrage.js?v=202609280947" defer></script>
|
||||
<script src="assets/js/meldung.js?v=202609281013" defer></script>
|
||||
<script src="assets/js/nachfrage.js?v=202609281013" defer></script>
|
||||
|
||||
<script src="assets/js/wahl.js?v=202609280947" defer></script>
|
||||
<script src="assets/js/bereiche.js?v=202609280947" defer></script>
|
||||
<script src="assets/js/installieren.js?v=202609280947" defer></script>
|
||||
<script src="assets/js/kopf.js?v=202609280947" defer></script>
|
||||
<script src="assets/js/glocke.js?v=202609280947" defer></script>
|
||||
<script src="assets/js/auskunft.js?v=202609280947" defer></script>
|
||||
<script src="assets/js/bewerben.js?v=202609280947" defer></script>
|
||||
<script src="assets/js/wahl.js?v=202609281013" defer></script>
|
||||
<script src="assets/js/bereiche.js?v=202609281013" defer></script>
|
||||
<script src="assets/js/installieren.js?v=202609281013" defer></script>
|
||||
<script src="assets/js/kopf.js?v=202609281013" defer></script>
|
||||
<script src="assets/js/glocke.js?v=202609281013" defer></script>
|
||||
<script src="assets/js/auskunft.js?v=202609281013" defer></script>
|
||||
<script src="assets/js/bewerben.js?v=202609281013" defer></script>
|
||||
</body>
|
||||
</html>
|
||||
|
||||
+18
-18
@@ -7,16 +7,16 @@
|
||||
<meta name="robots" content="noindex, nofollow" />
|
||||
<link rel="manifest" href="/workspace/app.webmanifest" />
|
||||
<meta name="theme-color" content="#06090f" />
|
||||
<link rel="icon" type="image/png" href="/assets/img/app-symbole/workspace-32.png?v=202609280947" />
|
||||
<link rel="apple-touch-icon" href="/assets/img/app-symbole/workspace-180.png?v=202609280947" />
|
||||
<link rel="stylesheet" href="assets/css/gate.css?v=202609280947" />
|
||||
<link rel="stylesheet" href="assets/css/start.css?v=202609280947" />
|
||||
<link rel="stylesheet" href="assets/css/aufgaben.css?v=202609280947" />
|
||||
<link rel="stylesheet" href="assets/css/entwicklung.css?v=202609280947" />
|
||||
<link rel="stylesheet" href="assets/css/bewerbung.css?v=202609280947" />
|
||||
<link rel="stylesheet" href="assets/css/module.css?v=202609280947" />
|
||||
<link rel="icon" type="image/png" href="/assets/img/app-symbole/workspace-32.png?v=202609281013" />
|
||||
<link rel="apple-touch-icon" href="/assets/img/app-symbole/workspace-180.png?v=202609281013" />
|
||||
<link rel="stylesheet" href="assets/css/gate.css?v=202609281013" />
|
||||
<link rel="stylesheet" href="assets/css/start.css?v=202609281013" />
|
||||
<link rel="stylesheet" href="assets/css/aufgaben.css?v=202609281013" />
|
||||
<link rel="stylesheet" href="assets/css/entwicklung.css?v=202609281013" />
|
||||
<link rel="stylesheet" href="assets/css/bewerbung.css?v=202609281013" />
|
||||
<link rel="stylesheet" href="assets/css/module.css?v=202609281013" />
|
||||
<!-- haus.css MUSS die letzte Stilvorlage sein - siehe treff-regeln.html. -->
|
||||
<link rel="stylesheet" href="assets/css/haus.css?v=202609280947" />
|
||||
<link rel="stylesheet" href="assets/css/haus.css?v=202609281013" />
|
||||
</head>
|
||||
|
||||
<body class="start">
|
||||
@@ -80,16 +80,16 @@
|
||||
|
||||
</main>
|
||||
|
||||
<script src="assets/js/meldung.js?v=202609280947" defer></script>
|
||||
<script src="assets/js/nachfrage.js?v=202609280947" defer></script>
|
||||
<script src="assets/js/meldung.js?v=202609281013" defer></script>
|
||||
<script src="assets/js/nachfrage.js?v=202609281013" defer></script>
|
||||
|
||||
|
||||
<script src="assets/js/wahl.js?v=202609280947" defer></script>
|
||||
<script src="assets/js/bereiche.js?v=202609280947" defer></script>
|
||||
<script src="assets/js/installieren.js?v=202609280947" defer></script>
|
||||
<script src="assets/js/kopf.js?v=202609280947" defer></script>
|
||||
<script src="assets/js/glocke.js?v=202609280947" defer></script>
|
||||
<script src="assets/js/auskunft.js?v=202609280947" defer></script>
|
||||
<script src="assets/js/bewerbungen.js?v=202609280947" defer></script>
|
||||
<script src="assets/js/wahl.js?v=202609281013" defer></script>
|
||||
<script src="assets/js/bereiche.js?v=202609281013" defer></script>
|
||||
<script src="assets/js/installieren.js?v=202609281013" defer></script>
|
||||
<script src="assets/js/kopf.js?v=202609281013" defer></script>
|
||||
<script src="assets/js/glocke.js?v=202609281013" defer></script>
|
||||
<script src="assets/js/auskunft.js?v=202609281013" defer></script>
|
||||
<script src="assets/js/bewerbungen.js?v=202609281013" defer></script>
|
||||
</body>
|
||||
</html>
|
||||
|
||||
@@ -47,6 +47,6 @@
|
||||
</head>
|
||||
<body>
|
||||
<div id="platz"></div>
|
||||
<script src="assets/js/buehne.js?v=202609280947" defer></script>
|
||||
<script src="assets/js/buehne.js?v=202609281013" defer></script>
|
||||
</body>
|
||||
</html>
|
||||
|
||||
+17
-17
@@ -12,20 +12,20 @@
|
||||
Ton wie die Kopfleiste darunter (#06090f), damit Leiste und Seite
|
||||
eine Flaeche sind statt zweier. -->
|
||||
<meta name="theme-color" content="#06090f" />
|
||||
<link rel="icon" type="image/png" href="/assets/img/app-symbole/workspace-32.png?v=202609280947" />
|
||||
<link rel="apple-touch-icon" href="/assets/img/app-symbole/workspace-180.png?v=202609280947" />
|
||||
<link rel="stylesheet" href="assets/css/gate.css?v=202609280947" />
|
||||
<link rel="stylesheet" href="assets/css/start.css?v=202609280947" />
|
||||
<link rel="stylesheet" href="assets/css/aufgaben.css?v=202609280947" />
|
||||
<link rel="stylesheet" href="assets/css/calls.css?v=202609280947" />
|
||||
<link rel="stylesheet" href="assets/css/module.css?v=202609280947" />
|
||||
<link rel="icon" type="image/png" href="/assets/img/app-symbole/workspace-32.png?v=202609281013" />
|
||||
<link rel="apple-touch-icon" href="/assets/img/app-symbole/workspace-180.png?v=202609281013" />
|
||||
<link rel="stylesheet" href="assets/css/gate.css?v=202609281013" />
|
||||
<link rel="stylesheet" href="assets/css/start.css?v=202609281013" />
|
||||
<link rel="stylesheet" href="assets/css/aufgaben.css?v=202609281013" />
|
||||
<link rel="stylesheet" href="assets/css/calls.css?v=202609281013" />
|
||||
<link rel="stylesheet" href="assets/css/module.css?v=202609281013" />
|
||||
<!-- haus.css MUSS die letzte Stilvorlage sein (10.09.2026).
|
||||
Auf der Agenturadresse ist sie leer -- das Haus hier IST der
|
||||
Grundzustand. Auf der Adresse von Team Dogi biegt der Server
|
||||
genau diesen Dateinamen auf crew-haus.css um, und die Seite
|
||||
kommt schon beim ERSTEN Abruf in Lila und Babyblau an --
|
||||
ohne Umfaerben im Browser, ohne Flackern. -->
|
||||
<link rel="stylesheet" href="assets/css/haus.css?v=202609280947" />
|
||||
<link rel="stylesheet" href="assets/css/haus.css?v=202609281013" />
|
||||
</head>
|
||||
|
||||
<body class="start">
|
||||
@@ -89,15 +89,15 @@
|
||||
|
||||
</main>
|
||||
|
||||
<script src="assets/js/meldung.js?v=202609280947" defer></script>
|
||||
<script src="assets/js/nachfrage.js?v=202609280947" defer></script>
|
||||
<script src="assets/js/meldung.js?v=202609281013" defer></script>
|
||||
<script src="assets/js/nachfrage.js?v=202609281013" defer></script>
|
||||
|
||||
<script src="assets/js/ki.js?v=202609280947" defer></script>
|
||||
<script src="assets/js/wahl.js?v=202609280947" defer></script>
|
||||
<script src="assets/js/bereiche.js?v=202609280947" defer></script>
|
||||
<script src="assets/js/installieren.js?v=202609280947" defer></script>
|
||||
<script src="assets/js/kopf.js?v=202609280947" defer></script>
|
||||
<script src="assets/js/glocke.js?v=202609280947" defer></script>
|
||||
<script src="assets/js/calls.js?v=202609280947" defer></script>
|
||||
<script src="assets/js/ki.js?v=202609281013" defer></script>
|
||||
<script src="assets/js/wahl.js?v=202609281013" defer></script>
|
||||
<script src="assets/js/bereiche.js?v=202609281013" defer></script>
|
||||
<script src="assets/js/installieren.js?v=202609281013" defer></script>
|
||||
<script src="assets/js/kopf.js?v=202609281013" defer></script>
|
||||
<script src="assets/js/glocke.js?v=202609281013" defer></script>
|
||||
<script src="assets/js/calls.js?v=202609281013" defer></script>
|
||||
</body>
|
||||
</html>
|
||||
|
||||
+20
-20
@@ -12,26 +12,26 @@
|
||||
Ton wie die Kopfleiste darunter (#06090f), damit Leiste und Seite
|
||||
eine Flaeche sind statt zweier. -->
|
||||
<meta name="theme-color" content="#06090f" />
|
||||
<link rel="icon" type="image/png" href="/assets/img/app-symbole/workspace-32.png?v=202609280947" />
|
||||
<link rel="apple-touch-icon" href="/assets/img/app-symbole/workspace-180.png?v=202609280947" />
|
||||
<link rel="stylesheet" href="assets/css/gate.css?v=202609280947" />
|
||||
<link rel="stylesheet" href="assets/css/start.css?v=202609280947" />
|
||||
<link rel="icon" type="image/png" href="/assets/img/app-symbole/workspace-32.png?v=202609281013" />
|
||||
<link rel="apple-touch-icon" href="/assets/img/app-symbole/workspace-180.png?v=202609281013" />
|
||||
<link rel="stylesheet" href="assets/css/gate.css?v=202609281013" />
|
||||
<link rel="stylesheet" href="assets/css/start.css?v=202609281013" />
|
||||
<!-- 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=202609280947" />
|
||||
<link rel="stylesheet" href="assets/css/chat.css?v=202609280947" />
|
||||
<link rel="stylesheet" href="assets/css/module.css?v=202609280947" />
|
||||
<link rel="stylesheet" href="assets/css/aufgaben.css?v=202609281013" />
|
||||
<link rel="stylesheet" href="assets/css/chat.css?v=202609281013" />
|
||||
<link rel="stylesheet" href="assets/css/module.css?v=202609281013" />
|
||||
<!-- haus.css MUSS die letzte Stilvorlage sein (10.09.2026).
|
||||
Auf der Agenturadresse ist sie leer -- das Haus hier IST der
|
||||
Grundzustand. Auf der Adresse von Team Dogi biegt der Server
|
||||
genau diesen Dateinamen auf crew-haus.css um, und die Seite
|
||||
kommt schon beim ERSTEN Abruf in Lila und Babyblau an --
|
||||
ohne Umfaerben im Browser, ohne Flackern. -->
|
||||
<link rel="stylesheet" href="assets/css/haus.css?v=202609280947" />
|
||||
<link rel="stylesheet" href="assets/css/haus.css?v=202609281013" />
|
||||
</head>
|
||||
|
||||
<body class="start">
|
||||
@@ -739,24 +739,24 @@
|
||||
</form>
|
||||
</dialog>
|
||||
|
||||
<script src="assets/js/bereiche.js?v=202609280947"></script>
|
||||
<script src="assets/js/bereiche.js?v=202609281013"></script>
|
||||
<!-- TEXTFORM VOR ALLEM ANDEREN (21.09.2026): chat.js und bereich.js
|
||||
fragen beim Zeichnen nach `window.Textform`. Kaeme sie spaeter,
|
||||
waere die erste gezeichnete Nachricht ohne Gestaltung -- und das
|
||||
faellt nur dem auf, der genau hinsieht. KEIN `defer`, damit sie
|
||||
wirklich vor den anderen dasteht. -->
|
||||
<script src="assets/js/textform.js?v=202609280947"></script>
|
||||
<script src="assets/js/meldung.js?v=202609280947" defer></script>
|
||||
<script src="assets/js/hochladen.js?v=202609280947" defer></script>
|
||||
<script src="assets/js/nachfrage.js?v=202609280947" defer></script>
|
||||
<script src="assets/js/wahl.js?v=202609280947" defer></script>
|
||||
<script src="assets/js/kopf.js?v=202609280947"></script>
|
||||
<script src="assets/js/glocke.js?v=202609280947"></script>
|
||||
<script src="assets/js/textform.js?v=202609281013"></script>
|
||||
<script src="assets/js/meldung.js?v=202609281013" defer></script>
|
||||
<script src="assets/js/hochladen.js?v=202609281013" defer></script>
|
||||
<script src="assets/js/nachfrage.js?v=202609281013" defer></script>
|
||||
<script src="assets/js/wahl.js?v=202609281013" defer></script>
|
||||
<script src="assets/js/kopf.js?v=202609281013"></script>
|
||||
<script src="assets/js/glocke.js?v=202609281013"></script>
|
||||
<!-- ANRUF VOR CHAT (18.09.2026): anruf.js stellt `window.anrufStarten`
|
||||
bereit, und chat.js baut die Knoepfe nur, wenn es das gibt.
|
||||
Andersherum waere die Reihenfolge eine stille Abhaengigkeit --
|
||||
die Knoepfe fehlten, und niemand wuesste warum. -->
|
||||
<script src="assets/js/anruf.js?v=202609280947"></script>
|
||||
<script src="assets/js/anruf.js?v=202609281013"></script>
|
||||
<!-- DIE BILDSCHAU (25.09.2026). Eigene Datei, weil sie nichts vom
|
||||
Chat weiss: Sie bekommt einen Weg und einen Namen und zeigt ein
|
||||
Bild. Jede andere Seite mit Fotos kann sie ebenso benutzen, ohne
|
||||
@@ -767,8 +767,8 @@
|
||||
sie beim ersten Foto noch nicht da -- und der erste Klick ginge
|
||||
wie frueher in den Tab. Ein Fehler, der nur beim ERSTEN Mal
|
||||
auftritt, ist der, den man nie nachstellen kann. -->
|
||||
<script src="assets/js/bildschau.js?v=202609280947"></script>
|
||||
<script src="assets/js/chat.js?v=202609280947"></script>
|
||||
<script src="assets/js/installieren.js?v=202609280947" defer></script>
|
||||
<script src="assets/js/bildschau.js?v=202609281013"></script>
|
||||
<script src="assets/js/chat.js?v=202609281013"></script>
|
||||
<script src="assets/js/installieren.js?v=202609281013" defer></script>
|
||||
</body>
|
||||
</html>
|
||||
|
||||
+17
-17
@@ -12,20 +12,20 @@
|
||||
Ton wie die Kopfleiste darunter (#06090f), damit Leiste und Seite
|
||||
eine Flaeche sind statt zweier. -->
|
||||
<meta name="theme-color" content="#06090f" />
|
||||
<link rel="icon" type="image/png" href="/assets/img/app-symbole/workspace-32.png?v=202609280947" />
|
||||
<link rel="apple-touch-icon" href="/assets/img/app-symbole/workspace-180.png?v=202609280947" />
|
||||
<link rel="stylesheet" href="assets/css/gate.css?v=202609280947" />
|
||||
<link rel="stylesheet" href="assets/css/start.css?v=202609280947" />
|
||||
<link rel="stylesheet" href="assets/css/aufgaben.css?v=202609280947" />
|
||||
<link rel="stylesheet" href="assets/css/content.css?v=202609280947" />
|
||||
<link rel="stylesheet" href="assets/css/module.css?v=202609280947" />
|
||||
<link rel="icon" type="image/png" href="/assets/img/app-symbole/workspace-32.png?v=202609281013" />
|
||||
<link rel="apple-touch-icon" href="/assets/img/app-symbole/workspace-180.png?v=202609281013" />
|
||||
<link rel="stylesheet" href="assets/css/gate.css?v=202609281013" />
|
||||
<link rel="stylesheet" href="assets/css/start.css?v=202609281013" />
|
||||
<link rel="stylesheet" href="assets/css/aufgaben.css?v=202609281013" />
|
||||
<link rel="stylesheet" href="assets/css/content.css?v=202609281013" />
|
||||
<link rel="stylesheet" href="assets/css/module.css?v=202609281013" />
|
||||
<!-- haus.css MUSS die letzte Stilvorlage sein (10.09.2026).
|
||||
Auf der Agenturadresse ist sie leer -- das Haus hier IST der
|
||||
Grundzustand. Auf der Adresse von Team Dogi biegt der Server
|
||||
genau diesen Dateinamen auf crew-haus.css um, und die Seite
|
||||
kommt schon beim ERSTEN Abruf in Lila und Babyblau an --
|
||||
ohne Umfaerben im Browser, ohne Flackern. -->
|
||||
<link rel="stylesheet" href="assets/css/haus.css?v=202609280947" />
|
||||
<link rel="stylesheet" href="assets/css/haus.css?v=202609281013" />
|
||||
</head>
|
||||
|
||||
<body class="start">
|
||||
@@ -179,15 +179,15 @@
|
||||
|
||||
</main>
|
||||
|
||||
<script src="assets/js/meldung.js?v=202609280947" defer></script>
|
||||
<script src="assets/js/nachfrage.js?v=202609280947" defer></script>
|
||||
<script src="assets/js/meldung.js?v=202609281013" defer></script>
|
||||
<script src="assets/js/nachfrage.js?v=202609281013" defer></script>
|
||||
|
||||
<script src="assets/js/wahl.js?v=202609280947" defer></script>
|
||||
<script src="assets/js/bereiche.js?v=202609280947" defer></script>
|
||||
<script src="assets/js/installieren.js?v=202609280947" defer></script>
|
||||
<script src="assets/js/kopf.js?v=202609280947" defer></script>
|
||||
<script src="assets/js/glocke.js?v=202609280947" defer></script>
|
||||
<script src="assets/js/checkliste.js?v=202609280947" defer></script>
|
||||
<script src="assets/js/content.js?v=202609280947" defer></script>
|
||||
<script src="assets/js/wahl.js?v=202609281013" defer></script>
|
||||
<script src="assets/js/bereiche.js?v=202609281013" defer></script>
|
||||
<script src="assets/js/installieren.js?v=202609281013" defer></script>
|
||||
<script src="assets/js/kopf.js?v=202609281013" defer></script>
|
||||
<script src="assets/js/glocke.js?v=202609281013" defer></script>
|
||||
<script src="assets/js/checkliste.js?v=202609281013" defer></script>
|
||||
<script src="assets/js/content.js?v=202609281013" defer></script>
|
||||
</body>
|
||||
</html>
|
||||
|
||||
@@ -36,15 +36,15 @@
|
||||
<link rel="preload" as="image" href="assets/img/buehne/crew-gate-hoch-580.webp"
|
||||
type="image/webp" media="(max-width: 899px)" />
|
||||
|
||||
<link rel="icon" type="image/png" href="/assets/img/app-symbole/crew-32.png?v=202609280947" />
|
||||
<link rel="apple-touch-icon" href="/assets/img/app-symbole/crew-180.png?v=202609280947" />
|
||||
<link rel="stylesheet" href="assets/css/gate.css?v=202609280947" />
|
||||
<link rel="icon" type="image/png" href="/assets/img/app-symbole/crew-32.png?v=202609281013" />
|
||||
<link rel="apple-touch-icon" href="/assets/img/app-symbole/crew-180.png?v=202609281013" />
|
||||
<link rel="stylesheet" href="assets/css/gate.css?v=202609281013" />
|
||||
<!-- Diese Wand steht NUR auf der Adresse von Team Dogi (ueberall sonst
|
||||
404, siehe crewWeiche). Sie darf das Haus deshalb direkt nennen
|
||||
statt ueber den Platzhalter haus.css zu gehen -- und sie MUSS es:
|
||||
Eine Zugangswand, die sich erst nach dem Umbiegen faerbt, waere
|
||||
die eine Seite, auf der man das Umfaerben sieht. -->
|
||||
<link rel="stylesheet" href="assets/css/crew-haus.css?v=202609280947" />
|
||||
<link rel="stylesheet" href="assets/css/crew-haus.css?v=202609281013" />
|
||||
</head>
|
||||
|
||||
<body class="gate gate--crew">
|
||||
@@ -459,7 +459,7 @@
|
||||
|
||||
|
||||
|
||||
<script src="assets/js/gate.js?v=202609280947" defer></script>
|
||||
<script src="assets/js/installieren.js?v=202609280947" defer></script>
|
||||
<script src="assets/js/gate.js?v=202609281013" defer></script>
|
||||
<script src="assets/js/installieren.js?v=202609281013" defer></script>
|
||||
</body>
|
||||
</html>
|
||||
|
||||
@@ -23,25 +23,25 @@
|
||||
},
|
||||
"icons": [
|
||||
{
|
||||
"src": "/assets/img/app-symbole/crew-192.png?v=202609280947",
|
||||
"src": "/assets/img/app-symbole/crew-192.png?v=202609281013",
|
||||
"sizes": "192x192",
|
||||
"type": "image/png",
|
||||
"purpose": "any"
|
||||
},
|
||||
{
|
||||
"src": "/assets/img/app-symbole/crew-512.png?v=202609280947",
|
||||
"src": "/assets/img/app-symbole/crew-512.png?v=202609281013",
|
||||
"sizes": "512x512",
|
||||
"type": "image/png",
|
||||
"purpose": "any"
|
||||
},
|
||||
{
|
||||
"src": "/assets/img/app-symbole/crew-192-maskable.png?v=202609280947",
|
||||
"src": "/assets/img/app-symbole/crew-192-maskable.png?v=202609281013",
|
||||
"sizes": "192x192",
|
||||
"type": "image/png",
|
||||
"purpose": "maskable"
|
||||
},
|
||||
{
|
||||
"src": "/assets/img/app-symbole/crew-512-maskable.png?v=202609280947",
|
||||
"src": "/assets/img/app-symbole/crew-512-maskable.png?v=202609281013",
|
||||
"sizes": "512x512",
|
||||
"type": "image/png",
|
||||
"purpose": "maskable"
|
||||
|
||||
+17
-17
@@ -12,20 +12,20 @@
|
||||
Ton wie die Kopfleiste darunter (#06090f), damit Leiste und Seite
|
||||
eine Flaeche sind statt zweier. -->
|
||||
<meta name="theme-color" content="#06090f" />
|
||||
<link rel="icon" type="image/png" href="/assets/img/app-symbole/workspace-32.png?v=202609280947" />
|
||||
<link rel="apple-touch-icon" href="/assets/img/app-symbole/workspace-180.png?v=202609280947" />
|
||||
<link rel="stylesheet" href="assets/css/gate.css?v=202609280947" />
|
||||
<link rel="stylesheet" href="assets/css/start.css?v=202609280947" />
|
||||
<link rel="stylesheet" href="assets/css/aufgaben.css?v=202609280947" />
|
||||
<link rel="stylesheet" href="assets/css/dateien.css?v=202609280947" />
|
||||
<link rel="stylesheet" href="assets/css/module.css?v=202609280947" />
|
||||
<link rel="icon" type="image/png" href="/assets/img/app-symbole/workspace-32.png?v=202609281013" />
|
||||
<link rel="apple-touch-icon" href="/assets/img/app-symbole/workspace-180.png?v=202609281013" />
|
||||
<link rel="stylesheet" href="assets/css/gate.css?v=202609281013" />
|
||||
<link rel="stylesheet" href="assets/css/start.css?v=202609281013" />
|
||||
<link rel="stylesheet" href="assets/css/aufgaben.css?v=202609281013" />
|
||||
<link rel="stylesheet" href="assets/css/dateien.css?v=202609281013" />
|
||||
<link rel="stylesheet" href="assets/css/module.css?v=202609281013" />
|
||||
<!-- haus.css MUSS die letzte Stilvorlage sein (10.09.2026).
|
||||
Auf der Agenturadresse ist sie leer -- das Haus hier IST der
|
||||
Grundzustand. Auf der Adresse von Team Dogi biegt der Server
|
||||
genau diesen Dateinamen auf crew-haus.css um, und die Seite
|
||||
kommt schon beim ERSTEN Abruf in Lila und Babyblau an --
|
||||
ohne Umfaerben im Browser, ohne Flackern. -->
|
||||
<link rel="stylesheet" href="assets/css/haus.css?v=202609280947" />
|
||||
<link rel="stylesheet" href="assets/css/haus.css?v=202609281013" />
|
||||
</head>
|
||||
|
||||
<body class="start">
|
||||
@@ -108,15 +108,15 @@
|
||||
|
||||
</main>
|
||||
|
||||
<script src="assets/js/meldung.js?v=202609280947" defer></script>
|
||||
<script src="assets/js/hochladen.js?v=202609280947" defer></script>
|
||||
<script src="assets/js/nachfrage.js?v=202609280947" defer></script>
|
||||
<script src="assets/js/meldung.js?v=202609281013" defer></script>
|
||||
<script src="assets/js/hochladen.js?v=202609281013" defer></script>
|
||||
<script src="assets/js/nachfrage.js?v=202609281013" defer></script>
|
||||
|
||||
<script src="assets/js/wahl.js?v=202609280947" defer></script>
|
||||
<script src="assets/js/bereiche.js?v=202609280947" defer></script>
|
||||
<script src="assets/js/installieren.js?v=202609280947" defer></script>
|
||||
<script src="assets/js/kopf.js?v=202609280947" defer></script>
|
||||
<script src="assets/js/glocke.js?v=202609280947" defer></script>
|
||||
<script src="assets/js/dateien.js?v=202609280947" defer></script>
|
||||
<script src="assets/js/wahl.js?v=202609281013" defer></script>
|
||||
<script src="assets/js/bereiche.js?v=202609281013" defer></script>
|
||||
<script src="assets/js/installieren.js?v=202609281013" defer></script>
|
||||
<script src="assets/js/kopf.js?v=202609281013" defer></script>
|
||||
<script src="assets/js/glocke.js?v=202609281013" defer></script>
|
||||
<script src="assets/js/dateien.js?v=202609281013" defer></script>
|
||||
</body>
|
||||
</html>
|
||||
|
||||
+18
-18
@@ -7,14 +7,14 @@
|
||||
<meta name="robots" content="noindex, nofollow" />
|
||||
<link rel="manifest" href="/workspace/app.webmanifest" />
|
||||
<meta name="theme-color" content="#06090f" />
|
||||
<link rel="icon" type="image/png" href="/assets/img/app-symbole/workspace-32.png?v=202609280947" />
|
||||
<link rel="apple-touch-icon" href="/assets/img/app-symbole/workspace-180.png?v=202609280947" />
|
||||
<link rel="stylesheet" href="assets/css/gate.css?v=202609280947" />
|
||||
<link rel="stylesheet" href="assets/css/start.css?v=202609280947" />
|
||||
<link rel="stylesheet" href="assets/css/aufgaben.css?v=202609280947" />
|
||||
<link rel="stylesheet" href="assets/css/entwicklung.css?v=202609280947" />
|
||||
<link rel="stylesheet" href="assets/css/module.css?v=202609280947" />
|
||||
<link rel="stylesheet" href="assets/css/haus.css?v=202609280947" />
|
||||
<link rel="icon" type="image/png" href="/assets/img/app-symbole/workspace-32.png?v=202609281013" />
|
||||
<link rel="apple-touch-icon" href="/assets/img/app-symbole/workspace-180.png?v=202609281013" />
|
||||
<link rel="stylesheet" href="assets/css/gate.css?v=202609281013" />
|
||||
<link rel="stylesheet" href="assets/css/start.css?v=202609281013" />
|
||||
<link rel="stylesheet" href="assets/css/aufgaben.css?v=202609281013" />
|
||||
<link rel="stylesheet" href="assets/css/entwicklung.css?v=202609281013" />
|
||||
<link rel="stylesheet" href="assets/css/module.css?v=202609281013" />
|
||||
<link rel="stylesheet" href="assets/css/haus.css?v=202609281013" />
|
||||
</head>
|
||||
|
||||
<body class="start">
|
||||
@@ -297,20 +297,20 @@
|
||||
|
||||
</main>
|
||||
|
||||
<script src="assets/js/meldung.js?v=202609280947" defer></script>
|
||||
<script src="assets/js/nachfrage.js?v=202609280947" defer></script>
|
||||
<script src="assets/js/meldung.js?v=202609281013" defer></script>
|
||||
<script src="assets/js/nachfrage.js?v=202609281013" defer></script>
|
||||
|
||||
|
||||
<script src="assets/js/wahl.js?v=202609280947" defer></script>
|
||||
<script src="assets/js/bereiche.js?v=202609280947" defer></script>
|
||||
<script src="assets/js/installieren.js?v=202609280947" defer></script>
|
||||
<script src="assets/js/kopf.js?v=202609280947" defer></script>
|
||||
<script src="assets/js/glocke.js?v=202609280947" defer></script>
|
||||
<script src="assets/js/holen.js?v=202609280947" defer></script>
|
||||
<script src="assets/js/wahl.js?v=202609281013" defer></script>
|
||||
<script src="assets/js/bereiche.js?v=202609281013" defer></script>
|
||||
<script src="assets/js/installieren.js?v=202609281013" defer></script>
|
||||
<script src="assets/js/kopf.js?v=202609281013" defer></script>
|
||||
<script src="assets/js/glocke.js?v=202609281013" defer></script>
|
||||
<script src="assets/js/holen.js?v=202609281013" defer></script>
|
||||
<!-- VOR entwicklung.js: Die Seite richtet den Katalog beim Start ein,
|
||||
also muss es ihn zu dem Zeitpunkt geben. Mit "defer" laufen beide
|
||||
in Dokumentreihenfolge. -->
|
||||
<script src="assets/js/vorlagenbrett.js?v=202609280947" defer></script>
|
||||
<script src="assets/js/entwicklung.js?v=202609280947" defer></script>
|
||||
<script src="assets/js/vorlagenbrett.js?v=202609281013" defer></script>
|
||||
<script src="assets/js/entwicklung.js?v=202609281013" defer></script>
|
||||
</body>
|
||||
</html>
|
||||
|
||||
+15
-15
@@ -7,13 +7,13 @@
|
||||
<meta name="robots" content="noindex, nofollow" />
|
||||
<link rel="manifest" href="/workspace/app.webmanifest" />
|
||||
<meta name="theme-color" content="#06090f" />
|
||||
<link rel="icon" type="image/png" href="/assets/img/app-symbole/workspace-32.png?v=202609280947" />
|
||||
<link rel="apple-touch-icon" href="/assets/img/app-symbole/workspace-180.png?v=202609280947" />
|
||||
<link rel="stylesheet" href="assets/css/gate.css?v=202609280947" />
|
||||
<link rel="stylesheet" href="assets/css/start.css?v=202609280947" />
|
||||
<link rel="stylesheet" href="assets/css/hilfe.css?v=202609280947" />
|
||||
<link rel="stylesheet" href="assets/css/module.css?v=202609280947" />
|
||||
<link rel="stylesheet" href="assets/css/haus.css?v=202609280947" />
|
||||
<link rel="icon" type="image/png" href="/assets/img/app-symbole/workspace-32.png?v=202609281013" />
|
||||
<link rel="apple-touch-icon" href="/assets/img/app-symbole/workspace-180.png?v=202609281013" />
|
||||
<link rel="stylesheet" href="assets/css/gate.css?v=202609281013" />
|
||||
<link rel="stylesheet" href="assets/css/start.css?v=202609281013" />
|
||||
<link rel="stylesheet" href="assets/css/hilfe.css?v=202609281013" />
|
||||
<link rel="stylesheet" href="assets/css/module.css?v=202609281013" />
|
||||
<link rel="stylesheet" href="assets/css/haus.css?v=202609281013" />
|
||||
</head>
|
||||
|
||||
<body class="start">
|
||||
@@ -146,14 +146,14 @@
|
||||
|
||||
</main>
|
||||
|
||||
<script src="assets/js/meldung.js?v=202609280947" defer></script>
|
||||
<script src="assets/js/nachfrage.js?v=202609280947" defer></script>
|
||||
<script src="assets/js/meldung.js?v=202609281013" defer></script>
|
||||
<script src="assets/js/nachfrage.js?v=202609281013" defer></script>
|
||||
|
||||
<script src="assets/js/wahl.js?v=202609280947" defer></script>
|
||||
<script src="assets/js/bereiche.js?v=202609280947" defer></script>
|
||||
<script src="assets/js/installieren.js?v=202609280947" defer></script>
|
||||
<script src="assets/js/kopf.js?v=202609280947" defer></script>
|
||||
<script src="assets/js/glocke.js?v=202609280947" defer></script>
|
||||
<script src="assets/js/hilfe.js?v=202609280947" defer></script>
|
||||
<script src="assets/js/wahl.js?v=202609281013" defer></script>
|
||||
<script src="assets/js/bereiche.js?v=202609281013" defer></script>
|
||||
<script src="assets/js/installieren.js?v=202609281013" defer></script>
|
||||
<script src="assets/js/kopf.js?v=202609281013" defer></script>
|
||||
<script src="assets/js/glocke.js?v=202609281013" defer></script>
|
||||
<script src="assets/js/hilfe.js?v=202609281013" defer></script>
|
||||
</body>
|
||||
</html>
|
||||
|
||||
@@ -30,9 +30,9 @@
|
||||
<link rel="preload" as="image" href="assets/img/buehne/gate-hoch-580.webp"
|
||||
type="image/webp" media="(max-width: 899px)" />
|
||||
|
||||
<link rel="icon" type="image/png" href="/assets/img/app-symbole/workspace-32.png?v=202609280947" />
|
||||
<link rel="apple-touch-icon" href="/assets/img/app-symbole/workspace-180.png?v=202609280947" />
|
||||
<link rel="stylesheet" href="assets/css/gate.css?v=202609280947" />
|
||||
<link rel="icon" type="image/png" href="/assets/img/app-symbole/workspace-32.png?v=202609281013" />
|
||||
<link rel="apple-touch-icon" href="/assets/img/app-symbole/workspace-180.png?v=202609281013" />
|
||||
<link rel="stylesheet" href="assets/css/gate.css?v=202609281013" />
|
||||
</head>
|
||||
|
||||
<body class="gate">
|
||||
@@ -427,7 +427,7 @@
|
||||
|
||||
|
||||
|
||||
<script src="assets/js/gate.js?v=202609280947" defer></script>
|
||||
<script src="assets/js/installieren.js?v=202609280947" defer></script>
|
||||
<script src="assets/js/gate.js?v=202609281013" defer></script>
|
||||
<script src="assets/js/installieren.js?v=202609281013" defer></script>
|
||||
</body>
|
||||
</html>
|
||||
|
||||
+17
-17
@@ -12,20 +12,20 @@
|
||||
Ton wie die Kopfleiste darunter (#06090f), damit Leiste und Seite
|
||||
eine Flaeche sind statt zweier. -->
|
||||
<meta name="theme-color" content="#06090f" />
|
||||
<link rel="icon" type="image/png" href="/assets/img/app-symbole/workspace-32.png?v=202609280947" />
|
||||
<link rel="apple-touch-icon" href="/assets/img/app-symbole/workspace-180.png?v=202609280947" />
|
||||
<link rel="stylesheet" href="assets/css/gate.css?v=202609280947" />
|
||||
<link rel="stylesheet" href="assets/css/start.css?v=202609280947" />
|
||||
<link rel="stylesheet" href="assets/css/aufgaben.css?v=202609280947" />
|
||||
<link rel="stylesheet" href="assets/css/kalender.css?v=202609280947" />
|
||||
<link rel="stylesheet" href="assets/css/module.css?v=202609280947" />
|
||||
<link rel="icon" type="image/png" href="/assets/img/app-symbole/workspace-32.png?v=202609281013" />
|
||||
<link rel="apple-touch-icon" href="/assets/img/app-symbole/workspace-180.png?v=202609281013" />
|
||||
<link rel="stylesheet" href="assets/css/gate.css?v=202609281013" />
|
||||
<link rel="stylesheet" href="assets/css/start.css?v=202609281013" />
|
||||
<link rel="stylesheet" href="assets/css/aufgaben.css?v=202609281013" />
|
||||
<link rel="stylesheet" href="assets/css/kalender.css?v=202609281013" />
|
||||
<link rel="stylesheet" href="assets/css/module.css?v=202609281013" />
|
||||
<!-- haus.css MUSS die letzte Stilvorlage sein (10.09.2026).
|
||||
Auf der Agenturadresse ist sie leer -- das Haus hier IST der
|
||||
Grundzustand. Auf der Adresse von Team Dogi biegt der Server
|
||||
genau diesen Dateinamen auf crew-haus.css um, und die Seite
|
||||
kommt schon beim ERSTEN Abruf in Lila und Babyblau an --
|
||||
ohne Umfaerben im Browser, ohne Flackern. -->
|
||||
<link rel="stylesheet" href="assets/css/haus.css?v=202609280947" />
|
||||
<link rel="stylesheet" href="assets/css/haus.css?v=202609281013" />
|
||||
</head>
|
||||
|
||||
<body class="start">
|
||||
@@ -383,15 +383,15 @@
|
||||
|
||||
</main>
|
||||
|
||||
<script src="assets/js/meldung.js?v=202609280947" defer></script>
|
||||
<script src="assets/js/nachfrage.js?v=202609280947" defer></script>
|
||||
<script src="assets/js/meldung.js?v=202609281013" defer></script>
|
||||
<script src="assets/js/nachfrage.js?v=202609281013" defer></script>
|
||||
|
||||
<script src="assets/js/wahl.js?v=202609280947" defer></script>
|
||||
<script src="assets/js/bereiche.js?v=202609280947" defer></script>
|
||||
<script src="assets/js/installieren.js?v=202609280947" defer></script>
|
||||
<script src="assets/js/kopf.js?v=202609280947" defer></script>
|
||||
<script src="assets/js/glocke.js?v=202609280947" defer></script>
|
||||
<script src="assets/js/kalender.js?v=202609280947" defer></script>
|
||||
<script src="assets/js/kalender-abo.js?v=202609280947" defer></script>
|
||||
<script src="assets/js/wahl.js?v=202609281013" defer></script>
|
||||
<script src="assets/js/bereiche.js?v=202609281013" defer></script>
|
||||
<script src="assets/js/installieren.js?v=202609281013" defer></script>
|
||||
<script src="assets/js/kopf.js?v=202609281013" defer></script>
|
||||
<script src="assets/js/glocke.js?v=202609281013" defer></script>
|
||||
<script src="assets/js/kalender.js?v=202609281013" defer></script>
|
||||
<script src="assets/js/kalender-abo.js?v=202609281013" defer></script>
|
||||
</body>
|
||||
</html>
|
||||
|
||||
+16
-16
@@ -12,20 +12,20 @@
|
||||
Ton wie die Kopfleiste darunter (#06090f), damit Leiste und Seite
|
||||
eine Flaeche sind statt zweier. -->
|
||||
<meta name="theme-color" content="#06090f" />
|
||||
<link rel="icon" type="image/png" href="/assets/img/app-symbole/workspace-32.png?v=202609280947" />
|
||||
<link rel="apple-touch-icon" href="/assets/img/app-symbole/workspace-180.png?v=202609280947" />
|
||||
<link rel="stylesheet" href="assets/css/gate.css?v=202609280947" />
|
||||
<link rel="stylesheet" href="assets/css/start.css?v=202609280947" />
|
||||
<link rel="stylesheet" href="assets/css/aufgaben.css?v=202609280947" />
|
||||
<link rel="stylesheet" href="assets/css/leistung.css?v=202609280947" />
|
||||
<link rel="stylesheet" href="assets/css/module.css?v=202609280947" />
|
||||
<link rel="icon" type="image/png" href="/assets/img/app-symbole/workspace-32.png?v=202609281013" />
|
||||
<link rel="apple-touch-icon" href="/assets/img/app-symbole/workspace-180.png?v=202609281013" />
|
||||
<link rel="stylesheet" href="assets/css/gate.css?v=202609281013" />
|
||||
<link rel="stylesheet" href="assets/css/start.css?v=202609281013" />
|
||||
<link rel="stylesheet" href="assets/css/aufgaben.css?v=202609281013" />
|
||||
<link rel="stylesheet" href="assets/css/leistung.css?v=202609281013" />
|
||||
<link rel="stylesheet" href="assets/css/module.css?v=202609281013" />
|
||||
<!-- haus.css MUSS die letzte Stilvorlage sein (10.09.2026).
|
||||
Auf der Agenturadresse ist sie leer -- das Haus hier IST der
|
||||
Grundzustand. Auf der Adresse von Team Dogi biegt der Server
|
||||
genau diesen Dateinamen auf crew-haus.css um, und die Seite
|
||||
kommt schon beim ERSTEN Abruf in Lila und Babyblau an --
|
||||
ohne Umfaerben im Browser, ohne Flackern. -->
|
||||
<link rel="stylesheet" href="assets/css/haus.css?v=202609280947" />
|
||||
<link rel="stylesheet" href="assets/css/haus.css?v=202609281013" />
|
||||
</head>
|
||||
|
||||
<body class="start">
|
||||
@@ -444,13 +444,13 @@
|
||||
</form>
|
||||
</dialog>
|
||||
|
||||
<script src="assets/js/meldung.js?v=202609280947"></script>
|
||||
<script src="assets/js/nachfrage.js?v=202609280947"></script>
|
||||
<script src="assets/js/wahl.js?v=202609280947"></script>
|
||||
<script src="assets/js/bereiche.js?v=202609280947"></script>
|
||||
<script src="assets/js/kopf.js?v=202609280947"></script>
|
||||
<script src="assets/js/glocke.js?v=202609280947"></script>
|
||||
<script src="assets/js/leistung.js?v=202609280947"></script>
|
||||
<script src="assets/js/installieren.js?v=202609280947" defer></script>
|
||||
<script src="assets/js/meldung.js?v=202609281013"></script>
|
||||
<script src="assets/js/nachfrage.js?v=202609281013"></script>
|
||||
<script src="assets/js/wahl.js?v=202609281013"></script>
|
||||
<script src="assets/js/bereiche.js?v=202609281013"></script>
|
||||
<script src="assets/js/kopf.js?v=202609281013"></script>
|
||||
<script src="assets/js/glocke.js?v=202609281013"></script>
|
||||
<script src="assets/js/leistung.js?v=202609281013"></script>
|
||||
<script src="assets/js/installieren.js?v=202609281013" defer></script>
|
||||
</body>
|
||||
</html>
|
||||
|
||||
+16
-16
@@ -12,13 +12,13 @@
|
||||
vergessen wird. -->
|
||||
<link rel="manifest" href="/workspace/app.webmanifest" />
|
||||
<meta name="theme-color" content="#06090f" />
|
||||
<link rel="icon" type="image/png" href="/assets/img/app-symbole/workspace-32.png?v=202609280947" />
|
||||
<link rel="apple-touch-icon" href="/assets/img/app-symbole/workspace-180.png?v=202609280947" />
|
||||
<link rel="stylesheet" href="assets/css/gate.css?v=202609280947" />
|
||||
<link rel="stylesheet" href="assets/css/start.css?v=202609280947" />
|
||||
<link rel="stylesheet" href="assets/css/material.css?v=202609280947" />
|
||||
<link rel="stylesheet" href="assets/css/module.css?v=202609280947" />
|
||||
<link rel="stylesheet" href="assets/css/haus.css?v=202609280947" />
|
||||
<link rel="icon" type="image/png" href="/assets/img/app-symbole/workspace-32.png?v=202609281013" />
|
||||
<link rel="apple-touch-icon" href="/assets/img/app-symbole/workspace-180.png?v=202609281013" />
|
||||
<link rel="stylesheet" href="assets/css/gate.css?v=202609281013" />
|
||||
<link rel="stylesheet" href="assets/css/start.css?v=202609281013" />
|
||||
<link rel="stylesheet" href="assets/css/material.css?v=202609281013" />
|
||||
<link rel="stylesheet" href="assets/css/module.css?v=202609281013" />
|
||||
<link rel="stylesheet" href="assets/css/haus.css?v=202609281013" />
|
||||
</head>
|
||||
<body class="start" data-ton="42" data-buehne="studio">
|
||||
|
||||
@@ -138,14 +138,14 @@
|
||||
<p class="m-laedt" id="laedt">Einen Moment …</p>
|
||||
</main>
|
||||
|
||||
<script src="assets/js/meldung.js?v=202609280947" defer></script>
|
||||
<script src="assets/js/nachfrage.js?v=202609280947" defer></script>
|
||||
<script src="assets/js/hochladen.js?v=202609280947" defer></script>
|
||||
<script src="assets/js/wahl.js?v=202609280947" defer></script>
|
||||
<script src="assets/js/bereiche.js?v=202609280947" defer></script>
|
||||
<script src="assets/js/installieren.js?v=202609280947" defer></script>
|
||||
<script src="assets/js/kopf.js?v=202609280947" defer></script>
|
||||
<script src="assets/js/glocke.js?v=202609280947" defer></script>
|
||||
<script src="assets/js/material.js?v=202609280947" defer></script>
|
||||
<script src="assets/js/meldung.js?v=202609281013" defer></script>
|
||||
<script src="assets/js/nachfrage.js?v=202609281013" defer></script>
|
||||
<script src="assets/js/hochladen.js?v=202609281013" defer></script>
|
||||
<script src="assets/js/wahl.js?v=202609281013" defer></script>
|
||||
<script src="assets/js/bereiche.js?v=202609281013" defer></script>
|
||||
<script src="assets/js/installieren.js?v=202609281013" defer></script>
|
||||
<script src="assets/js/kopf.js?v=202609281013" defer></script>
|
||||
<script src="assets/js/glocke.js?v=202609281013" defer></script>
|
||||
<script src="assets/js/material.js?v=202609281013" defer></script>
|
||||
</body>
|
||||
</html>
|
||||
|
||||
+14
-14
@@ -7,13 +7,13 @@
|
||||
<meta name="robots" content="noindex, nofollow" />
|
||||
<link rel="manifest" href="/workspace/app.webmanifest" />
|
||||
<meta name="theme-color" content="#06090f" />
|
||||
<link rel="icon" type="image/png" href="/assets/img/app-symbole/workspace-32.png?v=202609280947" />
|
||||
<link rel="apple-touch-icon" href="/assets/img/app-symbole/workspace-180.png?v=202609280947" />
|
||||
<link rel="stylesheet" href="assets/css/gate.css?v=202609280947" />
|
||||
<link rel="stylesheet" href="assets/css/start.css?v=202609280947" />
|
||||
<link rel="stylesheet" href="assets/css/notizen.css?v=202609280947" />
|
||||
<link rel="stylesheet" href="assets/css/module.css?v=202609280947" />
|
||||
<link rel="stylesheet" href="assets/css/haus.css?v=202609280947" />
|
||||
<link rel="icon" type="image/png" href="/assets/img/app-symbole/workspace-32.png?v=202609281013" />
|
||||
<link rel="apple-touch-icon" href="/assets/img/app-symbole/workspace-180.png?v=202609281013" />
|
||||
<link rel="stylesheet" href="assets/css/gate.css?v=202609281013" />
|
||||
<link rel="stylesheet" href="assets/css/start.css?v=202609281013" />
|
||||
<link rel="stylesheet" href="assets/css/notizen.css?v=202609281013" />
|
||||
<link rel="stylesheet" href="assets/css/module.css?v=202609281013" />
|
||||
<link rel="stylesheet" href="assets/css/haus.css?v=202609281013" />
|
||||
</head>
|
||||
|
||||
<body class="start" data-ton="46">
|
||||
@@ -181,12 +181,12 @@
|
||||
|
||||
<!-- bereiche.js VOR kopf.js: Dort steht `window.Bereiche`, und kopf.js
|
||||
liest daraus die Leitungsrollen. -->
|
||||
<script src="assets/js/bereiche.js?v=202609280947" defer></script>
|
||||
<script src="assets/js/wahl.js?v=202609280947" defer></script>
|
||||
<script src="assets/js/nachfrage.js?v=202609280947" defer></script>
|
||||
<script src="assets/js/installieren.js?v=202609280947" defer></script>
|
||||
<script src="assets/js/kopf.js?v=202609280947" defer></script>
|
||||
<script src="assets/js/glocke.js?v=202609280947" defer></script>
|
||||
<script src="assets/js/notizen.js?v=202609280947" defer></script>
|
||||
<script src="assets/js/bereiche.js?v=202609281013" defer></script>
|
||||
<script src="assets/js/wahl.js?v=202609281013" defer></script>
|
||||
<script src="assets/js/nachfrage.js?v=202609281013" defer></script>
|
||||
<script src="assets/js/installieren.js?v=202609281013" defer></script>
|
||||
<script src="assets/js/kopf.js?v=202609281013" defer></script>
|
||||
<script src="assets/js/glocke.js?v=202609281013" defer></script>
|
||||
<script src="assets/js/notizen.js?v=202609281013" defer></script>
|
||||
</body>
|
||||
</html>
|
||||
|
||||
+16
-16
@@ -12,20 +12,20 @@
|
||||
Ton wie die Kopfleiste darunter (#06090f), damit Leiste und Seite
|
||||
eine Flaeche sind statt zweier. -->
|
||||
<meta name="theme-color" content="#06090f" />
|
||||
<link rel="icon" type="image/png" href="/assets/img/app-symbole/workspace-32.png?v=202609280947" />
|
||||
<link rel="apple-touch-icon" href="/assets/img/app-symbole/workspace-180.png?v=202609280947" />
|
||||
<link rel="stylesheet" href="assets/css/gate.css?v=202609280947" />
|
||||
<link rel="stylesheet" href="assets/css/start.css?v=202609280947" />
|
||||
<link rel="stylesheet" href="assets/css/aufgaben.css?v=202609280947" />
|
||||
<link rel="stylesheet" href="assets/css/personen.css?v=202609280947" />
|
||||
<link rel="stylesheet" href="assets/css/module.css?v=202609280947" />
|
||||
<link rel="icon" type="image/png" href="/assets/img/app-symbole/workspace-32.png?v=202609281013" />
|
||||
<link rel="apple-touch-icon" href="/assets/img/app-symbole/workspace-180.png?v=202609281013" />
|
||||
<link rel="stylesheet" href="assets/css/gate.css?v=202609281013" />
|
||||
<link rel="stylesheet" href="assets/css/start.css?v=202609281013" />
|
||||
<link rel="stylesheet" href="assets/css/aufgaben.css?v=202609281013" />
|
||||
<link rel="stylesheet" href="assets/css/personen.css?v=202609281013" />
|
||||
<link rel="stylesheet" href="assets/css/module.css?v=202609281013" />
|
||||
<!-- haus.css MUSS die letzte Stilvorlage sein (10.09.2026).
|
||||
Auf der Agenturadresse ist sie leer -- das Haus hier IST der
|
||||
Grundzustand. Auf der Adresse von Team Dogi biegt der Server
|
||||
genau diesen Dateinamen auf crew-haus.css um, und die Seite
|
||||
kommt schon beim ERSTEN Abruf in Lila und Babyblau an --
|
||||
ohne Umfaerben im Browser, ohne Flackern. -->
|
||||
<link rel="stylesheet" href="assets/css/haus.css?v=202609280947" />
|
||||
<link rel="stylesheet" href="assets/css/haus.css?v=202609281013" />
|
||||
</head>
|
||||
|
||||
<body class="start">
|
||||
@@ -453,14 +453,14 @@
|
||||
|
||||
</main>
|
||||
|
||||
<script src="assets/js/meldung.js?v=202609280947" defer></script>
|
||||
<script src="assets/js/nachfrage.js?v=202609280947" defer></script>
|
||||
<script src="assets/js/meldung.js?v=202609281013" defer></script>
|
||||
<script src="assets/js/nachfrage.js?v=202609281013" defer></script>
|
||||
|
||||
<script src="assets/js/wahl.js?v=202609280947" defer></script>
|
||||
<script src="assets/js/bereiche.js?v=202609280947" defer></script>
|
||||
<script src="assets/js/installieren.js?v=202609280947" defer></script>
|
||||
<script src="assets/js/kopf.js?v=202609280947" defer></script>
|
||||
<script src="assets/js/glocke.js?v=202609280947" defer></script>
|
||||
<script src="assets/js/personen.js?v=202609280947" defer></script>
|
||||
<script src="assets/js/wahl.js?v=202609281013" defer></script>
|
||||
<script src="assets/js/bereiche.js?v=202609281013" defer></script>
|
||||
<script src="assets/js/installieren.js?v=202609281013" defer></script>
|
||||
<script src="assets/js/kopf.js?v=202609281013" defer></script>
|
||||
<script src="assets/js/glocke.js?v=202609281013" defer></script>
|
||||
<script src="assets/js/personen.js?v=202609281013" defer></script>
|
||||
</body>
|
||||
</html>
|
||||
|
||||
+18
-18
@@ -12,20 +12,20 @@
|
||||
Ton wie die Kopfleiste darunter (#06090f), damit Leiste und Seite
|
||||
eine Flaeche sind statt zweier. -->
|
||||
<meta name="theme-color" content="#06090f" />
|
||||
<link rel="icon" type="image/png" href="/assets/img/app-symbole/workspace-32.png?v=202609280947" />
|
||||
<link rel="apple-touch-icon" href="/assets/img/app-symbole/workspace-180.png?v=202609280947" />
|
||||
<link rel="stylesheet" href="assets/css/gate.css?v=202609280947" />
|
||||
<link rel="stylesheet" href="assets/css/start.css?v=202609280947" />
|
||||
<link rel="stylesheet" href="assets/css/aufgaben.css?v=202609280947" />
|
||||
<link rel="stylesheet" href="assets/css/profil.css?v=202609280947" />
|
||||
<link rel="stylesheet" href="assets/css/module.css?v=202609280947" />
|
||||
<link rel="icon" type="image/png" href="/assets/img/app-symbole/workspace-32.png?v=202609281013" />
|
||||
<link rel="apple-touch-icon" href="/assets/img/app-symbole/workspace-180.png?v=202609281013" />
|
||||
<link rel="stylesheet" href="assets/css/gate.css?v=202609281013" />
|
||||
<link rel="stylesheet" href="assets/css/start.css?v=202609281013" />
|
||||
<link rel="stylesheet" href="assets/css/aufgaben.css?v=202609281013" />
|
||||
<link rel="stylesheet" href="assets/css/profil.css?v=202609281013" />
|
||||
<link rel="stylesheet" href="assets/css/module.css?v=202609281013" />
|
||||
<!-- haus.css MUSS die letzte Stilvorlage sein (10.09.2026).
|
||||
Auf der Agenturadresse ist sie leer -- das Haus hier IST der
|
||||
Grundzustand. Auf der Adresse von Team Dogi biegt der Server
|
||||
genau diesen Dateinamen auf crew-haus.css um, und die Seite
|
||||
kommt schon beim ERSTEN Abruf in Lila und Babyblau an --
|
||||
ohne Umfaerben im Browser, ohne Flackern. -->
|
||||
<link rel="stylesheet" href="assets/css/haus.css?v=202609280947" />
|
||||
<link rel="stylesheet" href="assets/css/haus.css?v=202609281013" />
|
||||
</head>
|
||||
|
||||
<body class="start">
|
||||
@@ -214,16 +214,16 @@
|
||||
|
||||
</main>
|
||||
|
||||
<script src="assets/js/meldung.js?v=202609280947" defer></script>
|
||||
<script src="assets/js/hochladen.js?v=202609280947" defer></script>
|
||||
<script src="assets/js/nachfrage.js?v=202609280947" defer></script>
|
||||
<script src="assets/js/meldung.js?v=202609281013" defer></script>
|
||||
<script src="assets/js/hochladen.js?v=202609281013" defer></script>
|
||||
<script src="assets/js/nachfrage.js?v=202609281013" defer></script>
|
||||
|
||||
<script src="assets/js/wahl.js?v=202609280947" defer></script>
|
||||
<script src="assets/js/bereiche.js?v=202609280947" defer></script>
|
||||
<script src="assets/js/installieren.js?v=202609280947" defer></script>
|
||||
<script src="assets/js/kopf.js?v=202609280947" defer></script>
|
||||
<script src="assets/js/glocke.js?v=202609280947" defer></script>
|
||||
<script src="assets/js/steckbrief.js?v=202609280947" defer></script>
|
||||
<script src="assets/js/profil.js?v=202609280947" defer></script>
|
||||
<script src="assets/js/wahl.js?v=202609281013" defer></script>
|
||||
<script src="assets/js/bereiche.js?v=202609281013" defer></script>
|
||||
<script src="assets/js/installieren.js?v=202609281013" defer></script>
|
||||
<script src="assets/js/kopf.js?v=202609281013" defer></script>
|
||||
<script src="assets/js/glocke.js?v=202609281013" defer></script>
|
||||
<script src="assets/js/steckbrief.js?v=202609281013" defer></script>
|
||||
<script src="assets/js/profil.js?v=202609281013" defer></script>
|
||||
</body>
|
||||
</html>
|
||||
|
||||
+43
-17
@@ -7,14 +7,14 @@
|
||||
<meta name="robots" content="noindex, nofollow" />
|
||||
<link rel="manifest" href="/workspace/app.webmanifest" />
|
||||
<meta name="theme-color" content="#06090f" />
|
||||
<link rel="icon" type="image/png" href="/assets/img/app-symbole/workspace-32.png?v=202609280947" />
|
||||
<link rel="apple-touch-icon" href="/assets/img/app-symbole/workspace-180.png?v=202609280947" />
|
||||
<link rel="stylesheet" href="assets/css/gate.css?v=202609280947" />
|
||||
<link rel="stylesheet" href="assets/css/start.css?v=202609280947" />
|
||||
<link rel="stylesheet" href="assets/css/reaktion.css?v=202609280947" />
|
||||
<link rel="stylesheet" href="assets/css/spendenkarte.css?v=202609280947" />
|
||||
<link rel="stylesheet" href="assets/css/module.css?v=202609280947" />
|
||||
<link rel="stylesheet" href="assets/css/haus.css?v=202609280947" />
|
||||
<link rel="icon" type="image/png" href="/assets/img/app-symbole/workspace-32.png?v=202609281013" />
|
||||
<link rel="apple-touch-icon" href="/assets/img/app-symbole/workspace-180.png?v=202609281013" />
|
||||
<link rel="stylesheet" href="assets/css/gate.css?v=202609281013" />
|
||||
<link rel="stylesheet" href="assets/css/start.css?v=202609281013" />
|
||||
<link rel="stylesheet" href="assets/css/reaktion.css?v=202609281013" />
|
||||
<link rel="stylesheet" href="assets/css/spendenkarte.css?v=202609281013" />
|
||||
<link rel="stylesheet" href="assets/css/module.css?v=202609281013" />
|
||||
<link rel="stylesheet" href="assets/css/haus.css?v=202609281013" />
|
||||
</head>
|
||||
|
||||
<body class="start reaktion-seite" data-stand="laedt">
|
||||
@@ -337,6 +337,9 @@
|
||||
id="reiter-gaeste" aria-controls="tafel-gaeste" aria-selected="false">Gäste</button>
|
||||
<button type="button" class="reiter__knopf" role="tab" data-tafel="bild"
|
||||
id="reiter-bild" aria-controls="tafel-bild" aria-selected="false">Bild</button>
|
||||
<button type="button" class="reiter__knopf" role="tab" data-tafel="gestaltung"
|
||||
aria-selected="false" id="reiter-gestaltung"
|
||||
aria-controls="tafel-gestaltung">Gestaltung</button>
|
||||
<button type="button" class="reiter__knopf" role="tab" data-tafel="spenden"
|
||||
id="reiter-spenden" aria-controls="tafel-spenden" aria-selected="false">
|
||||
Spenden <span class="reiter__zahl" id="reiter-spenden-zahl" data-leer="ja">0</span>
|
||||
@@ -485,6 +488,29 @@
|
||||
<button type="button" class="knopf-still" id="obs-neu">Schlüssel neu erzeugen</button>
|
||||
</section>
|
||||
|
||||
<!-- ==== Gestaltung ==================================== -->
|
||||
<section class="pult-tafel" data-tafel="gestaltung" role="tabpanel" hidden
|
||||
id="tafel-gestaltung" aria-labelledby="reiter-gestaltung">
|
||||
<h3 class="pult__ueber">Wie eine Spende aussieht</h3>
|
||||
<p class="pult__klein">
|
||||
Je Stufe: ab welchem Betrag sie gilt, wie sie heißt, welches
|
||||
Zeichen, welche Farbe, wie lange sie steht und wie groß.
|
||||
Eine Spende bekommt immer die höchste Stufe, die auf sie
|
||||
passt.
|
||||
</p>
|
||||
<div class="stufen" id="stufen"></div>
|
||||
<div class="pult__zeile">
|
||||
<button type="button" class="knopf-still" id="stufe-neu">Stufe dazu</button>
|
||||
<button type="button" class="knopf-still knopf-still--haupt"
|
||||
id="stufen-sichern">Übernehmen</button>
|
||||
<span class="pult__klein" id="stufen-stand"></span>
|
||||
</div>
|
||||
<p class="pult__klein">
|
||||
„Ausprobieren" zeigt dir eine Karte — nur bei dir, und es wird
|
||||
keine Spende daraus. Im Saal sieht das niemand.
|
||||
</p>
|
||||
</section>
|
||||
|
||||
<!-- ==== Spenden ======================================= -->
|
||||
<section class="pult-tafel" data-tafel="spenden" role="tabpanel" hidden
|
||||
id="tafel-spenden" aria-labelledby="reiter-spenden">
|
||||
@@ -530,14 +556,14 @@
|
||||
|
||||
<!-- bereiche.js VOR kopf.js: Dort steht `window.Bereiche`, und kopf.js
|
||||
liest daraus die Leitungsrollen. -->
|
||||
<script src="assets/js/bereiche.js?v=202609280947" defer></script>
|
||||
<script src="assets/js/wahl.js?v=202609280947" defer></script>
|
||||
<script src="assets/js/nachfrage.js?v=202609280947" defer></script>
|
||||
<script src="assets/js/meldung.js?v=202609280947" defer></script>
|
||||
<script src="assets/js/installieren.js?v=202609280947" defer></script>
|
||||
<script src="assets/js/kopf.js?v=202609280947" defer></script>
|
||||
<script src="assets/js/glocke.js?v=202609280947" defer></script>
|
||||
<script src="assets/js/spendenkarte.js?v=202609280947" defer></script>
|
||||
<script src="assets/js/reaktion.js?v=202609280947" defer></script>
|
||||
<script src="assets/js/bereiche.js?v=202609281013" defer></script>
|
||||
<script src="assets/js/wahl.js?v=202609281013" defer></script>
|
||||
<script src="assets/js/nachfrage.js?v=202609281013" defer></script>
|
||||
<script src="assets/js/meldung.js?v=202609281013" defer></script>
|
||||
<script src="assets/js/installieren.js?v=202609281013" defer></script>
|
||||
<script src="assets/js/kopf.js?v=202609281013" defer></script>
|
||||
<script src="assets/js/glocke.js?v=202609281013" defer></script>
|
||||
<script src="assets/js/spendenkarte.js?v=202609281013" defer></script>
|
||||
<script src="assets/js/reaktion.js?v=202609281013" defer></script>
|
||||
</body>
|
||||
</html>
|
||||
|
||||
+17
-17
@@ -7,14 +7,14 @@
|
||||
<meta name="robots" content="noindex, nofollow" />
|
||||
<link rel="manifest" href="/workspace/app.webmanifest" />
|
||||
<meta name="theme-color" content="#06090f" />
|
||||
<link rel="icon" type="image/png" href="/assets/img/app-symbole/workspace-32.png?v=202609280947" />
|
||||
<link rel="apple-touch-icon" href="/assets/img/app-symbole/workspace-180.png?v=202609280947" />
|
||||
<link rel="stylesheet" href="assets/css/gate.css?v=202609280947" />
|
||||
<link rel="stylesheet" href="assets/css/start.css?v=202609280947" />
|
||||
<link rel="stylesheet" href="assets/css/aufgaben.css?v=202609280947" />
|
||||
<link rel="stylesheet" href="assets/css/treff.css?v=202609280947" />
|
||||
<link rel="stylesheet" href="assets/css/module.css?v=202609280947" />
|
||||
<link rel="stylesheet" href="assets/css/haus.css?v=202609280947" />
|
||||
<link rel="icon" type="image/png" href="/assets/img/app-symbole/workspace-32.png?v=202609281013" />
|
||||
<link rel="apple-touch-icon" href="/assets/img/app-symbole/workspace-180.png?v=202609281013" />
|
||||
<link rel="stylesheet" href="assets/css/gate.css?v=202609281013" />
|
||||
<link rel="stylesheet" href="assets/css/start.css?v=202609281013" />
|
||||
<link rel="stylesheet" href="assets/css/aufgaben.css?v=202609281013" />
|
||||
<link rel="stylesheet" href="assets/css/treff.css?v=202609281013" />
|
||||
<link rel="stylesheet" href="assets/css/module.css?v=202609281013" />
|
||||
<link rel="stylesheet" href="assets/css/haus.css?v=202609281013" />
|
||||
</head>
|
||||
|
||||
<body class="start">
|
||||
@@ -134,14 +134,14 @@
|
||||
Beim ersten Anlauf fehlte die Zeile auf genau diesen beiden neuen
|
||||
Seiten. Gefunden hat das nicht das Auge, sondern pruef-css-klassen,
|
||||
die seit dem 07.09. jede Seite danach absucht. -->
|
||||
<script src="assets/js/meldung.js?v=202609280947" defer></script>
|
||||
<script src="assets/js/nachfrage.js?v=202609280947" defer></script>
|
||||
<script src="assets/js/wahl.js?v=202609280947" defer></script>
|
||||
<script src="assets/js/bereiche.js?v=202609280947" defer></script>
|
||||
<script src="assets/js/installieren.js?v=202609280947" defer></script>
|
||||
<script src="assets/js/kopf.js?v=202609280947" defer></script>
|
||||
<script src="assets/js/glocke.js?v=202609280947" defer></script>
|
||||
<script src="assets/js/holen.js?v=202609280947" defer></script>
|
||||
<script src="assets/js/rechte.js?v=202609280947" defer></script>
|
||||
<script src="assets/js/meldung.js?v=202609281013" defer></script>
|
||||
<script src="assets/js/nachfrage.js?v=202609281013" defer></script>
|
||||
<script src="assets/js/wahl.js?v=202609281013" defer></script>
|
||||
<script src="assets/js/bereiche.js?v=202609281013" defer></script>
|
||||
<script src="assets/js/installieren.js?v=202609281013" defer></script>
|
||||
<script src="assets/js/kopf.js?v=202609281013" defer></script>
|
||||
<script src="assets/js/glocke.js?v=202609281013" defer></script>
|
||||
<script src="assets/js/holen.js?v=202609281013" defer></script>
|
||||
<script src="assets/js/rechte.js?v=202609281013" defer></script>
|
||||
</body>
|
||||
</html>
|
||||
|
||||
+18
-18
@@ -12,20 +12,20 @@
|
||||
Ton wie die Kopfleiste darunter (#06090f), damit Leiste und Seite
|
||||
eine Flaeche sind statt zweier. -->
|
||||
<meta name="theme-color" content="#06090f" />
|
||||
<link rel="icon" type="image/png" href="/assets/img/app-symbole/workspace-32.png?v=202609280947" />
|
||||
<link rel="apple-touch-icon" href="/assets/img/app-symbole/workspace-180.png?v=202609280947" />
|
||||
<link rel="stylesheet" href="assets/css/gate.css?v=202609280947" />
|
||||
<link rel="stylesheet" href="assets/css/start.css?v=202609280947" />
|
||||
<link rel="stylesheet" href="assets/css/aufgaben.css?v=202609280947" />
|
||||
<link rel="stylesheet" href="assets/css/report.css?v=202609280947" />
|
||||
<link rel="stylesheet" href="assets/css/module.css?v=202609280947" />
|
||||
<link rel="icon" type="image/png" href="/assets/img/app-symbole/workspace-32.png?v=202609281013" />
|
||||
<link rel="apple-touch-icon" href="/assets/img/app-symbole/workspace-180.png?v=202609281013" />
|
||||
<link rel="stylesheet" href="assets/css/gate.css?v=202609281013" />
|
||||
<link rel="stylesheet" href="assets/css/start.css?v=202609281013" />
|
||||
<link rel="stylesheet" href="assets/css/aufgaben.css?v=202609281013" />
|
||||
<link rel="stylesheet" href="assets/css/report.css?v=202609281013" />
|
||||
<link rel="stylesheet" href="assets/css/module.css?v=202609281013" />
|
||||
<!-- haus.css MUSS die letzte Stilvorlage sein (10.09.2026).
|
||||
Auf der Agenturadresse ist sie leer -- das Haus hier IST der
|
||||
Grundzustand. Auf der Adresse von Team Dogi biegt der Server
|
||||
genau diesen Dateinamen auf crew-haus.css um, und die Seite
|
||||
kommt schon beim ERSTEN Abruf in Lila und Babyblau an --
|
||||
ohne Umfaerben im Browser, ohne Flackern. -->
|
||||
<link rel="stylesheet" href="assets/css/haus.css?v=202609280947" />
|
||||
<link rel="stylesheet" href="assets/css/haus.css?v=202609281013" />
|
||||
</head>
|
||||
|
||||
<body class="start">
|
||||
@@ -106,17 +106,17 @@
|
||||
|
||||
</main>
|
||||
|
||||
<script src="assets/js/meldung.js?v=202609280947" defer></script>
|
||||
<script src="assets/js/nachfrage.js?v=202609280947" defer></script>
|
||||
<script src="assets/js/meldung.js?v=202609281013" defer></script>
|
||||
<script src="assets/js/nachfrage.js?v=202609281013" defer></script>
|
||||
|
||||
|
||||
<script src="assets/js/ki.js?v=202609280947" defer></script>
|
||||
<script src="assets/js/wahl.js?v=202609280947" defer></script>
|
||||
<script src="assets/js/bereiche.js?v=202609280947" defer></script>
|
||||
<script src="assets/js/installieren.js?v=202609280947" defer></script>
|
||||
<script src="assets/js/kopf.js?v=202609280947" defer></script>
|
||||
<script src="assets/js/glocke.js?v=202609280947" defer></script>
|
||||
<script src="assets/js/holen.js?v=202609280947" defer></script>
|
||||
<script src="assets/js/report.js?v=202609280947" defer></script>
|
||||
<script src="assets/js/ki.js?v=202609281013" defer></script>
|
||||
<script src="assets/js/wahl.js?v=202609281013" defer></script>
|
||||
<script src="assets/js/bereiche.js?v=202609281013" defer></script>
|
||||
<script src="assets/js/installieren.js?v=202609281013" defer></script>
|
||||
<script src="assets/js/kopf.js?v=202609281013" defer></script>
|
||||
<script src="assets/js/glocke.js?v=202609281013" defer></script>
|
||||
<script src="assets/js/holen.js?v=202609281013" defer></script>
|
||||
<script src="assets/js/report.js?v=202609281013" defer></script>
|
||||
</body>
|
||||
</html>
|
||||
|
||||
+16
-16
@@ -12,20 +12,20 @@
|
||||
Ton wie die Kopfleiste darunter (#06090f), damit Leiste und Seite
|
||||
eine Flaeche sind statt zweier. -->
|
||||
<meta name="theme-color" content="#06090f" />
|
||||
<link rel="icon" type="image/png" href="/assets/img/app-symbole/workspace-32.png?v=202609280947" />
|
||||
<link rel="apple-touch-icon" href="/assets/img/app-symbole/workspace-180.png?v=202609280947" />
|
||||
<link rel="stylesheet" href="assets/css/gate.css?v=202609280947" />
|
||||
<link rel="stylesheet" href="assets/css/start.css?v=202609280947" />
|
||||
<link rel="stylesheet" href="assets/css/aufgaben.css?v=202609280947" />
|
||||
<link rel="stylesheet" href="assets/css/scouting.css?v=202609280947" />
|
||||
<link rel="stylesheet" href="assets/css/module.css?v=202609280947" />
|
||||
<link rel="icon" type="image/png" href="/assets/img/app-symbole/workspace-32.png?v=202609281013" />
|
||||
<link rel="apple-touch-icon" href="/assets/img/app-symbole/workspace-180.png?v=202609281013" />
|
||||
<link rel="stylesheet" href="assets/css/gate.css?v=202609281013" />
|
||||
<link rel="stylesheet" href="assets/css/start.css?v=202609281013" />
|
||||
<link rel="stylesheet" href="assets/css/aufgaben.css?v=202609281013" />
|
||||
<link rel="stylesheet" href="assets/css/scouting.css?v=202609281013" />
|
||||
<link rel="stylesheet" href="assets/css/module.css?v=202609281013" />
|
||||
<!-- haus.css MUSS die letzte Stilvorlage sein (10.09.2026).
|
||||
Auf der Agenturadresse ist sie leer -- das Haus hier IST der
|
||||
Grundzustand. Auf der Adresse von Team Dogi biegt der Server
|
||||
genau diesen Dateinamen auf crew-haus.css um, und die Seite
|
||||
kommt schon beim ERSTEN Abruf in Lila und Babyblau an --
|
||||
ohne Umfaerben im Browser, ohne Flackern. -->
|
||||
<link rel="stylesheet" href="assets/css/haus.css?v=202609280947" />
|
||||
<link rel="stylesheet" href="assets/css/haus.css?v=202609281013" />
|
||||
</head>
|
||||
|
||||
<body class="start">
|
||||
@@ -173,14 +173,14 @@
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<script src="assets/js/meldung.js?v=202609280947" defer></script>
|
||||
<script src="assets/js/nachfrage.js?v=202609280947" defer></script>
|
||||
<script src="assets/js/meldung.js?v=202609281013" defer></script>
|
||||
<script src="assets/js/nachfrage.js?v=202609281013" defer></script>
|
||||
|
||||
<script src="assets/js/wahl.js?v=202609280947" defer></script>
|
||||
<script src="assets/js/bereiche.js?v=202609280947" defer></script>
|
||||
<script src="assets/js/installieren.js?v=202609280947" defer></script>
|
||||
<script src="assets/js/kopf.js?v=202609280947" defer></script>
|
||||
<script src="assets/js/glocke.js?v=202609280947" defer></script>
|
||||
<script src="assets/js/scouting.js?v=202609280947" defer></script>
|
||||
<script src="assets/js/wahl.js?v=202609281013" defer></script>
|
||||
<script src="assets/js/bereiche.js?v=202609281013" defer></script>
|
||||
<script src="assets/js/installieren.js?v=202609281013" defer></script>
|
||||
<script src="assets/js/kopf.js?v=202609281013" defer></script>
|
||||
<script src="assets/js/glocke.js?v=202609281013" defer></script>
|
||||
<script src="assets/js/scouting.js?v=202609281013" defer></script>
|
||||
</body>
|
||||
</html>
|
||||
|
||||
+16
-16
@@ -12,21 +12,21 @@
|
||||
Ton wie die Kopfleiste darunter (#06090f), damit Leiste und Seite
|
||||
eine Flaeche sind statt zweier. -->
|
||||
<meta name="theme-color" content="#06090f" />
|
||||
<link rel="icon" type="image/png" href="/assets/img/app-symbole/workspace-32.png?v=202609280947" />
|
||||
<link rel="apple-touch-icon" href="/assets/img/app-symbole/workspace-180.png?v=202609280947" />
|
||||
<link rel="stylesheet" href="assets/css/gate.css?v=202609280947" />
|
||||
<link rel="stylesheet" href="assets/css/start.css?v=202609280947" />
|
||||
<link rel="icon" type="image/png" href="/assets/img/app-symbole/workspace-32.png?v=202609281013" />
|
||||
<link rel="apple-touch-icon" href="/assets/img/app-symbole/workspace-180.png?v=202609281013" />
|
||||
<link rel="stylesheet" href="assets/css/gate.css?v=202609281013" />
|
||||
<link rel="stylesheet" href="assets/css/start.css?v=202609281013" />
|
||||
<!-- 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=202609280947" />
|
||||
<link rel="stylesheet" href="assets/css/module.css?v=202609280947" />
|
||||
<link rel="stylesheet" href="assets/css/heim.css?v=202609281013" />
|
||||
<link rel="stylesheet" href="assets/css/module.css?v=202609281013" />
|
||||
<!-- haus.css MUSS die letzte Stilvorlage sein (10.09.2026).
|
||||
Auf der Agenturadresse ist sie leer -- das Haus hier IST der
|
||||
Grundzustand. Auf der Adresse von Team Dogi biegt der Server
|
||||
genau diesen Dateinamen auf crew-haus.css um, und die Seite
|
||||
kommt schon beim ERSTEN Abruf in Lila und Babyblau an --
|
||||
ohne Umfaerben im Browser, ohne Flackern. -->
|
||||
<link rel="stylesheet" href="assets/css/haus.css?v=202609280947" />
|
||||
<link rel="stylesheet" href="assets/css/haus.css?v=202609281013" />
|
||||
</head>
|
||||
|
||||
<body class="start">
|
||||
@@ -732,16 +732,16 @@
|
||||
</p>
|
||||
</main>
|
||||
|
||||
<script src="assets/js/meldung.js?v=202609280947" defer></script>
|
||||
<script src="assets/js/nachfrage.js?v=202609280947" defer></script>
|
||||
<script src="assets/js/meldung.js?v=202609281013" defer></script>
|
||||
<script src="assets/js/nachfrage.js?v=202609281013" defer></script>
|
||||
|
||||
|
||||
<script src="assets/js/wahl.js?v=202609280947" defer></script>
|
||||
<script src="assets/js/bereiche.js?v=202609280947" defer></script>
|
||||
<script src="assets/js/installieren.js?v=202609280947" defer></script>
|
||||
<script src="assets/js/kopf.js?v=202609280947" defer></script>
|
||||
<script src="assets/js/glocke.js?v=202609280947" defer></script>
|
||||
<script src="assets/js/live.js?v=202609280947" defer></script>
|
||||
<script src="assets/js/start.js?v=202609280947" defer></script>
|
||||
<script src="assets/js/wahl.js?v=202609281013" defer></script>
|
||||
<script src="assets/js/bereiche.js?v=202609281013" defer></script>
|
||||
<script src="assets/js/installieren.js?v=202609281013" defer></script>
|
||||
<script src="assets/js/kopf.js?v=202609281013" defer></script>
|
||||
<script src="assets/js/glocke.js?v=202609281013" defer></script>
|
||||
<script src="assets/js/live.js?v=202609281013" defer></script>
|
||||
<script src="assets/js/start.js?v=202609281013" defer></script>
|
||||
</body>
|
||||
</html>
|
||||
|
||||
+17
-17
@@ -12,20 +12,20 @@
|
||||
Ton wie die Kopfleiste darunter (#06090f), damit Leiste und Seite
|
||||
eine Flaeche sind statt zweier. -->
|
||||
<meta name="theme-color" content="#06090f" />
|
||||
<link rel="icon" type="image/png" href="/assets/img/app-symbole/workspace-32.png?v=202609280947" />
|
||||
<link rel="apple-touch-icon" href="/assets/img/app-symbole/workspace-180.png?v=202609280947" />
|
||||
<link rel="stylesheet" href="assets/css/gate.css?v=202609280947" />
|
||||
<link rel="stylesheet" href="assets/css/start.css?v=202609280947" />
|
||||
<link rel="stylesheet" href="assets/css/aufgaben.css?v=202609280947" />
|
||||
<link rel="stylesheet" href="assets/css/startcheck.css?v=202609280947" />
|
||||
<link rel="stylesheet" href="assets/css/module.css?v=202609280947" />
|
||||
<link rel="icon" type="image/png" href="/assets/img/app-symbole/workspace-32.png?v=202609281013" />
|
||||
<link rel="apple-touch-icon" href="/assets/img/app-symbole/workspace-180.png?v=202609281013" />
|
||||
<link rel="stylesheet" href="assets/css/gate.css?v=202609281013" />
|
||||
<link rel="stylesheet" href="assets/css/start.css?v=202609281013" />
|
||||
<link rel="stylesheet" href="assets/css/aufgaben.css?v=202609281013" />
|
||||
<link rel="stylesheet" href="assets/css/startcheck.css?v=202609281013" />
|
||||
<link rel="stylesheet" href="assets/css/module.css?v=202609281013" />
|
||||
<!-- haus.css MUSS die letzte Stilvorlage sein (10.09.2026).
|
||||
Auf der Agenturadresse ist sie leer -- das Haus hier IST der
|
||||
Grundzustand. Auf der Adresse von Team Dogi biegt der Server
|
||||
genau diesen Dateinamen auf crew-haus.css um, und die Seite
|
||||
kommt schon beim ERSTEN Abruf in Lila und Babyblau an --
|
||||
ohne Umfaerben im Browser, ohne Flackern. -->
|
||||
<link rel="stylesheet" href="assets/css/haus.css?v=202609280947" />
|
||||
<link rel="stylesheet" href="assets/css/haus.css?v=202609281013" />
|
||||
</head>
|
||||
|
||||
<body class="start">
|
||||
@@ -85,16 +85,16 @@
|
||||
|
||||
</main>
|
||||
|
||||
<script src="assets/js/meldung.js?v=202609280947" defer></script>
|
||||
<script src="assets/js/nachfrage.js?v=202609280947" defer></script>
|
||||
<script src="assets/js/meldung.js?v=202609281013" defer></script>
|
||||
<script src="assets/js/nachfrage.js?v=202609281013" defer></script>
|
||||
|
||||
|
||||
<script src="assets/js/ki.js?v=202609280947" defer></script>
|
||||
<script src="assets/js/wahl.js?v=202609280947" defer></script>
|
||||
<script src="assets/js/bereiche.js?v=202609280947" defer></script>
|
||||
<script src="assets/js/installieren.js?v=202609280947" defer></script>
|
||||
<script src="assets/js/kopf.js?v=202609280947" defer></script>
|
||||
<script src="assets/js/glocke.js?v=202609280947" defer></script>
|
||||
<script src="assets/js/startcheck.js?v=202609280947" defer></script>
|
||||
<script src="assets/js/ki.js?v=202609281013" defer></script>
|
||||
<script src="assets/js/wahl.js?v=202609281013" defer></script>
|
||||
<script src="assets/js/bereiche.js?v=202609281013" defer></script>
|
||||
<script src="assets/js/installieren.js?v=202609281013" defer></script>
|
||||
<script src="assets/js/kopf.js?v=202609281013" defer></script>
|
||||
<script src="assets/js/glocke.js?v=202609281013" defer></script>
|
||||
<script src="assets/js/startcheck.js?v=202609281013" defer></script>
|
||||
</body>
|
||||
</html>
|
||||
|
||||
+18
-18
@@ -12,20 +12,20 @@
|
||||
Ton wie die Kopfleiste darunter (#06090f), damit Leiste und Seite
|
||||
eine Flaeche sind statt zweier. -->
|
||||
<meta name="theme-color" content="#06090f" />
|
||||
<link rel="icon" type="image/png" href="/assets/img/app-symbole/workspace-32.png?v=202609280947" />
|
||||
<link rel="apple-touch-icon" href="/assets/img/app-symbole/workspace-180.png?v=202609280947" />
|
||||
<link rel="stylesheet" href="assets/css/gate.css?v=202609280947" />
|
||||
<link rel="stylesheet" href="assets/css/start.css?v=202609280947" />
|
||||
<link rel="stylesheet" href="assets/css/aufgaben.css?v=202609280947" />
|
||||
<link rel="stylesheet" href="assets/css/profil.css?v=202609280947" />
|
||||
<link rel="stylesheet" href="assets/css/module.css?v=202609280947" />
|
||||
<link rel="icon" type="image/png" href="/assets/img/app-symbole/workspace-32.png?v=202609281013" />
|
||||
<link rel="apple-touch-icon" href="/assets/img/app-symbole/workspace-180.png?v=202609281013" />
|
||||
<link rel="stylesheet" href="assets/css/gate.css?v=202609281013" />
|
||||
<link rel="stylesheet" href="assets/css/start.css?v=202609281013" />
|
||||
<link rel="stylesheet" href="assets/css/aufgaben.css?v=202609281013" />
|
||||
<link rel="stylesheet" href="assets/css/profil.css?v=202609281013" />
|
||||
<link rel="stylesheet" href="assets/css/module.css?v=202609281013" />
|
||||
<!-- haus.css MUSS die letzte Stilvorlage sein (10.09.2026).
|
||||
Auf der Agenturadresse ist sie leer -- das Haus hier IST der
|
||||
Grundzustand. Auf der Adresse von Team Dogi biegt der Server
|
||||
genau diesen Dateinamen auf crew-haus.css um, und die Seite
|
||||
kommt schon beim ERSTEN Abruf in Lila und Babyblau an --
|
||||
ohne Umfaerben im Browser, ohne Flackern. -->
|
||||
<link rel="stylesheet" href="assets/css/haus.css?v=202609280947" />
|
||||
<link rel="stylesheet" href="assets/css/haus.css?v=202609281013" />
|
||||
</head>
|
||||
|
||||
<body class="start">
|
||||
@@ -150,16 +150,16 @@
|
||||
|
||||
</main>
|
||||
|
||||
<script src="assets/js/meldung.js?v=202609280947" defer></script>
|
||||
<script src="assets/js/hochladen.js?v=202609280947" defer></script>
|
||||
<script src="assets/js/nachfrage.js?v=202609280947" defer></script>
|
||||
<script src="assets/js/meldung.js?v=202609281013" defer></script>
|
||||
<script src="assets/js/hochladen.js?v=202609281013" defer></script>
|
||||
<script src="assets/js/nachfrage.js?v=202609281013" defer></script>
|
||||
|
||||
<script src="assets/js/wahl.js?v=202609280947" defer></script>
|
||||
<script src="assets/js/bereiche.js?v=202609280947" defer></script>
|
||||
<script src="assets/js/installieren.js?v=202609280947" defer></script>
|
||||
<script src="assets/js/kopf.js?v=202609280947" defer></script>
|
||||
<script src="assets/js/auskunft.js?v=202609280947" defer></script>
|
||||
<script src="assets/js/glocke.js?v=202609280947" defer></script>
|
||||
<script src="assets/js/steckbrief.js?v=202609280947" defer></script>
|
||||
<script src="assets/js/wahl.js?v=202609281013" defer></script>
|
||||
<script src="assets/js/bereiche.js?v=202609281013" defer></script>
|
||||
<script src="assets/js/installieren.js?v=202609281013" defer></script>
|
||||
<script src="assets/js/kopf.js?v=202609281013" defer></script>
|
||||
<script src="assets/js/auskunft.js?v=202609281013" defer></script>
|
||||
<script src="assets/js/glocke.js?v=202609281013" defer></script>
|
||||
<script src="assets/js/steckbrief.js?v=202609281013" defer></script>
|
||||
</body>
|
||||
</html>
|
||||
|
||||
+14
-14
@@ -7,13 +7,13 @@
|
||||
<meta name="robots" content="noindex, nofollow" />
|
||||
<link rel="manifest" href="/workspace/app.webmanifest" />
|
||||
<meta name="theme-color" content="#06090f" />
|
||||
<link rel="icon" type="image/png" href="/assets/img/app-symbole/workspace-32.png?v=202609280947" />
|
||||
<link rel="apple-touch-icon" href="/assets/img/app-symbole/workspace-180.png?v=202609280947" />
|
||||
<link rel="stylesheet" href="assets/css/gate.css?v=202609280947" />
|
||||
<link rel="stylesheet" href="assets/css/start.css?v=202609280947" />
|
||||
<link rel="stylesheet" href="assets/css/support.css?v=202609280947" />
|
||||
<link rel="stylesheet" href="assets/css/module.css?v=202609280947" />
|
||||
<link rel="stylesheet" href="assets/css/haus.css?v=202609280947" />
|
||||
<link rel="icon" type="image/png" href="/assets/img/app-symbole/workspace-32.png?v=202609281013" />
|
||||
<link rel="apple-touch-icon" href="/assets/img/app-symbole/workspace-180.png?v=202609281013" />
|
||||
<link rel="stylesheet" href="assets/css/gate.css?v=202609281013" />
|
||||
<link rel="stylesheet" href="assets/css/start.css?v=202609281013" />
|
||||
<link rel="stylesheet" href="assets/css/support.css?v=202609281013" />
|
||||
<link rel="stylesheet" href="assets/css/module.css?v=202609281013" />
|
||||
<link rel="stylesheet" href="assets/css/haus.css?v=202609281013" />
|
||||
</head>
|
||||
|
||||
<body class="start">
|
||||
@@ -128,16 +128,16 @@
|
||||
(reading 'LEITUNG')" ab -- gemessen am 24.09.2026, als diese
|
||||
Zeile beim Anlegen der Seite fehlte. Die Kopfleiste kam
|
||||
trotzdem, deshalb sah man es nur in der Browserkonsole. -->
|
||||
<script src="assets/js/bereiche.js?v=202609280947" defer></script>
|
||||
<script src="assets/js/bereiche.js?v=202609281013" defer></script>
|
||||
<!-- wahl.js gehoert zu kopf.js: Der Sicht-Umschalter in der
|
||||
Kopfleiste baut daraus seine Liste. pruef-css-klassen setzt das
|
||||
seit dem 07.09.2026 durch -- damals fehlte es auf chat.html und
|
||||
uebersicht.html, und heute hier. -->
|
||||
<script src="assets/js/wahl.js?v=202609280947" defer></script>
|
||||
<script src="assets/js/nachfrage.js?v=202609280947" defer></script>
|
||||
<script src="assets/js/installieren.js?v=202609280947" defer></script>
|
||||
<script src="assets/js/kopf.js?v=202609280947" defer></script>
|
||||
<script src="assets/js/glocke.js?v=202609280947" defer></script>
|
||||
<script src="assets/js/support.js?v=202609280947" defer></script>
|
||||
<script src="assets/js/wahl.js?v=202609281013" defer></script>
|
||||
<script src="assets/js/nachfrage.js?v=202609281013" defer></script>
|
||||
<script src="assets/js/installieren.js?v=202609281013" defer></script>
|
||||
<script src="assets/js/kopf.js?v=202609281013" defer></script>
|
||||
<script src="assets/js/glocke.js?v=202609281013" defer></script>
|
||||
<script src="assets/js/support.js?v=202609281013" defer></script>
|
||||
</body>
|
||||
</html>
|
||||
|
||||
@@ -23,7 +23,7 @@
|
||||
„Eigenes CSS" leer lassen (der Grund ist schon
|
||||
durchsichtig).
|
||||
====================================================================== -->
|
||||
<link rel="stylesheet" href="assets/css/spendenkarte.css?v=202609280947" />
|
||||
<link rel="stylesheet" href="assets/css/spendenkarte.css?v=202609281013" />
|
||||
<style>
|
||||
/* DURCHSICHTIG BIS AUF DIE KARTEN. OBS legt die Quelle über das
|
||||
Bild; jede Fläche, die hier steht, deckt dort etwas zu. */
|
||||
@@ -80,7 +80,7 @@
|
||||
<body>
|
||||
<div class="obs-tafel spendentafel" id="tafel" aria-live="polite"></div>
|
||||
|
||||
<script src="assets/js/spendenkarte.js?v=202609280947" defer></script>
|
||||
<script src="assets/js/tafel.js?v=202609280947" defer></script>
|
||||
<script src="assets/js/spendenkarte.js?v=202609281013" defer></script>
|
||||
<script src="assets/js/tafel.js?v=202609281013" defer></script>
|
||||
</body>
|
||||
</html>
|
||||
|
||||
+18
-18
@@ -7,18 +7,18 @@
|
||||
<meta name="robots" content="noindex, nofollow" />
|
||||
<link rel="manifest" href="/workspace/app.webmanifest" />
|
||||
<meta name="theme-color" content="#06090f" />
|
||||
<link rel="icon" type="image/png" href="/assets/img/app-symbole/workspace-32.png?v=202609280947" />
|
||||
<link rel="apple-touch-icon" href="/assets/img/app-symbole/workspace-180.png?v=202609280947" />
|
||||
<link rel="stylesheet" href="assets/css/gate.css?v=202609280947" />
|
||||
<link rel="stylesheet" href="assets/css/start.css?v=202609280947" />
|
||||
<link rel="stylesheet" href="assets/css/aufgaben.css?v=202609280947" />
|
||||
<link rel="stylesheet" href="assets/css/entwicklung.css?v=202609280947" />
|
||||
<link rel="icon" type="image/png" href="/assets/img/app-symbole/workspace-32.png?v=202609281013" />
|
||||
<link rel="apple-touch-icon" href="/assets/img/app-symbole/workspace-180.png?v=202609281013" />
|
||||
<link rel="stylesheet" href="assets/css/gate.css?v=202609281013" />
|
||||
<link rel="stylesheet" href="assets/css/start.css?v=202609281013" />
|
||||
<link rel="stylesheet" href="assets/css/aufgaben.css?v=202609281013" />
|
||||
<link rel="stylesheet" href="assets/css/entwicklung.css?v=202609281013" />
|
||||
<!-- Wegen des Kastens „Anfragen“ ueber der Liste. Eine eigene Kopie
|
||||
der Regel hier waere die zweite Stelle, an der dieselbe Sache
|
||||
anders aussieht. -->
|
||||
<link rel="stylesheet" href="assets/css/bewerbung.css?v=202609280947" />
|
||||
<link rel="stylesheet" href="assets/css/module.css?v=202609280947" />
|
||||
<link rel="stylesheet" href="assets/css/haus.css?v=202609280947" />
|
||||
<link rel="stylesheet" href="assets/css/bewerbung.css?v=202609281013" />
|
||||
<link rel="stylesheet" href="assets/css/module.css?v=202609281013" />
|
||||
<link rel="stylesheet" href="assets/css/haus.css?v=202609281013" />
|
||||
</head>
|
||||
|
||||
<body class="start">
|
||||
@@ -111,15 +111,15 @@
|
||||
|
||||
</main>
|
||||
|
||||
<script src="assets/js/meldung.js?v=202609280947" defer></script>
|
||||
<script src="assets/js/nachfrage.js?v=202609280947" defer></script>
|
||||
<script src="assets/js/meldung.js?v=202609281013" defer></script>
|
||||
<script src="assets/js/nachfrage.js?v=202609281013" defer></script>
|
||||
|
||||
<script src="assets/js/wahl.js?v=202609280947" defer></script>
|
||||
<script src="assets/js/bereiche.js?v=202609280947" defer></script>
|
||||
<script src="assets/js/installieren.js?v=202609280947" defer></script>
|
||||
<script src="assets/js/kopf.js?v=202609280947" defer></script>
|
||||
<script src="assets/js/glocke.js?v=202609280947" defer></script>
|
||||
<script src="assets/js/holen.js?v=202609280947" defer></script>
|
||||
<script src="assets/js/talente.js?v=202609280947" defer></script>
|
||||
<script src="assets/js/wahl.js?v=202609281013" defer></script>
|
||||
<script src="assets/js/bereiche.js?v=202609281013" defer></script>
|
||||
<script src="assets/js/installieren.js?v=202609281013" defer></script>
|
||||
<script src="assets/js/kopf.js?v=202609281013" defer></script>
|
||||
<script src="assets/js/glocke.js?v=202609281013" defer></script>
|
||||
<script src="assets/js/holen.js?v=202609281013" defer></script>
|
||||
<script src="assets/js/talente.js?v=202609281013" defer></script>
|
||||
</body>
|
||||
</html>
|
||||
|
||||
+16
-16
@@ -7,20 +7,20 @@
|
||||
<meta name="robots" content="noindex, nofollow" />
|
||||
<link rel="manifest" href="/workspace/app.webmanifest" />
|
||||
<meta name="theme-color" content="#06090f" />
|
||||
<link rel="icon" type="image/png" href="/assets/img/app-symbole/workspace-32.png?v=202609280947" />
|
||||
<link rel="apple-touch-icon" href="/assets/img/app-symbole/workspace-180.png?v=202609280947" />
|
||||
<link rel="stylesheet" href="assets/css/gate.css?v=202609280947" />
|
||||
<link rel="stylesheet" href="assets/css/start.css?v=202609280947" />
|
||||
<link rel="stylesheet" href="assets/css/aufgaben.css?v=202609280947" />
|
||||
<link rel="stylesheet" href="assets/css/team.css?v=202609280947" />
|
||||
<link rel="stylesheet" href="assets/css/module.css?v=202609280947" />
|
||||
<link rel="icon" type="image/png" href="/assets/img/app-symbole/workspace-32.png?v=202609281013" />
|
||||
<link rel="apple-touch-icon" href="/assets/img/app-symbole/workspace-180.png?v=202609281013" />
|
||||
<link rel="stylesheet" href="assets/css/gate.css?v=202609281013" />
|
||||
<link rel="stylesheet" href="assets/css/start.css?v=202609281013" />
|
||||
<link rel="stylesheet" href="assets/css/aufgaben.css?v=202609281013" />
|
||||
<link rel="stylesheet" href="assets/css/team.css?v=202609281013" />
|
||||
<link rel="stylesheet" href="assets/css/module.css?v=202609281013" />
|
||||
<!-- haus.css MUSS die letzte Stilvorlage sein (10.09.2026).
|
||||
Auf der Agenturadresse ist sie leer -- das Haus hier IST der
|
||||
Grundzustand. Auf der Adresse von Team Dogi biegt der Server
|
||||
genau diesen Dateinamen auf crew-haus.css um, und die Seite
|
||||
kommt schon beim ERSTEN Abruf in Lila und Babyblau an --
|
||||
ohne Umfaerben im Browser, ohne Flackern. -->
|
||||
<link rel="stylesheet" href="assets/css/haus.css?v=202609280947" />
|
||||
<link rel="stylesheet" href="assets/css/haus.css?v=202609281013" />
|
||||
</head>
|
||||
|
||||
<body class="start">
|
||||
@@ -110,15 +110,15 @@
|
||||
|
||||
</main>
|
||||
|
||||
<script src="assets/js/nachfrage.js?v=202609280947" defer></script>
|
||||
<script src="assets/js/nachfrage.js?v=202609281013" defer></script>
|
||||
|
||||
|
||||
<script src="assets/js/wahl.js?v=202609280947" defer></script>
|
||||
<script src="assets/js/bereiche.js?v=202609280947" defer></script>
|
||||
<script src="assets/js/installieren.js?v=202609280947" defer></script>
|
||||
<script src="assets/js/kopf.js?v=202609280947" defer></script>
|
||||
<script src="assets/js/glocke.js?v=202609280947" defer></script>
|
||||
<script src="assets/js/holen.js?v=202609280947" defer></script>
|
||||
<script src="assets/js/team.js?v=202609280947" defer></script>
|
||||
<script src="assets/js/wahl.js?v=202609281013" defer></script>
|
||||
<script src="assets/js/bereiche.js?v=202609281013" defer></script>
|
||||
<script src="assets/js/installieren.js?v=202609281013" defer></script>
|
||||
<script src="assets/js/kopf.js?v=202609281013" defer></script>
|
||||
<script src="assets/js/glocke.js?v=202609281013" defer></script>
|
||||
<script src="assets/js/holen.js?v=202609281013" defer></script>
|
||||
<script src="assets/js/team.js?v=202609281013" defer></script>
|
||||
</body>
|
||||
</html>
|
||||
|
||||
+17
-17
@@ -7,20 +7,20 @@
|
||||
<meta name="robots" content="noindex, nofollow" />
|
||||
<link rel="manifest" href="/workspace/app.webmanifest" />
|
||||
<meta name="theme-color" content="#06090f" />
|
||||
<link rel="icon" type="image/png" href="/assets/img/app-symbole/workspace-32.png?v=202609280947" />
|
||||
<link rel="apple-touch-icon" href="/assets/img/app-symbole/workspace-180.png?v=202609280947" />
|
||||
<link rel="stylesheet" href="assets/css/gate.css?v=202609280947" />
|
||||
<link rel="stylesheet" href="assets/css/start.css?v=202609280947" />
|
||||
<link rel="stylesheet" href="assets/css/aufgaben.css?v=202609280947" />
|
||||
<link rel="stylesheet" href="assets/css/team.css?v=202609280947" />
|
||||
<link rel="stylesheet" href="assets/css/module.css?v=202609280947" />
|
||||
<link rel="icon" type="image/png" href="/assets/img/app-symbole/workspace-32.png?v=202609281013" />
|
||||
<link rel="apple-touch-icon" href="/assets/img/app-symbole/workspace-180.png?v=202609281013" />
|
||||
<link rel="stylesheet" href="assets/css/gate.css?v=202609281013" />
|
||||
<link rel="stylesheet" href="assets/css/start.css?v=202609281013" />
|
||||
<link rel="stylesheet" href="assets/css/aufgaben.css?v=202609281013" />
|
||||
<link rel="stylesheet" href="assets/css/team.css?v=202609281013" />
|
||||
<link rel="stylesheet" href="assets/css/module.css?v=202609281013" />
|
||||
<!-- haus.css MUSS die letzte Stilvorlage sein (10.09.2026).
|
||||
Auf der Agenturadresse ist sie leer -- das Haus hier IST der
|
||||
Grundzustand. Auf der Adresse von Team Dogi biegt der Server
|
||||
genau diesen Dateinamen auf crew-haus.css um, und die Seite
|
||||
kommt schon beim ERSTEN Abruf in Lila und Babyblau an --
|
||||
ohne Umfaerben im Browser, ohne Flackern. -->
|
||||
<link rel="stylesheet" href="assets/css/haus.css?v=202609280947" />
|
||||
<link rel="stylesheet" href="assets/css/haus.css?v=202609281013" />
|
||||
</head>
|
||||
|
||||
<!-- `data-buehne` steht hier fest und nicht im Skript: Die Kachel zu
|
||||
@@ -84,15 +84,15 @@
|
||||
Kaputt ist dabei nichts -- er funktioniert. Genau deshalb faellt
|
||||
es niemandem auf, und deshalb prueft pruef-css-klassen die
|
||||
ABHAENGIGKEIT statt der Optik. Hier hat sie angeschlagen. -->
|
||||
<script src="assets/js/meldung.js?v=202609280947" defer></script>
|
||||
<script src="assets/js/nachfrage.js?v=202609280947" defer></script>
|
||||
<script src="assets/js/meldung.js?v=202609281013" defer></script>
|
||||
<script src="assets/js/nachfrage.js?v=202609281013" defer></script>
|
||||
|
||||
<script src="assets/js/wahl.js?v=202609280947" defer></script>
|
||||
<script src="assets/js/bereiche.js?v=202609280947" defer></script>
|
||||
<script src="assets/js/installieren.js?v=202609280947" defer></script>
|
||||
<script src="assets/js/kopf.js?v=202609280947" defer></script>
|
||||
<script src="assets/js/glocke.js?v=202609280947" defer></script>
|
||||
<script src="assets/js/holen.js?v=202609280947" defer></script>
|
||||
<script src="assets/js/teamlage.js?v=202609280947" defer></script>
|
||||
<script src="assets/js/wahl.js?v=202609281013" defer></script>
|
||||
<script src="assets/js/bereiche.js?v=202609281013" defer></script>
|
||||
<script src="assets/js/installieren.js?v=202609281013" defer></script>
|
||||
<script src="assets/js/kopf.js?v=202609281013" defer></script>
|
||||
<script src="assets/js/glocke.js?v=202609281013" defer></script>
|
||||
<script src="assets/js/holen.js?v=202609281013" defer></script>
|
||||
<script src="assets/js/teamlage.js?v=202609281013" defer></script>
|
||||
</body>
|
||||
</html>
|
||||
|
||||
+15
-15
@@ -7,13 +7,13 @@
|
||||
<meta name="robots" content="noindex, nofollow" />
|
||||
<link rel="manifest" href="/workspace/app.webmanifest" />
|
||||
<meta name="theme-color" content="#06090f" />
|
||||
<link rel="icon" type="image/png" href="/assets/img/app-symbole/workspace-32.png?v=202609280947" />
|
||||
<link rel="apple-touch-icon" href="/assets/img/app-symbole/workspace-180.png?v=202609280947" />
|
||||
<link rel="stylesheet" href="assets/css/gate.css?v=202609280947" />
|
||||
<link rel="stylesheet" href="assets/css/start.css?v=202609280947" />
|
||||
<link rel="stylesheet" href="assets/css/bereich.css?v=202609280947" />
|
||||
<link rel="stylesheet" href="assets/css/module.css?v=202609280947" />
|
||||
<link rel="stylesheet" href="assets/css/haus.css?v=202609280947" />
|
||||
<link rel="icon" type="image/png" href="/assets/img/app-symbole/workspace-32.png?v=202609281013" />
|
||||
<link rel="apple-touch-icon" href="/assets/img/app-symbole/workspace-180.png?v=202609281013" />
|
||||
<link rel="stylesheet" href="assets/css/gate.css?v=202609281013" />
|
||||
<link rel="stylesheet" href="assets/css/start.css?v=202609281013" />
|
||||
<link rel="stylesheet" href="assets/css/bereich.css?v=202609281013" />
|
||||
<link rel="stylesheet" href="assets/css/module.css?v=202609281013" />
|
||||
<link rel="stylesheet" href="assets/css/haus.css?v=202609281013" />
|
||||
</head>
|
||||
|
||||
<body class="start">
|
||||
@@ -112,15 +112,15 @@
|
||||
|
||||
</main>
|
||||
|
||||
<script src="assets/js/meldung.js?v=202609280947" defer></script>
|
||||
<script src="assets/js/nachfrage.js?v=202609280947" defer></script>
|
||||
<script src="assets/js/meldung.js?v=202609281013" defer></script>
|
||||
<script src="assets/js/nachfrage.js?v=202609281013" defer></script>
|
||||
|
||||
|
||||
<script src="assets/js/wahl.js?v=202609280947" defer></script>
|
||||
<script src="assets/js/bereiche.js?v=202609280947" defer></script>
|
||||
<script src="assets/js/installieren.js?v=202609280947" defer></script>
|
||||
<script src="assets/js/kopf.js?v=202609280947" defer></script>
|
||||
<script src="assets/js/glocke.js?v=202609280947" defer></script>
|
||||
<script src="assets/js/teilen.js?v=202609280947" defer></script>
|
||||
<script src="assets/js/wahl.js?v=202609281013" defer></script>
|
||||
<script src="assets/js/bereiche.js?v=202609281013" defer></script>
|
||||
<script src="assets/js/installieren.js?v=202609281013" defer></script>
|
||||
<script src="assets/js/kopf.js?v=202609281013" defer></script>
|
||||
<script src="assets/js/glocke.js?v=202609281013" defer></script>
|
||||
<script src="assets/js/teilen.js?v=202609281013" defer></script>
|
||||
</body>
|
||||
</html>
|
||||
|
||||
@@ -7,14 +7,14 @@
|
||||
<meta name="robots" content="noindex, nofollow" />
|
||||
<link rel="manifest" href="/workspace/app.webmanifest" />
|
||||
<meta name="theme-color" content="#06090f" />
|
||||
<link rel="icon" type="image/png" href="/assets/img/app-symbole/workspace-32.png?v=202609280947" />
|
||||
<link rel="apple-touch-icon" href="/assets/img/app-symbole/workspace-180.png?v=202609280947" />
|
||||
<link rel="stylesheet" href="assets/css/gate.css?v=202609280947" />
|
||||
<link rel="stylesheet" href="assets/css/start.css?v=202609280947" />
|
||||
<link rel="stylesheet" href="assets/css/aufgaben.css?v=202609280947" />
|
||||
<link rel="stylesheet" href="assets/css/treff.css?v=202609280947" />
|
||||
<link rel="stylesheet" href="assets/css/module.css?v=202609280947" />
|
||||
<link rel="stylesheet" href="assets/css/haus.css?v=202609280947" />
|
||||
<link rel="icon" type="image/png" href="/assets/img/app-symbole/workspace-32.png?v=202609281013" />
|
||||
<link rel="apple-touch-icon" href="/assets/img/app-symbole/workspace-180.png?v=202609281013" />
|
||||
<link rel="stylesheet" href="assets/css/gate.css?v=202609281013" />
|
||||
<link rel="stylesheet" href="assets/css/start.css?v=202609281013" />
|
||||
<link rel="stylesheet" href="assets/css/aufgaben.css?v=202609281013" />
|
||||
<link rel="stylesheet" href="assets/css/treff.css?v=202609281013" />
|
||||
<link rel="stylesheet" href="assets/css/module.css?v=202609281013" />
|
||||
<link rel="stylesheet" href="assets/css/haus.css?v=202609281013" />
|
||||
</head>
|
||||
|
||||
<body class="start">
|
||||
@@ -126,14 +126,14 @@
|
||||
|
||||
</main>
|
||||
|
||||
<script src="assets/js/meldung.js?v=202609280947" defer></script>
|
||||
<script src="assets/js/nachfrage.js?v=202609280947" defer></script>
|
||||
<script src="assets/js/meldung.js?v=202609281013" defer></script>
|
||||
<script src="assets/js/nachfrage.js?v=202609281013" defer></script>
|
||||
|
||||
<script src="assets/js/wahl.js?v=202609280947" defer></script>
|
||||
<script src="assets/js/bereiche.js?v=202609280947" defer></script>
|
||||
<script src="assets/js/installieren.js?v=202609280947" defer></script>
|
||||
<script src="assets/js/kopf.js?v=202609280947" defer></script>
|
||||
<script src="assets/js/glocke.js?v=202609280947" defer></script>
|
||||
<script src="assets/js/treff-moderation.js?v=202609280947" defer></script>
|
||||
<script src="assets/js/wahl.js?v=202609281013" defer></script>
|
||||
<script src="assets/js/bereiche.js?v=202609281013" defer></script>
|
||||
<script src="assets/js/installieren.js?v=202609281013" defer></script>
|
||||
<script src="assets/js/kopf.js?v=202609281013" defer></script>
|
||||
<script src="assets/js/glocke.js?v=202609281013" defer></script>
|
||||
<script src="assets/js/treff-moderation.js?v=202609281013" defer></script>
|
||||
</body>
|
||||
</html>
|
||||
|
||||
+16
-16
@@ -7,18 +7,18 @@
|
||||
<meta name="robots" content="noindex, nofollow" />
|
||||
<link rel="manifest" href="/workspace/app.webmanifest" />
|
||||
<meta name="theme-color" content="#06090f" />
|
||||
<link rel="icon" type="image/png" href="/assets/img/app-symbole/workspace-32.png?v=202609280947" />
|
||||
<link rel="apple-touch-icon" href="/assets/img/app-symbole/workspace-180.png?v=202609280947" />
|
||||
<link rel="stylesheet" href="assets/css/gate.css?v=202609280947" />
|
||||
<link rel="stylesheet" href="assets/css/start.css?v=202609280947" />
|
||||
<link rel="stylesheet" href="assets/css/aufgaben.css?v=202609280947" />
|
||||
<link rel="stylesheet" href="assets/css/treff.css?v=202609280947" />
|
||||
<link rel="stylesheet" href="assets/css/module.css?v=202609280947" />
|
||||
<link rel="icon" type="image/png" href="/assets/img/app-symbole/workspace-32.png?v=202609281013" />
|
||||
<link rel="apple-touch-icon" href="/assets/img/app-symbole/workspace-180.png?v=202609281013" />
|
||||
<link rel="stylesheet" href="assets/css/gate.css?v=202609281013" />
|
||||
<link rel="stylesheet" href="assets/css/start.css?v=202609281013" />
|
||||
<link rel="stylesheet" href="assets/css/aufgaben.css?v=202609281013" />
|
||||
<link rel="stylesheet" href="assets/css/treff.css?v=202609281013" />
|
||||
<link rel="stylesheet" href="assets/css/module.css?v=202609281013" />
|
||||
<!-- haus.css MUSS die letzte Stilvorlage sein. Auf der Adresse des
|
||||
Rudels biegt der Server genau diesen Dateinamen auf crew-haus.css
|
||||
um, und die Seite kommt schon beim ERSTEN Abruf in Lila und
|
||||
Babyblau an -- ohne Umfaerben im Browser, ohne Flackern. -->
|
||||
<link rel="stylesheet" href="assets/css/haus.css?v=202609280947" />
|
||||
<link rel="stylesheet" href="assets/css/haus.css?v=202609281013" />
|
||||
</head>
|
||||
|
||||
<body class="start">
|
||||
@@ -248,14 +248,14 @@
|
||||
Beim ersten Anlauf fehlte die Zeile auf genau diesen beiden neuen
|
||||
Seiten. Gefunden hat das nicht das Auge, sondern pruef-css-klassen,
|
||||
die seit dem 07.09. jede Seite danach absucht. -->
|
||||
<script src="assets/js/nachfrage.js?v=202609280947" defer></script>
|
||||
<script src="assets/js/nachfrage.js?v=202609281013" defer></script>
|
||||
|
||||
<script src="assets/js/wahl.js?v=202609280947" defer></script>
|
||||
<script src="assets/js/bereiche.js?v=202609280947" defer></script>
|
||||
<script src="assets/js/installieren.js?v=202609280947" defer></script>
|
||||
<script src="assets/js/kopf.js?v=202609280947" defer></script>
|
||||
<script src="assets/js/glocke.js?v=202609280947" defer></script>
|
||||
<script src="assets/js/auskunft.js?v=202609280947" defer></script>
|
||||
<script src="assets/js/treff-regeln.js?v=202609280947" defer></script>
|
||||
<script src="assets/js/wahl.js?v=202609281013" defer></script>
|
||||
<script src="assets/js/bereiche.js?v=202609281013" defer></script>
|
||||
<script src="assets/js/installieren.js?v=202609281013" defer></script>
|
||||
<script src="assets/js/kopf.js?v=202609281013" defer></script>
|
||||
<script src="assets/js/glocke.js?v=202609281013" defer></script>
|
||||
<script src="assets/js/auskunft.js?v=202609281013" defer></script>
|
||||
<script src="assets/js/treff-regeln.js?v=202609281013" defer></script>
|
||||
</body>
|
||||
</html>
|
||||
|
||||
+16
-16
@@ -12,22 +12,22 @@
|
||||
Ton wie die Kopfleiste darunter (#06090f), damit Leiste und Seite
|
||||
eine Flaeche sind statt zweier. -->
|
||||
<meta name="theme-color" content="#06090f" />
|
||||
<link rel="icon" type="image/png" href="/assets/img/app-symbole/workspace-32.png?v=202609280947" />
|
||||
<link rel="apple-touch-icon" href="/assets/img/app-symbole/workspace-180.png?v=202609280947" />
|
||||
<link rel="stylesheet" href="assets/css/gate.css?v=202609280947" />
|
||||
<link rel="stylesheet" href="assets/css/start.css?v=202609280947" />
|
||||
<link rel="icon" type="image/png" href="/assets/img/app-symbole/workspace-32.png?v=202609281013" />
|
||||
<link rel="apple-touch-icon" href="/assets/img/app-symbole/workspace-180.png?v=202609281013" />
|
||||
<link rel="stylesheet" href="assets/css/gate.css?v=202609281013" />
|
||||
<link rel="stylesheet" href="assets/css/start.css?v=202609281013" />
|
||||
<!-- Formular- und Dialogstile: seit dem 07.09.2026 steht hier der
|
||||
Dialog "Creator anlegen". -->
|
||||
<link rel="stylesheet" href="assets/css/aufgaben.css?v=202609280947" />
|
||||
<link rel="stylesheet" href="assets/css/uebersicht.css?v=202609280947" />
|
||||
<link rel="stylesheet" href="assets/css/module.css?v=202609280947" />
|
||||
<link rel="stylesheet" href="assets/css/aufgaben.css?v=202609281013" />
|
||||
<link rel="stylesheet" href="assets/css/uebersicht.css?v=202609281013" />
|
||||
<link rel="stylesheet" href="assets/css/module.css?v=202609281013" />
|
||||
<!-- haus.css MUSS die letzte Stilvorlage sein (10.09.2026).
|
||||
Auf der Agenturadresse ist sie leer -- das Haus hier IST der
|
||||
Grundzustand. Auf der Adresse von Team Dogi biegt der Server
|
||||
genau diesen Dateinamen auf crew-haus.css um, und die Seite
|
||||
kommt schon beim ERSTEN Abruf in Lila und Babyblau an --
|
||||
ohne Umfaerben im Browser, ohne Flackern. -->
|
||||
<link rel="stylesheet" href="assets/css/haus.css?v=202609280947" />
|
||||
<link rel="stylesheet" href="assets/css/haus.css?v=202609281013" />
|
||||
</head>
|
||||
|
||||
<body class="start">
|
||||
@@ -149,16 +149,16 @@
|
||||
|
||||
</main>
|
||||
|
||||
<script src="assets/js/meldung.js?v=202609280947" defer></script>
|
||||
<script src="assets/js/nachfrage.js?v=202609280947" defer></script>
|
||||
<script src="assets/js/meldung.js?v=202609281013" defer></script>
|
||||
<script src="assets/js/nachfrage.js?v=202609281013" defer></script>
|
||||
|
||||
|
||||
<script src="assets/js/bereiche.js?v=202609280947" defer></script>
|
||||
<script src="assets/js/bereiche.js?v=202609281013" defer></script>
|
||||
|
||||
<script src="assets/js/wahl.js?v=202609280947" defer></script>
|
||||
<script src="assets/js/installieren.js?v=202609280947" defer></script>
|
||||
<script src="assets/js/kopf.js?v=202609280947" defer></script>
|
||||
<script src="assets/js/glocke.js?v=202609280947" defer></script>
|
||||
<script src="assets/js/uebersicht.js?v=202609280947" defer></script>
|
||||
<script src="assets/js/wahl.js?v=202609281013" defer></script>
|
||||
<script src="assets/js/installieren.js?v=202609281013" defer></script>
|
||||
<script src="assets/js/kopf.js?v=202609281013" defer></script>
|
||||
<script src="assets/js/glocke.js?v=202609281013" defer></script>
|
||||
<script src="assets/js/uebersicht.js?v=202609281013" defer></script>
|
||||
</body>
|
||||
</html>
|
||||
|
||||
@@ -7,13 +7,13 @@
|
||||
<meta name="robots" content="noindex, nofollow" />
|
||||
<link rel="manifest" href="/workspace/app.webmanifest" />
|
||||
<meta name="theme-color" content="#06090f" />
|
||||
<link rel="icon" type="image/png" href="/assets/img/app-symbole/workspace-32.png?v=202609280947" />
|
||||
<link rel="apple-touch-icon" href="/assets/img/app-symbole/workspace-180.png?v=202609280947" />
|
||||
<link rel="stylesheet" href="assets/css/gate.css?v=202609280947" />
|
||||
<link rel="stylesheet" href="assets/css/start.css?v=202609280947" />
|
||||
<link rel="stylesheet" href="assets/css/unsere-seiten.css?v=202609280947" />
|
||||
<link rel="stylesheet" href="assets/css/module.css?v=202609280947" />
|
||||
<link rel="stylesheet" href="assets/css/haus.css?v=202609280947" />
|
||||
<link rel="icon" type="image/png" href="/assets/img/app-symbole/workspace-32.png?v=202609281013" />
|
||||
<link rel="apple-touch-icon" href="/assets/img/app-symbole/workspace-180.png?v=202609281013" />
|
||||
<link rel="stylesheet" href="assets/css/gate.css?v=202609281013" />
|
||||
<link rel="stylesheet" href="assets/css/start.css?v=202609281013" />
|
||||
<link rel="stylesheet" href="assets/css/unsere-seiten.css?v=202609281013" />
|
||||
<link rel="stylesheet" href="assets/css/module.css?v=202609281013" />
|
||||
<link rel="stylesheet" href="assets/css/haus.css?v=202609281013" />
|
||||
</head>
|
||||
|
||||
<body class="start">
|
||||
@@ -335,14 +335,14 @@
|
||||
|
||||
</main>
|
||||
|
||||
<script src="assets/js/nachfrage.js?v=202609280947" defer></script>
|
||||
<script src="assets/js/nachfrage.js?v=202609281013" defer></script>
|
||||
|
||||
<script src="assets/js/wahl.js?v=202609280947" defer></script>
|
||||
<script src="assets/js/bereiche.js?v=202609280947" defer></script>
|
||||
<script src="assets/js/installieren.js?v=202609280947" defer></script>
|
||||
<script src="assets/js/kopf.js?v=202609280947" defer></script>
|
||||
<script src="assets/js/glocke.js?v=202609280947" defer></script>
|
||||
<script src="assets/js/live.js?v=202609280947" defer></script>
|
||||
<script src="assets/js/unsere-seiten.js?v=202609280947" defer></script>
|
||||
<script src="assets/js/wahl.js?v=202609281013" defer></script>
|
||||
<script src="assets/js/bereiche.js?v=202609281013" defer></script>
|
||||
<script src="assets/js/installieren.js?v=202609281013" defer></script>
|
||||
<script src="assets/js/kopf.js?v=202609281013" defer></script>
|
||||
<script src="assets/js/glocke.js?v=202609281013" defer></script>
|
||||
<script src="assets/js/live.js?v=202609281013" defer></script>
|
||||
<script src="assets/js/unsere-seiten.js?v=202609281013" defer></script>
|
||||
</body>
|
||||
</html>
|
||||
|
||||
@@ -7,13 +7,13 @@
|
||||
<meta name="robots" content="noindex, nofollow" />
|
||||
<link rel="manifest" href="/workspace/app.webmanifest" />
|
||||
<meta name="theme-color" content="#06090f" />
|
||||
<link rel="icon" type="image/png" href="/assets/img/app-symbole/workspace-32.png?v=202609280947" />
|
||||
<link rel="apple-touch-icon" href="/assets/img/app-symbole/workspace-180.png?v=202609280947" />
|
||||
<link rel="stylesheet" href="assets/css/gate.css?v=202609280947" />
|
||||
<link rel="stylesheet" href="assets/css/start.css?v=202609280947" />
|
||||
<link rel="stylesheet" href="assets/css/unterstuetzen.css?v=202609280947" />
|
||||
<link rel="stylesheet" href="assets/css/module.css?v=202609280947" />
|
||||
<link rel="stylesheet" href="assets/css/haus.css?v=202609280947" />
|
||||
<link rel="icon" type="image/png" href="/assets/img/app-symbole/workspace-32.png?v=202609281013" />
|
||||
<link rel="apple-touch-icon" href="/assets/img/app-symbole/workspace-180.png?v=202609281013" />
|
||||
<link rel="stylesheet" href="assets/css/gate.css?v=202609281013" />
|
||||
<link rel="stylesheet" href="assets/css/start.css?v=202609281013" />
|
||||
<link rel="stylesheet" href="assets/css/unterstuetzen.css?v=202609281013" />
|
||||
<link rel="stylesheet" href="assets/css/module.css?v=202609281013" />
|
||||
<link rel="stylesheet" href="assets/css/haus.css?v=202609281013" />
|
||||
</head>
|
||||
|
||||
<body class="start">
|
||||
@@ -106,17 +106,17 @@
|
||||
<!-- bereiche.js VOR kopf.js: Dort steht `window.Bereiche`, und kopf.js
|
||||
liest daraus die Leitungsrollen. Ohne sie stürzt jede Seite mit
|
||||
„Cannot read properties of undefined (reading 'LEITUNG')" ab. -->
|
||||
<script src="assets/js/bereiche.js?v=202609280947" defer></script>
|
||||
<script src="assets/js/wahl.js?v=202609280947" defer></script>
|
||||
<script src="assets/js/nachfrage.js?v=202609280947" defer></script>
|
||||
<script src="assets/js/installieren.js?v=202609280947" defer></script>
|
||||
<script src="assets/js/kopf.js?v=202609280947" defer></script>
|
||||
<script src="assets/js/glocke.js?v=202609280947" defer></script>
|
||||
<script src="assets/js/holen.js?v=202609280947" defer></script>
|
||||
<script src="assets/js/bereiche.js?v=202609281013" defer></script>
|
||||
<script src="assets/js/wahl.js?v=202609281013" defer></script>
|
||||
<script src="assets/js/nachfrage.js?v=202609281013" defer></script>
|
||||
<script src="assets/js/installieren.js?v=202609281013" defer></script>
|
||||
<script src="assets/js/kopf.js?v=202609281013" defer></script>
|
||||
<script src="assets/js/glocke.js?v=202609281013" defer></script>
|
||||
<script src="assets/js/holen.js?v=202609281013" defer></script>
|
||||
<!-- Die Satz-Tafel. Ohne sie stand auf dieser Seite das Maschinenwort
|
||||
des Servers (z.B. "nicht_gefunden") statt eines Satzes -- gemeldet
|
||||
von pruef-meldungen, nicht beim Ansehen. -->
|
||||
<script src="assets/js/meldung.js?v=202609280947" defer></script>
|
||||
<script src="assets/js/unterstuetzen.js?v=202609280947" defer></script>
|
||||
<script src="assets/js/meldung.js?v=202609281013" defer></script>
|
||||
<script src="assets/js/unterstuetzen.js?v=202609281013" defer></script>
|
||||
</body>
|
||||
</html>
|
||||
|
||||
+16
-16
@@ -7,15 +7,15 @@
|
||||
<meta name="robots" content="noindex, nofollow" />
|
||||
<link rel="manifest" href="/workspace/app.webmanifest" />
|
||||
<meta name="theme-color" content="#06090f" />
|
||||
<link rel="icon" type="image/png" href="/assets/img/app-symbole/workspace-32.png?v=202609280947" />
|
||||
<link rel="apple-touch-icon" href="/assets/img/app-symbole/workspace-180.png?v=202609280947" />
|
||||
<link rel="stylesheet" href="assets/css/gate.css?v=202609280947" />
|
||||
<link rel="stylesheet" href="assets/css/start.css?v=202609280947" />
|
||||
<link rel="stylesheet" href="assets/css/aufgaben.css?v=202609280947" />
|
||||
<link rel="stylesheet" href="assets/css/entwicklung.css?v=202609280947" />
|
||||
<link rel="stylesheet" href="assets/css/werdegang.css?v=202609280947" />
|
||||
<link rel="stylesheet" href="assets/css/module.css?v=202609280947" />
|
||||
<link rel="stylesheet" href="assets/css/haus.css?v=202609280947" />
|
||||
<link rel="icon" type="image/png" href="/assets/img/app-symbole/workspace-32.png?v=202609281013" />
|
||||
<link rel="apple-touch-icon" href="/assets/img/app-symbole/workspace-180.png?v=202609281013" />
|
||||
<link rel="stylesheet" href="assets/css/gate.css?v=202609281013" />
|
||||
<link rel="stylesheet" href="assets/css/start.css?v=202609281013" />
|
||||
<link rel="stylesheet" href="assets/css/aufgaben.css?v=202609281013" />
|
||||
<link rel="stylesheet" href="assets/css/entwicklung.css?v=202609281013" />
|
||||
<link rel="stylesheet" href="assets/css/werdegang.css?v=202609281013" />
|
||||
<link rel="stylesheet" href="assets/css/module.css?v=202609281013" />
|
||||
<link rel="stylesheet" href="assets/css/haus.css?v=202609281013" />
|
||||
</head>
|
||||
|
||||
<body class="start">
|
||||
@@ -144,14 +144,14 @@
|
||||
|
||||
</main>
|
||||
|
||||
<script src="assets/js/nachfrage.js?v=202609280947" defer></script>
|
||||
<script src="assets/js/nachfrage.js?v=202609281013" defer></script>
|
||||
|
||||
|
||||
<script src="assets/js/wahl.js?v=202609280947" defer></script>
|
||||
<script src="assets/js/bereiche.js?v=202609280947" defer></script>
|
||||
<script src="assets/js/installieren.js?v=202609280947" defer></script>
|
||||
<script src="assets/js/kopf.js?v=202609280947" defer></script>
|
||||
<script src="assets/js/glocke.js?v=202609280947" defer></script>
|
||||
<script src="assets/js/werdegang.js?v=202609280947" defer></script>
|
||||
<script src="assets/js/wahl.js?v=202609281013" defer></script>
|
||||
<script src="assets/js/bereiche.js?v=202609281013" defer></script>
|
||||
<script src="assets/js/installieren.js?v=202609281013" defer></script>
|
||||
<script src="assets/js/kopf.js?v=202609281013" defer></script>
|
||||
<script src="assets/js/glocke.js?v=202609281013" defer></script>
|
||||
<script src="assets/js/werdegang.js?v=202609281013" defer></script>
|
||||
</body>
|
||||
</html>
|
||||
|
||||
+15
-15
@@ -12,13 +12,13 @@
|
||||
vergessen wird. -->
|
||||
<link rel="manifest" href="/workspace/app.webmanifest" />
|
||||
<meta name="theme-color" content="#06090f" />
|
||||
<link rel="icon" type="image/png" href="/assets/img/app-symbole/workspace-32.png?v=202609280947" />
|
||||
<link rel="apple-touch-icon" href="/assets/img/app-symbole/workspace-180.png?v=202609280947" />
|
||||
<link rel="stylesheet" href="assets/css/gate.css?v=202609280947" />
|
||||
<link rel="stylesheet" href="assets/css/start.css?v=202609280947" />
|
||||
<link rel="stylesheet" href="assets/css/willkommen.css?v=202609280947" />
|
||||
<link rel="stylesheet" href="assets/css/module.css?v=202609280947" />
|
||||
<link rel="stylesheet" href="assets/css/haus.css?v=202609280947" />
|
||||
<link rel="icon" type="image/png" href="/assets/img/app-symbole/workspace-32.png?v=202609281013" />
|
||||
<link rel="apple-touch-icon" href="/assets/img/app-symbole/workspace-180.png?v=202609281013" />
|
||||
<link rel="stylesheet" href="assets/css/gate.css?v=202609281013" />
|
||||
<link rel="stylesheet" href="assets/css/start.css?v=202609281013" />
|
||||
<link rel="stylesheet" href="assets/css/willkommen.css?v=202609281013" />
|
||||
<link rel="stylesheet" href="assets/css/module.css?v=202609281013" />
|
||||
<link rel="stylesheet" href="assets/css/haus.css?v=202609281013" />
|
||||
</head>
|
||||
<!-- KOERPERKLASSE "start", NICHT "gate" (berichtigt 21.09.2026).
|
||||
`body.gate` ist die Anmeldewand: `display:flex; align-items:center`,
|
||||
@@ -75,13 +75,13 @@
|
||||
<p class="fehler" id="fehler" hidden></p>
|
||||
</main>
|
||||
|
||||
<script src="assets/js/meldung.js?v=202609280947" defer></script>
|
||||
<script src="assets/js/bereiche.js?v=202609280947" defer></script>
|
||||
<script src="assets/js/wahl.js?v=202609280947" defer></script>
|
||||
<script src="assets/js/nachfrage.js?v=202609280947" defer></script>
|
||||
<script src="assets/js/installieren.js?v=202609280947" defer></script>
|
||||
<script src="assets/js/kopf.js?v=202609280947" defer></script>
|
||||
<script src="assets/js/glocke.js?v=202609280947" defer></script>
|
||||
<script src="assets/js/willkommen.js?v=202609280947" defer></script>
|
||||
<script src="assets/js/meldung.js?v=202609281013" defer></script>
|
||||
<script src="assets/js/bereiche.js?v=202609281013" defer></script>
|
||||
<script src="assets/js/wahl.js?v=202609281013" defer></script>
|
||||
<script src="assets/js/nachfrage.js?v=202609281013" defer></script>
|
||||
<script src="assets/js/installieren.js?v=202609281013" defer></script>
|
||||
<script src="assets/js/kopf.js?v=202609281013" defer></script>
|
||||
<script src="assets/js/glocke.js?v=202609281013" defer></script>
|
||||
<script src="assets/js/willkommen.js?v=202609281013" defer></script>
|
||||
</body>
|
||||
</html>
|
||||
|
||||
+17
-17
@@ -12,20 +12,20 @@
|
||||
Ton wie die Kopfleiste darunter (#06090f), damit Leiste und Seite
|
||||
eine Flaeche sind statt zweier. -->
|
||||
<meta name="theme-color" content="#06090f" />
|
||||
<link rel="icon" type="image/png" href="/assets/img/app-symbole/workspace-32.png?v=202609280947" />
|
||||
<link rel="apple-touch-icon" href="/assets/img/app-symbole/workspace-180.png?v=202609280947" />
|
||||
<link rel="stylesheet" href="assets/css/gate.css?v=202609280947" />
|
||||
<link rel="stylesheet" href="assets/css/start.css?v=202609280947" />
|
||||
<link rel="stylesheet" href="assets/css/aufgaben.css?v=202609280947" />
|
||||
<link rel="stylesheet" href="assets/css/wissen.css?v=202609280947" />
|
||||
<link rel="stylesheet" href="assets/css/module.css?v=202609280947" />
|
||||
<link rel="icon" type="image/png" href="/assets/img/app-symbole/workspace-32.png?v=202609281013" />
|
||||
<link rel="apple-touch-icon" href="/assets/img/app-symbole/workspace-180.png?v=202609281013" />
|
||||
<link rel="stylesheet" href="assets/css/gate.css?v=202609281013" />
|
||||
<link rel="stylesheet" href="assets/css/start.css?v=202609281013" />
|
||||
<link rel="stylesheet" href="assets/css/aufgaben.css?v=202609281013" />
|
||||
<link rel="stylesheet" href="assets/css/wissen.css?v=202609281013" />
|
||||
<link rel="stylesheet" href="assets/css/module.css?v=202609281013" />
|
||||
<!-- haus.css MUSS die letzte Stilvorlage sein (10.09.2026).
|
||||
Auf der Agenturadresse ist sie leer -- das Haus hier IST der
|
||||
Grundzustand. Auf der Adresse von Team Dogi biegt der Server
|
||||
genau diesen Dateinamen auf crew-haus.css um, und die Seite
|
||||
kommt schon beim ERSTEN Abruf in Lila und Babyblau an --
|
||||
ohne Umfaerben im Browser, ohne Flackern. -->
|
||||
<link rel="stylesheet" href="assets/css/haus.css?v=202609280947" />
|
||||
<link rel="stylesheet" href="assets/css/haus.css?v=202609281013" />
|
||||
</head>
|
||||
|
||||
<body class="start">
|
||||
@@ -190,15 +190,15 @@
|
||||
|
||||
</main>
|
||||
|
||||
<script src="assets/js/meldung.js?v=202609280947" defer></script>
|
||||
<script src="assets/js/hochladen.js?v=202609280947" defer></script>
|
||||
<script src="assets/js/nachfrage.js?v=202609280947" defer></script>
|
||||
<script src="assets/js/meldung.js?v=202609281013" defer></script>
|
||||
<script src="assets/js/hochladen.js?v=202609281013" defer></script>
|
||||
<script src="assets/js/nachfrage.js?v=202609281013" defer></script>
|
||||
|
||||
<script src="assets/js/wahl.js?v=202609280947" defer></script>
|
||||
<script src="assets/js/bereiche.js?v=202609280947" defer></script>
|
||||
<script src="assets/js/installieren.js?v=202609280947" defer></script>
|
||||
<script src="assets/js/kopf.js?v=202609280947" defer></script>
|
||||
<script src="assets/js/glocke.js?v=202609280947" defer></script>
|
||||
<script src="assets/js/wissen.js?v=202609280947" defer></script>
|
||||
<script src="assets/js/wahl.js?v=202609281013" defer></script>
|
||||
<script src="assets/js/bereiche.js?v=202609281013" defer></script>
|
||||
<script src="assets/js/installieren.js?v=202609281013" defer></script>
|
||||
<script src="assets/js/kopf.js?v=202609281013" defer></script>
|
||||
<script src="assets/js/glocke.js?v=202609281013" defer></script>
|
||||
<script src="assets/js/wissen.js?v=202609281013" defer></script>
|
||||
</body>
|
||||
</html>
|
||||
|
||||
Reference in New Issue
Block a user