Lehrer-Observability + Weltküche-Inhalt + Wrapper-Fix + Passstraße
teacher.html: Menü „Live" → „Ergebnisse" mit Unteransichten Tag·Aktuell·Vergleich·Gesamt (alte Ergebnisse-Ansicht ist jetzt „Gesamt"). Neue Kennzahl Qualität (grafischer richtig/falsch-Balken) in Aktuell + Vergleich + Weltküche-Zeile, Gerichte-Zähler (Fleiß), Labels entschärft („Kritisch" → Stark/Solide/Viele Fehler). Weltküche: korrekte Artikel (der/die/das) für alle 70 Zutaten in production-matrix.json; verdrehten Herkunfts-Satz + Heimat-Banner neu und marktbewusst (Ukraine-Distraktor ehrlich erklärt), „man"-Konstruktionen für Singular/Plural. _scripts.php: renderPage() injizierte Favicon per strrpos ins letzte </head> — das lag in teacher.htmls printBatchTickets-JS-String → SyntaxError zerschoss das ganze Inline-Script auf /teacher. Fix: strpos (erstes </head>). tourismusregion: neue Karte passstrasse in maps-custom.json (Route bergauf 136 Punkte, 41 Bauslots) aus Editor-Export. Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
This commit is contained in:
@@ -0,0 +1,46 @@
|
||||
-- ============================================================
|
||||
-- Weltküche: Lehrplan-Bezug erscheint nicht — Reparatur
|
||||
-- Stand: 2026-08-18 · Atlas
|
||||
-- ------------------------------------------------------------
|
||||
-- Ursache: Die phase3-Migration (2026-06-08) hat die Modul-
|
||||
-- Zuordnung über die Session-Variable @welternaehrung_id gesetzt:
|
||||
-- INSERT IGNORE INTO kompetenz_modules VALUES (@welternaehrung_id,'weltkueche',100,'primaer');
|
||||
-- War @welternaehrung_id beim Prod-Import NULL (anderer Connection-
|
||||
-- Kontext), wurde KEINE weltkueche-Zeile angelegt. Der INNER JOIN in
|
||||
-- modul_detail.php liefert dann nichts → „Noch keine Kompetenzen".
|
||||
--
|
||||
-- Die Kompetenz 'welternaehrung-konsum-disparitaeten' und ihre ~118
|
||||
-- Anker existieren bereits — es fehlt nur die Verknüpfung.
|
||||
--
|
||||
-- Diese Reparatur ist idempotent und referenziert die Kompetenz per
|
||||
-- key_slug (NICHT per Session-Variable / harter ID). Sekundär-Bezüge
|
||||
-- ebenfalls per key_slug, damit sie environment-unabhängig greifen.
|
||||
-- ============================================================
|
||||
|
||||
-- Primär: Welternährung, Konsum und globale Disparitäten
|
||||
INSERT INTO kompetenz_modules (kompetenz_id, module_id, level, strength)
|
||||
SELECT id, 'weltkueche', 100, 'primaer'
|
||||
FROM kompetenzen WHERE key_slug = 'welternaehrung-konsum-disparitaeten'
|
||||
ON DUPLICATE KEY UPDATE strength = VALUES(strength), level = VALUES(level);
|
||||
|
||||
-- Sekundär: Klimawandel (Klimazonen/Anbaugrenzen, Ökobilanz von Lebensmitteln)
|
||||
INSERT INTO kompetenz_modules (kompetenz_id, module_id, level, strength)
|
||||
SELECT id, 'weltkueche', 50, 'sekundaer'
|
||||
FROM kompetenzen WHERE key_slug = 'klimawandel'
|
||||
ON DUPLICATE KEY UPDATE strength = VALUES(strength);
|
||||
|
||||
-- Sekundär: Systemisches Denken (Welthandel, Lieferketten, Konsumfolgen)
|
||||
INSERT INTO kompetenz_modules (kompetenz_id, module_id, level, strength)
|
||||
SELECT id, 'weltkueche', 50, 'sekundaer'
|
||||
FROM kompetenzen WHERE key_slug = 'systemisches-denken'
|
||||
ON DUPLICATE KEY UPDATE strength = VALUES(strength);
|
||||
|
||||
-- Kontrolle:
|
||||
-- SELECT k.key_slug, km.strength, km.level
|
||||
-- FROM kompetenz_modules km JOIN kompetenzen k ON k.id = km.kompetenz_id
|
||||
-- WHERE km.module_id = 'weltkueche' ORDER BY km.strength;
|
||||
-- -> erwartet: primaer welternaehrung-konsum-disparitaeten (+ 2 sekundaer)
|
||||
--
|
||||
-- SELECT COUNT(*) FROM lehrplan_anchors
|
||||
-- WHERE kompetenz_id = (SELECT id FROM kompetenzen WHERE key_slug='welternaehrung-konsum-disparitaeten');
|
||||
-- -> erwartet: > 0 (Anker existieren bereits aus phase3)
|
||||
@@ -103,8 +103,14 @@ HTML;
|
||||
$html = preg_replace('/<link[^>]*rel=["\']icon["\'][^>]*>\s*/', '', $html);
|
||||
}
|
||||
|
||||
// Favicon vor LETZTEM </head> einfügen (nicht in JS-Strings injizieren)
|
||||
$headPos = strrpos($html, '</head>');
|
||||
// Favicon vor dem ERSTEN </head> einfügen (= echter Dokumentkopf).
|
||||
// WICHTIG: strpos (erstes), NICHT strrpos (letztes). Seiten wie teacher.html
|
||||
// enthalten in Body-Skripten ein w.document.write('<html><head>…</head>…')
|
||||
// (z.B. Ticket-Druck-Popup). Dessen </head> ist das LETZTE der Datei — strrpos
|
||||
// hätte den mehrzeiligen Favicon-Block mitten in den einfach-gequoteten
|
||||
// JS-String injiziert → „Invalid or unexpected token" → gesamtes Inline-Script
|
||||
// tot. Das echte Kopf-</head> ist immer das erste.
|
||||
$headPos = strpos($html, '</head>');
|
||||
if ($headPos !== false) {
|
||||
$html = substr($html, 0, $headPos) . $favicon . "\n" . substr($html, $headPos);
|
||||
}
|
||||
|
||||
File diff suppressed because it is too large
Load Diff
@@ -1,6 +1,7 @@
|
||||
{
|
||||
"pfeffer": {
|
||||
"nm": "Schwarzer Pfeffer",
|
||||
"art": "der",
|
||||
"ic": "🧂",
|
||||
"producers": {
|
||||
"vietnam": {
|
||||
@@ -49,6 +50,7 @@
|
||||
},
|
||||
"kakao": {
|
||||
"nm": "Kakao",
|
||||
"art": "der",
|
||||
"ic": "🍫",
|
||||
"producers": {
|
||||
"elfenbein": {
|
||||
@@ -105,6 +107,7 @@
|
||||
},
|
||||
"vanille": {
|
||||
"nm": "Vanille",
|
||||
"art": "die",
|
||||
"ic": "🌼",
|
||||
"producers": {
|
||||
"madagaskar": {
|
||||
@@ -136,6 +139,7 @@
|
||||
},
|
||||
"kurkuma": {
|
||||
"nm": "Kurkuma",
|
||||
"art": "die",
|
||||
"ic": "🟡",
|
||||
"producers": {
|
||||
"indien": {
|
||||
@@ -184,6 +188,7 @@
|
||||
},
|
||||
"ingwer": {
|
||||
"nm": "Ingwer",
|
||||
"art": "der",
|
||||
"ic": "🫚",
|
||||
"producers": {
|
||||
"indien": {
|
||||
@@ -235,6 +240,7 @@
|
||||
},
|
||||
"zimt": {
|
||||
"nm": "Zimt",
|
||||
"art": "der",
|
||||
"ic": "🪵",
|
||||
"producers": {
|
||||
"indonesien": {
|
||||
@@ -270,6 +276,7 @@
|
||||
},
|
||||
"kardamom": {
|
||||
"nm": "Kardamom",
|
||||
"art": "der",
|
||||
"ic": "🫛",
|
||||
"producers": {
|
||||
"guatemala": {
|
||||
@@ -305,6 +312,7 @@
|
||||
},
|
||||
"sesam": {
|
||||
"nm": "Sesam",
|
||||
"art": "der",
|
||||
"ic": "⚪",
|
||||
"producers": {
|
||||
"sudan": {
|
||||
@@ -356,6 +364,7 @@
|
||||
},
|
||||
"chili": {
|
||||
"nm": "Chili",
|
||||
"art": "die",
|
||||
"ic": "🌶️",
|
||||
"producers": {
|
||||
"indien": {
|
||||
@@ -403,6 +412,7 @@
|
||||
},
|
||||
"kumin": {
|
||||
"nm": "Kreuzkümmel (Cumin)",
|
||||
"art": "der",
|
||||
"ic": "🌿",
|
||||
"producers": {
|
||||
"indien": {
|
||||
@@ -437,6 +447,7 @@
|
||||
},
|
||||
"koriander": {
|
||||
"nm": "Koriander (Samen)",
|
||||
"art": "der",
|
||||
"ic": "🌿",
|
||||
"producers": {
|
||||
"indien": {
|
||||
@@ -481,6 +492,7 @@
|
||||
},
|
||||
"safran": {
|
||||
"nm": "Safran",
|
||||
"art": "der",
|
||||
"ic": "🌸",
|
||||
"producers": {
|
||||
"iran": {
|
||||
@@ -519,6 +531,7 @@
|
||||
},
|
||||
"muskat": {
|
||||
"nm": "Muskat",
|
||||
"art": "der",
|
||||
"ic": "🌰",
|
||||
"producers": {
|
||||
"indonesien": {
|
||||
@@ -548,6 +561,7 @@
|
||||
},
|
||||
"nelken": {
|
||||
"nm": "Gewürznelken",
|
||||
"art": "die",
|
||||
"ic": "🌾",
|
||||
"producers": {
|
||||
"indonesien": {
|
||||
@@ -577,6 +591,7 @@
|
||||
},
|
||||
"paprika": {
|
||||
"nm": "Paprika-Pulver",
|
||||
"art": "das",
|
||||
"ic": "🟥",
|
||||
"producers": {
|
||||
"china": {
|
||||
@@ -626,6 +641,7 @@
|
||||
},
|
||||
"kuemmel": {
|
||||
"nm": "Kümmel",
|
||||
"art": "der",
|
||||
"ic": "🌿",
|
||||
"producers": {
|
||||
"finnland": {
|
||||
@@ -668,6 +684,7 @@
|
||||
},
|
||||
"majoran": {
|
||||
"nm": "Majoran",
|
||||
"art": "der",
|
||||
"ic": "🌿",
|
||||
"producers": {
|
||||
"aegypten": {
|
||||
@@ -704,6 +721,7 @@
|
||||
},
|
||||
"kraeuter": {
|
||||
"nm": "Mediterrane Kräuter",
|
||||
"art": "die",
|
||||
"ic": "🌿",
|
||||
"producers": {
|
||||
"marokko": {
|
||||
@@ -759,6 +777,7 @@
|
||||
},
|
||||
"banane": {
|
||||
"nm": "Banane",
|
||||
"art": "die",
|
||||
"ic": "🍌",
|
||||
"producers": {
|
||||
"indien": {
|
||||
@@ -832,6 +851,7 @@
|
||||
},
|
||||
"avocado": {
|
||||
"nm": "Avocado",
|
||||
"art": "die",
|
||||
"ic": "🥑",
|
||||
"producers": {
|
||||
"mexiko": {
|
||||
@@ -894,6 +914,7 @@
|
||||
},
|
||||
"limette": {
|
||||
"nm": "Limette",
|
||||
"art": "die",
|
||||
"ic": "🟢",
|
||||
"producers": {
|
||||
"mexiko": {
|
||||
@@ -953,6 +974,7 @@
|
||||
},
|
||||
"orange": {
|
||||
"nm": "Orange / Orangensaft",
|
||||
"art": "die",
|
||||
"ic": "🍊",
|
||||
"producers": {
|
||||
"brasilien": {
|
||||
@@ -1029,6 +1051,7 @@
|
||||
},
|
||||
"zitrone": {
|
||||
"nm": "Zitrone",
|
||||
"art": "die",
|
||||
"ic": "🍋",
|
||||
"producers": {
|
||||
"indien": {
|
||||
@@ -1102,6 +1125,7 @@
|
||||
},
|
||||
"kokos": {
|
||||
"nm": "Kokosnuss / Kokosmilch",
|
||||
"art": "die",
|
||||
"ic": "🥥",
|
||||
"producers": {
|
||||
"indonesien": {
|
||||
@@ -1153,6 +1177,7 @@
|
||||
},
|
||||
"tamarinde": {
|
||||
"nm": "Tamarinde",
|
||||
"art": "die",
|
||||
"ic": "🟤",
|
||||
"producers": {
|
||||
"indien": {
|
||||
@@ -1187,6 +1212,7 @@
|
||||
},
|
||||
"kaffee": {
|
||||
"nm": "Kaffee",
|
||||
"art": "der",
|
||||
"ic": "☕",
|
||||
"producers": {
|
||||
"brasilien": {
|
||||
@@ -1244,6 +1270,7 @@
|
||||
},
|
||||
"wein": {
|
||||
"nm": "Wein (Reben)",
|
||||
"art": "der",
|
||||
"ic": "🍷",
|
||||
"producers": {
|
||||
"italien": {
|
||||
@@ -1322,6 +1349,7 @@
|
||||
},
|
||||
"reis": {
|
||||
"nm": "Reis",
|
||||
"art": "der",
|
||||
"ic": "🍚",
|
||||
"producers": {
|
||||
"china": {
|
||||
@@ -1420,6 +1448,7 @@
|
||||
},
|
||||
"reisnudeln": {
|
||||
"nm": "Reisnudeln",
|
||||
"art": "die",
|
||||
"ic": "🍜",
|
||||
"producers": {
|
||||
"china": {
|
||||
@@ -1461,6 +1490,7 @@
|
||||
},
|
||||
"hartweizen": {
|
||||
"nm": "Hartweizen (Durum)",
|
||||
"art": "der",
|
||||
"ic": "🌾",
|
||||
"producers": {
|
||||
"kanada": {
|
||||
@@ -1527,6 +1557,7 @@
|
||||
},
|
||||
"mehl": {
|
||||
"nm": "Mehl (Weichweizen)",
|
||||
"art": "das",
|
||||
"ic": "🌾",
|
||||
"producers": {
|
||||
"china": {
|
||||
@@ -1615,6 +1646,7 @@
|
||||
},
|
||||
"mais": {
|
||||
"nm": "Mais (Tortilla, Polenta)",
|
||||
"art": "der",
|
||||
"ic": "🌽",
|
||||
"producers": {
|
||||
"usa": {
|
||||
@@ -1711,6 +1743,7 @@
|
||||
},
|
||||
"mandeln": {
|
||||
"nm": "Mandeln",
|
||||
"art": "die",
|
||||
"ic": "🌰",
|
||||
"producers": {
|
||||
"usa": {
|
||||
@@ -1771,6 +1804,7 @@
|
||||
},
|
||||
"erdnuss": {
|
||||
"nm": "Erdnüsse",
|
||||
"art": "die",
|
||||
"ic": "🥜",
|
||||
"producers": {
|
||||
"china": {
|
||||
@@ -1846,6 +1880,7 @@
|
||||
},
|
||||
"kichererbsen": {
|
||||
"nm": "Kichererbsen",
|
||||
"art": "die",
|
||||
"ic": "🟤",
|
||||
"producers": {
|
||||
"indien": {
|
||||
@@ -1911,6 +1946,7 @@
|
||||
},
|
||||
"soja": {
|
||||
"nm": "Sojabohnen",
|
||||
"art": "die",
|
||||
"ic": "🫘",
|
||||
"producers": {
|
||||
"brasilien": {
|
||||
@@ -1990,6 +2026,7 @@
|
||||
},
|
||||
"soja-sauce": {
|
||||
"nm": "Sojasauce",
|
||||
"art": "die",
|
||||
"ic": "🥢",
|
||||
"producers": {
|
||||
"china": {
|
||||
@@ -2028,6 +2065,7 @@
|
||||
},
|
||||
"rohrzucker": {
|
||||
"nm": "Rohrzucker",
|
||||
"art": "der",
|
||||
"ic": "🧊",
|
||||
"producers": {
|
||||
"brasilien": {
|
||||
@@ -2100,6 +2138,7 @@
|
||||
},
|
||||
"apfel": {
|
||||
"nm": "Apfel",
|
||||
"art": "der",
|
||||
"ic": "🍎",
|
||||
"producers": {
|
||||
"china": {
|
||||
@@ -2223,6 +2262,7 @@
|
||||
},
|
||||
"marille": {
|
||||
"nm": "Marille (Aprikose)",
|
||||
"art": "die",
|
||||
"ic": "🍑",
|
||||
"producers": {
|
||||
"tuerkei": {
|
||||
@@ -2296,6 +2336,7 @@
|
||||
},
|
||||
"kirschen": {
|
||||
"nm": "Kirschen",
|
||||
"art": "die",
|
||||
"ic": "🍒",
|
||||
"producers": {
|
||||
"tuerkei": {
|
||||
@@ -2374,6 +2415,7 @@
|
||||
},
|
||||
"lebkuchen": {
|
||||
"nm": "Lebkuchen-Gewürz",
|
||||
"art": "das",
|
||||
"ic": "🍪",
|
||||
"producers": {
|
||||
"indonesien": {
|
||||
@@ -2409,6 +2451,7 @@
|
||||
},
|
||||
"rosinen": {
|
||||
"nm": "Rosinen (getr. Trauben)",
|
||||
"art": "die",
|
||||
"ic": "🍇",
|
||||
"producers": {
|
||||
"tuerkei": {
|
||||
@@ -2463,6 +2506,7 @@
|
||||
},
|
||||
"olivenoel": {
|
||||
"nm": "Olivenöl",
|
||||
"art": "das",
|
||||
"ic": "🫒",
|
||||
"producers": {
|
||||
"spanien": {
|
||||
@@ -2522,6 +2566,7 @@
|
||||
},
|
||||
"milch": {
|
||||
"nm": "Milch / Sahne",
|
||||
"art": "die",
|
||||
"ic": "🥛",
|
||||
"producers": {
|
||||
"indien": {
|
||||
@@ -2658,6 +2703,7 @@
|
||||
},
|
||||
"butter": {
|
||||
"nm": "Butter",
|
||||
"art": "die",
|
||||
"ic": "🧈",
|
||||
"producers": {
|
||||
"indien": {
|
||||
@@ -2749,6 +2795,7 @@
|
||||
},
|
||||
"feta": {
|
||||
"nm": "Feta (Käse)",
|
||||
"art": "der",
|
||||
"ic": "🧀",
|
||||
"producers": {
|
||||
"griechenland": {
|
||||
@@ -2781,6 +2828,7 @@
|
||||
},
|
||||
"mozzarella": {
|
||||
"nm": "Mozzarella",
|
||||
"art": "der",
|
||||
"ic": "🧀",
|
||||
"producers": {
|
||||
"italien": {
|
||||
@@ -2827,6 +2875,7 @@
|
||||
},
|
||||
"pecorino": {
|
||||
"nm": "Pecorino (Käse)",
|
||||
"art": "der",
|
||||
"ic": "🧀",
|
||||
"producers": {
|
||||
"italien": {
|
||||
@@ -2857,6 +2906,7 @@
|
||||
},
|
||||
"topfen": {
|
||||
"nm": "Topfen / Quark",
|
||||
"art": "der",
|
||||
"ic": "🥛",
|
||||
"producers": {
|
||||
"deutschland": {
|
||||
@@ -2911,6 +2961,7 @@
|
||||
},
|
||||
"schmand": {
|
||||
"nm": "Schmand / Saure Sahne",
|
||||
"art": "der",
|
||||
"ic": "🥛",
|
||||
"producers": {
|
||||
"deutschland": {
|
||||
@@ -2958,6 +3009,7 @@
|
||||
},
|
||||
"fleisch": {
|
||||
"nm": "Fleisch (Kalb/Schwein/Rind, regional)",
|
||||
"art": "das",
|
||||
"ic": "🥩",
|
||||
"producers": {
|
||||
"oesterreich": {
|
||||
@@ -3032,6 +3084,7 @@
|
||||
},
|
||||
"lamm": {
|
||||
"nm": "Lammfleisch",
|
||||
"art": "das",
|
||||
"ic": "🐑",
|
||||
"producers": {
|
||||
"tuerkei": {
|
||||
@@ -3123,6 +3176,7 @@
|
||||
},
|
||||
"huhn-spanien": {
|
||||
"nm": "Hähnchen / Huhn (Paella)",
|
||||
"art": "das",
|
||||
"ic": "🐔",
|
||||
"producers": {
|
||||
"spanien": {
|
||||
@@ -3166,6 +3220,7 @@
|
||||
},
|
||||
"rind-ungarn": {
|
||||
"nm": "Rind (für Gulasch)",
|
||||
"art": "das",
|
||||
"ic": "🥩",
|
||||
"producers": {
|
||||
"ungarn": {
|
||||
@@ -3215,6 +3270,7 @@
|
||||
},
|
||||
"speck": {
|
||||
"nm": "Speck (Pancetta/Tiroler)",
|
||||
"art": "der",
|
||||
"ic": "🥓",
|
||||
"producers": {
|
||||
"italien": {
|
||||
@@ -3268,6 +3324,7 @@
|
||||
},
|
||||
"speck-lorraine": {
|
||||
"nm": "Lardons (für Quiche)",
|
||||
"art": "die",
|
||||
"ic": "🥓",
|
||||
"producers": {
|
||||
"frankreich": {
|
||||
@@ -3299,6 +3356,7 @@
|
||||
},
|
||||
"eier": {
|
||||
"nm": "Eier",
|
||||
"art": "die",
|
||||
"ic": "🥚",
|
||||
"producers": {
|
||||
"china": {
|
||||
@@ -3397,6 +3455,7 @@
|
||||
},
|
||||
"fischsauce": {
|
||||
"nm": "Fischsauce",
|
||||
"art": "die",
|
||||
"ic": "🐟",
|
||||
"producers": {
|
||||
"vietnam": {
|
||||
@@ -3453,6 +3512,7 @@
|
||||
},
|
||||
"nori": {
|
||||
"nm": "Nori (Seetang)",
|
||||
"art": "der",
|
||||
"ic": "🟢",
|
||||
"producers": {
|
||||
"china": {
|
||||
@@ -3500,6 +3560,7 @@
|
||||
},
|
||||
"wasabi": {
|
||||
"nm": "Wasabi (echt)",
|
||||
"art": "der",
|
||||
"ic": "🟢",
|
||||
"producers": {
|
||||
"japan": {
|
||||
@@ -3541,6 +3602,7 @@
|
||||
},
|
||||
"tomaten": {
|
||||
"nm": "Tomaten",
|
||||
"art": "die",
|
||||
"ic": "🍅",
|
||||
"producers": {
|
||||
"china": {
|
||||
@@ -3632,6 +3694,7 @@
|
||||
},
|
||||
"gemuese": {
|
||||
"nm": "Sommer-Gemüse (Mittelmeer)",
|
||||
"art": "das",
|
||||
"ic": "🥬",
|
||||
"producers": {
|
||||
"spanien": {
|
||||
@@ -3681,6 +3744,7 @@
|
||||
},
|
||||
"wurzelgemuese": {
|
||||
"nm": "Wurzelgemüse (Möhre, Sellerie, Pastinake)",
|
||||
"art": "das",
|
||||
"ic": "🥕",
|
||||
"producers": {
|
||||
"china": {
|
||||
@@ -3749,6 +3813,7 @@
|
||||
},
|
||||
"kartoffel": {
|
||||
"nm": "Kartoffel",
|
||||
"art": "die",
|
||||
"ic": "🥔",
|
||||
"producers": {
|
||||
"china": {
|
||||
@@ -3885,6 +3950,7 @@
|
||||
},
|
||||
"zwiebel": {
|
||||
"nm": "Zwiebel",
|
||||
"art": "die",
|
||||
"ic": "🧅",
|
||||
"producers": {
|
||||
"china": {
|
||||
@@ -3978,6 +4044,7 @@
|
||||
},
|
||||
"knoblauch": {
|
||||
"nm": "Knoblauch",
|
||||
"art": "der",
|
||||
"ic": "🧄",
|
||||
"producers": {
|
||||
"china": {
|
||||
@@ -4056,6 +4123,7 @@
|
||||
},
|
||||
"champignons": {
|
||||
"nm": "Champignons",
|
||||
"art": "die",
|
||||
"ic": "🍄",
|
||||
"producers": {
|
||||
"china": {
|
||||
@@ -4140,6 +4208,7 @@
|
||||
},
|
||||
"hefe": {
|
||||
"nm": "Hefe",
|
||||
"art": "die",
|
||||
"ic": "🫧",
|
||||
"producers": {
|
||||
"frankreich": {
|
||||
@@ -4190,6 +4259,7 @@
|
||||
},
|
||||
"essig": {
|
||||
"nm": "Essig (Wein- / Apfelessig)",
|
||||
"art": "der",
|
||||
"ic": "🧪",
|
||||
"producers": {
|
||||
"italien": {
|
||||
@@ -4241,4 +4311,4 @@
|
||||
],
|
||||
"fact": "Aceto Balsamico Tradizionale di Modena reift mindestens 12 Jahre in Holzfässern — eine kleine Flasche kann über 100 € kosten."
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@@ -521,7 +521,7 @@ async function loadWeltkuecheData() {
|
||||
// ING-Map aus production-matrix bauen
|
||||
Object.entries(prodMatrix).forEach(([k, v]) => {
|
||||
ING[k] = {
|
||||
nm: v.nm, ic: v.ic,
|
||||
nm: v.nm, ic: v.ic, art: v.art || 'die',
|
||||
producers: v.producers || {},
|
||||
climate_possible: v.climate_possible || [],
|
||||
fact: v.fact || '',
|
||||
@@ -1021,6 +1021,16 @@ function impossibleCountries(corr, possible) {
|
||||
return out;
|
||||
}
|
||||
|
||||
// Zutat mit korrektem Artikel: „die Kartoffel", „der Pfeffer", „das Olivenöl".
|
||||
// Plural-Zutaten tragen art='die' — die Sätze nutzen bewusst „man"-Konstruktionen
|
||||
// (nimmt man / holt man …), damit Singular UND Plural grammatisch passen.
|
||||
function ingWas(ing, sTask, ingKey) {
|
||||
const label = sTask && sTask.label;
|
||||
if (label) return label;
|
||||
const a = (ing && ing.art) || 'die';
|
||||
return a + ' ' + (ing ? ing.nm : '');
|
||||
}
|
||||
|
||||
function buildTaskFor(ingKey) {
|
||||
if (_taskCache[ingKey]) return _taskCache[ingKey];
|
||||
const ing = ING[ingKey];
|
||||
@@ -1358,12 +1368,17 @@ function explainChoice(ingKey, key, isCorrect){
|
||||
const sTask = _taskCache[ingKey];
|
||||
if (sTask && sTask.signature) {
|
||||
const heimatN = C[sTask.heimat] ? C[sTask.heimat].n : '';
|
||||
const was = sTask.label || ('der/die/das ' + ing.nm);
|
||||
const was = ingWas(ing, sTask, ingKey);
|
||||
if (isCorrect) {
|
||||
return {cls:'ok', badge:'✓', text:`Dieses Gericht kommt aus <b>${heimatN}</b> – ${was} ist hier heimisch und wird vor Ort erzeugt.`};
|
||||
if (key === sTask.heimat)
|
||||
return {cls:'ok', badge:'✓', text:`Richtig – für ein Gericht aus <b>${heimatN}</b> nimmt man ${was} aus ${heimatN} selbst.`};
|
||||
return {cls:'ok', badge:'✓', text:`Auch richtig – ${heimatN} allein deckt den Bedarf nicht, darum ist ${C[key].n} als Nachbarland ein realistischer Zweit-Lieferant.`};
|
||||
}
|
||||
if (info) {
|
||||
return {cls:'mid', badge:'⚠️', text:`${C[key].n} erzeugt zwar viel ${ing.nm}${amount?' ('+amount+')':''} – aber in einem Gericht aus ${heimatN} stammt ${was} von dort.`};
|
||||
const m = info.market || 'global';
|
||||
if (m === 'world-far' || m === 'local')
|
||||
return {cls:'mid', badge:'🌐', text:`${C[key].n} erzeugt zwar riesige Mengen ${ing.nm}${amount?' ('+amount+')':''} – in unseren Handel kommt davon aber kaum etwas. Für ein Gericht aus ${heimatN} nimmt man ${was} aus ${heimatN} oder einem Nachbarland.`};
|
||||
return {cls:'mid', badge:'⚠️', text:`${C[key].n} ist auch ein echter Erzeuger${amount?' ('+amount+')':''} – aber für ein Gericht aus ${heimatN} nimmt man ${was} lieber aus ${heimatN} selbst oder dem nächsten Nachbarland.`};
|
||||
}
|
||||
// Nicht-Produzent-Fehlklick → normale „unmöglich"-Logik unten
|
||||
}
|
||||
@@ -1471,7 +1486,7 @@ function showSolved(ing,pts,bonus){
|
||||
const factLine = ing.fact ? `<div class="more-line"><b>Wusstest du?</b> ${esc(ing.fact)}</div>` : '';
|
||||
// Heimat-Regel: erklären, warum die Region die Antwort ist (nicht der größte Produzent)
|
||||
const sigLine = (task.signature && C[task.heimat])
|
||||
? `<div class="more-line" style="background:#eef5ec;border-left:3px solid #4a7c4e">🍽️ Das ist ein Gericht aus <b>${C[task.heimat].n}</b>. ${task.label ? ('<b>'+task.label+'</b>') : ('Der/die/das '+esc(ing.nm))} kommt von hier – nur Zutaten, die bei uns gar nicht wachsen, reisen von weit her.</div>`
|
||||
? `<div class="more-line" style="background:#eef5ec;border-left:3px solid #4a7c4e">🍽️ Das ist ein Gericht aus <b>${C[task.heimat].n}</b>. Zutaten werden zwar bevorzugt aus ${C[task.heimat].n} verwendet, aber ${C[task.heimat].n} allein deckt den Bedarf nicht ab – darum zählt auch ein Nachbarland als richtig. Nur Zutaten, die bei uns gar nicht wachsen, reisen von weit her.</div>`
|
||||
: '';
|
||||
// Caveats für world-far/off-season Korrekt-Picks (pro Land separat)
|
||||
const caveats = task.correct.map(k => {
|
||||
@@ -1521,8 +1536,12 @@ function showWrong(key, kind, ingKey){
|
||||
const info = ing.producers[key];
|
||||
const amount = info && info.t ? fmtTonnes(info.t) : 'verbreitet';
|
||||
const heimatN = C[sTask.heimat] ? C[sTask.heimat].n : '';
|
||||
const was = sTask.label || ('der/die/das ' + ing.nm);
|
||||
card.innerHTML = `<div class="rc-head">⚠️ ${c.f} ${c.n} erzeugt zwar viel ${ing.nm} (${amount}) – aber dieses Gericht kommt aus ${heimatN}, und ${was} stammt von dort.</div>`+
|
||||
const was = ingWas(ing, sTask, ingKey);
|
||||
const m = info.market || 'global';
|
||||
const head = (m === 'world-far' || m === 'local')
|
||||
? `⚠️ ${c.f} ${c.n} erzeugt zwar riesige Mengen ${ing.nm} (${amount}) – aber davon kommt bei uns fast nichts in den Handel. Für dieses Gericht aus ${heimatN} nimmt man ${was} aus ${heimatN} oder einem Nachbarland.`
|
||||
: `⚠️ ${c.f} ${c.n} ist auch ein echter Erzeuger (${amount}) – aber für dieses Gericht aus ${heimatN} nimmt man ${was} lieber aus ${heimatN} selbst oder dem nächsten Nachbarland.`;
|
||||
card.innerHTML = `<div class="rc-head">${head}</div>`+
|
||||
`<div class="note">${c.info}<br><br>🔎 Tipp: Achte auf den Namen des Gerichts – er verrät oft die Herkunft.</div>`;
|
||||
return;
|
||||
}
|
||||
|
||||
+82
-14
@@ -211,10 +211,9 @@
|
||||
<!-- Tabs -->
|
||||
<div class="tabs" id="tab-bar">
|
||||
<div class="tab on" onclick="switchTab('overview')">Übersicht</div>
|
||||
<div class="tab" id="tab-btn-live" onclick="switchTab('live')"><span class="live-dot"></span> Live<span class="live-count" id="live-count"></span></div>
|
||||
<div class="tab" id="tab-btn-live" onclick="switchTab('live')"><span class="live-dot"></span> Ergebnisse<span class="live-count" id="live-count"></span></div>
|
||||
<div class="tab" onclick="switchTab('modules')">Modulfreigabe</div>
|
||||
<div class="tab" onclick="switchTab('students')">Klasse</div>
|
||||
<div class="tab" onclick="switchTab('results')">Ergebnisse</div>
|
||||
<div class="tab" onclick="switchTab('licenses')">Lizenzen</div>
|
||||
<div class="tab" onclick="switchTab('classes')">Klassen</div>
|
||||
<a class="tab" href="buch" style="margin-left:auto;text-decoration:none">📖 Schulbuch</a>
|
||||
@@ -480,7 +479,7 @@ api('auth', {action:'status'}).then(function(r) {
|
||||
// === TABS ===
|
||||
function switchTab(tab) {
|
||||
currentTab = tab;
|
||||
var tabs = ['overview','live','modules','students','results','licenses','classes'];
|
||||
var tabs = ['overview','live','modules','students','licenses','classes'];
|
||||
document.querySelectorAll('#tab-bar .tab').forEach(function(t, i) { t.classList.toggle('on', tabs[i] === tab); });
|
||||
tabs.forEach(function(t) { document.getElementById('tab-' + t).classList.toggle('hidden', t !== tab); });
|
||||
// Live-Tab darf seinen Polling-Timer beim Verlassen aufräumen
|
||||
@@ -523,14 +522,27 @@ async function loadLive() {
|
||||
if (_liveTimer) clearInterval(_liveTimer);
|
||||
// Auto-Refresh: aktuell alle 4s, übersicht/vergleich nur wenn heute
|
||||
var refreshMs = (_liveMode === 'aktuell') ? 4000
|
||||
: (_liveMode === 'gesamt') ? 0
|
||||
: (_liveDate === new Date().toISOString().slice(0,10)) ? 60000 : 0;
|
||||
if (refreshMs) _liveTimer = setInterval(_renderLiveTab, refreshMs);
|
||||
}
|
||||
async function _renderLiveTab() {
|
||||
if (_liveMode === 'uebersicht') return renderLiveSummary();
|
||||
if (_liveMode === 'vergleich') return renderLiveCompare();
|
||||
if (_liveMode === 'gesamt') return renderLiveGesamt();
|
||||
return renderLive(); // 'aktuell'
|
||||
}
|
||||
// „Gesamt" = die klassische Ergebnis-/Auswertungsansicht (früher eigener Tab),
|
||||
// jetzt als 4. Unteransicht in „Ergebnisse". Rendert die results.php-Auswertung
|
||||
// in einen eingebetteten Container innerhalb von #tab-live.
|
||||
async function renderLiveGesamt() {
|
||||
var host = document.getElementById('tab-live');
|
||||
if (!host) return;
|
||||
host.innerHTML = _liveToggleHtml()
|
||||
+ '<div id="results-embed"><p style="font-size:.78rem;color:#8a8a8a;padding:1rem">Lade Gesamt-Auswertung…</p></div>';
|
||||
_resultsHost = 'results-embed';
|
||||
await loadResults();
|
||||
}
|
||||
window.setCompareSim = function(simId){ _liveCompareSim = simId; loadLive(); };
|
||||
function setLiveMode(mode) {
|
||||
console.log('[live] setLiveMode('+mode+')');
|
||||
@@ -563,6 +575,7 @@ function _liveToggleHtml() {
|
||||
+ ' <button class="btn-sm" onclick="setLiveMode(\'uebersicht\')" style="padding:.35rem .8rem;border:0;background:'+(_liveMode==='uebersicht'?'#4a7c8a':'transparent')+';color:'+(_liveMode==='uebersicht'?'#fff':'#3d5165')+';font-weight:700;font-size:.74rem">📅 Tag</button>'
|
||||
+ ' <button class="btn-sm" onclick="setLiveMode(\'aktuell\')" style="padding:.35rem .8rem;border:0;background:'+(_liveMode==='aktuell'?'#4a7c8a':'transparent')+';color:'+(_liveMode==='aktuell'?'#fff':'#3d5165')+';font-weight:700;font-size:.74rem">🔴 Aktuell</button>'
|
||||
+ ' <button class="btn-sm" onclick="setLiveMode(\'vergleich\')" style="padding:.35rem .8rem;border:0;background:'+(_liveMode==='vergleich'?'#4a7c8a':'transparent')+';color:'+(_liveMode==='vergleich'?'#fff':'#3d5165')+';font-weight:700;font-size:.74rem">📊 Vergleich</button>'
|
||||
+ ' <button class="btn-sm" onclick="setLiveMode(\'gesamt\')" style="padding:.35rem .8rem;border:0;border-left:1.5px solid rgba(0,0,0,.08);background:'+(_liveMode==='gesamt'?'#4a7c8a':'transparent')+';color:'+(_liveMode==='gesamt'?'#fff':'#3d5165')+';font-weight:700;font-size:.74rem">📚 Gesamt</button>'
|
||||
+ '</div>'
|
||||
+ (_liveMode==='uebersicht' ?
|
||||
'<div style="display:inline-flex;gap:.3rem;align-items:center;margin-left:.6rem">'
|
||||
@@ -749,21 +762,26 @@ var LIVE_PRIMARY_FIELDS = {
|
||||
{k:'dishName', label:'Gericht', align:'left', fmt:function(v){
|
||||
return v ? '<b>'+esc(v)+'</b>' : '<span style="color:#8a8a8a">Auswahl</span>';
|
||||
}},
|
||||
{k:'dishOrigin', label:'Herkunft', align:'left', fmt:function(v){
|
||||
return v ? esc(v) : '<span style="color:#8a8a8a">—</span>';
|
||||
// Fleiß in dieser Sitzung: fertige Gerichte / gesamt
|
||||
{k:'completed', label:'Gerichte', align:'center', fmt:function(v, row){
|
||||
var s = row.state||{}; var t = s.completedTotal||0;
|
||||
if (!t) return '<span style="color:#8a8a8a">—</span>';
|
||||
var done = v||0; var c = done>=t ? '#5a8a5e' : '#3d5165';
|
||||
return '<b style="color:'+c+'">'+done+'</b><span style="color:#8a8a8a"> / '+t+'</span>';
|
||||
}},
|
||||
{k:'ingSolved', label:'Zutaten', fmt:function(v, row){
|
||||
{k:'ingSolved', label:'Zutaten akt.', fmt:function(v, row){
|
||||
var s = row.state||{}; var t = s.ingTotal||0;
|
||||
if (!s.dishName || !t) return '<span style="color:#8a8a8a">—</span>';
|
||||
var done = v||0; var pct = done/t; var c = pct>=1 ? '#5a8a5e' : pct>=.5 ? '#c9913a' : '#8a7a4a';
|
||||
return '<span style="color:'+c+';font-weight:700">'+done+' <span style="color:#8a8a8a;font-weight:400">/ '+t+'</span></span>';
|
||||
}},
|
||||
{k:'mistakesInDish', label:'Fehlklicks', align:'center', fmt:function(v){
|
||||
// Qualität = grafisches Verhältnis richtige ↔ falsche Klicks (blödeln vs. gut)
|
||||
{k:'__quality', label:'Qualität', align:'left', fmt:function(v, row){ return _liveQualityFromState(row.module_id, row.state); }},
|
||||
{k:'mistakesInDish', label:'Fehler (akt.)', align:'center', fmt:function(v){
|
||||
var n = v||0; var c = n>=12 ? '#c07a6b' : n>=5 ? '#c9913a' : '#5a8a5e';
|
||||
return '<span style="color:'+c+';font-weight:700">'+n+'</span>';
|
||||
}},
|
||||
{k:'__prog', label:'Fortschritt', align:'left', fmt:function(v, row){ return _liveProgressBar(row.module_id, row.state); }},
|
||||
{k:'__lage', label:'Lage', align:'center', fmt:function(v, row){ return _liveMoodBadge(row.module_id, row.state); }},
|
||||
{k:'__lage', label:'Lage', align:'center', fmt:function(v, row){ return _liveMoodBadge(row.module_id, row.state); }},
|
||||
],
|
||||
'busfahrt': [
|
||||
{k:'levelId', label:'Stufe', align:'center'},
|
||||
@@ -1230,13 +1248,53 @@ function _liveProgressBar(simId, s) {
|
||||
function _liveMoodBadge(simId, s) {
|
||||
var m = _liveMood(simId, s);
|
||||
if (!m) return '<span style="color:#8a8a8a">—</span>';
|
||||
var map = { good:['#5a8a5e','Gut'], mid:['#c9913a','OK'], bad:['#c07a6b','Kritisch'] };
|
||||
// Klartext statt Jargon („Kritisch"): stark / solide / viele Fehler.
|
||||
var map = { good:['#5a8a5e','Stark'], mid:['#c9913a','Solide'], bad:['#c07a6b','Viele Fehler'] };
|
||||
var x = map[m] || map.mid;
|
||||
return '<span style="display:inline-flex;align-items:center;gap:.3rem">'
|
||||
+ '<span style="width:8px;height:8px;border-radius:50%;background:'+x[0]+';display:inline-block"></span>'
|
||||
+ '<span style="font-size:.66rem;color:'+x[0]+';font-weight:700">'+x[1]+'</span></span>';
|
||||
}
|
||||
|
||||
// KENNZAHL QUALITÄT — grafisches Verhältnis richtige ↔ falsche Klicks.
|
||||
// Zweifarbiger Balken (grün = richtig-Anteil, rot = Fehler-Anteil) + %-Wert.
|
||||
// Funktioniert live (GGS_LIVE_STATE.correctClicks/wrongClicks) UND aus
|
||||
// gespeicherten assessment.data-Feldern (gleiche Keys).
|
||||
function _liveClicks(simId, s) {
|
||||
if (!s) return null;
|
||||
if (typeof s.correctClicks === 'number' || typeof s.wrongClicks === 'number')
|
||||
return { correct: s.correctClicks || 0, wrong: s.wrongClicks || 0 };
|
||||
// Fallbacks für Sims, die (noch) keine correct/wrongClicks liefern:
|
||||
switch (simId) {
|
||||
case 'heli':
|
||||
if (s.planTotal) return { correct: s.planCorrect || 0, wrong: Math.max(0, s.planTotal - (s.planCorrect || 0)) };
|
||||
break;
|
||||
}
|
||||
return null;
|
||||
}
|
||||
function _liveQualityBar(correct, wrong) {
|
||||
correct = Math.max(0, correct || 0);
|
||||
wrong = Math.max(0, wrong || 0);
|
||||
var tot = correct + wrong;
|
||||
if (!tot) return '<span style="color:#8a8a8a">—</span>';
|
||||
var gp = Math.round(correct / tot * 100);
|
||||
var rp = 100 - gp;
|
||||
var c = gp >= 80 ? '#5a8a5e' : gp >= 55 ? '#c9913a' : '#c07a6b';
|
||||
return '<span title="'+correct+' richtig · '+wrong+' Fehler ('+gp+' % richtig)" '
|
||||
+ 'style="display:inline-flex;align-items:center;gap:.35rem;font-variant-numeric:tabular-nums">'
|
||||
+ '<span aria-hidden="true" style="display:inline-flex;width:56px;height:9px;border-radius:99px;overflow:hidden;background:#ece8dc">'
|
||||
+ '<span style="width:'+gp+'%;background:#5a8a5e"></span>'
|
||||
+ '<span style="width:'+rp+'%;background:#d98b7a"></span>'
|
||||
+ '</span>'
|
||||
+ '<span style="font-size:.72rem;font-weight:700;color:'+c+';min-width:2.3em;text-align:right">'+gp+' %</span>'
|
||||
+ '</span>';
|
||||
}
|
||||
// Bequemer Wrapper aus einem Live-State (für Vergleich/Aktuell-Tabellen).
|
||||
function _liveQualityFromState(simId, s) {
|
||||
var cw = _liveClicks(simId, s);
|
||||
return cw ? _liveQualityBar(cw.correct, cw.wrong) : '<span style="color:#8a8a8a">—</span>';
|
||||
}
|
||||
|
||||
var _liveReflCache = '', _liveReflAt = 0;
|
||||
// Aktiv = Lebenszeichen in den letzten 90 s. Ältere Sessions bleiben sichtbar,
|
||||
// aber als „pausiert" (Lernende:r macht Pause, kann später weitermachen).
|
||||
@@ -1735,6 +1793,11 @@ function _renderGenericCompareBody(rows, simId) {
|
||||
return 0;
|
||||
}
|
||||
function qualityScore(s) {
|
||||
// Sims mit echten richtig/falsch-Klicks (z. B. Weltküche): Anteil richtig
|
||||
if (typeof s.correctClicks === 'number' || typeof s.wrongClicks === 'number') {
|
||||
var t = (s.correctClicks||0) + (s.wrongClicks||0);
|
||||
return t ? (s.correctClicks||0) / t * 100 : null;
|
||||
}
|
||||
// Heli: planCorrect / planTotal
|
||||
if (typeof s.planCorrect === 'number' && s.planTotal) return Math.min(100, s.planCorrect / s.planTotal * 100);
|
||||
// Busfahrt: quizFirstTry / orderIndex
|
||||
@@ -1750,6 +1813,8 @@ function _renderGenericCompareBody(rows, simId) {
|
||||
displayName: _liveCleanName(ls.displayName, idx+1),
|
||||
phase: s.phase || '',
|
||||
progress: p, quality: q,
|
||||
// grafischer richtig/falsch-Balken, wenn Klick-Daten vorhanden
|
||||
qualityHtml: _liveClicks(ls.module_id, s) ? _liveQualityFromState(ls.module_id, s) : null,
|
||||
stars: (typeof s.totalStars === 'number') ? s.totalStars : null,
|
||||
};
|
||||
});
|
||||
@@ -1764,7 +1829,7 @@ function _renderGenericCompareBody(rows, simId) {
|
||||
+ '<th style="text-align:left;padding:.45rem .5rem;font-size:.7rem;text-transform:uppercase;color:#6a6a6a;border-bottom:2px solid rgba(0,0,0,.08)">Name</th>'
|
||||
+ '<th style="text-align:left;padding:.45rem .5rem;font-size:.7rem;text-transform:uppercase;color:#6a6a6a;border-bottom:2px solid rgba(0,0,0,.08);min-width:180px">📈 Fortschritt</th>'
|
||||
+ '<th style="text-align:left;padding:.45rem .5rem;font-size:.7rem;text-transform:uppercase;color:#6a6a6a;border-bottom:2px solid rgba(0,0,0,.08);min-width:180px">🎯 Qualität</th>'
|
||||
+ '<th style="text-align:right;padding:.45rem .5rem;font-size:.7rem;text-transform:uppercase;color:#6a6a6a;border-bottom:2px solid rgba(0,0,0,.08)">Phase</th>'
|
||||
+ '<th style="text-align:right;padding:.45rem .5rem;font-size:.7rem;text-transform:uppercase;color:#6a6a6a;border-bottom:2px solid rgba(0,0,0,.08)">Gerade dabei</th>'
|
||||
+ '</tr></thead><tbody>';
|
||||
data.forEach(function(r, i){
|
||||
var bg = (Math.floor(i/5) % 2 === 1) ? 'background:rgba(0,0,0,.02)' : '';
|
||||
@@ -1775,7 +1840,7 @@ function _renderGenericCompareBody(rows, simId) {
|
||||
+ 'onclick="openLiveSpectator('+r.ls.student_id+',\''+r.ls.module_id+'\')">';
|
||||
html += '<td style="padding:.4rem .5rem;white-space:nowrap"><span style="display:inline-flex;align-items:center;gap:.4rem">'+avatarHtml+'<strong>'+esc(r.displayName)+'</strong></span></td>';
|
||||
html += '<td style="padding:.4rem .5rem">'+_klimaBar(r.progress, Math.round(r.progress)+'%')+'</td>';
|
||||
html += '<td style="padding:.4rem .5rem">'+(r.quality!=null ? _klimaBar(r.quality, Math.round(r.quality)+'%') : '<span style="color:#aaa">—</span>')+'</td>';
|
||||
html += '<td style="padding:.4rem .5rem">'+(r.qualityHtml ? r.qualityHtml : (r.quality!=null ? _klimaBar(r.quality, Math.round(r.quality)+'%') : '<span style="color:#aaa">—</span>'))+'</td>';
|
||||
html += '<td style="text-align:right;padding:.4rem .5rem;color:#6a6a6a;font-size:.72rem">'+esc(r.phase||'—')+'</td>';
|
||||
html += '</tr>';
|
||||
});
|
||||
@@ -3487,6 +3552,9 @@ async function toggleEasyLanguage(studentId, enabled) {
|
||||
// Performance: zwei parallele API-Calls pro Tab-Wechsel, clientseitige Sortierung,
|
||||
// Modul-Detail lazy bei Klick.
|
||||
|
||||
// Ziel-Container der Gesamt-Auswertung. Default #tab-results (Legacy), im
|
||||
// neuen Menü rendert die „Gesamt"-Unteransicht in #results-embed (in #tab-live).
|
||||
var _resultsHost = 'tab-results';
|
||||
var _resultsState = {
|
||||
matrix: null, // {students, modules, cells, totals}
|
||||
activity: null, // {range, buckets, series}
|
||||
@@ -3500,7 +3568,7 @@ var _resultsState = {
|
||||
};
|
||||
|
||||
async function loadResults() {
|
||||
var host = document.getElementById('tab-results');
|
||||
var host = document.getElementById(_resultsHost) || document.getElementById('tab-results');
|
||||
host.innerHTML = '<p style="font-size:.78rem;color:#8a8a8a;padding:1rem">Lade Ergebnisse…</p>';
|
||||
|
||||
// Drei parallele API-Calls: Fleiß (NEU oben) + Matrix + Activity (alt)
|
||||
@@ -3521,7 +3589,7 @@ async function loadResults() {
|
||||
}
|
||||
|
||||
function renderResults() {
|
||||
var host = document.getElementById('tab-results');
|
||||
var host = document.getElementById(_resultsHost) || document.getElementById('tab-results');
|
||||
host.innerHTML = ''
|
||||
+ '<div id="res-fleiss"></div>'
|
||||
+ '<div id="res-matrix"></div>'
|
||||
|
||||
Reference in New Issue
Block a user