feat: Cursor in einer Beschreibung wählt ihren Knoten aus

Bisher fiel die Hervorhebung weg, sobald der Cursor von der Knotenzeile auf die
`"`-Zeile darunter rückte: Die trägt keinen Knoten, also fand die Zeilensuche
nichts. Falsche Auskunft — sie trägt keinen EIGENEN Knoten, gehört aber zu
einem, und wer in ihr schreibt, arbeitet an genau diesem.

Gilt für beide Formen, nicht nur die Kurzform: Die Zuordnung entsteht an
derselben Stelle im Parser, an der auch die `---`-Blöcke landen, und dort trägt
die Begründung sogar weiter — der Langtext steht am Dateiende, weit weg von
seinem Knoten. Zugeordnet werden Textzeilen, Block-Kopfzeile (sie nennt den
Knoten) und Leerzeilen innerhalb eines Blocks; nicht der `---`-Trenner und
nichts unter unbekannter ID.

`node.descLines` entsteht im Parser, der Renderer gibt sie als
`data-desc-lines="3 4 5"` aus, app.js trifft sie per `[data-desc-lines~="N"]`.
Bewusst getrennt von `descLines` (dem Text): Dort fallen Leerzeilen zu einem
Absatztrenner zusammen und Blocktext unter unbekannter ID kommt gar nicht an.

Beide Richtungen gehen jetzt über eine Auflösung (`nodeOfLine()`) — sonst wäre
der ausdrückliche Alt+Klick aus einer Beschreibung heraus stumm geblieben, und
das ist gerade der Ort, an dem man ihn braucht.

5 neue Tests (204 gesamt). SPEC §9 und D40 (Nachtrag 2) nachgezogen.

Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
This commit is contained in:
mhoennig
2026-08-23 08:01:56 +02:00
co-authored by Claude Fable 5
parent e223734d58
commit 24a70ca49e
7 changed files with 122 additions and 13 deletions
+7 -2
View File
@@ -99,6 +99,11 @@ function nodeHtml(n, extra, opts, fold){
Querverbindungs-Ebene und den Export — beide arbeiten auf dem DOM. */
const idAttr = n.id ? ` data-id="${attr(n.id)}"` : '';
const depsAttr = n.deps && n.deps.length ? ` data-deps="${attr(n.deps.join(' '))}"` : '';
/* Zeilen der Beschreibung (SPEC §9): Steht der Cursor dort, gilt dieser
Knoten als ausgewählt — die Zeile hat keinen eigenen. Als Liste, damit
der Attribut-Selektor `~=` sie einzeln trifft. */
const descLinesAttr = n.descLines && n.descLines.length
? ` data-desc-lines="${attr(n.descLines.join(' '))}"` : '';
/* Tooltip: erst die Beschreibung (mehrzeilig, D40), dann die Kurz-Fakten.
Die Fakten hängen NICHT mit ` · ` an den Fließtext an — sie sind eine
andere Art von Aussage, und in der einen Zeile ging der Übergang unter
@@ -156,8 +161,8 @@ function nodeHtml(n, extra, opts, fold){
ownChip;
const aria = ` aria-label="${attr(nodeAria(n, opts, fold))}"`;
const html = n.url
? `<a class="${cls}" href="${attr(n.url)}" target="_blank" rel="noopener"${lineAttr}${idAttr}${depsAttr}${aria}${expanded}${title}>${inner}</a>`
: `<div class="${cls}" tabindex="0"${lineAttr}${idAttr}${depsAttr}${aria}${expanded}${title}>${inner}</div>`;
? `<a class="${cls}" href="${attr(n.url)}" target="_blank" rel="noopener"${lineAttr}${idAttr}${depsAttr}${descLinesAttr}${aria}${expanded}${title}>${inner}</a>`
: `<div class="${cls}" tabindex="0"${lineAttr}${idAttr}${depsAttr}${descLinesAttr}${aria}${expanded}${title}>${inner}</div>`;
const ghostTip = attr(t('ghostTooltip'));
const ghost = `<div class="ghost-node" aria-label="${ghostTip}" title="${ghostTip}">${esc(t('ghost'))}</div>`;
return html + (need ? ghost : '');