From ab6d02eccb8b4fdc6c72a32aa9f6b937007b1a58 Mon Sep 17 00:00:00 2001 From: Erik Thiele Date: Sat, 22 Aug 2026 12:10:50 +0200 Subject: [PATCH] Fix: Ausstehender Autosave ueberschrieb das geladene Projekt Beim Laden eines Projekts blieb der alte Projektname stehen, wenn kurz zuvor getippt wurde. Ursache: projektLaden() brach den laufenden Autosave-Timer nicht ab. Der feuerte 500 ms nach dem letzten Tastendruck, las die noch alten Formularfelder aus und schrieb sie ueber den gerade geladenen Stand. Anschliessend folgte ein location.reload(), der den ueberschriebenen Stand anzeigte. Auf localhost war das Zeitfenster meist zu klein, ueber LAN gegen den Container dagegen zuverlaessig zu treffen. - projektLaden() und projektNeu() brechen saveTimeout und calcTimeout ab. - /projekte/laden und /projekte/neu liefern den neuen Stand zurueck, das Frontend setzt die Felder direkt (neue Funktion standUebernehmen). - Kein location.reload() mehr. Das beseitigt zusaetzlich die Formular-Wiederherstellung, mit der Firefox und Safari von Hand geaenderte Felder nach einem Reload zurueckholen -- betroffen waere genau das Projektnamen-Feld gewesen. Reproduziert und gegengeprueft: mit der alten Reihenfolge schreibt der Autosave "Projekt B" ueber das geladene "Projekt A"; mit dem Fix bleiben Feld und Serverstand ueber mehrere Wechsel hinweg stabil. Co-Authored-By: Claude Opus 5 --- app.py | 14 ++++++++++---- static/script.js | 38 +++++++++++++++++++++++++++++++++++--- 2 files changed, 45 insertions(+), 7 deletions(-) diff --git a/app.py b/app.py index 8c5cb68..f4afea6 100644 --- a/app.py +++ b/app.py @@ -679,8 +679,13 @@ def projekt_laden(): if feld in eintrag: config[feld] = eintrag[feld] config['projektName'] = name - save_config(_migriere(config)) - return jsonify({'status': 'ok', 'name': name}) + config = _migriere(config) + save_config(config) + # Den geladenen Stand mitschicken, damit das Frontend die Felder + # direkt setzen kann -- ein location.reload() wuerde von Hand + # geaenderte Felder in manchen Browsern wiederherstellen. + return jsonify({'status': 'ok', 'name': name, + 'stand': projekt_aus_config(config)}) @app.route('/projekte/neu', methods=['POST']) @@ -694,8 +699,9 @@ def projekt_neu(): with _config_lock: config = load_config() config.update(leerer_projektstand()) - save_config(_migriere(config)) - return jsonify({'status': 'ok'}) + config = _migriere(config) + save_config(config) + return jsonify({'status': 'ok', 'stand': projekt_aus_config(config)}) @app.route('/projekte/loeschen', methods=['POST']) diff --git a/static/script.js b/static/script.js index 5779b63..d9e05dd 100644 --- a/static/script.js +++ b/static/script.js @@ -327,6 +327,10 @@ async function projektLaden() { `Ungespeicherte Aenderungen gehen dabei verloren. Fortfahren?`)) { return; } + // Ausstehenden Autosave verwerfen: er wuerde sonst mit den ALTEN + // Formulardaten feuern und den gerade geladenen Stand ueberschreiben. + clearTimeout(saveTimeout); + clearTimeout(calcTimeout); try { const res = await fetch('/projekte/laden', { method: 'POST', @@ -338,13 +342,37 @@ async function projektLaden() { showNotification(daten.error || 'Laden fehlgeschlagen'); return; } - // Neu laden: die Positionskarten baut der Server-Datenblock auf. - location.reload(); + standUebernehmen(daten.stand); + showNotification(`Projekt "${name}" geladen`); } catch (e) { showNotification('Laden fehlgeschlagen'); } } +/** Uebernimmt einen vom Server gelieferten Projektstand in die Felder. + * + * Bewusst ohne location.reload(): Firefox und Safari stellen beim Reload + * von Hand geaenderte Formularfelder wieder her und wuerden damit den + * gerade geladenen Projektnamen sofort wieder ueberschreiben. + */ +function standUebernehmen(stand) { + if (!stand) return; + + const nameFeld = document.getElementById('projekt-name'); + if (nameFeld) nameFeld.value = stand.projektName || ''; + + const liste = document.getElementById('positionen-liste'); + if (liste) { + liste.innerHTML = ''; + const positionen = (stand.positionen && stand.positionen.length) + ? stand.positionen + : [{ materialPreisProKg: 25, stueckzahl: 1 }]; + positionen.forEach(positionAnlegen); + } + recalculate(); + projekteAktualisieren(); +} + /** Beginnt einen leeren Auftrag. Betriebswerte bleiben erhalten. */ async function projektNeu() { // Offenen Autosave durchdruecken, damit der Server den wirklich @@ -364,13 +392,17 @@ async function projektNeu() { 'Trotzdem neu anfangen?')) { return; } + clearTimeout(saveTimeout); + clearTimeout(calcTimeout); try { const res = await fetch('/projekte/neu', { method: 'POST' }); + const daten = await res.json(); if (!res.ok) { showNotification('Zuruecksetzen fehlgeschlagen'); return; } - location.reload(); + standUebernehmen(daten.stand); + showNotification('Neues Projekt begonnen'); } catch (e) { showNotification('Zuruecksetzen fehlgeschlagen'); }