change: Textfeld bricht Zeilen nicht mehr um, waagerechter Balken (D49)
Gewünscht — und damit die ausdrückliche Umkehrung der D33-Abwägung („Verworfen: wrap=off … der Umbruch ist die wichtigere Eigenschaft"). Der dort notierte Preis bleibt richtig; nicht bedacht war die andere Seite: Ein weicher Umbruch zerstört die Einrückung, und die trägt in dieser Notation die Hierarchie. Die Fortsetzung einer umbrochenen Zeile beginnt am linken Rand und sieht aus wie ein Wurzelknoten — betroffen sind genau die langen Zeilen, also die mit ID, Größe und Kommentar, seit D48 praktisch jede Zeile des Plans. Umgesetzt als `wrap="off"` am Element (Eigenschaft des Feldes, nicht seiner Gestaltung), `overflow:auto` daneben im Stylesheet. Der Spiegel musste mit: `syncMirror()` maß mit `white-space:pre-wrap` und fester Breite — genau die Kombination, die im Spiegel Zeilen umbräche, die im Textfeld ungebrochen stehen; alles darunter läge zu tief und die Zeilennummern wanderten weg. Jetzt `pre` und ohne Breitenvorgabe. Gemessen wird trotzdem weiter statt `Zeilenhöhe × n` zu rechnen: Die Schriftgröße unterscheidet sich zwischen Telefon und Schreibtisch, die Messung stimmt in beiden Fällen von selbst. Der Sprung setzt `scrollLeft` zurück. `jumpToLine()` markiert die ganze Zeile, woraufhin der Browser von sich aus an deren Ende scrollt — man landete am rechten Rand, ohne Einrückung, Zeichen und Statusbox zu sehen. Der Sprung zeigt auf eine Zeile, nicht auf ihr Ende. Nachgemessen am Plan (903 Zeilen, längste 122 Zeichen): 903 Bildzeilen zu 903 logischen Zeilen in beiden Ansichten; Schiebeweg 211 px am Schreibtisch, 432 px auf 375 px Breite; der Zeilennummern-Streifen bleibt beim waagerechten Verschieben stehen (linke Kante unverändert bei 180 px Versatz); Abweichung der Zahlen am Dateiende 2 px auf 903 Zeilen (Rundung von `offsetTop`, sammelt sich nicht auf). 236 Tests grün. SPEC §9 (Zeilennummern) und D49 halten es fest; die D33-Stelle bekommt einen Verweis, dass die Abwägung umgekehrt wurde — gelöscht wird dort nichts. Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
This commit is contained in:
co-authored by
Claude Fable 5
parent
623b68799f
commit
1b8bf06973
+21
-14
@@ -701,22 +701,23 @@ function lineRange(line){
|
||||
return {start, end: start + lines[line - 1].length};
|
||||
}
|
||||
|
||||
/* Vertikale Position eines Zeichenoffsets im Textfeld. Zeilenhöhe × n scheitert
|
||||
an weichen Umbrüchen (lange Zeilen belegen mehrere Bildzeilen), deshalb ein
|
||||
unsichtbarer Spiegel mit gleicher Typografie und Breite plus Marker-Span. */
|
||||
/* Vertikale Position eines Zeichenoffsets im Textfeld: ein unsichtbarer Spiegel
|
||||
mit gleicher Typografie plus Marker-Span.
|
||||
|
||||
Seit `wrap="off"` (D49) bricht das Textfeld nicht mehr um — der Spiegel
|
||||
deshalb ebenfalls `white-space:pre` und **ohne** vorgegebene Breite. Beides
|
||||
gehört zusammen: Eine feste Breite bei `pre-wrap` bräche im Spiegel Zeilen um,
|
||||
die im Textfeld ungebrochen stehen, und alles darunter läge zu tief.
|
||||
Gemessen wird trotzdem weiter, statt `Zeilenhöhe × n` zu rechnen — die
|
||||
Schriftgröße unterscheidet sich zwischen Telefon und Schreibtisch (D17), und
|
||||
die Messung stimmt in beiden Fällen von selbst. */
|
||||
let mirrorEl = null;
|
||||
function syncMirror(){
|
||||
if(!mirrorEl){
|
||||
mirrorEl = document.createElement('div');
|
||||
mirrorEl.setAttribute('aria-hidden', 'true');
|
||||
/* `box-sizing:border-box` ist Pflicht: `src.clientWidth` **enthält** die
|
||||
Innenabstände. Ohne das ist der Spiegel um genau diese 32 px breiter als
|
||||
das Textfeld und bricht später um — lange Zeilen landeten dadurch zu weit
|
||||
oben (fiel beim Bau der Zeilennummern auf, D33; betraf auch schon das
|
||||
Scrollen beim Sprung, D25). */
|
||||
mirrorEl.style.cssText = 'position:absolute;visibility:hidden;top:0;left:-9999px;' +
|
||||
'box-sizing:border-box;' +
|
||||
'white-space:pre-wrap;overflow-wrap:break-word;';
|
||||
'box-sizing:border-box;white-space:pre;';
|
||||
document.body.appendChild(mirrorEl);
|
||||
}
|
||||
const cs = getComputedStyle(src);
|
||||
@@ -724,7 +725,6 @@ function syncMirror(){
|
||||
'paddingTop','paddingLeft','paddingRight','borderTopWidth','tabSize']){
|
||||
mirrorEl.style[p] = cs[p];
|
||||
}
|
||||
mirrorEl.style.width = src.clientWidth + 'px';
|
||||
return mirrorEl;
|
||||
}
|
||||
const ZWSP = '';
|
||||
@@ -804,9 +804,11 @@ function markCurrentLineNo(){
|
||||
if(s) s.classList.add('cur');
|
||||
}
|
||||
src.addEventListener('scroll', syncLineNoScroll);
|
||||
/* Der Umbruch hängt an der Breite: Splitter, Fenster, Drehung, Tastatur. Beim
|
||||
Ziehen am Splitter kämen sonst je Bild mehrere Messungen — einmal je Bild
|
||||
genügt. */
|
||||
/* Seit D49 hängen die Zeilenhöhen nicht mehr an der Breite (es wird nicht mehr
|
||||
umbrochen), wohl aber an der Schriftgröße — und die wechselt beim Übergang
|
||||
zwischen Telefon und Schreibtisch (D17), den der Beobachter als
|
||||
Größenänderung mitbekommt. Beim Ziehen am Splitter kämen sonst je Bild
|
||||
mehrere Messungen; einmal je Bild genügt. */
|
||||
let lineNoPending = false;
|
||||
if(window.ResizeObserver) new ResizeObserver(() => {
|
||||
if(lineNoPending) return;
|
||||
@@ -868,6 +870,11 @@ function jumpToLine(line){
|
||||
src.focus({preventScroll: true});
|
||||
src.setSelectionRange(r.start, r.end);
|
||||
scrollEditorToOffset(r.start);
|
||||
/* Ohne Umbruch (D49) scrollt der Browser beim Markieren einer langen Zeile
|
||||
bis an ihr **Ende** — man landete am rechten Rand und sähe den Anfang der
|
||||
Zeile nicht, also gerade Einrückung, Zeichen und Statusbox. Der Sprung
|
||||
zeigt auf eine Zeile, nicht auf ihr Ende. */
|
||||
src.scrollLeft = 0;
|
||||
caretLine = line;
|
||||
highlightCurrentNode(true);
|
||||
}
|
||||
|
||||
+12
-4
@@ -467,9 +467,13 @@
|
||||
.docdel:hover{border-color:#D897A8;color:#B4415E}
|
||||
.togglebtn[aria-pressed="true"]{background:var(--or);color:#fff;border-color:var(--or)}
|
||||
.togglebtn[aria-pressed="true"]:hover{color:#fff}
|
||||
/* Kein Zeilenumbruch (D49, `wrap="off"` am Element): Die Einrückung trägt die
|
||||
Hierarchie, und ein weicher Umbruch setzt die Fortsetzung an den linken Rand
|
||||
— die Ebene wäre damit gerade dort nicht mehr abzulesen, wo eine Zeile lang
|
||||
ist. Lange Zeilen bekommen stattdessen einen waagerechten Balken. */
|
||||
textarea{
|
||||
display:block;width:100%;min-height:0;
|
||||
border:0;outline:none;resize:none;
|
||||
border:0;outline:none;resize:none;overflow:auto;
|
||||
padding:14px 16px;
|
||||
font-family:'IBM Plex Mono',monospace;
|
||||
font-size:.85rem;line-height:1.7;
|
||||
@@ -482,9 +486,13 @@
|
||||
ist der Hauptinhalt und kein ausgegrautes Formularfeld. */
|
||||
textarea.readonly{background:#F1F4F7;cursor:default}
|
||||
/* Zeilennummern (D33). Die Warnungen nennen Zeilennummern — ohne Streifen
|
||||
muss man sie im Textfeld abzählen. Weich umbrochene Zeilen belegen mehrere
|
||||
Bildzeilen, deshalb steht jede Zahl auf einer **gemessenen** Höhe
|
||||
(`renderLineNos()` in app.js), nicht auf „Zeilenhöhe × n". Typografie muss
|
||||
muss man sie im Textfeld abzählen. Jede Zahl steht auf einer **gemessenen**
|
||||
Höhe (`renderLineNos()` in app.js), nicht auf „Zeilenhöhe × n"; seit D49
|
||||
bricht nichts mehr um, aber die Schriftgröße unterscheidet sich zwischen
|
||||
Telefon und Schreibtisch, und die Messung stimmt in beiden Fällen von
|
||||
selbst. Der Streifen scrollt **nur senkrecht** mit: Er verschiebt sich
|
||||
gegen `src.scrollTop`, den waagerechten Balken des Textfelds macht er
|
||||
nicht mit — die Zahlen bleiben stehen, wo sie hingehören. Typografie muss
|
||||
mit dem Textfeld übereinstimmen, sonst wandern die Zahlen weg. */
|
||||
.lineno{
|
||||
position:relative;overflow:hidden;flex:0 0 auto;
|
||||
|
||||
Reference in New Issue
Block a user