update
This commit is contained in:
@@ -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;
|
||||
|
||||
Reference in New Issue
Block a user