UNPKG

r2-navigator-js

Version:

Readium 2 'navigator' for NodeJS (TypeScript)

851 lines 39.6 kB
"use strict"; Object.defineProperty(exports, "__esModule", { value: true }); exports.computeEpubTypes = void 0; exports.combineTextNodes = combineTextNodes; exports.getLanguage = getLanguage; exports.getDirection = getDirection; exports.normalizeHtmlText = normalizeHtmlText; exports.normalizeText = normalizeText; exports.consoleLogTtsQueueItem = consoleLogTtsQueueItem; exports.consoleLogTtsQueue = consoleLogTtsQueue; exports.getTtsQueueLength = getTtsQueueLength; exports.getTtsQueueItemRefText = getTtsQueueItemRefText; exports.getTtsQueueItemRef = getTtsQueueItemRef; exports.findTtsQueueItemIndex = findTtsQueueItemIndex; exports.generateTtsQueue = generateTtsQueue; const sentence_splitter_1 = require("sentence-splitter"); const styles_1 = require("../../common/styles"); const cssselector3_1 = require("../common/cssselector3"); const win = global.window; function combineTextNodes(textNodes, skipNormalize) { if (textNodes && textNodes.length) { let str = ""; for (const textNode of textNodes) { let txt = textNode.nodeValue; if (textNode.__RUBY) { } else if (txt) { if (!txt.trim().length) { txt = " "; str += txt; } else { str += (skipNormalize ? txt : normalizeText(txt)); } } } return str; } return ""; } function getLanguage(el) { let currentElement = el; while (currentElement && currentElement.nodeType === Node.ELEMENT_NODE) { let lang = currentElement.getAttribute("xml:lang"); if (!lang) { lang = currentElement.getAttributeNS("http://www.w3.org/XML/1998/namespace", "lang"); } if (!lang) { lang = currentElement.getAttribute("lang"); } if (lang) { return lang; } currentElement = currentElement.parentNode; } return "und"; } function getDirection(el) { let currentElement = el; while (currentElement && currentElement.nodeType === Node.ELEMENT_NODE) { const dir = currentElement.getAttribute("dir"); if (dir) { return dir; } currentElement = currentElement.parentNode; } return undefined; } function normalizeHtmlText(str) { return str.replace(/&/g, "&amp;").replace(/</g, "&lt;").replace(/>/g, "&gt;"); } function normalizeText(str) { return normalizeHtmlText(str).replace(/[\r\n]/g, " ").replace(/\s\s+/g, " "); } function consoleLogTtsQueueItem(i) { console.log("<<----"); console.log(i.dir); console.log(i.lang); const cssSelector = (0, cssselector3_1.uniqueCssSelector)(i.parentElement, i.parentElement.ownerDocument, {}); console.log(cssSelector); console.log(i.parentElement.tagName); console.log(i.combinedText); if (i.combinedTextSentences) { console.log("......."); for (const j of i.combinedTextSentences) { console.log(j); } console.log("......."); } console.log("---->>"); } function consoleLogTtsQueue(f) { for (const i of f) { consoleLogTtsQueueItem(i); } } function getTtsQueueLength(items) { let l = 0; for (const it of items) { if (it.combinedTextSentences) { l += it.combinedTextSentences.length; } else { l++; } } return l; } function getTtsQueueItemRefText(obj) { if (obj.iSentence === -1) { return obj.item.combinedText; } if (obj.item.combinedTextSentences) { return obj.item.combinedTextSentences[obj.iSentence]; } return ""; } function getTtsQueueItemRef(items, index) { let i = -1; let k = -1; for (const it of items) { k++; if (it.combinedTextSentences) { let j = -1; for (const _sent of it.combinedTextSentences) { j++; i++; if (index === i) { return { item: it, iArray: k, iGlobal: i, iSentence: j }; } } } else { i++; if (index === i) { return { item: it, iArray: k, iGlobal: i, iSentence: -1 }; } } } return undefined; } function findTtsQueueItemIndex(ttsQueue, element, startTextNode, startTextNodeOffset, rootElem) { var _a, _b, _c; let i = 0; for (const ttsQueueItem of ttsQueue) { if (startTextNode) { if ((_a = ttsQueueItem.textNodes) === null || _a === void 0 ? void 0 : _a.includes(startTextNode)) { if (ttsQueueItem.combinedTextSentences && ttsQueueItem.combinedTextSentencesRangeBegin && ttsQueueItem.combinedTextSentencesRangeEnd) { let offset = 0; for (const txtNode of ttsQueueItem.textNodes) { if (!txtNode.nodeValue && txtNode.nodeValue !== "") { continue; } if (txtNode.__RUBY) { continue; } if (txtNode === startTextNode) { offset += startTextNodeOffset; break; } offset += txtNode.nodeValue.length; } let j = i - 1; for (const end of ttsQueueItem.combinedTextSentencesRangeEnd) { j++; if (end < offset) { continue; } return j; } return i; } else { return i; } } } else if ((element === ttsQueueItem.parentElement || (ttsQueueItem.parentElement !== element.ownerDocument.body && ttsQueueItem.parentElement !== rootElem && ttsQueueItem.parentElement.contains(element)) || element.contains(ttsQueueItem.parentElement))) { return i; } if (ttsQueueItem.combinedTextSentences) { i += ttsQueueItem.combinedTextSentences.length; } else { i++; } } i = 0; for (const ttsQueueItem of ttsQueue) { if (startTextNode && ((_b = ttsQueueItem.textNodes) === null || _b === void 0 ? void 0 : _b.includes(startTextNode))) { if (ttsQueueItem.combinedTextSentences && ttsQueueItem.combinedTextSentencesRangeBegin && ttsQueueItem.combinedTextSentencesRangeEnd) { let offset = 0; for (const txtNode of ttsQueueItem.textNodes) { if (!txtNode.nodeValue && txtNode.nodeValue !== "") { continue; } if (txtNode.__RUBY) { continue; } if (txtNode === startTextNode) { offset += startTextNodeOffset; break; } offset += txtNode.nodeValue.length; } let j = i - 1; for (const end of ttsQueueItem.combinedTextSentencesRangeEnd) { j++; if (end < offset) { continue; } return j; } return i; } else { return i; } } else if ((!startTextNode || !((_c = ttsQueueItem.textNodes) === null || _c === void 0 ? void 0 : _c.length)) && (element === ttsQueueItem.parentElement || (ttsQueueItem.parentElement !== element.ownerDocument.body && ttsQueueItem.parentElement !== rootElem && ttsQueueItem.parentElement.contains(element)) || element.contains(ttsQueueItem.parentElement))) { return i; } if (ttsQueueItem.combinedTextSentences) { i += ttsQueueItem.combinedTextSentences.length; } else { i++; } } return -1; } const _putInElementStackTagNames = ["h1", "h2", "h3", "h4", "h5", "h6", "p", "th", "td", "caption", "li", "blockquote", "q", "dt", "dd", "figcaption", "div", "pre"]; const _doNotProcessDeepChildTagNames = ["svg", "img", "sup", "sub", "audio", "video", "source", "button", "canvas", "del", "dialog", "embed", "form", "head", "iframe", "meter", "noscript", "object", "s", "script", "select", "style", "textarea"]; const _skippables = [ "footnote", "endnote", "pagebreak", "note", "rearnote", "sidebar", "marginalia", "annotation", ]; const computeEpubTypes = (childElement) => { let epubType = childElement.getAttribute("epub:type"); if (!epubType) { epubType = childElement.getAttributeNS("http://www.idpf.org/2007/ops", "type"); if (!epubType) { epubType = childElement.getAttribute("role"); if (epubType) { epubType = epubType.replace(/doc-/g, ""); } } } if (epubType) { epubType = epubType.replace(/\s\s+/g, " ").trim(); if (epubType.length === 0) { epubType = null; } } const epubTypes = epubType ? epubType.split(" ") : []; return epubTypes; }; exports.computeEpubTypes = computeEpubTypes; function generateTtsQueue(rootElement, splitSentences) { let ttsQueue = []; const elementStack = []; function processTextNode(textNode) { var _a, _b; if (textNode.nodeType !== Node.TEXT_NODE) { return; } if (!textNode.nodeValue) { return; } const parentElement = elementStack[elementStack.length - 1]; if (!parentElement) { return; } const documant = (textNode.parentElement || parentElement).ownerDocument; const lowerTagName = (_b = (_a = textNode.parentElement) === null || _a === void 0 ? void 0 : _a.tagName) === null || _b === void 0 ? void 0 : _b.toLowerCase(); if (documant.documentElement.classList.contains(styles_1.ROOT_CLASS_NO_RUBY)) { if (lowerTagName === "rp" || lowerTagName === "rt") { return; } if ((lowerTagName === "ruby" || lowerTagName === "rb") && textNode.__RUBY) { textNode.__RUBY = false; } } else { if (lowerTagName === "ruby" || lowerTagName === "rb") { textNode.__RUBY = true; } } let current = ttsQueue[ttsQueue.length - 1]; const lang = textNode.parentElement ? getLanguage(textNode.parentElement) : undefined; const dir = textNode.parentElement ? getDirection(textNode.parentElement) : undefined; if (!current || current.parentElement !== parentElement || current.lang !== lang || current.dir !== dir) { if (win.READIUM2.ttsSkippabilityEnabled) { const epubTypes = (0, exports.computeEpubTypes)(parentElement); const isSkippable = epubTypes.find((et) => _skippables.includes(et)) ? true : undefined; if (isSkippable) { return; } } current = { combinedText: "", combinedTextSentences: undefined, combinedTextSentencesRangeBegin: undefined, combinedTextSentencesRangeEnd: undefined, dir, lang, parentElement, textNodes: [], }; ttsQueue.push(current); } current.textNodes.push(textNode); } let first = true; function processElement(element) { var _a, _b, _c, _d, _e, _f, _g, _h; if (element.nodeType !== Node.ELEMENT_NODE) { first = false; return; } const documant = element.ownerDocument; function isHidden(el) { var _a, _b; if (el.getAttribute("id") === styles_1.SKIP_LINK_ID) { return true; } const lower = (_a = el.tagName) === null || _a === void 0 ? void 0 : _a.toLowerCase(); if (documant.documentElement.classList.contains(styles_1.ROOT_CLASS_NO_RUBY)) { if (lower === "rt" || lower === "rp") { return true; } } else { if (true && (lower === "rb")) { } } let curEl = el; do { if (curEl.nodeType === Node.ELEMENT_NODE && ((_b = curEl.tagName) === null || _b === void 0 ? void 0 : _b.toLowerCase()) === "details" && !curEl.open) { return true; } } while (curEl.parentNode && curEl.parentNode.nodeType === Node.ELEMENT_NODE && (curEl = curEl.parentNode)); const elStyle = win.getComputedStyle(el); if (elStyle) { const display = elStyle.getPropertyValue("display"); if (display === "none") { return true; } else { const opacity = elStyle.getPropertyValue("opacity"); if (opacity === "0") { return true; } } } if (el.getAttribute("hidden") || el.getAttribute("aria-hidden") === "true") { return true; } return false; } const hidden = isHidden(element); if (hidden) { first = false; return; } if (win.READIUM2.ttsSkippabilityEnabled) { const epubTypes = (0, exports.computeEpubTypes)(element); const isSkippable = epubTypes.find((et) => _skippables.includes(et)) ? true : undefined; if (isSkippable) { first = false; return; } } const tagNameLow = element.tagName ? element.tagName.toLowerCase() : undefined; const putInElementStack = first || tagNameLow && _putInElementStackTagNames.includes(tagNameLow); first = false; if (putInElementStack) { elementStack.push(element); } for (const childNode of element.childNodes) { switch (childNode.nodeType) { case Node.ELEMENT_NODE: const childElement = childNode; const childTagNameLow = childElement.tagName ? childElement.tagName.toLowerCase() : undefined; const hidden = isHidden(childElement); const epubTypes = (0, exports.computeEpubTypes)(childElement); const isSkippable = epubTypes.find((et) => _skippables.includes(et)) ? true : undefined; if (win.READIUM2.ttsSkippabilityEnabled && isSkippable) { continue; } const isPageBreak = epubTypes.find((et) => et === "pagebreak") ? true : false; let pageBreakNeedsDeepDive = isPageBreak && !hidden; if (pageBreakNeedsDeepDive) { let altAttr = childElement.getAttribute("title"); if (altAttr) { const txt = altAttr.trim(); if (txt) { pageBreakNeedsDeepDive = false; const lang = getLanguage(childElement); const dir = undefined; ttsQueue.push({ combinedText: txt, combinedTextSentences: undefined, combinedTextSentencesRangeBegin: undefined, combinedTextSentencesRangeEnd: undefined, dir, lang, parentElement: childElement, textNodes: [], }); } } else { altAttr = childElement.getAttribute("aria-label"); if (altAttr) { const txt = altAttr.trim(); if (txt) { pageBreakNeedsDeepDive = false; const lang = getLanguage(childElement); const dir = undefined; ttsQueue.push({ combinedText: txt, combinedTextSentences: undefined, combinedTextSentencesRangeBegin: undefined, combinedTextSentencesRangeEnd: undefined, dir, lang, parentElement: childElement, textNodes: [], }); } } } } const isLink = childTagNameLow === "a" && childElement.href; let linkNeedsDeepDive = isLink && !hidden; if (linkNeedsDeepDive) { let altAttr = childElement.getAttribute("title"); if (altAttr) { const txt = altAttr.trim(); if (txt) { linkNeedsDeepDive = false; const lang = getLanguage(childElement); const dir = undefined; ttsQueue.push({ combinedText: txt, combinedTextSentences: undefined, combinedTextSentencesRangeBegin: undefined, combinedTextSentencesRangeEnd: undefined, dir, lang, parentElement: childElement, textNodes: [], }); } } else { altAttr = childElement.getAttribute("aria-label"); if (altAttr) { const txt = altAttr.trim(); if (txt) { linkNeedsDeepDive = false; const lang = getLanguage(childElement); const dir = undefined; ttsQueue.push({ combinedText: txt, combinedTextSentences: undefined, combinedTextSentencesRangeBegin: undefined, combinedTextSentencesRangeEnd: undefined, dir, lang, parentElement: childElement, textNodes: [], }); } } } } const isMathJax = childTagNameLow && childTagNameLow.startsWith("mjx-"); const isMathML = childTagNameLow === "math"; const processDeepChild = pageBreakNeedsDeepDive || linkNeedsDeepDive || (!isPageBreak && !isLink && !isMathJax && !isMathML && childTagNameLow && !_doNotProcessDeepChildTagNames.includes(childTagNameLow)); if (processDeepChild) { processElement(childElement); } else if (!hidden) { if (isPageBreak || isLink) { } else if (isMathML) { const altAttr = childElement.getAttribute("alttext"); if (altAttr) { const txt = altAttr.trim(); if (txt) { const lang = getLanguage(childElement); const dir = undefined; ttsQueue.push({ combinedText: txt, combinedTextSentences: undefined, combinedTextSentencesRangeBegin: undefined, combinedTextSentencesRangeEnd: undefined, dir, lang, parentElement: childElement, textNodes: [], }); } } else { const txt = (_a = childElement.textContent) === null || _a === void 0 ? void 0 : _a.trim(); if (txt) { const lang = getLanguage(childElement); const dir = getDirection(childElement); ttsQueue.push({ combinedText: txt, combinedTextSentences: undefined, combinedTextSentencesRangeBegin: undefined, combinedTextSentencesRangeEnd: undefined, dir, lang, parentElement: childElement, textNodes: [], }); } } } else if (isMathJax) { if (childTagNameLow === "mjx-container") { let mathJaxEl; let mathJaxElMathML; const mathJaxContainerChildren = Array.from(childElement.children); for (const mathJaxContainerChild of mathJaxContainerChildren) { if (((_b = mathJaxContainerChild.tagName) === null || _b === void 0 ? void 0 : _b.toLowerCase()) === "mjx-math") { mathJaxEl = mathJaxContainerChild; } else if (((_c = mathJaxContainerChild.tagName) === null || _c === void 0 ? void 0 : _c.toLowerCase()) === "mjx-assistive-mml") { const mathJaxAMMLChildren = Array.from(mathJaxContainerChild.children); for (const mathJaxAMMLChild of mathJaxAMMLChildren) { if (((_d = mathJaxAMMLChild.tagName) === null || _d === void 0 ? void 0 : _d.toLowerCase()) === "math") { mathJaxElMathML = mathJaxAMMLChild; break; } } } } const altAttr = childElement.getAttribute("aria-label"); if (altAttr) { const txt = altAttr.trim(); if (txt) { const lang = getLanguage(childElement); const dir = undefined; ttsQueue.push({ combinedText: txt, combinedTextSentences: undefined, combinedTextSentencesRangeBegin: undefined, combinedTextSentencesRangeEnd: undefined, dir, lang, parentElement: mathJaxEl !== null && mathJaxEl !== void 0 ? mathJaxEl : childElement, textNodes: [], }); } } else if (mathJaxElMathML) { const altAttr = mathJaxElMathML.getAttribute("alttext"); if (altAttr) { const txt = altAttr.trim(); if (txt) { const lang = getLanguage(mathJaxElMathML); const dir = undefined; ttsQueue.push({ combinedText: txt, combinedTextSentences: undefined, combinedTextSentencesRangeBegin: undefined, combinedTextSentencesRangeEnd: undefined, dir, lang, parentElement: mathJaxEl !== null && mathJaxEl !== void 0 ? mathJaxEl : childElement, textNodes: [], }); } } else { const txt = (_e = mathJaxElMathML.textContent) === null || _e === void 0 ? void 0 : _e.trim(); if (txt) { const lang = getLanguage(mathJaxElMathML); const dir = getDirection(mathJaxElMathML); ttsQueue.push({ combinedText: txt, combinedTextSentences: undefined, combinedTextSentencesRangeBegin: undefined, combinedTextSentencesRangeEnd: undefined, dir, lang, parentElement: mathJaxEl !== null && mathJaxEl !== void 0 ? mathJaxEl : childElement, textNodes: [], }); } } break; } } } else if (childTagNameLow === "img" && childElement.src) { let altAttr = childElement.getAttribute("alt"); if (altAttr) { const txt = altAttr.trim(); if (txt) { const lang = getLanguage(childElement); const dir = undefined; ttsQueue.push({ combinedText: txt, combinedTextSentences: undefined, combinedTextSentencesRangeBegin: undefined, combinedTextSentencesRangeEnd: undefined, dir, lang, parentElement: childElement, textNodes: [], }); } } else { altAttr = childElement.getAttribute("aria-label"); if (altAttr) { const txt = altAttr.trim(); if (txt) { const lang = getLanguage(childElement); const dir = undefined; ttsQueue.push({ combinedText: txt, combinedTextSentences: undefined, combinedTextSentencesRangeBegin: undefined, combinedTextSentencesRangeEnd: undefined, dir, lang, parentElement: childElement, textNodes: [], }); } } } } else if (childTagNameLow === "svg") { let done = false; const altAttr = childElement.getAttribute("aria-label"); if (altAttr) { const txt = altAttr.trim(); if (txt) { done = true; const lang = getLanguage(childElement); const dir = undefined; ttsQueue.push({ combinedText: txt, combinedTextSentences: undefined, combinedTextSentencesRangeBegin: undefined, combinedTextSentencesRangeEnd: undefined, dir, lang, parentElement: childElement, textNodes: [], }); } } else { const svgChildren = Array.from(childElement.children); for (const svgChild of svgChildren) { if (((_f = svgChild.tagName) === null || _f === void 0 ? void 0 : _f.toLowerCase()) === "title") { const txt = (_g = svgChild.textContent) === null || _g === void 0 ? void 0 : _g.trim(); if (txt) { done = true; const lang = getLanguage(svgChild); const dir = getDirection(svgChild); ttsQueue.push({ combinedText: txt, combinedTextSentences: undefined, combinedTextSentencesRangeBegin: undefined, combinedTextSentencesRangeEnd: undefined, dir, lang, parentElement: childElement, textNodes: [], }); } break; } } } if (!done) { const iter = win.document.createNodeIterator(childElement, NodeFilter.SHOW_ELEMENT, { acceptNode: (node) => { const low = node.nodeName.toLowerCase(); return low === "text" || low === "math" ? NodeFilter.FILTER_ACCEPT : NodeFilter.FILTER_REJECT; }, }); let n; while (n = iter.nextNode()) { const el = n; const parentElement = elementStack[elementStack.length - 1]; if (parentElement !== el) { elementStack.push(el); } try { processElement(el); } catch (err) { console.log("SVG TTS error: ", err); const txt = (_h = el.textContent) === null || _h === void 0 ? void 0 : _h.trim(); if (txt) { const lang = getLanguage(el); const dir = getDirection(el); ttsQueue.push({ combinedText: txt, combinedTextSentences: undefined, combinedTextSentencesRangeBegin: undefined, combinedTextSentencesRangeEnd: undefined, dir, lang, parentElement: el, textNodes: [], }); } } elementStack.pop(); } } } } break; case Node.TEXT_NODE: if (elementStack.length !== 0) { processTextNode(childNode); } break; default: break; } } if (putInElementStack) { elementStack.pop(); } } processElement(rootElement); function finalizeTextNodes(ttsQueueItem) { if (!ttsQueueItem.textNodes || !ttsQueueItem.textNodes.length) { if (!ttsQueueItem.combinedText || !ttsQueueItem.combinedText.length) { ttsQueueItem.combinedText = ""; } ttsQueueItem.combinedTextSentences = undefined; return; } ttsQueueItem.combinedText = combineTextNodes(ttsQueueItem.textNodes, true).replace(/[\r\n]/g, " "); if (!ttsQueueItem.combinedText.trim().length) { ttsQueueItem.combinedText = ""; ttsQueueItem.combinedTextSentences = undefined; return; } let skipSplitSentences = false; let parent = ttsQueueItem.parentElement; while (parent) { if (parent.tagName) { const tag = parent.tagName.toLowerCase(); if (tag === "pre" || tag === "code" || tag === "video" || tag === "audio" || tag === "img" || tag === "svg" || tag === "math" || tag.startsWith("mjx-")) { skipSplitSentences = true; break; } } parent = parent.parentElement; } if (splitSentences && !skipSplitSentences) { try { const txt = ttsQueueItem.combinedText; ttsQueueItem.combinedTextSentences = undefined; const sentences = (0, sentence_splitter_1.split)(txt); ttsQueueItem.combinedTextSentences = []; ttsQueueItem.combinedTextSentencesRangeBegin = []; ttsQueueItem.combinedTextSentencesRangeEnd = []; for (const sentence of sentences) { if (sentence.type === "Sentence") { ttsQueueItem.combinedTextSentences.push(sentence.raw); ttsQueueItem.combinedTextSentencesRangeBegin.push(sentence.range[0]); ttsQueueItem.combinedTextSentencesRangeEnd.push(sentence.range[1]); } } if (ttsQueueItem.combinedTextSentences.length === 0 || ttsQueueItem.combinedTextSentences.length === 1) { ttsQueueItem.combinedTextSentences = undefined; } else { } } catch (err) { console.log(err); ttsQueueItem.combinedTextSentences = undefined; } } else { ttsQueueItem.combinedTextSentences = undefined; } } for (const ttsQueueItem of ttsQueue) { finalizeTextNodes(ttsQueueItem); } ttsQueue = ttsQueue.filter((item) => { return !!item.combinedText.length; }); return ttsQueue; } //# sourceMappingURL=dom-text-utils.js.map