diff --git a/internal/web/static/app.css b/internal/web/static/app.css index bdba0f8..f5543da 100644 --- a/internal/web/static/app.css +++ b/internal/web/static/app.css @@ -603,6 +603,10 @@ a.admin-link:hover { color: var(--fg); text-decoration: underline; } .editor-wrap { min-height: 45vh; } .editor { font-size: 15px; } .gutter { font-size: 15px; } + /* #167: the paste-view gutter must track .code's font size, not the editor + gutter's — mismatched font sizes make gutline rows taller/shorter than + code rows and every number drifts off its line start */ + .code .gutter { font-size: var(--code-fs); } .editor-head { flex-wrap: wrap; } .editor-head-title { flex: 1 1 100%; } .editor-head input { min-width: 0; font-size: 16px; } diff --git a/internal/web/static/paste-lines.js b/internal/web/static/paste-lines.js index a71d8ba..4d9e7d6 100644 --- a/internal/web/static/paste-lines.js +++ b/internal/web/static/paste-lines.js @@ -54,7 +54,16 @@ // is closest to its line's top. var bodyTop = body.getBoundingClientRect().top; var lh = parseFloat(getComputedStyle(body).lineHeight) || 1; - var totalRows = Math.max(lines.length, Math.ceil(body.getBoundingClientRect().height / lh)); + var maxBottom = 0; + for (var j = 0; j < lines.length; j++) { + var btm = lines[j].getBoundingClientRect().bottom - bodyTop; + if (btm > maxBottom) maxBottom = btm; + } + // Rows needed through the last visual row of the deepest line (ceil, so a + // partially-filled last row still gets its gutter span). + // Rows needed: floor(last line bottom / lh) + 1 — the row a line STARTS on + // must exist even when its bottom lands exactly on the body's edge. + var totalRows = Math.max(lines.length, Math.floor(maxBottom / lh) + 1); gutter.textContent = ''; var frag = document.createDocumentFragment(); var spans = []; @@ -97,7 +106,7 @@ // size change (paste of lots of text, window resize, zoom). Only width // changes of the code column affect wrapping, so observe width only — // height changes caused by our own renumbering must not re-trigger. - var mo = new MutationObserver(renumber); + var mo = new MutationObserver(function () { setTimeout(renumber, 0); }); mo.observe(document.documentElement, { attributes: true, attributeFilter: ['data-wrap'] }); var lastW = body.getBoundingClientRect().width; if (window.ResizeObserver) {