feat(web): PDF adjust v2 — re-selection replaces the extent; vertical grip clamp
Multi-line partial extents ("line 1's tail + the first words of line
2") were inexpressible with one-rect-per-drag grips, and the vertical
drags produced sliver rects whose text recompute swept fragments. The
web's re-selection uses what creation already uses: a selection made
during a rect-edge session is intercepted in checkPDFSelectionFor —
rects rebuild from the selection's per-line client rects, text re-reads
via the deduped glyph boxes, saved immediately (grip release-to-save
parity), and the create popover is suppressed for that gesture.
Vertical grip drags clamp to the rect's OWN line box (band ±quarter
height) — multi-line changes go through re-selection, slivers are gone.
Also verifies clean under the duplicated text-layer span sets (the
fork's pdf.js render never clears .textLayer — open bug): the text
recompute dedupes by glyph overlap.
CDP-verified end-to-end: session → multi-line selection → 6-rect
extent + clean text persisted (PUT 200); create popover correctly
suppressed during the session.
This commit is contained in:
1 parent
dbeefb395c
commit
f69e659d94
1 file changed
+47
-2
@@ -1798,8 +1798,12 @@ document.addEventListener("alpine:init", () => {
|
||||
if (!map || !r) return;
|
||||
const vertical = edge === "left" || edge === "right";
|
||||
// Band: the rect's y-range widened to catch neighbouring line
|
||||
// boundaries (horizontal-edge drags snap to line tops/bottoms).
|
||||
const bandPad = vertical ? 0.002 : Math.max(r[3] * 0.75, 0.008);
|
||||
// boundaries — but only ±quarter height now: a vertical drag adjusts
|
||||
// THIS line box's height and can no longer swallow a neighbouring
|
||||
// line (that produced sliver rects whose text recompute swept
|
||||
// fragments — "some 14ng that scholars…"). Multi-line changes go
|
||||
// through re-selection below.
|
||||
const bandPad = vertical ? 0.002 : Math.max(r[3] * 0.25, 0.004);
|
||||
const bandTop = r[1] - bandPad;
|
||||
const bandBottom = r[1] + r[3] + bandPad;
|
||||
const band = this.pdfCharBoxes(map.doc, bandTop, bandBottom);
|
||||
@@ -2150,6 +2154,47 @@ document.addEventListener("alpine:init", () => {
|
||||
const range = sel.getRangeAt(0);
|
||||
const text = sel.toString().replace(/\s+/g, " ").trim();
|
||||
if (!text) return;
|
||||
// Adjust re-selection (v2): a selection made during a rect-edge
|
||||
// session REPLACES the working extent — any lines, partial lines
|
||||
// (the exact gap the grips could not express). Rects rebuild from
|
||||
// the selection's line boxes, text re-reads, saved immediately:
|
||||
// the grips' release-to-save parity.
|
||||
if (this.pdfAdjust) {
|
||||
const canvasRect =
|
||||
(doc.querySelector("#canvas canvas") as HTMLElement) ||
|
||||
(doc.querySelector("img") as HTMLElement);
|
||||
const dr = canvasRect?.getBoundingClientRect();
|
||||
if (!dr || !dr.width || !dr.height) return;
|
||||
const rects: number[][] = [];
|
||||
for (const r of range.getClientRects()) {
|
||||
const x = (r.left - dr.left) / dr.width;
|
||||
const y = (r.top - dr.top) / dr.height;
|
||||
const w = r.width / dr.width;
|
||||
const h = r.height / dr.height;
|
||||
if (w > 0 && h > 0) rects.push([x, y, w, h]);
|
||||
}
|
||||
if (!rects.length) return;
|
||||
const t = this.pdfTextForRects(doc, rects);
|
||||
if (!t) {
|
||||
showToast("Highlights can't be empty", "error");
|
||||
return;
|
||||
}
|
||||
const session = this.pdfAdjust;
|
||||
session.committed = true;
|
||||
this.cancelPdfAdjust();
|
||||
const p = this.selectionPopover;
|
||||
p.id = session.id;
|
||||
p.pdfPage = session.page;
|
||||
p.pdfRects = rects;
|
||||
p.text = t;
|
||||
this.saveHighlightChanges();
|
||||
try {
|
||||
sel.removeAllRanges();
|
||||
} catch {
|
||||
/* doc may be gone */
|
||||
}
|
||||
return;
|
||||
}
|
||||
// Denominator: the element whose post-transform screen rect IS
|
||||
// the visible page. For PDFs that's the rendered canvas — pdf.js
|
||||
// scales <html> by 1/devicePixelRatio, so documentElement's rect
|
||||
|
||||
Reference in new issue
Block a user