fix(menü): Wiederherstellen nur noch über den Neu-laden-Knopf der Titelzeile (D81-Nachtrag 2)
Das Zeilen-Symbol im Dokumenten-Menü konnte ein UNGEÖFFNETES mitgeliefertes Dokument zurücksetzen — ohne zu sehen, was man verwirft (Nutzer-Einwand). Umbenennen und Löschen bleiben je Zeile; restoreDoc() wirkt nur noch auf das geöffnete Dokument und prüft das selbst. Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
This commit is contained in:
co-authored by
Claude Fable 5
parent
67d0ef421b
commit
ed81a2fe41
+1
-1
@@ -24,7 +24,7 @@ reverse.
|
|||||||
## 2026-08-26
|
## 2026-08-26
|
||||||
|
|
||||||
- The document picker moved into the app header: `Werkbaum › name` opens the menu — on the phone it is reachable from both panes, and the name takes over the subtitle line
|
- The document picker moved into the app header: `Werkbaum › name` opens the menu — on the phone it is reachable from both panes, and the name takes over the subtitle line
|
||||||
- The document menu groups by kind — included, yours, sources — carries rename, delete and restore on each row, and scrolls instead of being cut off on small screens
|
- The document menu groups by kind — included, yours, sources — carries rename and delete on each row, and scrolls instead of being cut off on small screens
|
||||||
- The editor title bar is labelled `Text editor` again and holds the document's own buttons: save, snapshot, history, reload from the source, and a short `Share` button that puts the plan on a server
|
- The editor title bar is labelled `Text editor` again and holds the document's own buttons: save, snapshot, history, reload from the source, and a short `Share` button that puts the plan on a server
|
||||||
- The address bar follows the document you switch to: `?live=` and `?sourceUrl=` name what is in front of you, so a reload brings back the same plan
|
- The address bar follows the document you switch to: `?live=` and `?sourceUrl=` name what is in front of you, so a reload brings back the same plan
|
||||||
- Switching to a server document in the picker now really opens it live — before it only showed its last state
|
- Switching to a server document in the picker now really opens it live — before it only showed its last state
|
||||||
|
|||||||
@@ -7041,3 +7041,15 @@ cross-origin.
|
|||||||
Abbruch tut nichts; die Probe gegen das echte Backend liefert
|
Abbruch tut nichts; die Probe gegen das echte Backend liefert
|
||||||
`{name:"editor-backend"}`. `infoUrl()` liegt headless in live.js (39
|
`{name:"editor-backend"}`. `infoUrl()` liegt headless in live.js (39
|
||||||
Live-Tests, +1).
|
Live-Tests, +1).
|
||||||
|
|
||||||
|
**Nachtrag 2 — Wiederherstellen fliegt aus den Menü-Zeilen wieder raus.**
|
||||||
|
Nutzer-Einwand nach dem ersten Arbeiten damit: Im Menü ließe sich ein
|
||||||
|
**ungeöffnetes** Dokument zurücksetzen — „was keinen Sinn ergäbe". Der
|
||||||
|
Einwand trifft: Wiederherstellen verwirft Änderungen, und wer das Dokument
|
||||||
|
nicht vor sich hat, sieht nicht, was er verwirft. Umbenennen und Löschen
|
||||||
|
bleiben je Zeile (dort ist der Blick auf den Inhalt nicht nötig — der Name
|
||||||
|
steht da, und Löschen fragt nach); Wiederherstellen wirkt nur noch über den
|
||||||
|
**Neu-laden-Knopf der Editor-Titelzeile**, also auf das geöffnete Dokument.
|
||||||
|
`restoreDoc()` prüft das selbst (`d.id !== activeId` → nichts), statt sich
|
||||||
|
auf den Aufrufer zu verlassen. Der D81-Haupttext oben beschreibt insoweit
|
||||||
|
den Zwischenstand von einem Tag.
|
||||||
|
|||||||
@@ -532,9 +532,10 @@
|
|||||||
|
|
||||||
#ed.docs.picker
|
#ed.docs.picker
|
||||||
The app header reads "Werkbaum > name": the chip opens the menu, grouped by
|
The app header reads "Werkbaum > name": the chip opens the menu, grouped by
|
||||||
kind (shipped, yours, sources), with rename, delete and restore on each row.
|
kind (shipped, yours, sources), with rename and delete on each row. Restore
|
||||||
It scrolls as a whole instead of being cut off on small screens, and on the
|
lives on the editor title bar's reload button instead, acting only on the
|
||||||
phone it is reachable from both panes.
|
open document. The menu scrolls as a whole instead of being cut off on
|
||||||
|
small screens, and on the phone it is reachable from both panes.
|
||||||
|
|
||||||
#ed.docs.url
|
#ed.docs.url
|
||||||
A link can carry the address of a text file, which is then fetched on every
|
A link can carry the address of a text file, which is then fetched on every
|
||||||
|
|||||||
+6
-4
@@ -155,10 +155,12 @@ verworfene Elemente. Quelle sind ES-Module unter `src/`; `index.html` ist der
|
|||||||
Text in den Editor. `saveSrc()` schreibt den Editortext ins aktive Dokument.
|
Text in den Editor. `saveSrc()` schreibt den Editortext ins aktive Dokument.
|
||||||
Der Wähler ist eine **Brotkrume im App-Kopf** (`#docTrigger`/`#docMenu`,
|
Der Wähler ist eine **Brotkrume im App-Kopf** (`#docTrigger`/`#docMenu`,
|
||||||
„Werkbaum › Name", D81); das Menü gruppiert nach Dokumentart (`docKind()` in
|
„Werkbaum › Name", D81); das Menü gruppiert nach Dokumentart (`docKind()` in
|
||||||
docurl.js, headless getestet) und trägt Umbenennen/Löschen/Wiederherstellen
|
docurl.js, headless getestet) und trägt Umbenennen/Löschen als Symbole
|
||||||
als Symbole **je Zeile** — `renameDoc/deleteDoc/restoreDoc` nehmen deshalb
|
**je Zeile** — `renameDoc/deleteDoc` nehmen deshalb eine **id**, nicht das
|
||||||
eine **id**, nicht das aktive Dokument, und Verwaltungs-Aktionen lassen das
|
aktive Dokument, und Verwaltungs-Aktionen lassen das Menü offen.
|
||||||
Menü offen. Die Editor-Titelzeile heißt wieder „Text-Editor" und trägt die
|
Wiederherstellen gibt es im Menü bewusst **nicht** (D81-Nachtrag 2): Es
|
||||||
|
läuft über den Neu-laden-Knopf der Titelzeile und wirkt nur auf das
|
||||||
|
geöffnete Dokument — `restoreDoc()` prüft das selbst. Die Editor-Titelzeile heißt wieder „Text-Editor" und trägt die
|
||||||
Stand-Knöpfe (`saveBtn`/`snapAddBtn`/`snapBtn`/`reloadBtn`/`shareBtn` in der
|
Stand-Knöpfe (`saveBtn`/`snapAddBtn`/`snapBtn`/`reloadBtn`/`shareBtn` in der
|
||||||
`.standgroup`); ihren Zustand setzt `updateDocButtons()` — aufgerufen aus
|
`.standgroup`); ihren Zustand setzt `updateDocButtons()` — aufgerufen aus
|
||||||
`updateDocName()` UND am `input`-Ereignis, denn die Abweichung vom
|
`updateDocName()` UND am `input`-Ereignis, denn die Abweichung vom
|
||||||
|
|||||||
+15
-18
@@ -3571,15 +3571,17 @@ function serverHostOf(id){
|
|||||||
if(!roh.startsWith('live:')) return null;
|
if(!roh.startsWith('live:')) return null;
|
||||||
try{ return new URL(roh.slice(5)).host; }catch(_){ return null; }
|
try{ return new URL(roh.slice(5)).host; }catch(_){ return null; }
|
||||||
}
|
}
|
||||||
/* Kleine Zeilen-Icons (Feather-Stil wie überall): Stift, Papierkorb,
|
/* Kleine Zeilen-Icons (Feather-Stil wie überall): Stift, Papierkorb.
|
||||||
Wiederherstellen. Als Konstanten, damit der Renderer lesbar bleibt. */
|
Als Konstanten, damit der Renderer lesbar bleibt. */
|
||||||
const IC_RENAME = '<svg viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="1.8" stroke-linecap="round" stroke-linejoin="round" aria-hidden="true"><path d="M17 3a2.83 2.83 0 1 1 4 4L7.5 20.5 2 22l1.5-5.5L17 3z"/></svg>';
|
const IC_RENAME = '<svg viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="1.8" stroke-linecap="round" stroke-linejoin="round" aria-hidden="true"><path d="M17 3a2.83 2.83 0 1 1 4 4L7.5 20.5 2 22l1.5-5.5L17 3z"/></svg>';
|
||||||
const IC_DELETE = '<svg viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="1.8" stroke-linecap="round" stroke-linejoin="round" aria-hidden="true"><path d="M3 6h18M8 6V4a2 2 0 0 1 2-2h4a2 2 0 0 1 2 2v2M19 6v14a2 2 0 0 1-2 2H7a2 2 0 0 1-2-2V6"/></svg>';
|
const IC_DELETE = '<svg viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="1.8" stroke-linecap="round" stroke-linejoin="round" aria-hidden="true"><path d="M3 6h18M8 6V4a2 2 0 0 1 2-2h4a2 2 0 0 1 2 2v2M19 6v14a2 2 0 0 1-2 2H7a2 2 0 0 1-2-2V6"/></svg>';
|
||||||
const IC_RESTORE = '<svg viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="1.8" stroke-linecap="round" stroke-linejoin="round" aria-hidden="true"><path d="M1.7 5v5.5h5.5"/><path d="M4 15a8.5 8.5 0 1 0 .5-7.5L1.7 10.5"/></svg>';
|
|
||||||
/* Eine Menüzeile: Wählen-Knopf + Zeilen-Aktionen als GESCHWISTER — ein Knopf
|
/* Eine Menüzeile: Wählen-Knopf + Zeilen-Aktionen als GESCHWISTER — ein Knopf
|
||||||
im Knopf wäre ungültiges HTML. Die Aktionen sind immer sichtbar (Touch
|
im Knopf wäre ungültiges HTML. Die Aktionen sind immer sichtbar (Touch
|
||||||
kennt kein Hover): Umbenennen und Löschen überall, Wiederherstellen nur an
|
kennt kein Hover): Umbenennen und Löschen, beides überall. Wiederherstellen
|
||||||
einem mitgelieferten Dokument, das vom Auslieferungsstand abweicht. */
|
gibt es hier bewusst NICHT (D81-Nachtrag 2): Es wirkt über den
|
||||||
|
Neu-laden-Knopf der Editor-Titelzeile nur auf das geöffnete Dokument —
|
||||||
|
ein ungeöffnetes zurückzusetzen, ohne zu sehen, was man verwirft, ergäbe
|
||||||
|
keinen Sinn. */
|
||||||
function docRowHtml(d){
|
function docRowHtml(d){
|
||||||
if(d.id === renamingId){
|
if(d.id === renamingId){
|
||||||
/* Inline-Umbenennen direkt im Menü (kein window.prompt — das ist in
|
/* Inline-Umbenennen direkt im Menü (kein window.prompt — das ist in
|
||||||
@@ -3593,8 +3595,6 @@ function docRowHtml(d){
|
|||||||
verriete den Unterschied. */
|
verriete den Unterschied. */
|
||||||
const host = serverHostOf(d.id);
|
const host = serverHostOf(d.id);
|
||||||
const zusatz = host ? `<span class="docitem-where">${esc(host)}</span>` : '';
|
const zusatz = host ? `<span class="docitem-where">${esc(host)}</span>` : '';
|
||||||
const shipped = shippedStateOf(d.id);
|
|
||||||
const abweichend = shipped && (d.text !== shipped.text || d.name !== shipped.name);
|
|
||||||
const iconBtn = (act, label, svg, extra) =>
|
const iconBtn = (act, label, svg, extra) =>
|
||||||
`<button type="button" class="dociconbtn${extra || ''}" data-act="${act}" ` +
|
`<button type="button" class="dociconbtn${extra || ''}" data-act="${act}" ` +
|
||||||
`title="${esc(label)}" aria-label="${esc(label)}">${svg}</button>`;
|
`title="${esc(label)}" aria-label="${esc(label)}">${svg}</button>`;
|
||||||
@@ -3604,7 +3604,6 @@ function docRowHtml(d){
|
|||||||
`<span class="doccheck" aria-hidden="true">✓</span>` +
|
`<span class="doccheck" aria-hidden="true">✓</span>` +
|
||||||
`<span class="docitem-name">${esc(d.name)}</span>${zusatz}</button>` +
|
`<span class="docitem-name">${esc(d.name)}</span>${zusatz}</button>` +
|
||||||
`<span class="docacts">` +
|
`<span class="docacts">` +
|
||||||
(abweichend ? iconBtn('restore', t('docRestore'), IC_RESTORE) : '') +
|
|
||||||
iconBtn('rename', t('docRename'), IC_RENAME) +
|
iconBtn('rename', t('docRename'), IC_RENAME) +
|
||||||
iconBtn('delete', t('docDelete'), IC_DELETE, ' docdelbtn') +
|
iconBtn('delete', t('docDelete'), IC_DELETE, ' docdelbtn') +
|
||||||
`</span></div>`;
|
`</span></div>`;
|
||||||
@@ -3682,22 +3681,21 @@ function updateDocButtons(){
|
|||||||
speichern.title = t('docSaveFile') + (h ? '\n' + h.name : '');
|
speichern.title = t('docSaveFile') + (h ? '\n' + h.name : '');
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
/* Wiederherstellen gilt jetzt je Zeile des Menüs UND — für das aktive
|
/* Original wiederherstellen — erreichbar über den Neu-laden-Knopf der
|
||||||
Dokument — dem Neu-laden-Knopf der Titelzeile. */
|
Editor-Titelzeile und damit nur für das GEÖFFNETE mitgelieferte Dokument
|
||||||
|
(D81-Nachtrag 2): Ein ungeöffnetes zurückzusetzen, ohne zu sehen, was man
|
||||||
|
verwirft, ergäbe keinen Sinn. */
|
||||||
function restoreDoc(id){
|
function restoreDoc(id){
|
||||||
const d = docs.find(x => x.id === id);
|
const d = docs.find(x => x.id === id);
|
||||||
const shipped = d && shippedStateOf(d.id);
|
const shipped = d && shippedStateOf(d.id);
|
||||||
if(!shipped) return;
|
if(!shipped || d.id !== activeId) return;
|
||||||
if(!window.confirm(t('docRestoreConfirm', {name: d.name}))) return;
|
if(!window.confirm(t('docRestoreConfirm', {name: d.name}))) return;
|
||||||
d.text = shipped.text;
|
d.text = shipped.text;
|
||||||
d.name = shipped.name;
|
d.name = shipped.name;
|
||||||
if(d.id === activeId){
|
foldOverrides.clear();
|
||||||
foldOverrides.clear();
|
loadActiveIntoEditor();
|
||||||
loadActiveIntoEditor();
|
|
||||||
}
|
|
||||||
persistDocs();
|
persistDocs();
|
||||||
if(!docMenu.hidden) renderDocMenu();
|
if(!docMenu.hidden) renderDocMenu(); /* der Name kann sich zurückgeändert haben */
|
||||||
updateDocButtons();
|
|
||||||
}
|
}
|
||||||
/* Aus der Quelle neu laden (D81): mitgeliefert → Original wiederherstellen;
|
/* Aus der Quelle neu laden (D81): mitgeliefert → Original wiederherstellen;
|
||||||
URL-Dokument → frisch holen (die URL ist die Quelle der Wahrheit, D23);
|
URL-Dokument → frisch holen (die URL ist die Quelle der Wahrheit, D23);
|
||||||
@@ -4964,7 +4962,6 @@ docList.addEventListener('click', e => {
|
|||||||
if(!id) return;
|
if(!id) return;
|
||||||
if(akt.dataset.act === 'rename') renameDoc(id);
|
if(akt.dataset.act === 'rename') renameDoc(id);
|
||||||
else if(akt.dataset.act === 'delete') deleteDoc(id);
|
else if(akt.dataset.act === 'delete') deleteDoc(id);
|
||||||
else if(akt.dataset.act === 'restore') restoreDoc(id);
|
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
const btn = e.target.closest('.docpick');
|
const btn = e.target.closest('.docpick');
|
||||||
|
|||||||
Reference in New Issue
Block a user