Fix #167 r2: gutter rows align with wrapped visual rows #193
@@ -1,7 +1,13 @@
|
||||
// #167: with line wrapping on, a logical line can occupy several visual
|
||||
// lines; the gutter must show one number per VISUAL line. Per-line spans
|
||||
// give each logical line its own box so offsetTop order stays correct even
|
||||
// when highlighting spans cross no line boundaries.
|
||||
// lines; the gutter must show one number per logical line, aligned with its
|
||||
// FIRST visual row, and blank rows below it so later numbers don't drift.
|
||||
//
|
||||
// Row accounting must be based on actual rendered geometry, not per-span
|
||||
// height: in a pre-wrap container the newline text nodes BETWEEN the
|
||||
// .codeline blocks each render as their own anonymous-block row, so a
|
||||
// logical line's visual footprint is (next line's top - this line's top),
|
||||
// not this line's own box height. Measuring the gap between consecutive
|
||||
// line tops captures both the wrapped rows and the newline row.
|
||||
(function () {
|
||||
var body = document.getElementById('codebody');
|
||||
var gutter = document.getElementById('gutter');
|
||||
@@ -28,21 +34,32 @@
|
||||
var lines = body.querySelectorAll('.codeline');
|
||||
var s = '';
|
||||
if (wrapOn() && lines.length) {
|
||||
// Each logical line block occupies rows = height / line-height when
|
||||
// wrapped; its number sits on the first row and the remaining rows get
|
||||
// blank gutter lines so numbers stay aligned with line starts.
|
||||
// The code column width must not change while measuring (the gutter is
|
||||
// flex-shrink:0 so its own row count never affects it), and renumber
|
||||
// must be idempotent to avoid a ResizeObserver feedback loop.
|
||||
// Rows per logical line = rendered vertical gap to the next line's
|
||||
// first row (wrapped rows + the pre-wrap newline row between blocks),
|
||||
// divided by line-height. The last line has no following newline, so
|
||||
// its own box height is correct. The code column width must not
|
||||
// change while measuring (the gutter is flex-shrink:0 so its own row
|
||||
// count never affects it), and renumber must be idempotent to avoid a
|
||||
// ResizeObserver feedback loop: only width changes re-trigger it.
|
||||
var lh = parseFloat(getComputedStyle(body).lineHeight) || 1;
|
||||
var tops = [];
|
||||
for (var i = 0; i < lines.length; i++) {
|
||||
tops.push(lines[i].getBoundingClientRect().top);
|
||||
}
|
||||
gutter.textContent = '';
|
||||
var frag = document.createDocumentFragment();
|
||||
for (var i = 0; i < lines.length; i++) {
|
||||
for (var j = 0; j < lines.length; j++) {
|
||||
var span;
|
||||
if (j < lines.length - 1) {
|
||||
span = tops[j + 1] - tops[j];
|
||||
} else {
|
||||
span = lines[j].getBoundingClientRect().height;
|
||||
}
|
||||
var rows = Math.max(1, Math.round(span / lh));
|
||||
var num = document.createElement('span');
|
||||
num.className = 'gutline';
|
||||
num.textContent = String(i + 1);
|
||||
num.textContent = String(j + 1);
|
||||
frag.appendChild(num);
|
||||
var rows = Math.max(1, Math.round(lines[i].getBoundingClientRect().height / lh));
|
||||
for (var r = 1; r < rows; r++) {
|
||||
var blank = document.createElement('span');
|
||||
blank.className = 'gutline';
|
||||
|
||||
Reference in New Issue
Block a user