From e554b6d9b8ffdb6fc5e882ab661e10893a3e0762 Mon Sep 17 00:00:00 2001 From: mhoennig Date: Sun, 23 Aug 2026 14:47:19 +0200 Subject: [PATCH] feat: ein neues Dokument beginnt mit seinem Namen (D51) MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit „+ Neu" legte das Dokument unter „Unbenannt" an und setzte den Cursor ins leere Textfeld; das Umbenennen war ein eigener, zweiter Gang durchs Menü — und wurde entsprechend oft nicht gemacht. Jetzt öffnet sich unmittelbar das Inline-Umbenennen (D22) mit ausgewähltem Vorschlag: tippen ersetzt ihn, Enter bestätigt. Das Dokument existiert vorher: angelegt, gespeichert und aktiviert wie bisher, nur der Fokus geht ins Namensfeld statt ins Textfeld. Ein Abbruch verwirft nichts — Esc behält den Vorschlag. Der Gegenentwurf (erst benennen, dann anlegen) hätte ein Dokument im Schwebezustand gebraucht. Nach dem Benennen geht es im Textfeld weiter — Anlegen heißt schreiben wollen. Der Merker `renameIsNew` unterscheidet diesen Fall vom gewöhnlichen Umbenennen aus dem Menü, das unverändert bleibt (Menü bleibt offen, Fokus wandert nicht); `closeDocMenu()` setzt ihn mit zurück, sonst trüge ein abgebrochener Vorgang seine Sonderbehandlung in den nächsten hinein. Nachgemessen: Nach „+ Neu" hat das Eingabefeld den Fokus und der Vorschlag ist vollständig markiert. Enter mit „Sprint 15" -> Titelzeile, `werkbaum-docs` und Fokus im leeren Textfeld stimmen. Esc -> Vorschlag bleibt, Menü zu, Fokus im Text. Bestehendes Dokument umbenennen -> Menü bleibt offen, Fokus bleibt. 236 Tests grün. Grenze der Prüfung, benannt: Der Fokusverlust ließ sich nur als zugestelltes Ereignis prüfen, nicht als echter Fokuswechsel — ein synthetisches `.blur()` löst im Automaten keinen aus. Gegenprobe am unveränderten Pfad zeigt dasselbe, es ist also die Werkzeuggrenze und keine Regression (Lehre aus D25). Co-Authored-By: Claude Fable 5 --- docs/DECISIONS.md | 41 +++++++++++++++++++++++++++++++++++++++++ frontend/src/app.js | 29 ++++++++++++++++++++++++++--- 2 files changed, 67 insertions(+), 3 deletions(-) diff --git a/docs/DECISIONS.md b/docs/DECISIONS.md index fa99e65..fdc2ec1 100644 --- a/docs/DECISIONS.md +++ b/docs/DECISIONS.md @@ -3247,3 +3247,44 @@ und bei 320 px. `overflow` gibt, entscheidet damit über alles, was aus ihr herausragen soll — Menüs, Tooltips, Overlays. In `frontend/CLAUDE.md` steht das jetzt bei der Kopfzeilen-Stolperfalle. + +## D51 — Ein neues Dokument beginnt mit seinem Namen +Bisher legte „+ Neu" das Dokument unter „Unbenannt" an und setzte den Cursor +ins leere Textfeld. Das Umbenennen war ein eigener, zweiter Gang durchs Menü — +und wurde entsprechend oft nicht gemacht: Wer drei Pläne führt, hat drei +„Unbenannt". Jetzt öffnet sich unmittelbar das Inline-Umbenennen (D22) mit +**ausgewähltem** Vorschlag; tippen ersetzt ihn, Enter bestätigt. + +**Das Dokument existiert vorher.** Angelegt, gespeichert und aktiviert wird wie +bisher; nur der Fokus geht ins Namensfeld statt ins Textfeld. Ein **Abbruch +verwirft nichts** — Esc behält den Vorschlag „Unbenannt", so wie es vorher der +Normalfall war. Der Gegenentwurf (erst benennen, dann anlegen) hätte ein +Dokument im Schwebezustand gebraucht und die Frage aufgeworfen, was bei Esc +passiert; das ist mehr Mechanik für weniger Verlässlichkeit. + +**Nach dem Benennen geht es im Textfeld weiter.** Anlegen heißt schreiben +wollen — den Namen zu vergeben ist die erste Hälfte der Geste, nicht ihr Zweck. +Der Merker `renameIsNew` unterscheidet diesen Fall vom gewöhnlichen Umbenennen +aus dem Menü, das unverändert bleibt (Menü bleibt offen, Fokus wandert nicht). +Er wird in `closeDocMenu()` mit zurückgesetzt, sonst trüge ein abgebrochener +Vorgang seine Sonderbehandlung in den nächsten hinein. + +Für alle drei Wege aus dem Eingabefeld gilt dasselbe: **Enter**, **Esc** und +**Fokusverlust** benennen (bzw. behalten den Vorschlag), schließen das Menü und +setzen den Cursor in den Text. Auf dem Telefon ist das zugleich der Moment, in +dem die Bildschirmtastatur gebraucht wird — `keyboardOnJump(false)` steht schon +da, aus demselben Grund (D25: neues, leeres Dokument = tippen ist gemeint). + +**Nachgemessen:** Nach „+ Neu" trägt das Eingabefeld den Fokus, der Vorschlag +ist vollständig markiert (`selectionStart` 0 bis Länge). Enter mit „Sprint 15": +Titelzeile, `werkbaum-docs` und der Fokus im leeren Textfeld stimmen. Esc: +Vorschlag bleibt, Menü zu, Fokus im Text. Umbenennen eines bestehenden +Dokuments: Menü bleibt offen, Fokus bleibt, wo er war. + +**Grenze der Prüfung, benannt:** Der Fokusverlust ließ sich nur als +**zugestelltes Ereignis** prüfen, nicht als echter Fokuswechsel — ein +synthetisches `.blur()` löst im Automaten keinen aus. Gegenprobe am +**unveränderten** Pfad (bestehendes Dokument umbenennen): dort passiert +ebenfalls nichts, es ist also die Werkzeuggrenze und keine Regression. Dieselbe +Lehre wie in D25 und D17-Nachtrag 4 — was die Geräteumgebung stellt, beweist +der Emulator nicht. diff --git a/frontend/src/app.js b/frontend/src/app.js index 48c52f4..548c178 100644 --- a/frontend/src/app.js +++ b/frontend/src/app.js @@ -2603,6 +2603,9 @@ function updateDocName(){ updatePadLink(); /* Schreibschutz + Pad-Knopf hängen am aktiven Dokument (D31) */ } let renamingId = null; /* id des gerade inline umbenannten Dokuments (oder null) */ +/* Kam das Umbenennen von einem frisch angelegten Dokument? Dann geht es danach + im Textfeld weiter — Anlegen heißt schreiben wollen (D51). */ +let renameIsNew = false; function renderDocMenu(){ docList.innerHTML = docs.map(d => { if(d.id === renamingId){ @@ -2664,7 +2667,7 @@ function restoreDoc(){ closeDocMenu(); } function openDocMenu(){ renderDocMenu(); updateRestoreBtn(); docMenu.hidden = false; docTrigger.setAttribute('aria-expanded', 'true'); } -function closeDocMenu(){ renamingId = null; docMenu.hidden = true; docTrigger.setAttribute('aria-expanded', 'false'); } +function closeDocMenu(){ renamingId = null; renameIsNew = false; docMenu.hidden = true; docTrigger.setAttribute('aria-expanded', 'false'); } function toggleDocMenu(){ docMenu.hidden ? openDocMenu() : closeDocMenu(); } /* Beim Wechseln/Anlegen/Löschen zuerst den aktuellen Editortext ins aktive Dokument sichern, dann das Ziel laden und neu rendern. */ @@ -2728,6 +2731,11 @@ function switchDoc(id){ loadActiveIntoEditor(); persistDocs(); } +/* Ein neues Dokument beginnt mit seinem Namen (D51): Statt es unter „Neues + Dokument" abzulegen und den Cursor ins leere Textfeld zu setzen, öffnet sich + sofort das Inline-Umbenennen mit **ausgewähltem** Vorschlag — tippen ersetzt + ihn, Enter bestätigt. Wer nichts eingibt, behält den Vorschlag; das Dokument + ist bereits angelegt, ein Abbruch verwirft es nicht. */ function newDoc(){ flushActive(); const d = { id: uid(), name: uniqueName(t('docNewName')), text: '' }; @@ -2737,11 +2745,23 @@ function newDoc(){ loadActiveIntoEditor(); persistDocs(); keyboardOnJump(false); /* neues, leeres Dokument = tippen ist gemeint */ + renamingId = d.id; + renameIsNew = true; + renderDocMenu(); /* setzt den Fokus ins Eingabefeld und markiert es */ +} +/* Nach dem Benennen eines frisch angelegten Dokuments geht es im Textfeld + weiter — die zweite Hälfte derselben Geste. Gilt auch für Esc: Der Vorschlag + bleibt dann stehen, das Dokument existiert ohnehin. */ +function finishNewDoc(){ + if(!renameIsNew) return; + renameIsNew = false; + closeDocMenu(); src.focus(); } function renameDoc(){ if(!activeDoc()) return; renamingId = activeId; /* aktives Dokument inline umbenennen */ + renameIsNew = false; renderDocMenu(); } function commitRename(){ @@ -2752,8 +2772,9 @@ function commitRename(){ renamingId = null; if(d && val){ d.name = val; persistDocs(); updateDocName(); } renderDocMenu(); + finishNewDoc(); } -function cancelRename(){ renamingId = null; renderDocMenu(); } +function cancelRename(){ renamingId = null; renderDocMenu(); finishNewDoc(); } function deleteDoc(){ const d = activeDoc(); if(!d) return; @@ -3091,7 +3112,9 @@ docList.addEventListener('click', e => { switchDoc(btn.dataset.id); closeDocMenu(); }); -document.getElementById('docNew').addEventListener('click', e => { e.stopPropagation(); newDoc(); renderDocMenu(); }); +/* `newDoc()` zeichnet das Menü selbst neu — es geht direkt ins Umbenennen + (D51), und ein zweiter Durchlauf baute das Eingabefeld nur noch einmal auf. */ +document.getElementById('docNew').addEventListener('click', e => { e.stopPropagation(); newDoc(); }); document.getElementById('docRename').addEventListener('click', e => { e.stopPropagation(); renameDoc(); }); document.getElementById('docDelete').addEventListener('click', e => { e.stopPropagation(); deleteDoc(); }); document.getElementById('docRestore').addEventListener('click', e => { e.stopPropagation(); restoreDoc(); });