feat: Speichern schreibt in die geöffnete Datei zurück (D72-Nachtrag, Stufe 2)

File System Access API, wo vorhanden (Chromium): Öffnen merkt sich das
FileSystemFileHandle (IndexedDB, überlebt den Neustart), Speichern schreibt
in dieselbe Datei; dieselbe Datei öffnet per isSameEntry wieder in dasselbe
Dokument. Firefox/Safari behalten den Stufe-1-Download.

Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
This commit is contained in:
mhoennig
2026-08-25 14:31:51 +02:00
co-authored by Claude Fable 5
parent defeaf84d0
commit 2648d72e45
6 changed files with 207 additions and 12 deletions
+1
View File
@@ -19,6 +19,7 @@ reverse.
## 2026-08-25
- In Chromium browsers, saving writes back to the opened file, and the same file reopens into the same document
- Open a local `.werkbaum` file and save the document back as a file, from the document menu
- An AI integration recorded as an idea in the plan — edit the tree in a dialogue, with your own API key and `llms.md` as the model's guide
- A warning flags the bottleneck when one `@name` carries more than half of the open work on the cheapest path — their tag pills turn amber on the open nodes
+50
View File
@@ -5339,3 +5339,53 @@ Input ist geleert (dieselbe Datei bleibt erneut wählbar); Speichern liefert
`tests/localfile.test.js`. Werkzeuggrenze wie in D25/D53: Der echte
Dateidialog und der echte Download lassen sich nicht automatisiert auslösen —
geprüft ist alles bis an diese Kante.
**Nachtrag — Stufe 2: die File System Access API macht aus „Speichern unter"
ein „Speichern".** Wo die Picker existieren (`showOpenFilePicker` als
Feature-Detection — Chromium; Firefox und Safari haben sie bewusst nicht),
ändert sich hinter denselben zwei Menü-Einträgen das Verhalten:
- **Öffnen** liefert ein `FileSystemFileHandle`. Damit gibt es die
Datei-Identität, die Stufe 1 nicht hatte: `isSameEntry` prüft gegen die
gemerkten Handles, **dieselbe Datei öffnet wieder in dasselbe Dokument**
(aktualisiert den Text), eine andere Datei gleichen Namens bleibt ein
eigenes. `adoptFile()` trägt beide Wege — der Stufe-1-Input ruft es ohne
Handle, dann entsteht immer ein neues Dokument wie bisher.
- **Speichern** schreibt mit gemerktem Handle **in dieselbe Datei zurück**
(`createWritable`), ohne Dialog. Ohne Handle fragt `showSaveFilePicker`
(mit `saveFileName()` als Vorschlag) und merkt sich das Ergebnis — der
Komfort greift ab dem zweiten Speichern. Ein **Abbruch** des Dialogs tut
nichts — bewusst auch kein Download hinterher: Wer abbricht, will nicht
woandershin speichern. Der Menü-Eintrag trägt den Dateinamen des Handles
als Tooltip (Dateinamen sind Daten, kein i18n).
- **Handles überleben den Neustart in IndexedDB** — localStorage kann sie
nicht halten (nicht JSON-serialisierbar), IndexedDB kann es (structured
clone). Beim Start werden sie zurückgeholt; verwaiste Einträge (Dokument
gelöscht) und Fremdes ohne `createWritable` räumen sich dabei weg. Nach dem
Neustart steht die Berechtigung auf `prompt` — der Browser fragt beim
ersten Speichern einmal nach (der Menü-Klick ist die nötige Nutzergeste);
verweigert er, entscheidet der Dialog neu. **Alles daran ist Komfort, keine
Pflicht**: Jeder IndexedDB-Fehler wird geschluckt, Speichern funktioniert
dann eben wieder über den Dialog.
- `deleteDoc()` nimmt das Handle mit (Map und IndexedDB) — wie die Stände
(D54): Mit dem Dokument geht, was an ihm hängt.
**Kein Strg+S** — erwogen und zurückgestellt: Der Browser-Default (Seite
speichern) müsste abgefangen werden, und ohne Handle öffnete die Geste
unvermittelt einen Dialog; wenn, dann als eigene Entscheidung mit
Legenden-Zeile.
**Nachgemessen** im Browser (echtes Chromium, `hasFsAccess === true`; die
Picker gestubbt — den nativen Dialog kann die Automatisierung nicht bedienen,
die Logik dahinter schon; Werkzeuggrenze wie D52): Öffnen legt das Dokument
mit Handle an, der Speichern-Eintrag trägt den Dateinamen als Tooltip,
Speichern schreibt in place (**0** Dialog-Aufrufe), dieselbe Datei erneut
geöffnet aktualisiert **dasselbe** Dokument (Anzahl unverändert, Text auf
Version 2, Diagramm folgt); ein Dokument ohne Handle bekommt beim ersten
Speichern den Dialog (`suggestedName` korrekt) und beim zweiten nicht mehr
(1 Aufruf, 2 Schreibvorgänge); Abbruch bzw. verweigerte Berechtigung
schreiben nichts und laden nichts herunter. **Nicht messbar** blieb die
IndexedDB-Rundreise über einen Neustart: Stub-Handles überleben den
Structured Clone nicht (`DataCloneError`, planmäßig geschluckt) — echte
Handles sind gerade dafür klonbar; dieser eine Pfad ist Code-Review statt
Messung. 480 Tests.
+6
View File
@@ -87,6 +87,7 @@
- [^] #ed.snaps: Earlier states of a document, every ten minutes (S) %% only when something changed
- [^] #ed.snaps.manual: Save a state by hand, before a larger change (XS) %% ten minutes is the wrong beat for that moment
- [x] #ed.files: Open and save .werkbaum files (S)
- [x] #ed.files.inplace: Saving writes back into the opened file (S) %% File System Access, Chromium
+ [^] #ed.fresh: Show what is new since your last visit (S)
- [^] #ed.fresh.news: A star in the header, with the last few days (S) %% see D58
+ [?] #ed.percolor: A pastel colour per person (S)
@@ -608,6 +609,11 @@
format was the one thing that could not leave the browser as a file, while
the diagram always could.
#ed.files.inplace
Where the File System Access API exists (Chromium), opening keeps a file
handle: saving writes back into the same file, and the same file reopens
into the same document. Firefox and Safari keep the plain download.
#ed.fresh
For documents that come from outside, nodes that went to production since
your last visit get a yellow halo. New means live, not "line added" — a line