From 2b048cf34f77e1cfed01ce3fa7224fee7e618880 Mon Sep 17 00:00:00 2001 From: Juergen Kunz Date: Wed, 28 Jan 2026 17:02:52 +0000 Subject: [PATCH] update --- .../dees-pdf-viewer/component.ts | 83 +++++++++++++++++-- .../00group-media/dees-pdf-viewer/styles.ts | 6 +- 2 files changed, 81 insertions(+), 8 deletions(-) diff --git a/ts_web/elements/00group-media/dees-pdf-viewer/component.ts b/ts_web/elements/00group-media/dees-pdf-viewer/component.ts index 5aea607..4d28135 100644 --- a/ts_web/elements/00group-media/dees-pdf-viewer/component.ts +++ b/ts_web/elements/00group-media/dees-pdf-viewer/component.ts @@ -515,6 +515,9 @@ export class DeesPdfViewer extends DeesElement { textLayerDiv.style.width = `${viewport.width}px`; textLayerDiv.style.height = `${viewport.height}px`; + // Set the scale factor CSS variable - required by PDF.js text layer + textLayerDiv.style.setProperty('--scale-factor', String(viewport.scale)); + const textLayerRenderTask = pdfjs.renderTextLayer({ textContentSource: textContent, container: textLayerDiv, @@ -529,14 +532,80 @@ export class DeesPdfViewer extends DeesElement { endOfContent.className = 'endOfContent'; textLayerDiv.appendChild(endOfContent); - // Selection class handling - textLayerDiv.addEventListener('mousedown', () => { - textLayerDiv.classList.add('selecting'); - const onMouseUp = () => { + // Custom drag selection for Shadow DOM compatibility + // caretRangeFromPoint doesn't pierce shadow DOM, so we find spans manually + let isDragging = false; + let anchorNode: Node | null = null; + let anchorOffset = 0; + + const getTextPositionFromPoint = (x: number, y: number): { node: Node; offset: number } | null => { + // Find span at coordinates by checking bounding rects + const spans = Array.from(textLayerDiv.querySelectorAll('span')); + for (const span of spans) { + const rect = span.getBoundingClientRect(); + if (x >= rect.left && x <= rect.right && y >= rect.top && y <= rect.bottom) { + const textNode = span.firstChild; + if (textNode && textNode.nodeType === Node.TEXT_NODE) { + // Calculate character offset based on x position + const text = textNode.textContent || ''; + const charWidth = rect.width / text.length; + const relativeX = x - rect.left; + const offset = Math.min(Math.round(relativeX / charWidth), text.length); + return { node: textNode, offset }; + } + } + } + return null; + }; + + const handleMouseUp = () => { + if (isDragging) { + isDragging = false; + anchorNode = null; textLayerDiv.classList.remove('selecting'); - document.removeEventListener('mouseup', onMouseUp); - }; - document.addEventListener('mouseup', onMouseUp); + } + document.removeEventListener('mouseup', handleMouseUp); + document.removeEventListener('mousemove', handleMouseMove); + }; + + const handleMouseMove = (e: MouseEvent) => { + if (!isDragging || !anchorNode) return; + + e.preventDefault(); + const pos = getTextPositionFromPoint(e.clientX, e.clientY); + if (pos) { + const selection = window.getSelection(); + if (selection) { + try { + selection.setBaseAndExtent(anchorNode, anchorOffset, pos.node, pos.offset); + } catch (err) { + // Ignore errors from invalid selections + } + } + } + }; + + textLayerDiv.addEventListener('mousedown', (e: MouseEvent) => { + if (e.button !== 0) return; + + const pos = getTextPositionFromPoint(e.clientX, e.clientY); + if (pos) { + // Prevent native selection behavior + e.preventDefault(); + + isDragging = true; + anchorNode = pos.node; + anchorOffset = pos.offset; + textLayerDiv.classList.add('selecting'); + + // Clear existing selection + const selection = window.getSelection(); + selection?.removeAllRanges(); + + // Add document-level listeners for drag + document.addEventListener('mousemove', handleMouseMove); + document.addEventListener('mouseup', handleMouseUp); + } }); pageInfo.textLayerRendered = true; diff --git a/ts_web/elements/00group-media/dees-pdf-viewer/styles.ts b/ts_web/elements/00group-media/dees-pdf-viewer/styles.ts index 65e8472..583217b 100644 --- a/ts_web/elements/00group-media/dees-pdf-viewer/styles.ts +++ b/ts_web/elements/00group-media/dees-pdf-viewer/styles.ts @@ -289,12 +289,14 @@ export const viewerStyles = [ .text-layer { position: absolute; inset: 0; - overflow: clip; + overflow: visible; line-height: 1; text-size-adjust: none; forced-color-adjust: none; transform-origin: 0 0; z-index: 1; + user-select: text; + -webkit-user-select: text; } .text-layer span, @@ -304,6 +306,8 @@ export const viewerStyles = [ white-space: pre; cursor: text; transform-origin: 0% 0%; + user-select: text; + -webkit-user-select: text; } .text-layer ::selection {