fecd8bb9c9
562 Ersetzungen in 50 Dateien: Halbgeviertstrich zwischen zwei Ziffern (= "bis"-Bereich) bekommt Leerzeichen davor/danach (3–4 -> 3 – 4). Regex /([0-9])\s*–\s*(?=[0-9])/ auf Rohtext (format-erhaltend, CRLF/Einrueckung unveraendert), Bindestriche in Woertern und Minuszeichen unangetastet, alle JSON weiter gueltig. Energiemanager-Zeitbloecke sind Display-Labels (kein Logik-Key) -> safe. Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
273 lines
18 KiB
HTML
273 lines
18 KiB
HTML
<!DOCTYPE html>
|
||
<html lang="de">
|
||
<head>
|
||
<meta charset="UTF-8">
|
||
<meta name="viewport" content="width=device-width, initial-scale=1.0">
|
||
<title>GeoGraSim — Test-Checkliste (19.08.2026)</title>
|
||
<style>
|
||
:root{
|
||
--bg:#f4f2ec; --card:#fff; --ink:#242018; --muted:#7a7266; --line:rgba(0,0,0,.08);
|
||
--accent:#4a7c8a; --accent-d:#356070; --ok:#4a8a5a; --warn:#c58a2a; --sim:#7a5ca8;
|
||
}
|
||
*{margin:0;padding:0;box-sizing:border-box}
|
||
body{font-family:'Inter',system-ui,-apple-system,sans-serif;background:var(--bg);color:var(--ink);line-height:1.5;padding-bottom:4rem}
|
||
header{position:sticky;top:0;z-index:10;background:#fff;border-bottom:1px solid var(--line);
|
||
padding:.9rem 1.2rem;display:flex;align-items:center;gap:1rem;flex-wrap:wrap;box-shadow:0 1px 6px rgba(0,0,0,.04)}
|
||
header h1{font-size:1.15rem;font-weight:900;color:var(--accent-d);letter-spacing:-.02em}
|
||
header .sub{font-size:.72rem;color:var(--muted)}
|
||
.progress{margin-left:auto;display:flex;align-items:center;gap:.6rem;font-size:.8rem;font-weight:700;color:var(--accent-d)}
|
||
.bar{width:160px;height:9px;border-radius:99px;background:#e4e0d6;overflow:hidden}
|
||
.bar > div{height:100%;background:var(--ok);width:0;transition:width .3s}
|
||
.reset{font-size:.66rem;color:var(--muted);border:1px solid var(--line);background:#fff;border-radius:6px;padding:.25rem .5rem;cursor:pointer}
|
||
.wrap{max-width:920px;margin:1.4rem auto;padding:0 1.1rem}
|
||
.intro{font-size:.86rem;color:var(--muted);margin-bottom:1.4rem;background:#fff;border:1px solid var(--line);border-radius:10px;padding:.8rem 1rem}
|
||
.intro code{background:#eee9df;padding:.05rem .35rem;border-radius:4px;font-size:.85em}
|
||
section{margin-bottom:1.8rem}
|
||
.sec-h{font-size:.7rem;font-weight:800;text-transform:uppercase;letter-spacing:.1em;color:var(--accent);
|
||
margin:0 0 .6rem .2rem;display:flex;align-items:center;gap:.5rem}
|
||
.sec-h .cnt{font-size:.62rem;color:var(--muted);font-weight:600;letter-spacing:.02em}
|
||
.item{background:var(--card);border:1px solid var(--line);border-radius:12px;padding:.85rem 1rem;margin-bottom:.7rem;
|
||
box-shadow:0 1px 3px rgba(0,0,0,.03);transition:opacity .2s}
|
||
.item.done{opacity:.55}
|
||
.item-top{display:flex;gap:.7rem;align-items:flex-start}
|
||
.item-top input[type=checkbox]{width:22px;height:22px;margin-top:.1rem;accent-color:var(--ok);cursor:pointer;flex-shrink:0}
|
||
.item-title{font-weight:800;font-size:.98rem}
|
||
.item.done .item-title{text-decoration:line-through;text-decoration-color:rgba(0,0,0,.3)}
|
||
.tag{display:inline-block;font-size:.58rem;font-weight:800;text-transform:uppercase;letter-spacing:.05em;
|
||
padding:.12rem .5rem;border-radius:99px;vertical-align:middle;margin-left:.5rem}
|
||
.tag.live{background:#dceadd;color:#2f6b3a}
|
||
.tag.pending{background:#fdeecd;color:#8a6510}
|
||
.body{padding-left:calc(22px + .7rem);margin-top:.4rem;font-size:.86rem;color:#4a463d}
|
||
.body .row{margin:.28rem 0}
|
||
.body b{color:var(--ink)}
|
||
.k{display:inline-block;min-width:74px;font-weight:700;color:var(--muted);font-size:.72rem;text-transform:uppercase;letter-spacing:.03em}
|
||
a.url{color:var(--accent-d);font-family:ui-monospace,monospace;font-size:.82em;text-decoration:none;border-bottom:1px dotted var(--accent)}
|
||
a.url:hover{background:#eaf2f4}
|
||
.exp{background:#f0f6f1;border-left:3px solid var(--ok);border-radius:0 6px 6px 0;padding:.35rem .6rem;margin-top:.35rem;font-size:.82rem;color:#33613f}
|
||
.note{width:100%;margin-top:.5rem;border:1px solid var(--line);border-radius:7px;padding:.4rem .55rem;font-family:inherit;
|
||
font-size:.82rem;resize:vertical;min-height:0;height:2rem;background:#fcfbf8;color:var(--ink)}
|
||
.note::placeholder{color:#b3ac9e}
|
||
footer{text-align:center;color:var(--muted);font-size:.72rem;margin:2rem 0}
|
||
</style>
|
||
</head>
|
||
<body>
|
||
<header>
|
||
<div>
|
||
<h1>🧪 GeoGraSim — Test-Checkliste</h1>
|
||
<div class="sub">Alle Erledigungen seit den Weltküche-Lebensmitteln · Stand 19.08.2026 · lokal testen</div>
|
||
</div>
|
||
<div class="progress">
|
||
<span id="pcount">0 / 0</span>
|
||
<div class="bar"><div id="pbar"></div></div>
|
||
<button class="reset" onclick="if(confirm('Alle Haken + Notizen zurücksetzen?')){localStorage.clear();location.reload();}">reset</button>
|
||
</div>
|
||
</header>
|
||
|
||
<div class="wrap">
|
||
<div class="intro">
|
||
Basis-URL lokal: <code>http://localhost/geograsim/App/</code> · <b>Haken & Notizen</b> werden im Browser gespeichert.
|
||
<span class="tag live">live</span> = auf Prod, <span class="tag pending">bereit</span> = committed, kommt mit dem nächsten Deploy.
|
||
Für Admin-Seiten zuerst über <a class="url" href="http://localhost/geograsim/App/admin.html" target="_blank">admin.html</a> anmelden (Username <b>Thomas</b> → PIN ist lokal vorausgefüllt).
|
||
</div>
|
||
|
||
<!-- ================= WELTKÜCHE (SIM) ================= -->
|
||
<section data-sec="Weltküche – Simulation"></section>
|
||
|
||
<!-- ================= WELTKÜCHE (LEHRPLAN/ADMIN) ================= -->
|
||
<section data-sec="Weltküche – Lehrplan & Admin"></section>
|
||
|
||
<!-- ================= LEHRER-COCKPIT ================= -->
|
||
<section data-sec="Lehrer-Cockpit (teacher.html)"></section>
|
||
|
||
<!-- ================= TOURISMUSREGION ================= -->
|
||
<section data-sec="Tourismusregion"></section>
|
||
|
||
<!-- ================= LOGISTIK & PLATTFORM ================= -->
|
||
<section data-sec="Logistik & Plattform"></section>
|
||
|
||
<!-- ================= ADMIN & AUTH ================= -->
|
||
<section data-sec="Admin & Auth-Fundament"></section>
|
||
</div>
|
||
|
||
<footer>GeoGraSim · Test-Checkliste · lokal generiert 19.08.2026</footer>
|
||
|
||
<script>
|
||
// Alle Test-Items als Daten — daraus wird die Liste gebaut.
|
||
const BASE = 'http://localhost/geograsim/App/';
|
||
function u(path){ return BASE + path; }
|
||
const ITEMS = {
|
||
'Weltküche – Simulation': [
|
||
{ id:'wk-artikel', t:'Korrekte Artikel für alle 70 Zutaten', tag:'live',
|
||
w:'der/die/das je Zutat („die Kartoffel", „der Pfeffer", „das Olivenöl") statt Platzhalter.',
|
||
url:'sims/weltkueche/game.html', steps:'Ein Gericht spielen, Zutat lösen/falsch klicken – im Feedback-Satz steht der richtige Artikel.',
|
||
exp:'Nie mehr „der/die/das Kartoffel" – immer „die Kartoffel" usw.' },
|
||
{ id:'wk-ukraine', t:'Verdrehter Herkunfts-Satz korrigiert (Ukraine-Fall)', tag:'live',
|
||
w:'Bei fernem Großproduzenten (z. B. Ukraine-Kartoffel im AT-Gericht) sachlich korrektes Feedback.',
|
||
url:'sims/weltkueche/game.html', steps:'Tiroler Gröstl → Kartoffel → ein fernes Land wie Ukraine anklicken.',
|
||
exp:'„…in unseren Handel kommt davon kaum etwas… nimmt man die Kartoffel aus Österreich oder einem Nachbarland." (nicht mehr „…stammt die Kartoffel von dort").' },
|
||
{ id:'wk-heimat', t:'Heimat-Banner neu formuliert', tag:'live',
|
||
w:'Erklärt „bevorzugt aus AT, aber AT deckt den Bedarf nicht allein".',
|
||
url:'sims/weltkueche/game.html', steps:'AT-Gericht, eine Heimat-Zutat lösen → grünes Banner lesen.',
|
||
exp:'„Zutaten werden zwar bevorzugt aus Österreich verwendet, aber Österreich allein deckt den Bedarf nicht ab – darum zählt auch ein Nachbarland."' },
|
||
{ id:'wk-gravitation', t:'Herkunft per Handels-Gravitation (Nähe × Menge)', tag:'pending',
|
||
w:'Zweit-Lieferant = nächster großer Nachbar, nicht ferner Großproduzent.',
|
||
url:'sims/weltkueche/game.html', steps:'Ein AT-Gericht mit Eiern/Kartoffel spielen – richtige Länder prüfen.',
|
||
exp:'AT-Eier → Österreich + Deutschland (NICHT Frankreich), obwohl FR mehr Eier erzeugt.' },
|
||
{ id:'wk-punkte', t:'Punktefix: „alle Falschen zuerst = 0"', tag:'pending',
|
||
w:'Strafe pro Fehlklick = 100 ÷ Anzahl Distraktoren.',
|
||
url:'sims/weltkueche/game.html', steps:'Bei einer Zutat ALLE falschen Länder zuerst anklicken, dann die richtigen.',
|
||
exp:'Ergebnis 0 Punkte. Banner zeigt die tatsächliche Strafe pro Fehlklick.' },
|
||
{ id:'wk-phase', t:'Live-State zeigt echten Fortschritt statt „forschen"', tag:'live',
|
||
w:'GGS_LIVE_STATE-Phase = „Gericht X · Zutat Y/Z".',
|
||
url:'teacher.html', steps:'Als Lehrer im Cockpit „Aktuell" ein Weltküche-Kind ansehen (oder Live-State im Sim prüfen).',
|
||
exp:'Phase/Info zeigt „Gericht 2 · Zutat 3/5" – nicht dauerhaft „forschen".' },
|
||
{ id:'wk-submit', t:'Backend-Submit + Persistenz geschaffter Gerichte', tag:'live',
|
||
w:'Pro fertigem Gericht ein assessments-Eintrag; geschaffte Gerichte bleiben nach Reload.',
|
||
url:'sims/weltkueche/game.html', steps:'Ein Gericht abschließen, Seite neu laden.',
|
||
exp:'Bereits geschaffte Gerichte bleiben erkennbar; im Lehrer-Cockpit taucht das Ergebnis auf.' },
|
||
],
|
||
'Weltküche – Lehrplan & Admin': [
|
||
{ id:'wk-lehrplan', t:'Lehrplan-Bezug auf der Weltküche-Modulseite', tag:'live',
|
||
w:'Kompetenz „Welternährung, Konsum und globale Disparitäten" + Anker.',
|
||
url:'modul-weltkueche', steps:'Seite öffnen, zu „Lehrplan-Bezug" scrollen.',
|
||
exp:'Kompetenzen + Anker sichtbar (nicht mehr „Noch keine Kompetenzen zugeordnet").' },
|
||
{ id:'wk-filter', t:'Länder-Filter im Lehrplan-Bezug wirkt', tag:'live',
|
||
w:'Filter-Chips (Alle/AT/DE/CH/FL) blenden Fach-Anker wirklich um.',
|
||
url:'modul-weltkueche', steps:'Bei „Lehrplan-Bezug" auf Deutschland, dann Österreich klicken.',
|
||
exp:'Sichtbare Fach-Anker ändern sich je Land (vorher passierte nichts).' },
|
||
{ id:'wk-admin', t:'Admin-QA: Weltküche-Herkunftsübersicht (NEU)', tag:'pending',
|
||
w:'Pro Gericht × Zutat richtige Länder + Distraktoren; „nur Auffällige"-Filter.',
|
||
url:'admin-weltkueche.html', steps:'Als Admin einloggen, Seite öffnen. Suche/Kategorie testen, „nur Auffällige" aktivieren.',
|
||
exp:'30 Gerichte; Kartoffel/Eier → 🟢 AT+DE. „Nur Auffällige" zeigt ~5 Kandidaten zum Prüfen.' },
|
||
],
|
||
'Lehrer-Cockpit (teacher.html)': [
|
||
{ id:'tc-menu', t:'Menü „Live" → „Ergebnisse" mit Tag · Aktuell · Vergleich · Gesamt', tag:'pending',
|
||
w:'Umbenannt + 4. Unteransicht „Gesamt" (alte Ergebnis-Ansicht).',
|
||
url:'teacher.html', steps:'Als Lehrer einloggen, Klasse wählen, Tab „Ergebnisse".',
|
||
exp:'Vier Unteransichten; „Gesamt" zeigt die frühere Ergebnis-/Auswertungsansicht.' },
|
||
{ id:'tc-quali', t:'Qualitäts-Kennzahl (richtig ↔ falsch als Balken)', tag:'pending',
|
||
w:'Grafischer Balken (grün/rot) je Kind in Aktuell + Vergleich.',
|
||
url:'teacher.html', steps:'Ergebnisse → Aktuell/Vergleich bei aktivem Weltküche-Kind.',
|
||
exp:'Zweifarbiger Balken + %-Wert („blödeln vs. gut" sichtbar).' },
|
||
{ id:'tc-labels', t:'Klartext-Labels statt Jargon', tag:'pending',
|
||
w:'„Stark/Solide/Viele Fehler" statt „Kritisch/OK"; „Gerade dabei" statt „Phase".',
|
||
url:'teacher.html', steps:'Aktuell/Vergleich ansehen.',
|
||
exp:'Keine „Kritisch"-Bezeichnung mehr.' },
|
||
{ id:'tc-simlabels', t:'Sim-Bezeichner: Wort + 3-Buchstaben-Kürzel', tag:'pending',
|
||
w:'Kein „Log L1" mehr — enger Balken zeigt Kürzel (LOG), breiter das Wort.',
|
||
url:'teacher.html', steps:'Ergebnisse → Tag, Session-Balken ansehen.',
|
||
exp:'Balken tragen LOG/Logistik statt „Log L1".' },
|
||
{ id:'tc-logistik', t:'Logistik hat kuratierte Spalten (statt Roh-Dump)', tag:'pending',
|
||
w:'Stufe · Budget · Geliefert · Unterwegs · Offen · Verspätet · Fortschritt.',
|
||
url:'teacher.html', steps:'Ergebnisse → Aktuell mit aktivem Logistik-Kind.',
|
||
exp:'Sinnvolle Spalten – keine simId/__activeMs/timestamp-Spalten mehr.' },
|
||
{ id:'tc-streifen', t:'Aktivitätsstreifen: Farbe je Sim, Höhe=Erfolg, Rahmen=Zustand', tag:'pending',
|
||
w:'Fertig = geschlossener Rahmen · läuft = rechts offen · Abbruch = gestrichelt + ✖.',
|
||
url:'teacher.html', steps:'Ergebnisse → Tag, mit Sessions eines Tages.',
|
||
exp:'Balken je Sim gefärbt, höher = besser; Rahmen/✖ zeigen den Zustand; Legende erklärt es.' },
|
||
{ id:'tc-assess', t:'assessment-Skip-Fix (keine leeren Ping-Zeilen mehr)', tag:'pending',
|
||
w:'„started/running"-Pings landen nicht mehr als leere Zeilen in Ergebnisse/Tag.',
|
||
url:'teacher.html', steps:'Nach etwas Spielzeit Ergebnisse/Tag ansehen.',
|
||
exp:'Nur echte Abschlüsse als Balken – kein leeres Rauschen.' },
|
||
],
|
||
'Tourismusregion': [
|
||
{ id:'tr-start', t:'Startseite: keine Name/Klasscode-Felder, Klick auf Route startet', tag:'live',
|
||
w:'Felder entfernt; Klick auf eine Wegkarte startet sofort (kein „Partie starten").',
|
||
url:'sims/tourismusregion/game.html', steps:'Sim öffnen, eine Wegkarte anklicken.',
|
||
exp:'Keine Eingabefelder; Partie startet direkt bei Kartenklick.' },
|
||
{ id:'tr-ipad', t:'iPad-Responsive (Panels decken die Karte nicht mehr zu)', tag:'live',
|
||
w:'Panels mit Höhen-Deckel + eigene iPad-Landscape-Regeln. AM IPAD TESTEN!',
|
||
url:'sims/tourismusregion/game.html', steps:'Am echten iPad (Landscape) öffnen und ein Gebäude antippen.',
|
||
exp:'KPIs/Baumenü/Info-Panel überdecken die Karte nicht; Info-Panel scrollt statt zu überziehen.' },
|
||
{ id:'tr-lift', t:'Seilbahn hat eine Talstation (nicht mehr „transparent")', tag:'live',
|
||
w:'Talstation mit Dach + Umlenkrad unten am Lift.',
|
||
url:'sims/tourismusregion/game.html', steps:'Seilbahn bauen (Berg erschließen), auf die Talstation schauen.',
|
||
exp:'Solider Baukörper unten – kein durchsichtiger Lift-Anfang.' },
|
||
{ id:'tr-save', t:'Abschluss: kein „Ergebnis speichern"-Button (Auto-Save)', tag:'live',
|
||
w:'Automatisches Speichern am Partie-Ende; Button entfernt.',
|
||
url:'sims/tourismusregion/game.html', steps:'Eine Partie zu Ende bringen.',
|
||
exp:'Hinweis „automatisch gespeichert", kein Speichern-Button.' },
|
||
{ id:'tr-pass', t:'Neue Karte „Passstraße"', tag:'live',
|
||
w:'Route bergauf (136 Punkte) + 41 Bauslots + Hintergrundbild.',
|
||
url:'sims/tourismusregion/game.html', steps:'Im Startbildschirm „Passstraße" wählen.',
|
||
exp:'Karte lädt, Route + Bauslots passen aufs Bild (optisch prüfen).' },
|
||
{ id:'tr-balance', t:'Balance: Umwelt beißt jetzt (Übertourismus)', tag:'pending',
|
||
w:'Zu viel Bauen + Verkehr senken die Umwelt spürbar; Umwelt-Malus wirkt.',
|
||
url:'sims/tourismusregion/game.html', steps:'Viel/dicht bauen und laufen lassen; Umwelt-KPI beobachten.',
|
||
exp:'Umwelt fällt deutlich (Richtung <45), umweltbewusste Gäste werden unzufriedener.' },
|
||
{ id:'tr-erklaer', t:'Schüler-Erklärung: Umwelt & Naturschutzgebiet', tag:'pending',
|
||
w:'Willkommenskarte + Warnkarte bei Umwelt<50 + klarere Naturschutz-Beschreibung.',
|
||
url:'sims/tourismusregion/game.html', steps:'Neu starten → Willkommenskarte lesen; Umwelt absacken lassen → Warnkarte.',
|
||
exp:'Karte erklärt Umwelt-Mechanik + Naturschutzgebiet; Warnkarte erscheint bei <50.' },
|
||
],
|
||
'Logistik & Plattform': [
|
||
{ id:'lg-pause', t:'Logistik-Pause friert die Aktivzeit ein', tag:'pending',
|
||
w:'Bei Pause zählt die „Seit"-Zeit im Cockpit nicht weiter.',
|
||
url:'sims/logistik/game.html', steps:'Logistik spielen, ⏸ drücken, im Lehrer-Cockpit die Aktivzeit beobachten.',
|
||
exp:'Aktivzeit steht still, solange pausiert; läuft nach dem Fortsetzen weiter.' },
|
||
{ id:'pf-scripts', t:'Wrapper-Bug behoben (/teacher lud kein Script mehr)', tag:'live',
|
||
w:'Favicon wurde ins letzte </head> injiziert – zerschoss ein JS-Popup-Script.',
|
||
url:'teacher', steps:'Die /teacher-Route (Wrapper) öffnen.',
|
||
exp:'Seite lädt sauber, keine „Invalid token"-Konsolenfehler. (teacher.html direkt lief immer.)' },
|
||
],
|
||
'Admin & Auth-Fundament': [
|
||
{ id:'ad-login', t:'Lokaler Admin-Login ohne Mailversand (Dev-PIN)', tag:'pending',
|
||
w:'PIN wird lokal vorausgefüllt; Mailer-Fehler sperrt nicht mehr aus. Auf Prod bleibt 2FA-Mail Pflicht.',
|
||
url:'admin.html', steps:'Username Thomas + Passwort → „Anmelden".',
|
||
exp:'PIN-Feld ist vorausgefüllt („Dev: … vorausgefüllt"), „Bestätigen" → eingeloggt.' },
|
||
{ id:'auth-found', t:'Auth-Fundament JWT + Redis (schlafend, non-breaking)', tag:'pending',
|
||
w:'firebase/php-jwt + predis + Jwt/SessionStore + Session-Kanalisierung. AUTH_BACKEND=session.',
|
||
url:'', steps:'Kein direkter Test nötig — nur sicherstellen, dass Login/Admin normal funktionieren.',
|
||
exp:'Alles läuft wie bisher (das Fundament ist inaktiv, bis der JWT-Cutover kommt).' },
|
||
],
|
||
};
|
||
|
||
const listWrap = document.querySelector('.wrap');
|
||
document.querySelectorAll('section[data-sec]').forEach(sec => {
|
||
const name = sec.getAttribute('data-sec');
|
||
const items = ITEMS[name] || [];
|
||
let html = '<div class="sec-h">' + name + ' <span class="cnt">' + items.length + ' Punkte</span></div>';
|
||
items.forEach(it => {
|
||
const urlHtml = it.url ? '<a class="url" href="' + u(it.url) + '" target="_blank" rel="noopener">' + u(it.url) + '</a>' : '<span style="color:#b3ac9e">—</span>';
|
||
html += ''
|
||
+ '<div class="item" data-id="' + it.id + '">'
|
||
+ '<div class="item-top">'
|
||
+ '<input type="checkbox" data-check="' + it.id + '">'
|
||
+ '<div style="flex:1"><span class="item-title">' + it.t + '</span>'
|
||
+ '<span class="tag ' + it.tag + '">' + (it.tag==='live'?'live':'bereit') + '</span></div>'
|
||
+ '</div>'
|
||
+ '<div class="body">'
|
||
+ '<div class="row"><span class="k">Was</span> ' + it.w + '</div>'
|
||
+ '<div class="row"><span class="k">Öffnen</span> ' + urlHtml + '</div>'
|
||
+ '<div class="row"><span class="k">Testen</span> ' + it.steps + '</div>'
|
||
+ '<div class="exp">✓ Erwartet: ' + it.exp + '</div>'
|
||
+ '<textarea class="note" data-note="' + it.id + '" placeholder="Notiz / gefundene Abweichung…"></textarea>'
|
||
+ '</div>'
|
||
+ '</div>';
|
||
});
|
||
sec.innerHTML = html;
|
||
});
|
||
|
||
// Persistenz + Fortschritt
|
||
const checks = document.querySelectorAll('input[data-check]');
|
||
function refresh(){
|
||
let done = 0;
|
||
checks.forEach(c => { if(c.checked){ done++; c.closest('.item').classList.add('done'); } else c.closest('.item').classList.remove('done'); });
|
||
document.getElementById('pcount').textContent = done + ' / ' + checks.length;
|
||
document.getElementById('pbar').style.width = (checks.length? (done/checks.length*100):0) + '%';
|
||
}
|
||
checks.forEach(c => {
|
||
const key = 'chk_' + c.getAttribute('data-check');
|
||
c.checked = localStorage.getItem(key) === '1';
|
||
c.addEventListener('change', () => { localStorage.setItem(key, c.checked?'1':'0'); refresh(); });
|
||
});
|
||
document.querySelectorAll('textarea[data-note]').forEach(t => {
|
||
const key = 'note_' + t.getAttribute('data-note');
|
||
t.value = localStorage.getItem(key) || '';
|
||
t.addEventListener('input', () => localStorage.setItem(key, t.value));
|
||
});
|
||
refresh();
|
||
</script>
|
||
</body>
|
||
</html>
|