286513def8
- Slug transliteriert Umlaute/ß (fuer statt f-r); aktiver Tab mit Akzent + Unterstrich; kein aktiver Tab bei zugeklapptem Panel (mode.clear) - Suche: Live-Update auch beim Löschen (<3 Zeichen: Hinweis), #tag-Filter in der Query, Treffer öffnen im Dokument-Tab (panel_load, ohne Frontmatter); Wiki-Sprung-Button im Dokument; Wiki-Fehler sichtbar als Toast - Archiv-Formular am Archiv-Button (Ordner/Beschreibung/Schlagwörter); panel_archive_cmd nimmt Meta entgegen - Wiki-Übersicht: Zuletzt-Sektion, Backlink-Zähler, Wurzel-Eyebrow - Themes: Panel-Farben über CSS-Variablen, applyTheme leitet sie aus dem jeweiligen Theme ab (auch helle); gemeinsames themes.ts - Fenster: Doppelklick maximiert; gelöstes Fenster merkt Größe/Position (Window-ACL: set-position/outer-position/inner-size ergänzt); open_panel_window async (GTK-Deadlock-Vorgabe); Panel-Fenster spiegelt JS-Fehler ins Dev-Log - Archiv pro Projekt wähl-/abwählbar (Einstellungsdialog, setzt/entfernt Permissions); require_archive_home legt den Ordner an; ohne Archiv nur Befehle+Dokument im Panel - Frontend-Tests: vitest + happy-dom, 27 Tests über Modus-, Such-, Wiki-, Editor- und Formular-Logik (npm test)
69 lines
2.5 KiB
TypeScript
69 lines
2.5 KiB
TypeScript
// Dokument-Ansicht: Wikilink-Verlinkung im DOM und Editor-Flush.
|
|
import { describe, expect, it, vi } from "vitest";
|
|
import { initPanelView, linkWikiRefs } from "./panel-view";
|
|
|
|
describe("linkWikiRefs", () => {
|
|
it("verlinkt [[ziel]] und [[ziel|Label]], Code bleibt unangetastet", () => {
|
|
const root = document.createElement("div");
|
|
root.innerHTML =
|
|
"<p>Siehe [[adr-logging]] und [[notiz|die Notiz]].</p>" +
|
|
"<pre><code>if [[ -f x ]]; then</code></pre>";
|
|
const onClick = vi.fn();
|
|
linkWikiRefs(root, onClick);
|
|
const links = [...root.querySelectorAll<HTMLElement>("a.wiki")];
|
|
expect(links.map((a) => a.textContent)).toEqual(["adr-logging", "die Notiz"]);
|
|
links[1].click();
|
|
expect(onClick).toHaveBeenCalledWith("notiz");
|
|
expect(root.querySelector("code")!.textContent).toBe("if [[ -f x ]]; then");
|
|
});
|
|
});
|
|
|
|
function viewSetup(onCommit: (text: string) => void | Promise<void>) {
|
|
document.body.innerHTML = `
|
|
<div id="content"></div>
|
|
<button id="copy"></button>
|
|
<button id="mode"></button>
|
|
<button id="edit"></button>`;
|
|
const view = initPanelView({
|
|
content: document.getElementById("content")!,
|
|
copyBtn: document.getElementById("copy")!,
|
|
modeBtn: document.getElementById("mode")!,
|
|
editContentBtn: document.getElementById("edit")!,
|
|
onCommit,
|
|
});
|
|
const editor = document.querySelector<HTMLTextAreaElement>(".panel-editor")!;
|
|
return { view, editor, editBtn: document.getElementById("edit")! };
|
|
}
|
|
|
|
describe("initPanelView — Editor", () => {
|
|
it("flush speichert eine offene Bearbeitung und beendet sie", async () => {
|
|
const onCommit = vi.fn();
|
|
const { view, editor, editBtn } = viewSetup(onCommit);
|
|
view.set("Alt");
|
|
editBtn.click();
|
|
expect(editor.hidden).toBe(false);
|
|
editor.value = "Neu";
|
|
await view.flush();
|
|
expect(onCommit).toHaveBeenCalledWith("Neu");
|
|
expect(editor.hidden).toBe(true);
|
|
});
|
|
|
|
it("flush ohne offene Bearbeitung tut nichts", async () => {
|
|
const onCommit = vi.fn();
|
|
const { view } = viewSetup(onCommit);
|
|
view.set("Alt");
|
|
await view.flush();
|
|
expect(onCommit).not.toHaveBeenCalled();
|
|
});
|
|
|
|
it("puffert eingehende Updates während der Bearbeitung", () => {
|
|
const { view, editor, editBtn } = viewSetup(() => {});
|
|
view.set("Alt");
|
|
editBtn.click();
|
|
view.set("Update von außen");
|
|
expect(editBtn.classList.contains("changed")).toBe(true);
|
|
editor.dispatchEvent(new KeyboardEvent("keydown", { key: "Escape" }));
|
|
expect(view.raw()).toBe("Update von außen");
|
|
});
|
|
});
|