diff --git a/web/src/reader/reader.ts b/web/src/reader/reader.ts index fec3af81..ba2702f6 100644 --- a/web/src/reader/reader.ts +++ b/web/src/reader/reader.ts @@ -1737,47 +1737,54 @@ document.addEventListener("alpine:init", () => { if (!first || !last) return; // Start dot at the first rect's LEFT-MIDDLE, end dot at the last // rect's RIGHT-MIDDLE — the range boundary points. - const pts: Array<{ which: string; fx: number; fy: number }> = [ + const pts: Array<{ which: "start" | "end"; fx: number; fy: number }> = [ { which: "start", fx: first[0], fy: first[1] + first[3] / 2 }, { which: "end", fx: last[0] + last[2], fy: last[1] + last[3] / 2 }, ]; for (const pt of pts) { + // Create each dot ONCE per session; every later call only + // REPOSITIONS the existing element. An innerHTML rebuild here + // destroys the dot mid-drag — it loses pointer capture and the + // drag dies silently ("handles not moving", user report). + let dot = layer.querySelector( + `.adjust-handle[data-which="${pt.which}"]`, + ); + if (!dot) { + dot = document.createElement("div"); + dot.className = "adjust-handle"; + dot.dataset.which = pt.which; + const which = pt.which; + // Pointer events (mouse + touch + pen); the page's own touch + // handlers are not engaged because the dots live in the HOST + // document, above the iframe. + dot.addEventListener("pointerdown", (e) => { + e.preventDefault(); + try { + dot!.setPointerCapture(e.pointerId); + } catch {} + dot!.dataset.dragging = "1"; + }); + dot.addEventListener("pointermove", (e) => { + if (!dot!.dataset.dragging) return; + this.pdfAdjustHandleMove(which, e.clientX, e.clientY); + }); + dot.addEventListener("pointerup", (e) => { + if (!dot!.dataset.dragging) return; + delete dot!.dataset.dragging; + try { + dot!.releasePointerCapture?.(e.pointerId); + } catch {} + this.pdfAdjustRelease(); + }); + dot.addEventListener("pointercancel", () => { + if (!dot!.dataset.dragging) return; + delete dot!.dataset.dragging; + }); + layer.appendChild(dot); + } const host = map.toHost(pt.fx, pt.fy); - const dot = document.createElement("div"); - dot.className = "adjust-handle"; - dot.dataset.which = pt.which; dot.style.left = `${host.x - 13}px`; dot.style.top = `${host.y - 13}px`; - // Pointer events (mouse + touch + pen); the page's own touch - // handlers are not engaged because the dots live in the HOST - // document, above the iframe. - dot.addEventListener("pointerdown", (e) => { - e.preventDefault(); - try { - dot.setPointerCapture(e.pointerId); - } catch {} - dot.dataset.dragging = "1"; - }); - dot.addEventListener("pointermove", (e) => { - if (!dot.dataset.dragging) return; - this.pdfAdjustHandleMove( - pt.which, - e.clientX, - e.clientY, - ); - }); - dot.addEventListener("pointerup", (e) => { - if (!dot.dataset.dragging) return; - delete dot.dataset.dragging; - try { - dot.releasePointerCapture?.(e.pointerId); - } catch {} - this.pdfAdjustRelease(); - }); - dot.addEventListener("pointercancel", () => { - delete dot.dataset.dragging; - }); - layer.appendChild(dot); } }, /** Endpoint drag: the finger (host px) re-anchors the grabbed end at