import { ANNOTATION_TYPE } from '../constants'; import { parseAnnotationObject } from './annotation'; type GetMarkupWithSelectionFunc = ({ color, type, opacity, scale, }: { color: string; type: string; opacity: number; scale: number; }) => AnnotationType | null; export const getMarkupWithSelection: GetMarkupWithSelectionFunc = ({ color, type, opacity, scale, }) => { const selection: Selection | null = window.getSelection(); if (!selection || !selection.rangeCount) return null; const { startContainer, startOffset, endContainer, endOffset, } = selection.getRangeAt(0); const startElement = startContainer.parentNode as HTMLElement; const endElement = endContainer.parentNode as HTMLElement; const startPage = startElement?.parentNode?.parentNode as HTMLElement; const endPage = endElement?.parentNode?.parentNode as HTMLElement; const startPageNum = parseInt( startPage.getAttribute('data-page-num') as string, 10 ); const endPageNum = parseInt( endPage.getAttribute('data-page-num') as string, 10 ); const textLayer = startPage.querySelector( '[data-id="text-layer"]' ) as HTMLElement; const pageHeight = startPage.offsetHeight; if (startPageNum !== endPageNum) return null; if (startOffset === endOffset && startOffset === endOffset) return null; const startCloneEle = startElement.cloneNode(true) as HTMLElement; const endCloneEle = endElement.cloneNode(true) as HTMLElement; const startText = startElement.innerText.substring(0, startOffset); const endText = endElement.innerText.substring(endOffset); startCloneEle.innerText = startText; endCloneEle.innerText = endText; textLayer.appendChild(startCloneEle); textLayer.appendChild(endCloneEle); const startExtraWidth = startCloneEle.getBoundingClientRect().width; const endExtraWidth = endCloneEle.getBoundingClientRect().width; textLayer.removeChild(startCloneEle); textLayer.removeChild(endCloneEle); const info: AnnotationType = { obj_type: '', obj_attr: { page: 0, bdcolor: '', position: [], transparency: 0, }, }; const position: PositionType[] = []; const startRect = startElement.getBoundingClientRect(); const endRect = endElement.getBoundingClientRect(); // left to right and up to down select let startX = startElement.offsetLeft + startExtraWidth; let startY = startElement.offsetTop; let endX = endElement.offsetLeft + endRect.width - endExtraWidth; let endY = endElement.offsetTop + endRect.height; if (startX > endX && startY >= endY) { // right to left and down to up select startX = endElement.offsetLeft + startExtraWidth; startY = endElement.offsetTop; endX = startElement.offsetLeft + startRect.width - endExtraWidth; endY = startElement.offsetTop + startRect.height; } // eslint-disable-next-line @typescript-eslint/ban-ts-ignore // @ts-ignore const textElements = [...textLayer.childNodes]; textElements.forEach((ele: HTMLElement) => { const { offsetTop, offsetLeft, offsetHeight, offsetWidth } = ele; const offsetRight = offsetLeft + offsetWidth; const offsetBottom = offsetTop + offsetHeight; const coords = { top: offsetTop, bottom: offsetBottom, left: offsetLeft, right: offsetRight, }; if (startElement === ele && endElement === ele) { // in same element coords.left = startX; coords.right = endX; position.push(coords); } else if (startElement === ele) { // in start element coords.left = startX; position.push(coords); } else if (endElement === ele) { // in end element coords.right = endX; position.push(coords); } else if ( offsetTop >= startY + offsetHeight && offsetBottom <= endY - offsetHeight ) { // in row position.push(coords); } else if ( offsetLeft > startX && offsetRight < endX && offsetTop >= startY && offsetBottom <= endY ) { // in line position.push(coords); } else if (offsetTop >= startY - 3 && offsetBottom <= endY + 3) { if ( (offsetLeft > startX && offsetTop >= startY - 3 && offsetBottom < endY - offsetHeight) || (offsetRight < endX && offsetBottom <= endY + 3 && offsetTop > startY + offsetHeight) ) { // in first line and end line position.push(coords); } } }); for (let i = 1; i < position.length; i += 1) { if ( position[i].top >= position[i - 1].top - 4 && position[i].bottom <= position[i - 1].bottom + 4 ) { position[i - 1].right = position[i].left; } } info.obj_type = ANNOTATION_TYPE[type]; info.obj_attr = { page: startPageNum, bdcolor: color, position, transparency: opacity, }; return parseAnnotationObject(info, pageHeight, scale); }; export default getMarkupWithSelection;