feat: „Original wiederherstellen" im Dokumenten-Menü (D22-Nachtrag)
Auf der Prod-Instanz gab es keinen Weg, ein bearbeitetes mitgeliefertes Dokument wieder auf den Auslieferungsstand zu bringen — der Reset ist ein Debug-Knopf, und das Fingerabdruck-Nachziehen (D27) fasst bearbeitete Texte nie an. Stilles Überschreiben beim Laden wäre überraschender Datenverlust (verworfen); stattdessen ein Menü-Eintrag, sichtbar nur für mitgelieferte Dokumente und nur bei Abweichung vom Auslieferungsstand, mit Rückfrage. Stellt Text und Name wieder her, verwirft Falt-Eingriffe. i18n in allen 9 Sprachen; im Browser durchgespielt (erscheint nach Edit, stellt her, verschwindet wieder). Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
This commit is contained in:
co-authored by
Claude Fable 5
parent
7eebc985b1
commit
ea2c7eef4a
@@ -387,6 +387,21 @@ Die GUI-Ansichts-Einstellungen (Modus, Zoom, Aufteilung; `werkbaum-ui`) bleiben
|
||||
bewusst **global** über alle Dokumente — pro-Dokument-Ansichtszustand wäre eine
|
||||
spätere Erweiterung.
|
||||
|
||||
**Nachtrag — „Original wiederherstellen“ ist jetzt ein Produkt-Feature im
|
||||
Dokumenten-Menü.** Auslöser: Auf der Prod-Instanz gab es **keinen** Weg, ein
|
||||
bearbeitetes mitgeliefertes Dokument wieder auf den Auslieferungsstand zu
|
||||
bringen — der Reset ist ein Debug-Knopf außerhalb des Prod-Builds, und das
|
||||
Fingerabdruck-Nachziehen (D27) fasst bearbeitete Texte grundsätzlich nicht an.
|
||||
Wer im Beispiel herumprobiert hatte, sah neue Beispiel-Fassungen also nie.
|
||||
Erwogen und **verworfen**: die Alternative, dass eine neue Fassung lokale
|
||||
Änderungen still überschreibt — das wäre überraschender Datenverlust und
|
||||
bräche die D22/D27-Linie („bearbeitete Inhalte nie anfassen“). Stattdessen ein
|
||||
Menü-Eintrag, sichtbar nur für die **mitgelieferten** Dokumente und nur, wenn
|
||||
Text oder Name vom Auslieferungsstand abweichen; mit Rückfrage, die den
|
||||
Verlust benennt. Wiederhergestellt werden Text **und** Name (der Eintrag sagt
|
||||
„Original“); Falt-Eingriffe werden mit verworfen. Der Debug-Reset bleibt
|
||||
daneben bestehen — er setzt zusätzlich Einstellungen und Merker zurück.
|
||||
|
||||
## D23 — Notationstext per `?sourceUrl=` von einer URL laden
|
||||
Der Editor kann den Notationstext aus einer **externen Textdatei** beziehen:
|
||||
`…/index.html?sourceUrl=https://example.org/plan.txt`. Damit lässt sich ein
|
||||
|
||||
@@ -58,6 +58,7 @@
|
||||
- [^] Several documents in one editor (M)
|
||||
- [^] Switcher in the editor title bar (S)
|
||||
- [^] Load a document from ?sourceUrl= (S)
|
||||
- [x] Restore a shipped document from the menu (XS)
|
||||
- [^] Jump between diagram and text (S)
|
||||
- [^] Line numbers in the text editor (XS) %% the warnings name them
|
||||
- [^] Collapsible subtrees (M)
|
||||
|
||||
+4
-1
@@ -105,7 +105,10 @@ verworfene Elemente. Quelle sind ES-Module unter `src/`; `index.html` ist der
|
||||
`text === INITIAL` (nie echte Nutzerinhalte). Eine neue INITIAL-Fassung wird
|
||||
wie beim Werkbaum-Dokument per Fingerabdruck nachgezogen
|
||||
(`werkbaum-seeded-example`, D27-Nachtrag) — nur bei unverändertem Text; der
|
||||
Reset setzt beide Merker. `resetToDefaults()` setzt **nur**
|
||||
Reset setzt beide Merker. Bearbeitete mitgelieferte Dokumente holt der
|
||||
Nutzer über „Original wiederherstellen" im Dokumenten-Menü zurück
|
||||
(`restoreDoc()`, D22-Nachtrag) — sichtbar nur bei Abweichung vom
|
||||
Auslieferungsstand, stellt Text UND Name wieder her. `resetToDefaults()` setzt **nur**
|
||||
das Beispiel-Dokument (id `example`) auf `INITIAL`/„Example" zurück und verwirft
|
||||
`werkbaum-ui`/`werkbaum-lang`/Update-Flags — **andere Dokumente bleiben stehen**
|
||||
(nicht mehr pauschal alle `werkbaum-*` löschen!). Das letzte gelöschte Dokument
|
||||
|
||||
@@ -55,6 +55,7 @@
|
||||
<div class="docmenu-actions">
|
||||
<button type="button" class="docact" id="docNew" data-i18n="docNew">Neues Dokument</button>
|
||||
<button type="button" class="docact" id="docRename" data-i18n="docRename">Umbenennen</button>
|
||||
<button type="button" class="docact" id="docRestore" data-i18n="docRestore" hidden>Original wiederherstellen</button>
|
||||
<button type="button" class="docact docdel" id="docDelete" data-i18n="docDelete">Löschen</button>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
+48
-1
@@ -1273,6 +1273,8 @@ const I18N = {
|
||||
docNew:"Neues Dokument", docRename:"Umbenennen", docDelete:"Löschen",
|
||||
docNewName:"Unbenannt",
|
||||
docDeleteConfirm:"Dokument „{name}“ löschen?",
|
||||
docRestore:"Original wiederherstellen",
|
||||
docRestoreConfirm:"„{name}“ auf den mitgelieferten Stand zurücksetzen? Eigene Änderungen gehen verloren.",
|
||||
copy:"kopieren", copyDone:"kopiert ✓", copyTooltip:"Text in die Zwischenablage kopieren",
|
||||
copyDiagramTooltip:"Diagramm als PNG-Bild in die Zwischenablage kopieren",
|
||||
downloadDiagramTooltip:"Diagramm als SVG-Datei herunterladen (z. B. für LibreOffice: Einfügen → Bild)",
|
||||
@@ -1349,6 +1351,8 @@ const I18N = {
|
||||
docNew:"New document", docRename:"Rename", docDelete:"Delete",
|
||||
docNewName:"Untitled",
|
||||
docDeleteConfirm:"Delete document “{name}”?",
|
||||
docRestore:"Restore original",
|
||||
docRestoreConfirm:"Reset “{name}” to the shipped version? Your changes will be lost.",
|
||||
copy:"copy", copyDone:"copied ✓", copyTooltip:"Copy text to clipboard",
|
||||
copyDiagramTooltip:"Copy diagram as a PNG image to the clipboard",
|
||||
downloadDiagramTooltip:"Download diagram as an SVG file (e.g. for LibreOffice: Insert → Image)",
|
||||
@@ -1425,6 +1429,8 @@ const I18N = {
|
||||
docNew:"Nuevo documento", docRename:"Renombrar", docDelete:"Eliminar",
|
||||
docNewName:"Sin título",
|
||||
docDeleteConfirm:"¿Eliminar el documento «{name}»?",
|
||||
docRestore:"Restaurar original",
|
||||
docRestoreConfirm:"¿Restablecer «{name}» a la versión incluida? Tus cambios se perderán.",
|
||||
copy:"copiar", copyDone:"copiado ✓", copyTooltip:"Copiar el texto al portapapeles",
|
||||
copyDiagramTooltip:"Copiar el diagrama como imagen PNG al portapapeles",
|
||||
downloadDiagramTooltip:"Descargar el diagrama como archivo SVG (p. ej. para LibreOffice: Insertar → Imagen)",
|
||||
@@ -1501,6 +1507,8 @@ const I18N = {
|
||||
docNew:"Nouveau document", docRename:"Renommer", docDelete:"Supprimer",
|
||||
docNewName:"Sans titre",
|
||||
docDeleteConfirm:"Supprimer le document « {name} » ?",
|
||||
docRestore:"Restaurer l’original",
|
||||
docRestoreConfirm:"Réinitialiser « {name} » à la version livrée ? Vos modifications seront perdues.",
|
||||
copy:"copier", copyDone:"copié ✓", copyTooltip:"Copier le texte dans le presse-papiers",
|
||||
copyDiagramTooltip:"Copier le diagramme comme image PNG dans le presse-papiers",
|
||||
downloadDiagramTooltip:"Télécharger le diagramme en fichier SVG (p. ex. pour LibreOffice : Insertion → Image)",
|
||||
@@ -1577,6 +1585,8 @@ const I18N = {
|
||||
docNew:"Nowy dokument", docRename:"Zmień nazwę", docDelete:"Usuń",
|
||||
docNewName:"Bez nazwy",
|
||||
docDeleteConfirm:"Usunąć dokument „{name}”?",
|
||||
docRestore:"Przywróć oryginał",
|
||||
docRestoreConfirm:"Przywrócić „{name}” do dostarczonej wersji? Twoje zmiany zostaną utracone.",
|
||||
copy:"kopiuj", copyDone:"skopiowano ✓", copyTooltip:"Kopiuj tekst do schowka",
|
||||
copyDiagramTooltip:"Kopiuj diagram jako obraz PNG do schowka",
|
||||
downloadDiagramTooltip:"Pobierz diagram jako plik SVG (np. dla LibreOffice: Wstaw → Obraz)",
|
||||
@@ -1653,6 +1663,8 @@ const I18N = {
|
||||
docNew:"Новый документ", docRename:"Переименовать", docDelete:"Удалить",
|
||||
docNewName:"Без названия",
|
||||
docDeleteConfirm:"Удалить документ «{name}»?",
|
||||
docRestore:"Восстановить оригинал",
|
||||
docRestoreConfirm:"Вернуть «{name}» к поставляемой версии? Ваши изменения будут потеряны.",
|
||||
copy:"копировать", copyDone:"скопировано ✓", copyTooltip:"Скопировать текст в буфер обмена",
|
||||
copyDiagramTooltip:"Скопировать диаграмму как изображение PNG в буфер обмена",
|
||||
downloadDiagramTooltip:"Скачать диаграмму как файл SVG (напр. для LibreOffice: Вставка → Изображение)",
|
||||
@@ -1729,6 +1741,8 @@ const I18N = {
|
||||
docNew:"नया दस्तावेज़", docRename:"नाम बदलें", docDelete:"हटाएँ",
|
||||
docNewName:"बिना शीर्षक",
|
||||
docDeleteConfirm:"दस्तावेज़ „{name}“ हटाएँ?",
|
||||
docRestore:"मूल पुनर्स्थापित करें",
|
||||
docRestoreConfirm:"„{name}“ को मूल संस्करण पर लौटाएँ? आपके परिवर्तन खो जाएँगे।",
|
||||
copy:"कॉपी करें", copyDone:"कॉपी हो गया ✓", copyTooltip:"टेक्स्ट को क्लिपबोर्ड पर कॉपी करें",
|
||||
copyDiagramTooltip:"आरेख को PNG छवि के रूप में क्लिपबोर्ड पर कॉपी करें",
|
||||
downloadDiagramTooltip:"आरेख को SVG फ़ाइल के रूप में डाउनलोड करें (जैसे LibreOffice: सम्मिलित करें → छवि)",
|
||||
@@ -1805,6 +1819,8 @@ const I18N = {
|
||||
docNew:"新建文档", docRename:"重命名", docDelete:"删除",
|
||||
docNewName:"未命名",
|
||||
docDeleteConfirm:"删除文档“{name}”?",
|
||||
docRestore:"恢复原始版本",
|
||||
docRestoreConfirm:"将“{name}”重置为随附版本?您的更改将丢失。",
|
||||
copy:"复制", copyDone:"已复制 ✓", copyTooltip:"将文本复制到剪贴板",
|
||||
copyDiagramTooltip:"将图表作为 PNG 图片复制到剪贴板",
|
||||
downloadDiagramTooltip:"将图表下载为 SVG 文件(例如用于 LibreOffice:插入 → 图像)",
|
||||
@@ -1881,6 +1897,8 @@ const I18N = {
|
||||
docNew:"新規ドキュメント", docRename:"名前を変更", docDelete:"削除",
|
||||
docNewName:"無題",
|
||||
docDeleteConfirm:"ドキュメント「{name}」を削除しますか?",
|
||||
docRestore:"オリジナルを復元",
|
||||
docRestoreConfirm:"「{name}」を同梱版に戻しますか?変更内容は失われます。",
|
||||
copy:"コピー", copyDone:"コピーしました ✓", copyTooltip:"テキストをクリップボードにコピー",
|
||||
copyDiagramTooltip:"ダイアグラムを PNG 画像としてクリップボードにコピー",
|
||||
downloadDiagramTooltip:"ダイアグラムを SVG ファイルとしてダウンロード(例:LibreOffice の 挿入 → 画像)",
|
||||
@@ -2275,7 +2293,35 @@ function renderDocMenu(){
|
||||
}
|
||||
}
|
||||
}
|
||||
function openDocMenu(){ renderDocMenu(); docMenu.hidden = false; docTrigger.setAttribute('aria-expanded', 'true'); }
|
||||
/* „Original wiederherstellen" (D22-Nachtrag): nur für die mitgelieferten
|
||||
Dokumente, und nur wenn sie vom Auslieferungsstand abweichen — der einzige
|
||||
Weg auf der Prod-Instanz (ohne Debug-Reset), ein bearbeitetes Beispiel
|
||||
wieder frisch zu bekommen. Bewusste Handlung mit Rückfrage statt stillem
|
||||
Überschreiben beim Laden (D22/D27: bearbeitete Inhalte nie anfassen). */
|
||||
function shippedStateOf(id){
|
||||
if(id === EXAMPLE_ID) return {name: EXAMPLE_NAME, text: INITIAL};
|
||||
if(id === WERKBAUM_ID) return {name: WERKBAUM_NAME, text: WERKBAUM_DOC};
|
||||
return null;
|
||||
}
|
||||
function updateRestoreBtn(){
|
||||
const d = activeDoc();
|
||||
const shipped = d && shippedStateOf(d.id);
|
||||
document.getElementById('docRestore').hidden =
|
||||
!shipped || (d.text === shipped.text && d.name === shipped.name);
|
||||
}
|
||||
function restoreDoc(){
|
||||
const d = activeDoc();
|
||||
const shipped = d && shippedStateOf(d.id);
|
||||
if(!shipped) return;
|
||||
if(!window.confirm(t('docRestoreConfirm', {name: d.name}))) return;
|
||||
d.text = shipped.text;
|
||||
d.name = shipped.name;
|
||||
foldOverrides.clear();
|
||||
loadActiveIntoEditor();
|
||||
persistDocs();
|
||||
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 toggleDocMenu(){ docMenu.hidden ? openDocMenu() : closeDocMenu(); }
|
||||
/* Beim Wechseln/Anlegen/Löschen zuerst den aktuellen Editortext ins aktive
|
||||
@@ -2706,6 +2752,7 @@ docList.addEventListener('click', e => {
|
||||
document.getElementById('docNew').addEventListener('click', e => { e.stopPropagation(); newDoc(); renderDocMenu(); });
|
||||
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(); });
|
||||
/* Klick außerhalb schließt das Menü. */
|
||||
document.addEventListener('click', e => {
|
||||
if(!docMenu.hidden && !docMenu.contains(e.target) && !docTrigger.contains(e.target)) closeDocMenu();
|
||||
|
||||
Reference in New Issue
Block a user