import { ANNOTATION_TYPE } from '../constants'; import { parseAnnotationObject, appendUserIdAndDate } from './annotation'; type GetMarkupWithSelectionFunc = ({ color, type, opacity, scale, }: { color: string; type: string; opacity: number; scale: number; textLayer: HTMLElement; }) => AnnotationType | null; export const getMarkupWithSelection: GetMarkupWithSelectionFunc = ({ color, type, opacity, scale, textLayer, }) => { const selection: Selection | null = document.getSelection(); if (!selection || selection.isCollapsed) 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 startPageNum = parseInt( startPage.getAttribute('data-page-num') as string, 10, ); const pageHeight = startPage.offsetHeight; 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; } const textElements = Array.prototype.slice.call(textLayer.childNodes); let inRange = false; textElements.forEach((ele: HTMLElement) => { const { height, width } = ele.getBoundingClientRect(); const { offsetTop, offsetLeft } = ele; const top = offsetTop; const left = offsetLeft; const right = offsetLeft + width; const bottom = offsetTop + height; const coords = { top, bottom, left, right, }; 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); inRange = true; } else if (endElement === ele) { // in end element coords.right = endX; position.push(coords); inRange = false; } else if (inRange) { // middle element 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 appendUserIdAndDate(parseAnnotationObject(info, pageHeight, scale)); }; export default getMarkupWithSelection;