update
This commit is contained in:
@@ -515,6 +515,9 @@ export class DeesPdfViewer extends DeesElement {
|
|||||||
textLayerDiv.style.width = `${viewport.width}px`;
|
textLayerDiv.style.width = `${viewport.width}px`;
|
||||||
textLayerDiv.style.height = `${viewport.height}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({
|
const textLayerRenderTask = pdfjs.renderTextLayer({
|
||||||
textContentSource: textContent,
|
textContentSource: textContent,
|
||||||
container: textLayerDiv,
|
container: textLayerDiv,
|
||||||
@@ -529,14 +532,80 @@ export class DeesPdfViewer extends DeesElement {
|
|||||||
endOfContent.className = 'endOfContent';
|
endOfContent.className = 'endOfContent';
|
||||||
textLayerDiv.appendChild(endOfContent);
|
textLayerDiv.appendChild(endOfContent);
|
||||||
|
|
||||||
// Selection class handling
|
// Custom drag selection for Shadow DOM compatibility
|
||||||
textLayerDiv.addEventListener('mousedown', () => {
|
// caretRangeFromPoint doesn't pierce shadow DOM, so we find spans manually
|
||||||
textLayerDiv.classList.add('selecting');
|
let isDragging = false;
|
||||||
const onMouseUp = () => {
|
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');
|
textLayerDiv.classList.remove('selecting');
|
||||||
document.removeEventListener('mouseup', onMouseUp);
|
}
|
||||||
};
|
document.removeEventListener('mouseup', handleMouseUp);
|
||||||
document.addEventListener('mouseup', onMouseUp);
|
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;
|
pageInfo.textLayerRendered = true;
|
||||||
|
|||||||
@@ -289,12 +289,14 @@ export const viewerStyles = [
|
|||||||
.text-layer {
|
.text-layer {
|
||||||
position: absolute;
|
position: absolute;
|
||||||
inset: 0;
|
inset: 0;
|
||||||
overflow: clip;
|
overflow: visible;
|
||||||
line-height: 1;
|
line-height: 1;
|
||||||
text-size-adjust: none;
|
text-size-adjust: none;
|
||||||
forced-color-adjust: none;
|
forced-color-adjust: none;
|
||||||
transform-origin: 0 0;
|
transform-origin: 0 0;
|
||||||
z-index: 1;
|
z-index: 1;
|
||||||
|
user-select: text;
|
||||||
|
-webkit-user-select: text;
|
||||||
}
|
}
|
||||||
|
|
||||||
.text-layer span,
|
.text-layer span,
|
||||||
@@ -304,6 +306,8 @@ export const viewerStyles = [
|
|||||||
white-space: pre;
|
white-space: pre;
|
||||||
cursor: text;
|
cursor: text;
|
||||||
transform-origin: 0% 0%;
|
transform-origin: 0% 0%;
|
||||||
|
user-select: text;
|
||||||
|
-webkit-user-select: text;
|
||||||
}
|
}
|
||||||
|
|
||||||
.text-layer ::selection {
|
.text-layer ::selection {
|
||||||
|
|||||||
Reference in New Issue
Block a user