UNPKG

r2-navigator-js

Version:

Readium 2 'navigator' for NodeJS (TypeScript)

591 lines 24.8 kB
"use strict"; Object.defineProperty(exports, "__esModule", { value: true }); exports.normalizeRange = exports.convertRangeInfo = exports.convertRange = exports.createOrderedRange = exports.getCurrentSelectionInfo = exports.cleanupStr = exports.collapseWhitespaces = exports.clearCurrentSelection = void 0; var IS_DEV = (process.env.NODE_ENV === "development" || process.env.NODE_ENV === "dev"); function dumpDebug(msg, startNode, startOffset, endNode, endOffset, getCssSelector) { console.log("$$$$$$$$$$$$$$$$$ " + msg); console.log("**** START"); console.log("Node type (1=element, 3=text): " + startNode.nodeType); if (startNode.nodeType === Node.ELEMENT_NODE) { console.log("CSS Selector: " + getCssSelector(startNode)); console.log("Element children count: " + startNode.childNodes.length); if (startOffset >= 0 && startOffset < startNode.childNodes.length) { console.log("Child node type (1=element, 3=text): " + startNode.childNodes[startOffset].nodeType); if (startNode.childNodes[endOffset].nodeType === Node.ELEMENT_NODE) { console.log("Child CSS Selector: " + getCssSelector(startNode.childNodes[endOffset])); } } else { console.log("startOffset >= 0 && startOffset < startNode.childNodes.length ... " + startOffset + " // " + startNode.childNodes.length); } } if (startNode.parentNode && startNode.parentNode.nodeType === Node.ELEMENT_NODE) { console.log("- Parent CSS Selector: " + getCssSelector(startNode.parentNode)); console.log("- Parent element children count: " + startNode.parentNode.childNodes.length); } console.log("Offset: " + startOffset); console.log("**** END"); console.log("Node type (1=element, 3=text): " + endNode.nodeType); if (endNode.nodeType === Node.ELEMENT_NODE) { console.log("CSS Selector: " + getCssSelector(endNode)); console.log("Element children count: " + endNode.childNodes.length); if (endOffset >= 0 && endOffset < endNode.childNodes.length) { console.log("Child node type (1=element, 3=text): " + endNode.childNodes[endOffset].nodeType); if (endNode.childNodes[endOffset].nodeType === Node.ELEMENT_NODE) { console.log("Child CSS Selector: " + getCssSelector(endNode.childNodes[endOffset])); } } else { console.log("endOffset >= 0 && endOffset < endNode.childNodes.length ... " + endOffset + " // " + endNode.childNodes.length); } } if (endNode.parentNode && endNode.parentNode.nodeType === Node.ELEMENT_NODE) { console.log("- Parent CSS Selector: " + getCssSelector(endNode.parentNode)); console.log("- Parent element children count: " + endNode.parentNode.childNodes.length); } console.log("Offset: " + endOffset); console.log("$$$$$$$$$$$$$$$$$"); } function clearCurrentSelection(win) { var selection = win.getSelection(); if (!selection) { return; } selection.removeAllRanges(); } exports.clearCurrentSelection = clearCurrentSelection; var collapseWhitespaces = function (str) { return str.replace(/\n/g, " ").replace(/\s\s+/g, " "); }; exports.collapseWhitespaces = collapseWhitespaces; var cleanupStr = function (str) { return (0, exports.collapseWhitespaces)(str).trim(); }; exports.cleanupStr = cleanupStr; function getCurrentSelectionInfo(win, getCssSelector, computeElementCFI) { var selection = win.getSelection(); if (!selection) { return undefined; } if (selection.isCollapsed) { console.log("^^^ SELECTION COLLAPSED."); return undefined; } var rawText = selection.toString(); var cleanText = (0, exports.collapseWhitespaces)(rawText); if (cleanText.length === 0) { console.log("^^^ SELECTION TEXT EMPTY."); return undefined; } if (!selection.anchorNode || !selection.focusNode) { return undefined; } var r = selection.rangeCount === 1 ? selection.getRangeAt(0) : createOrderedRange(selection.anchorNode, selection.anchorOffset, selection.focusNode, selection.focusOffset); if (!r || r.collapsed) { console.log("$$$$$$$$$$$$$$$$$ CANNOT GET NON-COLLAPSED SELECTION RANGE?!"); return undefined; } var range = normalizeRange(r); if (IS_DEV) { if (range.startContainer !== r.startContainer) { console.log(">>>>>>>>>>>>>>>>>>>>>>> SELECTION RANGE NORMALIZE diff: startContainer"); console.log(range.startContainer); console.log(r.startContainer); } if (range.startOffset !== r.startOffset) { console.log(">>>>>>>>>>>>>>>>>>>>>>> SELECTION RANGE NORMALIZE diff: startOffset"); console.log("".concat(range.startOffset, " !== ").concat(r.startOffset)); } if (range.endContainer !== r.endContainer) { console.log(">>>>>>>>>>>>>>>>>>>>>>> SELECTION RANGE NORMALIZE diff: endContainer"); console.log(range.endContainer); console.log(r.endContainer); } if (range.endOffset !== r.endOffset) { console.log(">>>>>>>>>>>>>>>>>>>>>>> SELECTION RANGE NORMALIZE diff: endOffset"); console.log("".concat(range.endOffset, " !== ").concat(r.endOffset)); } } var tuple = convertRange(range, getCssSelector, computeElementCFI); if (!tuple) { console.log("^^^ SELECTION RANGE INFO FAIL?!"); return undefined; } var rangeInfo = tuple[0]; var textInfo = tuple[1]; if (IS_DEV) { if (textInfo.cleanText !== cleanText) { console.log(">>>>>>>>>>>>>>>>>>>>>>> SELECTION TEXT INFO diff: cleanText"); console.log("".concat(textInfo.cleanText, " !== ").concat(cleanText)); } if (textInfo.rawText !== rawText) { console.log(">>>>>>>>>>>>>>>>>>>>>>> SELECTION TEXT INFO diff: rawText"); console.log("".concat(textInfo.rawText, " !== ").concat(rawText)); } } if (IS_DEV && win.READIUM2.DEBUG_VISUALS) { var restoredRange = convertRangeInfo(win.document, rangeInfo); if (restoredRange) { if (restoredRange.startOffset === range.startOffset && restoredRange.endOffset === range.endOffset && restoredRange.startContainer === range.startContainer && restoredRange.endContainer === range.endContainer) { console.log("SELECTION RANGE RESTORED OKAY (dev check)."); } else { console.log("SELECTION RANGE RESTORE FAIL (dev check)."); dumpDebug("SELECTION", selection.anchorNode, selection.anchorOffset, selection.focusNode, selection.focusOffset, getCssSelector); dumpDebug("ORDERED RANGE FROM SELECTION", range.startContainer, range.startOffset, range.endContainer, range.endOffset, getCssSelector); dumpDebug("RESTORED RANGE", restoredRange.startContainer, restoredRange.startOffset, restoredRange.endContainer, restoredRange.endOffset, getCssSelector); } } else { console.log("CANNOT RESTORE SELECTION RANGE ??!"); } } else { } return { rangeInfo: rangeInfo, cleanBefore: textInfo.cleanBefore, cleanText: textInfo.cleanText, cleanAfter: textInfo.cleanAfter, rawBefore: textInfo.rawBefore, rawText: textInfo.rawText, rawAfter: textInfo.rawAfter, }; } exports.getCurrentSelectionInfo = getCurrentSelectionInfo; function createOrderedRange(startNode, startOffset, endNode, endOffset) { var range = new Range(); range.setStart(startNode, startOffset); range.setEnd(endNode, endOffset); if (!range.collapsed) { return range; } console.log(">>> createOrderedRange COLLAPSED ... RANGE REVERSE?"); var rangeReverse = new Range(); rangeReverse.setStart(endNode, endOffset); rangeReverse.setEnd(startNode, startOffset); if (!rangeReverse.collapsed) { console.log(">>> createOrderedRange RANGE REVERSE OK."); return range; } console.log(">>> createOrderedRange RANGE REVERSE ALSO COLLAPSED?!"); return undefined; } exports.createOrderedRange = createOrderedRange; function convertRange(range, getCssSelector, computeElementCFI) { var _a, _b; var startIsElement = range.startContainer.nodeType === Node.ELEMENT_NODE; var startContainerElement = startIsElement ? range.startContainer : ((range.startContainer.parentNode && range.startContainer.parentNode.nodeType === Node.ELEMENT_NODE) ? range.startContainer.parentNode : undefined); if (!startContainerElement) { return undefined; } var startContainerChildTextNodeIndex = startIsElement ? -1 : Array.from(startContainerElement.childNodes).indexOf(range.startContainer); if (startContainerChildTextNodeIndex < -1) { return undefined; } var startContainerElementCssSelector = getCssSelector(startContainerElement); var endIsElement = range.endContainer.nodeType === Node.ELEMENT_NODE; var endContainerElement = endIsElement ? range.endContainer : ((range.endContainer.parentNode && range.endContainer.parentNode.nodeType === Node.ELEMENT_NODE) ? range.endContainer.parentNode : undefined); if (!endContainerElement) { return undefined; } var endContainerChildTextNodeIndex = endIsElement ? -1 : Array.from(endContainerElement.childNodes).indexOf(range.endContainer); if (endContainerChildTextNodeIndex < -1) { return undefined; } var endContainerElementCssSelector = getCssSelector(endContainerElement); var commonElementAncestor = getCommonAncestorElement(range.startContainer, range.endContainer); if (!commonElementAncestor) { console.log("^^^ NO RANGE COMMON ANCESTOR?!"); return undefined; } if (range.commonAncestorContainer) { var rangeCommonAncestorElement = range.commonAncestorContainer.nodeType === Node.ELEMENT_NODE ? range.commonAncestorContainer : range.commonAncestorContainer.parentNode; if (rangeCommonAncestorElement && rangeCommonAncestorElement.nodeType === Node.ELEMENT_NODE) { if (commonElementAncestor !== rangeCommonAncestorElement) { console.log(">>>>>> COMMON ANCESTOR CONTAINER DIFF??!"); console.log(getCssSelector(commonElementAncestor)); console.log(getCssSelector(rangeCommonAncestorElement)); } } } var SELECTION_BEFORE_AFTER_TEXT_LENGTH = 30; var rawBefore = ""; var rawText = range.toString(); var rawAfter = ""; var cleanBefore = ""; var cleanText = (0, exports.collapseWhitespaces)(rawText); var cleanAfter = ""; var currentParent = commonElementAncestor; while (currentParent) { if (((_a = currentParent.tagName) === null || _a === void 0 ? void 0 : _a.toLowerCase()) === "html") { break; } var beforeNeedsToGrow = cleanBefore.length < SELECTION_BEFORE_AFTER_TEXT_LENGTH; var afterNeedsToGrow = cleanAfter.length < SELECTION_BEFORE_AFTER_TEXT_LENGTH; if (!beforeNeedsToGrow && !afterNeedsToGrow) { break; } if (beforeNeedsToGrow) { try { var rangeBefore = new Range(); rangeBefore.setStartBefore(currentParent); rangeBefore.setEnd(range.startContainer, range.startOffset); rawBefore = rangeBefore.toString(); cleanBefore = (0, exports.collapseWhitespaces)(rawBefore); if (cleanBefore.length > SELECTION_BEFORE_AFTER_TEXT_LENGTH) { cleanBefore = cleanBefore.substring(cleanBefore.length - SELECTION_BEFORE_AFTER_TEXT_LENGTH, cleanBefore.length); } } catch (ex1) { console.log(ex1); } } if (afterNeedsToGrow) { try { var rangeAfter = new Range(); rangeAfter.setStart(range.endContainer, range.endOffset); rangeAfter.setEndAfter(currentParent); rawAfter = rangeAfter.toString(); cleanAfter = (0, exports.collapseWhitespaces)(rawAfter); if (cleanAfter.length > SELECTION_BEFORE_AFTER_TEXT_LENGTH) { cleanAfter = cleanAfter.substring(0, SELECTION_BEFORE_AFTER_TEXT_LENGTH); } } catch (ex2) { console.log(ex2); } } if (((_b = currentParent.tagName) === null || _b === void 0 ? void 0 : _b.toLowerCase()) === "body") { break; } currentParent = currentParent.parentNode; } if (cleanBefore.length) { var j = 0; var i = rawBefore.length - 1; var wasWhiteSpace = false; for (; i >= 0; i--) { var isWhiteSpace = /[\n\s]/.test(rawBefore[i]); if (isWhiteSpace && i !== 0 && i !== rawBefore.length - 1 && wasWhiteSpace) { wasWhiteSpace = isWhiteSpace; continue; } wasWhiteSpace = isWhiteSpace; j++; if (j >= cleanBefore.length) { break; } } rawBefore = rawBefore.substring(i, rawBefore.length); } if (cleanAfter.length) { var j = 0; var i = 0; var wasWhiteSpace = false; for (; i < rawAfter.length; i++) { var isWhiteSpace = /[\n\s]/.test(rawAfter[i]); if (isWhiteSpace && i !== 0 && i !== rawAfter.length - 1 && wasWhiteSpace) { wasWhiteSpace = isWhiteSpace; continue; } wasWhiteSpace = isWhiteSpace; j++; if (j >= cleanAfter.length) { break; } } rawAfter = rawAfter.substring(0, i + 1); } var rootElementCfi = computeElementCFI(commonElementAncestor); var startElementCfi = computeElementCFI(startContainerElement); var endElementCfi = computeElementCFI(endContainerElement); var cfi; if (rootElementCfi && startElementCfi && endElementCfi) { var startElementOrTextCfi = startElementCfi; if (!startIsElement) { var startContainerChildTextNodeIndexForCfi = getChildTextNodeCfiIndex(startContainerElement, range.startContainer); startElementOrTextCfi = startElementCfi + "/" + startContainerChildTextNodeIndexForCfi + ":" + range.startOffset; } else { if (range.startOffset >= 0 && range.startOffset < startContainerElement.childNodes.length) { var childNode = startContainerElement.childNodes[range.startOffset]; if (childNode.nodeType === Node.ELEMENT_NODE) { startElementOrTextCfi = startElementCfi + "/" + ((range.startOffset + 1) * 2); } else { var cfiTextNodeIndex = getChildTextNodeCfiIndex(startContainerElement, childNode); startElementOrTextCfi = startElementCfi + "/" + cfiTextNodeIndex; } } else { var cfiIndexOfLastElement = ((startContainerElement.childElementCount) * 2); var lastChildNode = startContainerElement.childNodes[startContainerElement.childNodes.length - 1]; if (lastChildNode.nodeType === Node.ELEMENT_NODE) { startElementOrTextCfi = startElementCfi + "/" + (cfiIndexOfLastElement + 1); } else { startElementOrTextCfi = startElementCfi + "/" + (cfiIndexOfLastElement + 2); } } } var endElementOrTextCfi = endElementCfi; if (!endIsElement) { var endContainerChildTextNodeIndexForCfi = getChildTextNodeCfiIndex(endContainerElement, range.endContainer); endElementOrTextCfi = endElementCfi + "/" + endContainerChildTextNodeIndexForCfi + ":" + range.endOffset; } else { if (range.endOffset >= 0 && range.endOffset < endContainerElement.childNodes.length) { var childNode = endContainerElement.childNodes[range.endOffset]; if (childNode.nodeType === Node.ELEMENT_NODE) { endElementOrTextCfi = endElementCfi + "/" + ((range.endOffset + 1) * 2); } else { var cfiTextNodeIndex = getChildTextNodeCfiIndex(endContainerElement, childNode); endElementOrTextCfi = endElementCfi + "/" + cfiTextNodeIndex; } } else { var cfiIndexOfLastElement = ((endContainerElement.childElementCount) * 2); var lastChildNode = endContainerElement.childNodes[endContainerElement.childNodes.length - 1]; if (lastChildNode.nodeType === Node.ELEMENT_NODE) { endElementOrTextCfi = endElementCfi + "/" + (cfiIndexOfLastElement + 1); } else { endElementOrTextCfi = endElementCfi + "/" + (cfiIndexOfLastElement + 2); } } } cfi = rootElementCfi + "," + startElementOrTextCfi.replace(rootElementCfi, "") + "," + endElementOrTextCfi.replace(rootElementCfi, ""); } return [{ cfi: cfi, endContainerChildTextNodeIndex: endContainerChildTextNodeIndex, endContainerElementCFI: endElementCfi, endContainerElementCssSelector: endContainerElementCssSelector, endOffset: range.endOffset, startContainerChildTextNodeIndex: startContainerChildTextNodeIndex, startContainerElementCFI: startElementCfi, startContainerElementCssSelector: startContainerElementCssSelector, startOffset: range.startOffset, }, { cleanBefore: cleanBefore, cleanText: cleanText, cleanAfter: cleanAfter, rawBefore: rawBefore, rawText: rawText, rawAfter: rawAfter, }]; } exports.convertRange = convertRange; function convertRangeInfo(documant, rangeInfo) { var startElement = documant.querySelector(rangeInfo.startContainerElementCssSelector); if (!startElement) { console.log("^^^ convertRangeInfo NO START ELEMENT CSS SELECTOR?!", rangeInfo.startContainerElementCssSelector); return undefined; } var startContainer = startElement; if (rangeInfo.startContainerChildTextNodeIndex >= 0) { if (rangeInfo.startContainerChildTextNodeIndex >= startElement.childNodes.length) { console.log("^^^ convertRangeInfo rangeInfo.startContainerChildTextNodeIndex >= startElement.childNodes.length?!"); return undefined; } startContainer = startElement.childNodes[rangeInfo.startContainerChildTextNodeIndex]; if (startContainer.nodeType !== Node.TEXT_NODE) { console.log("^^^ convertRangeInfo startContainer.nodeType !== Node.TEXT_NODE?!"); return undefined; } } var endElement = documant.querySelector(rangeInfo.endContainerElementCssSelector); if (!endElement) { console.log("^^^ convertRangeInfo NO END ELEMENT CSS SELECTOR?!", rangeInfo.endContainerElementCssSelector); return undefined; } var endContainer = endElement; if (rangeInfo.endContainerChildTextNodeIndex >= 0) { if (rangeInfo.endContainerChildTextNodeIndex >= endElement.childNodes.length) { console.log("^^^ convertRangeInfo rangeInfo.endContainerChildTextNodeIndex >= endElement.childNodes.length?!"); return undefined; } endContainer = endElement.childNodes[rangeInfo.endContainerChildTextNodeIndex]; if (endContainer.nodeType !== Node.TEXT_NODE) { console.log("^^^ convertRangeInfo endContainer.nodeType !== Node.TEXT_NODE?!"); return undefined; } } return createOrderedRange(startContainer, rangeInfo.startOffset, endContainer, rangeInfo.endOffset); } exports.convertRangeInfo = convertRangeInfo; function getCommonAncestorElement(node1, node2) { if (node1.nodeType === Node.ELEMENT_NODE && node1 === node2) { return node1; } if (node1.nodeType === Node.ELEMENT_NODE && node1.contains(node2)) { return node1; } if (node2.nodeType === Node.ELEMENT_NODE && node2.contains(node1)) { return node2; } var node1ElementAncestorChain = []; var parent = node1.parentNode; while (parent && parent.nodeType === Node.ELEMENT_NODE) { node1ElementAncestorChain.push(parent); parent = parent.parentNode; } var node2ElementAncestorChain = []; parent = node2.parentNode; while (parent && parent.nodeType === Node.ELEMENT_NODE) { node2ElementAncestorChain.push(parent); parent = parent.parentNode; } var commonAncestor = node1ElementAncestorChain.find(function (node1ElementAncestor) { return node2ElementAncestorChain.indexOf(node1ElementAncestor) >= 0; }); if (!commonAncestor) { commonAncestor = node2ElementAncestorChain.find(function (node2ElementAncestor) { return node1ElementAncestorChain.indexOf(node2ElementAncestor) >= 0; }); } return commonAncestor; } function isCfiTextNode(node) { return node.nodeType !== Node.ELEMENT_NODE; } function getChildTextNodeCfiIndex(element, child) { var found = -1; var textNodeIndex = -1; var previousWasElement = false; for (var i = 0; i < element.childNodes.length; i++) { var childNode = element.childNodes[i]; var isText = isCfiTextNode(childNode); if (isText || previousWasElement) { textNodeIndex += 2; } if (isText) { if (childNode === child) { found = textNodeIndex; break; } } previousWasElement = childNode.nodeType === Node.ELEMENT_NODE; } return found; } function normalizeRange(r) { var range = r.cloneRange(); var sc = range.startContainer; var so = range.startOffset; var ec = range.endContainer; var eo = range.endOffset; if (sc.childNodes.length && so > 0) { sc = lastLeaf(sc.childNodes[so - 1]); so = sc.length || 0; } if (eo < ec.childNodes.length) { ec = firstLeaf(ec.childNodes[eo]); eo = 0; } var start = firstLeaf(sc); var end = lastLeaf(ec); function isLeafNodeInRange(node) { if (node.childNodes.length) { return false; } var length = node.length || 0; if (node === sc && so === length) { return false; } if (node === ec && eo === 0) { return false; } return true; } while (start && !isLeafNodeInRange(start) && start !== end) { start = documentForward(start); } if (start === sc) { range.setStart(sc, so); } else if (start !== null) { if (start.nodeType === 3) { range.setStart(start, 0); } else { range.setStartBefore(start); } } while (end && !isLeafNodeInRange(end) && end !== start) { end = documentReverse(end); } if (end === ec) { range.setEnd(ec, eo); } else if (end !== null) { if (end.nodeType === 3) { range.setEnd(end, end.length); } else { range.setEndAfter(end); } } return range; } exports.normalizeRange = normalizeRange; function documentForward(node) { if (node.firstChild) { return node.firstChild; } var n = node; while (!n.nextSibling) { n = n.parentNode; if (!n) { return null; } } return n.nextSibling; } function documentReverse(node) { if (node.lastChild) { return node.lastChild; } var n = node; while (!n.previousSibling) { n = n.parentNode; if (!n) { return null; } } return n.previousSibling; } function firstLeaf(node) { while (node.firstChild) { node = node.firstChild; } return node; } function lastLeaf(node) { while (node.lastChild) { node = node.lastChild; } return node; } //# sourceMappingURL=selection.js.map