Files
2026-06-30 21:31:35 +02:00

66 lines
1.9 KiB
JavaScript

import { escapeChar } from "./html.js";
function bufferColToDomOffset(lineText, col) {
let offset = 0;
for (let i = 0; i < col && i < lineText.length; i++)
offset += escapeChar(lineText[i]).length;
return offset;
}
function findTextNode(parent, targetOffset) {
let remaining = targetOffset;
const walker = document.createTreeWalker(parent, NodeFilter.SHOW_TEXT);
let node;
while ((node = walker.nextNode())) {
if (remaining <= node.textContent.length)
return { node, offset: remaining };
remaining -= node.textContent.length;
}
return { node: parent, offset: parent.childNodes.length };
}
function posToElement(line, col, buffer) {
const spans = document.querySelectorAll("#text > span");
if (line >= spans.length) return null;
const span = spans[line];
const range = document.createRange();
const lineText = buffer[line] || "";
const offset = bufferColToDomOffset(lineText, col);
const tn = findTextNode(span, offset);
range.setStart(tn.node, tn.offset);
range.collapse(true);
const rect = range.getBoundingClientRect();
return { x: rect.left, y: rect.top, height: rect.height };
}
export function elementToPos(x, y, buffer) {
const spans = document.querySelectorAll("#text > span");
let bestLine = 0;
let bestDistY = Infinity;
for (let i = 0; i < spans.length; i++) {
const rect = spans[i].getBoundingClientRect();
const midY = rect.top + rect.height / 2;
const distY = Math.abs(y - midY);
if (distY < bestDistY) {
bestDistY = distY;
bestLine = i;
}
}
let bestCol = 0;
let bestDistX = Infinity;
const lineText = buffer[bestLine] || "";
for (let c = 0; c <= lineText.length; c++) {
const pos = posToElement(bestLine, c, buffer);
if (!pos) continue;
const dist = Math.abs(x - pos.x);
if (dist < bestDistX) {
bestDistX = dist;
bestCol = c;
}
}
return { line: bestLine, col: bestCol };
}