@internetarchive/bookreader 5.0.0-61 → 5.0.0-62
Sign up to get free protection for your applications and to get access to all the features.
- package/BookReader/BookReader.css +63 -14
- package/BookReader/BookReader.js +1 -1
- package/BookReader/BookReader.js.map +1 -1
- package/BookReader/plugins/plugin.search.js +1 -1
- package/BookReader/plugins/plugin.search.js.map +1 -1
- package/BookReader/plugins/plugin.text_selection.js +1 -1
- package/BookReader/plugins/plugin.text_selection.js.map +1 -1
- package/BookReader/plugins/plugin.tts.js +1 -1
- package/BookReader/plugins/plugin.tts.js.map +1 -1
- package/BookReaderDemo/BookReaderDemo.css +2 -0
- package/BookReaderDemo/demo-internetarchive.html +91 -0
- package/CHANGELOG.md +5 -0
- package/package.json +2 -2
- package/src/BookReader/BookModel.js +2 -2
- package/src/BookReader/ModeThumb.js +1 -1
- package/src/BookReader/PageContainer.js +12 -0
- package/src/BookReader/events.js +0 -2
- package/src/BookReader/utils/SelectionObserver.js +43 -0
- package/src/BookReader.js +0 -264
- package/src/css/_BRpages.scss +2 -0
- package/src/css/_TextSelection.scss +84 -23
- package/src/plugins/plugin.text_selection.js +437 -112
- package/src/plugins/search/view.js +0 -9
- package/tests/jest/BookReader/BookModel.test.js +15 -0
- package/tests/jest/BookReader/utils/SelectionObserver.test.js +43 -0
- package/tests/jest/plugins/plugin.text_selection.test.js +166 -44
- package/src/BookReader/utils/SelectionStartedObserver.js +0 -46
- package/tests/jest/BookReader/utils/SelectionStartedObserver.test.js +0 -73
@@ -1 +1 @@
|
|
1
|
-
{"version":3,"file":"plugins/plugin.text_selection.js","mappings":"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","sources":["webpack://@internetarchive/bookreader/./src/BookReader/utils/SelectionStartedObserver.js","webpack://@internetarchive/bookreader/./src/util/strings.js","webpack://@internetarchive/bookreader/./src/plugins/plugin.text_selection.js","webpack://@internetarchive/bookreader/./src/util/browserSniffing.js","webpack://@internetarchive/bookreader/./node_modules/core-js/internals/number-parse-float.js","webpack://@internetarchive/bookreader/./node_modules/core-js/internals/string-trim-forced.js","webpack://@internetarchive/bookreader/./node_modules/core-js/modules/es.parse-float.js","webpack://@internetarchive/bookreader/./node_modules/core-js/modules/es.string.trim.js"],"sourcesContent":["// @ts-check\nexport class SelectionStartedObserver {\n loggedForSelection = false;\n startedInSelector = false;\n\n /**\n * @param {string} selector\n * @param {function(): any} handler\n */\n constructor(selector, handler) {\n this.selector = selector;\n this.handler = handler;\n }\n\n attach() {\n // We can't just use select start, because Chrome fires that willy\n // nilly even when a user slightly long presses.\n document.addEventListener(\"selectstart\", this._onSelectStart);\n // This has to be on document :/\n document.addEventListener(\"selectionchange\", this._onSelectionChange);\n }\n\n detach() {\n document.removeEventListener(\"selectstart\", this._onSelectStart);\n document.removeEventListener(\"selectionchange\", this._onSelectionChange);\n }\n\n /**\n * @param {Event} ev\n */\n _onSelectStart = (ev) => {\n this.loggedForSelection = false;\n // Use jQuery because ev.target could be a Node (eg TextNode), which\n // doesn't have .closest on it.\n this.startedInSelector = $(ev.target).closest(this.selector).length > 0;\n };\n\n _onSelectionChange = () => {\n if (this.loggedForSelection || !this.startedInSelector) return;\n const sel = window.getSelection();\n if (sel.toString()) {\n this.loggedForSelection = true;\n this.handler();\n }\n };\n}\n","/**\n * @typedef {String} StringWithVars\n * A template string with {{foo}} style variables\n * Also supports filters, like {{bookPath|urlencode}} (See APPLY_FILTERS for the\n * supported list of filters)\n **/\n\n/**\n * @param {StringWithVars|String} template\n * @param { {[varName: string]: { toString: () => string} } } vars\n * @param { {[varName: string]: { toString: () => string} } } [overrides]\n */\nexport function applyVariables(template, vars, overrides = {}, possibleFilters = APPLY_FILTERS) {\n return template?.replace(/\\{\\{([^}]*?)\\}\\}/g, ($0, $1) => {\n if (!$1) return $0;\n /** @type {string} */\n const expression = $1;\n const [varName, ...filterNames] = expression.split('|').map(x => x.trim());\n const defined = varName in overrides || varName in vars;\n\n // If it's not defined, don't expand it at all\n if (!defined) return $0;\n\n const value = varName in overrides ? overrides[varName]\n : varName in vars ? vars[varName] : null;\n const filters = filterNames.map(n => possibleFilters[n]);\n return filters.reduce((acc, cur) => cur(acc), value && value.toString());\n });\n}\n\n/** @type { {[filterName: String]:( string => string)} } */\nexport const APPLY_FILTERS = {\n urlencode: encodeURIComponent,\n};\n","//@ts-check\nimport { createSVGPageLayer } from '../BookReader/PageContainer.js';\nimport { SelectionStartedObserver } from '../BookReader/utils/SelectionStartedObserver.js';\nimport { isFirefox, isSafari } from '../util/browserSniffing.js';\nimport { applyVariables } from '../util/strings.js';\n/** @typedef {import('../util/strings.js').StringWithVars} StringWithVars */\n/** @typedef {import('../BookReader/PageContainer.js').PageContainer} PageContainer */\n\nconst BookReader = /** @type {typeof import('../BookReader').default} */(window.BookReader);\n\nexport const DEFAULT_OPTIONS = {\n enabled: true,\n /** @type {StringWithVars} The URL to fetch the entire DJVU xml. Supports options.vars */\n fullDjvuXmlUrl: null,\n /** @type {StringWithVars} The URL to fetch a single page of the DJVU xml. Supports options.vars. Also has {{pageIndex}} */\n singlePageDjvuXmlUrl: null,\n /** Whether to fetch the XML as a jsonp */\n jsonp: false,\n};\n/** @typedef {typeof DEFAULT_OPTIONS} TextSelectionPluginOptions */\n\n/**\n * @template T\n */\nexport class Cache {\n constructor(maxSize = 10) {\n this.maxSize = maxSize;\n /** @type {T[]} */\n this.entries = [];\n }\n\n /**\n * @param {T} entry\n */\n add(entry) {\n if (this.entries.length >= this.maxSize) {\n this.entries.shift();\n }\n this.entries.push(entry);\n }\n}\n\nexport class TextSelectionPlugin {\n\n constructor(options = DEFAULT_OPTIONS, optionVariables, avoidTspans = isFirefox(), pointerEventsOnParagraph = isSafari()) {\n this.options = options;\n this.optionVariables = optionVariables;\n /**@type {PromiseLike<JQuery<HTMLElement>|undefined>} */\n this.djvuPagesPromise = null;\n // Using text elements instead of tspans for words because Firefox does not allow svg tspan stretch.\n // Tspans are necessary on Chrome because they prevent newline character after every word when copying\n this.svgParagraphElement = \"text\";\n this.svgWordElement = \"tspan\";\n this.insertNewlines = avoidTspans;\n // Safari has a bug where `pointer-events` doesn't work on `<tspans>`. So\n // there we will set `pointer-events: all` on the paragraph element. We don't\n // do this everywhere, because it's a worse experience. Thanks Safari :/\n this.pointerEventsOnParagraph = pointerEventsOnParagraph;\n if (avoidTspans) {\n this.svgParagraphElement = \"g\";\n this.svgWordElement = \"text\";\n }\n\n /** @type {Cache<{index: number, response: any}>} */\n this.pageTextCache = new Cache();\n\n /**\n * Sometimes there are too many words on a page, and the browser becomes near\n * unusable. For now don't render text layer for pages with too many words.\n */\n this.maxWordRendered = 2500;\n }\n\n init() {\n // Only fetch the full djvu xml if the single page url isn't there\n if (this.options.singlePageDjvuXmlUrl) return;\n this.djvuPagesPromise = $.ajax({\n type: \"GET\",\n url: applyVariables(this.options.fullDjvuXmlUrl, this.optionVariables),\n dataType: this.options.jsonp ? \"jsonp\" : \"html\",\n cache: true,\n error: (e) => undefined\n }).then((res) => {\n try {\n const xmlMap = $.parseXML(res);\n return xmlMap && $(xmlMap).find(\"OBJECT\");\n } catch (e) {\n return undefined;\n }\n });\n }\n\n /**\n * @param {number} index\n * @returns {Promise<HTMLElement|undefined>}\n */\n async getPageText(index) {\n if (this.options.singlePageDjvuXmlUrl) {\n const cachedEntry = this.pageTextCache.entries.find(x => x.index == index);\n if (cachedEntry) {\n return cachedEntry.response;\n }\n const res = await $.ajax({\n type: \"GET\",\n url: applyVariables(this.options.singlePageDjvuXmlUrl, this.optionVariables, { pageIndex: index }),\n dataType: this.options.jsonp ? \"jsonp\" : \"html\",\n cache: true,\n error: (e) => undefined,\n });\n try {\n const xmlDoc = $.parseXML(res);\n const result = xmlDoc && $(xmlDoc).find(\"OBJECT\")[0];\n this.pageTextCache.add({ index, response: result });\n return result;\n } catch (e) {\n return undefined;\n }\n } else {\n const XMLpagesArr = await this.djvuPagesPromise;\n if (XMLpagesArr) return XMLpagesArr[index];\n }\n }\n\n /**\n * Intercept copied text to remove any styling applied to it\n * @param {JQuery} $container\n */\n interceptCopy($container) {\n $container[0].addEventListener('copy', (event) => {\n const selection = document.getSelection();\n event.clipboardData.setData('text/plain', selection.toString());\n event.preventDefault();\n });\n }\n\n /**\n * Applies mouse events when in default mode\n * @param {SVGElement} svg\n */\n defaultMode(svg) {\n svg.classList.remove(\"selectingSVG\");\n $(svg).on(\"mousedown.textSelectPluginHandler\", (event) => {\n if (!$(event.target).is(\".BRwordElement\")) return;\n event.stopPropagation();\n svg.classList.add(\"selectingSVG\");\n $(svg).one(\"mouseup.textSelectPluginHandler\", (event) => {\n if (window.getSelection().toString() != \"\") {\n event.stopPropagation();\n $(svg).off(\".textSelectPluginHandler\");\n this.textSelectingMode(svg);\n }\n else svg.classList.remove(\"selectingSVG\");\n });\n });\n }\n\n /**\n * Applies mouse events when in textSelecting mode\n * @param {SVGElement} svg\n */\n textSelectingMode(svg) {\n $(svg).on('mousedown.textSelectPluginHandler', (event) => {\n if (!$(event.target).is(\".BRwordElement\")) {\n if (window.getSelection().toString() != \"\") window.getSelection().removeAllRanges();\n }\n event.stopPropagation();\n });\n $(svg).on('mouseup.textSelectPluginHandler', (event) => {\n event.stopPropagation();\n if (window.getSelection().toString() == \"\") {\n $(svg).off(\".textSelectPluginHandler\");\n this.defaultMode(svg); }\n });\n }\n\n /**\n * Initializes text selection modes if there is an svg on the page\n * @param {JQuery} $container\n */\n stopPageFlip($container) {\n /** @type {JQuery<SVGElement>} */\n const $svg = $container.find('svg.textSelectionSVG');\n if (!$svg.length) return;\n $svg.each((i, s) => this.defaultMode(s));\n this.interceptCopy($container);\n }\n\n /**\n * @param {PageContainer} pageContainer\n */\n async createTextLayer(pageContainer) {\n const pageIndex = pageContainer.page.index;\n const $container = pageContainer.$container;\n const $svgLayers = $container.find('.textSelectionSVG');\n if ($svgLayers.length) return;\n const XMLpage = await this.getPageText(pageIndex);\n if (!XMLpage) return;\n\n const totalWords = $(XMLpage).find(\"WORD\").length;\n if (totalWords > this.maxWordRendered) {\n console.log(`Page ${pageIndex} has too many words (${totalWords} > ${this.maxWordRendered}). Not rendering text layer.`);\n return;\n }\n\n const svg = createSVGPageLayer(pageContainer.page, 'textSelectionSVG');\n $container.append(svg);\n\n $(XMLpage).find(\"PARAGRAPH\").each((i, paragraph) => {\n // Adding text element for each paragraph in the page\n const words = $(paragraph).find(\"WORD\");\n if (!words.length) return;\n const paragSvg = document.createElementNS(\"http://www.w3.org/2000/svg\", this.svgParagraphElement);\n paragSvg.setAttribute(\"class\", \"BRparagElement\");\n if (this.pointerEventsOnParagraph) {\n paragSvg.style.pointerEvents = \"all\";\n }\n\n const wordHeightArr = [];\n\n for (let i = 0; i < words.length; i++) {\n // Adding tspan for each word in paragraph\n const currWord = words[i];\n // eslint-disable-next-line no-unused-vars\n const [left, bottom, right, top] = $(currWord).attr(\"coords\").split(',').map(parseFloat);\n const wordHeight = bottom - top;\n wordHeightArr.push(wordHeight);\n\n const wordTspan = document.createElementNS(\"http://www.w3.org/2000/svg\", this.svgWordElement);\n wordTspan.setAttribute(\"class\", \"BRwordElement\");\n wordTspan.setAttribute(\"x\", left.toString());\n wordTspan.setAttribute(\"y\", bottom.toString());\n wordTspan.setAttribute(\"textLength\", (right - left).toString());\n wordTspan.setAttribute(\"lengthAdjust\", \"spacingAndGlyphs\");\n wordTspan.textContent = currWord.textContent;\n paragSvg.appendChild(wordTspan);\n\n // Adding spaces after words except at the end of the paragraph\n // TODO: assumes left-to-right text\n if (i < words.length - 1) {\n const nextWord = words[i + 1];\n // eslint-disable-next-line no-unused-vars\n const [leftNext, bottomNext, rightNext, topNext] = $(nextWord).attr(\"coords\").split(',').map(parseFloat);\n const spaceTspan = document.createElementNS(\"http://www.w3.org/2000/svg\", this.svgWordElement);\n spaceTspan.setAttribute(\"class\", \"BRwordElement\");\n spaceTspan.setAttribute(\"x\", right.toString());\n spaceTspan.setAttribute(\"y\", bottom.toString());\n if ((leftNext - right) > 0) spaceTspan.setAttribute(\"textLength\", (leftNext - right).toString());\n spaceTspan.setAttribute(\"lengthAdjust\", \"spacingAndGlyphs\");\n spaceTspan.textContent = \" \";\n paragSvg.appendChild(spaceTspan);\n }\n\n // Adds newline at the end of paragraph on Firefox\n if ((i == words.length - 1 && (this.insertNewlines))) {\n paragSvg.appendChild(document.createTextNode(\"\\n\"));\n }\n }\n\n wordHeightArr.sort();\n const paragWordHeight = wordHeightArr[Math.floor(wordHeightArr.length * 0.85)];\n paragSvg.setAttribute(\"font-size\", paragWordHeight.toString());\n svg.appendChild(paragSvg);\n });\n this.stopPageFlip($container);\n }\n}\n\nexport class BookreaderWithTextSelection extends BookReader {\n init() {\n const options = Object.assign({}, DEFAULT_OPTIONS, this.options.plugins.textSelection);\n if (options.enabled) {\n this.textSelectionPlugin = new TextSelectionPlugin(options, this.options.vars);\n // Write this back; this way the plugin is the source of truth, and BR just\n // contains a reference to it.\n this.options.plugins.textSelection = options;\n this.textSelectionPlugin.init();\n\n // Track how often selection is used\n const sso = new SelectionStartedObserver('.textSelectionSVG', () => {\n // Don't assume the order of the plugins ; the analytics plugin could\n // have been added later. But at this point we should know for certain.\n if (!this.archiveAnalyticsSendEvent) {\n sso.detach();\n } else {\n this.archiveAnalyticsSendEvent('BookReader', 'SelectStart');\n }\n });\n sso.attach();\n }\n\n super.init();\n }\n\n /**\n * @param {number} index\n */\n _createPageContainer(index) {\n const pageContainer = super._createPageContainer(index);\n // Disable if thumb mode; it's too janky\n // .page can be null for \"pre-cover\" region\n if (this.mode !== this.constModeThumb && pageContainer.page) {\n this.textSelectionPlugin?.createTextLayer(pageContainer);\n }\n return pageContainer;\n }\n}\nwindow.BookReader = BookreaderWithTextSelection;\nexport default BookreaderWithTextSelection;\n","\n/**\n * Checks whether the current browser is a Chrome/Chromium browser\n * Code from https://stackoverflow.com/a/4565120/2317712\n * @param {string} [userAgent]\n * @param {string} [vendor]\n * @return {boolean}\n */\nexport function isChrome(userAgent = navigator.userAgent, vendor = navigator.vendor) {\n return /chrome/i.test(userAgent) && /google inc/i.test(vendor);\n}\n\n/**\n * Checks whether the current browser is firefox\n * @param {string} [userAgent]\n * @return {boolean}\n */\nexport function isFirefox(userAgent = navigator.userAgent) {\n return /firefox/i.test(userAgent);\n}\n\n/**\n * Checks whether the current browser is safari\n * https://developer.mozilla.org/en-US/docs/Web/HTTP/Browser_detection_using_the_user_agent#Browser_Name\n * @param {string} [userAgent]\n * @return {boolean}\n */\nexport function isSafari(userAgent = navigator.userAgent) {\n return /safari/i.test(userAgent) && !/chrome|chromium/i.test(userAgent);\n}\n","var global = require('../internals/global');\nvar fails = require('../internals/fails');\nvar uncurryThis = require('../internals/function-uncurry-this');\nvar toString = require('../internals/to-string');\nvar trim = require('../internals/string-trim').trim;\nvar whitespaces = require('../internals/whitespaces');\n\nvar charAt = uncurryThis(''.charAt);\nvar n$ParseFloat = global.parseFloat;\nvar Symbol = global.Symbol;\nvar ITERATOR = Symbol && Symbol.iterator;\nvar FORCED = 1 / n$ParseFloat(whitespaces + '-0') !== -Infinity\n // MS Edge 18- broken with boxed symbols\n || (ITERATOR && !fails(function () { n$ParseFloat(Object(ITERATOR)); }));\n\n// `parseFloat` method\n// https://tc39.es/ecma262/#sec-parsefloat-string\nmodule.exports = FORCED ? function parseFloat(string) {\n var trimmedString = trim(toString(string));\n var result = n$ParseFloat(trimmedString);\n return result === 0 && charAt(trimmedString, 0) == '-' ? -0 : result;\n} : n$ParseFloat;\n","var PROPER_FUNCTION_NAME = require('../internals/function-name').PROPER;\nvar fails = require('../internals/fails');\nvar whitespaces = require('../internals/whitespaces');\n\nvar non = '\\u200B\\u0085\\u180E';\n\n// check that a method works with the correct list\n// of whitespaces and has a correct name\nmodule.exports = function (METHOD_NAME) {\n return fails(function () {\n return !!whitespaces[METHOD_NAME]()\n || non[METHOD_NAME]() !== non\n || (PROPER_FUNCTION_NAME && whitespaces[METHOD_NAME].name !== METHOD_NAME);\n });\n};\n","var $ = require('../internals/export');\nvar $parseFloat = require('../internals/number-parse-float');\n\n// `parseFloat` method\n// https://tc39.es/ecma262/#sec-parsefloat-string\n$({ global: true, forced: parseFloat != $parseFloat }, {\n parseFloat: $parseFloat\n});\n","'use strict';\nvar $ = require('../internals/export');\nvar $trim = require('../internals/string-trim').trim;\nvar forcedStringTrimMethod = require('../internals/string-trim-forced');\n\n// `String.prototype.trim` method\n// https://tc39.es/ecma262/#sec-string.prototype.trim\n$({ target: 'String', proto: true, forced: forcedStringTrimMethod('trim') }, {\n trim: function trim() {\n return $trim(this);\n }\n});\n"],"names":["SelectionStartedObserver","selector","handler","ev","loggedForSelection","startedInSelector","$","target","closest","length","window","getSelection","toString","this","document","addEventListener","_onSelectStart","_onSelectionChange","removeEventListener","applyVariables","template","vars","overrides","possibleFilters","APPLY_FILTERS","replace","$0","$1","split","map","x","trim","varName","filterNames","value","n","reduce","acc","cur","urlencode","encodeURIComponent","BookReader","DEFAULT_OPTIONS","enabled","fullDjvuXmlUrl","singlePageDjvuXmlUrl","jsonp","Cache","maxSize","entries","entry","shift","push","TextSelectionPlugin","options","optionVariables","avoidTspans","isFirefox","pointerEventsOnParagraph","isSafari","djvuPagesPromise","svgParagraphElement","svgWordElement","insertNewlines","pageTextCache","maxWordRendered","ajax","type","url","dataType","cache","error","e","then","res","xmlMap","parseXML","find","index","cachedEntry","response","pageIndex","xmlDoc","result","add","undefined","XMLpagesArr","$container","event","selection","clipboardData","setData","preventDefault","svg","classList","remove","on","is","stopPropagation","one","off","textSelectingMode","removeAllRanges","defaultMode","$svg","each","i","s","interceptCopy","pageContainer","page","getPageText","XMLpage","totalWords","console","log","createSVGPageLayer","append","paragraph","words","paragSvg","createElementNS","setAttribute","style","pointerEvents","wordHeightArr","currWord","attr","parseFloat","left","bottom","right","wordHeight","wordTspan","textContent","appendChild","nextWord","leftNext","spaceTspan","createTextNode","sort","paragWordHeight","Math","floor","stopPageFlip","BookreaderWithTextSelection","Object","assign","plugins","textSelection","textSelectionPlugin","init","sso","archiveAnalyticsSendEvent","detach","attach","mode","constModeThumb","createTextLayer","isChrome","userAgent","navigator","vendor","test","global","fails","uncurryThis","whitespaces","charAt","n$ParseFloat","Symbol","ITERATOR","iterator","FORCED","module","exports","string","trimmedString","PROPER_FUNCTION_NAME","METHOD_NAME","name","$parseFloat","forced","$trim","proto","forcedStringTrimMethod"],"sourceRoot":""}
|
1
|
+
{"version":3,"file":"plugins/plugin.text_selection.js","mappings":"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","sources":["webpack://@internetarchive/bookreader/./src/BookReader/utils/SelectionObserver.js","webpack://@internetarchive/bookreader/./src/util/strings.js","webpack://@internetarchive/bookreader/./src/plugins/plugin.text_selection.js","webpack://@internetarchive/bookreader/./node_modules/core-js/internals/number-parse-float.js","webpack://@internetarchive/bookreader/./node_modules/core-js/internals/string-trim-forced.js","webpack://@internetarchive/bookreader/./node_modules/core-js/modules/es.parse-float.js","webpack://@internetarchive/bookreader/./node_modules/core-js/modules/es.string.trim.js"],"sourcesContent":["// @ts-check\nexport class SelectionObserver {\n selecting = false;\n startedInSelector = false;\n /** @type {HTMLElement} */\n target = null;\n\n /**\n * @param {string} selector\n * @param {function('started' | 'cleared', HTMLElement): any} handler\n */\n constructor(selector, handler) {\n this.selector = selector;\n this.handler = handler;\n }\n\n attach() {\n // We can't just use selectstart, because safari on iOS just\n // randomly decides when to fire it 😤\n // document.addEventListener(\"selectstart\", this._onSelectStart);\n // This has to be on document :/\n document.addEventListener(\"selectionchange\", this._onSelectionChange);\n }\n\n detach() {\n document.removeEventListener(\"selectionchange\", this._onSelectionChange);\n }\n\n _onSelectionChange = () => {\n const sel = window.getSelection();\n\n if (!this.selecting && sel.toString()) {\n this.selecting = true;\n this.target = $(sel.anchorNode).closest(this.selector)[0];\n this.handler('started', this.target);\n }\n\n if (this.selecting && (sel.isCollapsed || !sel.toString() || !$(sel.anchorNode).closest(this.selector)[0])) {\n this.selecting = false;\n this.handler('cleared', this.target);\n }\n };\n}\n","/**\n * @typedef {String} StringWithVars\n * A template string with {{foo}} style variables\n * Also supports filters, like {{bookPath|urlencode}} (See APPLY_FILTERS for the\n * supported list of filters)\n **/\n\n/**\n * @param {StringWithVars|String} template\n * @param { {[varName: string]: { toString: () => string} } } vars\n * @param { {[varName: string]: { toString: () => string} } } [overrides]\n */\nexport function applyVariables(template, vars, overrides = {}, possibleFilters = APPLY_FILTERS) {\n return template?.replace(/\\{\\{([^}]*?)\\}\\}/g, ($0, $1) => {\n if (!$1) return $0;\n /** @type {string} */\n const expression = $1;\n const [varName, ...filterNames] = expression.split('|').map(x => x.trim());\n const defined = varName in overrides || varName in vars;\n\n // If it's not defined, don't expand it at all\n if (!defined) return $0;\n\n const value = varName in overrides ? overrides[varName]\n : varName in vars ? vars[varName] : null;\n const filters = filterNames.map(n => possibleFilters[n]);\n return filters.reduce((acc, cur) => cur(acc), value && value.toString());\n });\n}\n\n/** @type { {[filterName: String]:( string => string)} } */\nexport const APPLY_FILTERS = {\n urlencode: encodeURIComponent,\n};\n","//@ts-check\nimport { createDIVPageLayer } from '../BookReader/PageContainer.js';\nimport { SelectionObserver } from '../BookReader/utils/SelectionObserver.js';\nimport { applyVariables } from '../util/strings.js';\n/** @typedef {import('../util/strings.js').StringWithVars} StringWithVars */\n/** @typedef {import('../BookReader/PageContainer.js').PageContainer} PageContainer */\n\nconst BookReader = /** @type {typeof import('../BookReader').default} */(window.BookReader);\n\nexport const DEFAULT_OPTIONS = {\n enabled: true,\n /** @type {StringWithVars} The URL to fetch the entire DJVU xml. Supports options.vars */\n fullDjvuXmlUrl: null,\n /** @type {StringWithVars} The URL to fetch a single page of the DJVU xml. Supports options.vars. Also has {{pageIndex}} */\n singlePageDjvuXmlUrl: null,\n /** Whether to fetch the XML as a jsonp */\n jsonp: false,\n};\n/** @typedef {typeof DEFAULT_OPTIONS} TextSelectionPluginOptions */\n\n/**\n * @template T\n */\nexport class Cache {\n constructor(maxSize = 10) {\n this.maxSize = maxSize;\n /** @type {T[]} */\n this.entries = [];\n }\n\n /**\n * @param {T} entry\n */\n add(entry) {\n if (this.entries.length >= this.maxSize) {\n this.entries.shift();\n }\n this.entries.push(entry);\n }\n}\n\nexport class TextSelectionPlugin {\n /**\n * @param {'lr' | 'rl'} pageProgression In the future this should be in the ocr file\n * since a book being right to left doesn't mean the ocr is right to left. But for\n * now we do make that assumption.\n */\n constructor(options = DEFAULT_OPTIONS, optionVariables, pageProgression = 'lr') {\n this.options = options;\n this.optionVariables = optionVariables;\n /**@type {PromiseLike<JQuery<HTMLElement>|undefined>} */\n this.djvuPagesPromise = null;\n /** Whether the book is right-to-left */\n this.rtl = pageProgression === 'rl';\n\n /** @type {Cache<{index: number, response: any}>} */\n this.pageTextCache = new Cache();\n\n /**\n * Sometimes there are too many words on a page, and the browser becomes near\n * unusable. For now don't render text layer for pages with too many words.\n */\n this.maxWordRendered = 2500;\n\n this.selectionObserver = new SelectionObserver('.BRtextLayer', this._onSelectionChange);\n }\n\n /**\n * @param {'started' | 'cleared'} type\n * @param {HTMLElement} target\n */\n _onSelectionChange = (type, target) => {\n if (type === 'started') {\n this.textSelectingMode(target);\n } else if (type === 'cleared') {\n this.defaultMode(target);\n } else {\n throw new Error(`Unknown type ${type}`);\n }\n }\n\n init() {\n this.selectionObserver.attach();\n\n // Only fetch the full djvu xml if the single page url isn't there\n if (this.options.singlePageDjvuXmlUrl) return;\n this.djvuPagesPromise = $.ajax({\n type: \"GET\",\n url: applyVariables(this.options.fullDjvuXmlUrl, this.optionVariables),\n dataType: this.options.jsonp ? \"jsonp\" : \"html\",\n cache: true,\n error: (e) => undefined\n }).then((res) => {\n try {\n const xmlMap = $.parseXML(res);\n return xmlMap && $(xmlMap).find(\"OBJECT\");\n } catch (e) {\n return undefined;\n }\n });\n }\n\n /**\n * @param {number} index\n * @returns {Promise<HTMLElement|undefined>}\n */\n async getPageText(index) {\n if (this.options.singlePageDjvuXmlUrl) {\n const cachedEntry = this.pageTextCache.entries.find(x => x.index == index);\n if (cachedEntry) {\n return cachedEntry.response;\n }\n const res = await $.ajax({\n type: \"GET\",\n url: applyVariables(this.options.singlePageDjvuXmlUrl, this.optionVariables, { pageIndex: index }),\n dataType: this.options.jsonp ? \"jsonp\" : \"html\",\n cache: true,\n error: (e) => undefined,\n });\n try {\n const xmlDoc = $.parseXML(res);\n const result = xmlDoc && $(xmlDoc).find(\"OBJECT\")[0];\n this.pageTextCache.add({ index, response: result });\n return result;\n } catch (e) {\n return undefined;\n }\n } else {\n const XMLpagesArr = await this.djvuPagesPromise;\n if (XMLpagesArr) return XMLpagesArr[index];\n }\n }\n\n /**\n * Intercept copied text to remove any styling applied to it\n * @param {JQuery} $container\n */\n interceptCopy($container) {\n $container[0].addEventListener('copy', (event) => {\n const selection = document.getSelection();\n event.clipboardData.setData('text/plain', selection.toString());\n event.preventDefault();\n });\n }\n\n /**\n * Applies mouse events when in default mode\n * @param {HTMLElement} textLayer\n */\n defaultMode(textLayer) {\n const $pageContainer = $(textLayer).closest('.BRpagecontainer');\n textLayer.style.pointerEvents = \"none\";\n $pageContainer.find(\"img\").css(\"pointer-events\", \"auto\");\n\n $(textLayer).off(\".textSelectPluginHandler\");\n const startedMouseDown = this.mouseIsDown;\n let skipNextMouseup = this.mouseIsDown;\n if (startedMouseDown) {\n textLayer.style.pointerEvents = \"auto\";\n }\n\n // Need to stop propagation to prevent DragScrollable from\n // blocking selection\n $(textLayer).on(\"mousedown.textSelectPluginHandler\", (event) => {\n this.mouseIsDown = true;\n if ($(event.target).is(\".BRwordElement, .BRspace\")) {\n event.stopPropagation();\n }\n });\n\n $(textLayer).on(\"mouseup.textSelectPluginHandler\", (event) => {\n this.mouseIsDown = false;\n textLayer.style.pointerEvents = \"none\";\n if (skipNextMouseup) {\n skipNextMouseup = false;\n event.stopPropagation();\n }\n });\n }\n\n /**\n * This mode is active while there is a selection on the given textLayer\n * @param {HTMLElement} textLayer\n */\n textSelectingMode(textLayer) {\n const $pageContainer = $(textLayer).closest('.BRpagecontainer');\n // Make text layer consume all events\n textLayer.style.pointerEvents = \"all\";\n // Block img from getting long-press to save while selecting\n $pageContainer.find(\"img\").css(\"pointer-events\", \"none\");\n\n $(textLayer).off(\".textSelectPluginHandler\");\n\n $(textLayer).on('mousedown.textSelectPluginHandler', (event) => {\n this.mouseIsDown = true;\n event.stopPropagation();\n });\n\n // Prevent page flip on click\n $(textLayer).on('mouseup.textSelectPluginHandler', (event) => {\n this.mouseIsDown = false;\n event.stopPropagation();\n });\n }\n\n /**\n * Initializes text selection modes if there is a text layer on the page\n * @param {JQuery} $container\n */\n stopPageFlip($container) {\n /** @type {JQuery<HTMLElement>} */\n const $textLayer = $container.find('.BRtextLayer');\n if (!$textLayer.length) return;\n $textLayer.each((i, s) => this.defaultMode(s));\n this.interceptCopy($container);\n }\n\n /**\n * @param {PageContainer} pageContainer\n */\n async createTextLayer(pageContainer) {\n const pageIndex = pageContainer.page.index;\n const $container = pageContainer.$container;\n const $textLayers = $container.find('.BRtextLayer');\n if ($textLayers.length) return;\n const XMLpage = await this.getPageText(pageIndex);\n if (!XMLpage) return;\n recursivelyAddCoords(XMLpage);\n\n const totalWords = $(XMLpage).find(\"WORD\").length;\n if (totalWords > this.maxWordRendered) {\n console.log(`Page ${pageIndex} has too many words (${totalWords} > ${this.maxWordRendered}). Not rendering text layer.`);\n return;\n }\n\n const textLayer = createDIVPageLayer(pageContainer.page, 'BRtextLayer');\n const ratioW = parseFloat(pageContainer.$container[0].style.width) / pageContainer.page.width;\n const ratioH = parseFloat(pageContainer.$container[0].style.height) / pageContainer.page.height;\n textLayer.style.transform = `scale(${ratioW}, ${ratioH})`;\n textLayer.setAttribute(\"dir\", this.rtl ? \"rtl\" : \"ltr\");\n\n const ocrParagraphs = $(XMLpage).find(\"PARAGRAPH[coords]\").toArray();\n const paragEls = ocrParagraphs.map(p => {\n const el = this.renderParagraph(p);\n textLayer.appendChild(el);\n return el;\n });\n\n // Fix up paragraph positions\n const paragraphRects = determineRealRects(textLayer, '.BRparagraphElement');\n let yAdded = 0;\n for (const [ocrParagraph, paragEl] of zip(ocrParagraphs, paragEls)) {\n const ocrParagBounds = $(ocrParagraph).attr(\"coords\").split(\",\").map(parseFloat);\n const realRect = paragraphRects.get(paragEl);\n const [ocrLeft, , ocrRight, ocrTop] = ocrParagBounds;\n const newStartMargin = this.rtl ? (realRect.right - ocrRight) : (ocrLeft - realRect.left);\n const newTop = ocrTop - (realRect.top + yAdded);\n\n paragEl.style[this.rtl ? 'marginRight' : 'marginLeft'] = `${newStartMargin}px`;\n paragEl.style.marginTop = `${newTop}px`;\n yAdded += newTop;\n textLayer.appendChild(paragEl);\n }\n $container.append(textLayer);\n this.stopPageFlip($container);\n }\n\n /**\n * @param {HTMLElement} ocrParagraph\n * @returns {HTMLParagraphElement}\n */\n renderParagraph(ocrParagraph) {\n const paragEl = document.createElement('p');\n paragEl.classList.add('BRparagraphElement');\n const [paragLeft, paragBottom, paragRight, paragTop] = $(ocrParagraph).attr(\"coords\").split(\",\").map(parseFloat);\n const wordHeightArr = [];\n const lines = $(ocrParagraph).find(\"LINE[coords]\").toArray();\n if (!lines.length) return paragEl;\n\n\n for (const [prevLine, line, nextLine] of lookAroundWindow(genMap(lines, augmentLine))) {\n const isLastLineOfParagraph = line.ocrElement == lines[lines.length - 1];\n const lineEl = document.createElement('span');\n lineEl.classList.add('BRlineElement');\n\n for (const [wordIndex, currWord] of line.words.entries()) {\n const [, bottom, right, top] = $(currWord).attr(\"coords\").split(',').map(parseFloat);\n const wordHeight = bottom - top;\n wordHeightArr.push(wordHeight);\n\n if (wordIndex == 0 && prevLine?.lastWord.textContent.trim().endsWith('-')) {\n // ideally prefer the next line to determine the left position,\n // since the previous line could be the first line of the paragraph\n // and hence have an incorrectly indented first word.\n // E.g. https://archive.org/details/driitaleofdaring00bachuoft/page/360/mode/2up\n const [newLeft, , , ] = $((nextLine || prevLine).firstWord).attr(\"coords\").split(',').map(parseFloat);\n $(currWord).attr(\"coords\", `${newLeft},${bottom},${right},${top}`);\n }\n\n const wordEl = document.createElement('span');\n wordEl.setAttribute(\"class\", \"BRwordElement\");\n wordEl.textContent = currWord.textContent.trim();\n\n if (wordIndex > 0) {\n const space = document.createElement('span');\n space.classList.add('BRspace');\n space.textContent = ' ';\n lineEl.append(space);\n\n // Edge ignores empty elements (like BRspace), so add another\n // space to ensure Edge's ReadAloud works correctly.\n lineEl.appendChild(document.createTextNode(' '));\n }\n\n lineEl.appendChild(wordEl);\n }\n\n const hasHyphen = line.lastWord.textContent.trim().endsWith('-');\n const lastWordEl = lineEl.children[lineEl.children.length - 1];\n if (hasHyphen && !isLastLineOfParagraph) {\n lastWordEl.textContent = lastWordEl.textContent.trim().slice(0, -1);\n lastWordEl.classList.add('BRwordElement--hyphen');\n }\n\n paragEl.appendChild(lineEl);\n if (!isLastLineOfParagraph && !hasHyphen) {\n // Edge does not correctly have spaces between the lines.\n paragEl.appendChild(document.createTextNode(' '));\n }\n }\n\n wordHeightArr.sort((a, b) => a - b);\n const paragWordHeight = wordHeightArr[Math.floor(wordHeightArr.length * 0.85)] + 4;\n paragEl.style.left = `${paragLeft}px`;\n paragEl.style.top = `${paragTop}px`;\n paragEl.style.width = `${paragRight - paragLeft}px`;\n paragEl.style.height = `${paragBottom - paragTop}px`;\n paragEl.style.fontSize = `${paragWordHeight}px`;\n\n // Fix up sizes - stretch/crush words as necessary using letter spacing\n let wordRects = determineRealRects(paragEl, '.BRwordElement');\n const ocrWords = $(ocrParagraph).find(\"WORD\").toArray();\n const wordEls = paragEl.querySelectorAll('.BRwordElement');\n for (const [ocrWord, wordEl] of zip(ocrWords, wordEls)) {\n const realRect = wordRects.get(wordEl);\n const [left, , right ] = $(ocrWord).attr(\"coords\").split(',').map(parseFloat);\n let ocrWidth = right - left;\n // Some books (eg theworksofplato01platiala) have a space _inside_ the <WORD>\n // element. That makes it impossible to determine the correct positining\n // of everything, but to avoid the BRspace's being width 0, which makes selection\n // janky on Chrome Android, assume the space is the same width as one of the\n // letters.\n if (ocrWord.textContent.endsWith(' ')) {\n ocrWidth = ocrWidth * (ocrWord.textContent.length - 1) / ocrWord.textContent.length;\n }\n const diff = ocrWidth - realRect.width;\n wordEl.style.letterSpacing = `${diff / (ocrWord.textContent.length - 1)}px`;\n }\n\n // Stretch/crush lines as necessary using line spacing\n // Recompute rects after letter spacing\n wordRects = determineRealRects(paragEl, '.BRwordElement');\n const spaceRects = determineRealRects(paragEl, '.BRspace');\n\n const ocrLines = $(ocrParagraph).find(\"LINE[coords]\").toArray();\n const lineEls = Array.from(paragEl.querySelectorAll('.BRlineElement'));\n\n let ySoFar = paragTop;\n for (const [ocrLine, lineEl] of zip(ocrLines, lineEls)) {\n // shift words using marginLeft to align with the correct x position\n const words = $(ocrLine).find(\"WORD\").toArray();\n // const ocrLineLeft = Math.min(...words.map(w => parseFloat($(w).attr(\"coords\").split(',')[0])));\n let xSoFar = this.rtl ? paragRight : paragLeft;\n for (const [ocrWord, wordEl] of zip(words, lineEl.querySelectorAll('.BRwordElement'))) {\n // start of line, need to compute the offset relative to the OCR words\n const wordRect = wordRects.get(wordEl);\n const [ocrLeft, , ocrRight ] = $(ocrWord).attr(\"coords\").split(',').map(parseFloat);\n const diff = (this.rtl ? -(ocrRight - xSoFar) : ocrLeft - xSoFar);\n\n if (wordEl.previousElementSibling) {\n const space = wordEl.previousElementSibling;\n space.style.letterSpacing = `${diff - spaceRects.get(space).width}px`;\n } else {\n wordEl.style[this.rtl ? 'paddingRight' : 'paddingLeft'] = `${diff}px`;\n }\n if (this.rtl) xSoFar -= diff + wordRect.width;\n else xSoFar += diff + wordRect.width;\n }\n // And also fix y position\n const ocrLineTop = Math.min(...words.map(w => parseFloat($(w).attr(\"coords\").split(',')[3])));\n const diff = ocrLineTop - ySoFar;\n if (lineEl.previousElementSibling) {\n lineEl.previousElementSibling.style.lineHeight = `${diff}px`;\n ySoFar += diff;\n }\n }\n\n // The last line will have a line height subtracting from the paragraph height\n lineEls[lineEls.length - 1].style.lineHeight = `${paragBottom - ySoFar}px`;\n\n // Edge does not include a newline for some reason when copying/pasting the <p> els\n paragEl.appendChild(document.createElement('br'));\n return paragEl;\n }\n}\n\nexport class BookreaderWithTextSelection extends BookReader {\n init() {\n const options = Object.assign({}, DEFAULT_OPTIONS, this.options.plugins.textSelection);\n if (options.enabled) {\n this.textSelectionPlugin = new TextSelectionPlugin(options, this.options.vars, this.pageProgression);\n // Write this back; this way the plugin is the source of truth, and BR just\n // contains a reference to it.\n this.options.plugins.textSelection = options;\n this.textSelectionPlugin.init();\n\n new SelectionObserver('.BRtextLayer', (selectEvent) => {\n // Track how often selection is used\n if (selectEvent == 'started') {\n this.archiveAnalyticsSendEvent?.('BookReader', 'SelectStart');\n\n // Set a class on the page to avoid hiding it when zooming/etc\n this.refs.$br.find('.BRpagecontainer--hasSelection').removeClass('BRpagecontainer--hasSelection');\n $(window.getSelection().anchorNode).closest('.BRpagecontainer').addClass('BRpagecontainer--hasSelection');\n }\n }).attach();\n }\n\n super.init();\n }\n\n /**\n * @param {number} index\n */\n _createPageContainer(index) {\n const pageContainer = super._createPageContainer(index);\n // Disable if thumb mode; it's too janky\n // .page can be null for \"pre-cover\" region\n if (this.mode !== this.constModeThumb && pageContainer.page) {\n this.textSelectionPlugin?.createTextLayer(pageContainer);\n }\n return pageContainer;\n }\n}\nwindow.BookReader = BookreaderWithTextSelection;\nexport default BookreaderWithTextSelection;\n\n\n/**\n * @param {HTMLElement} parentEl\n * @param {string} selector\n * @returns {Map<Element, Rect>}\n */\nfunction determineRealRects(parentEl, selector) {\n const initals = {\n position: parentEl.style.position,\n visibility: parentEl.style.visibility,\n top: parentEl.style.top,\n left: parentEl.style.left,\n transform: parentEl.style.transform,\n };\n parentEl.style.position = 'absolute';\n parentEl.style.visibility = 'hidden';\n parentEl.style.top = '0';\n parentEl.style.left = '0';\n parentEl.style.transform = 'none';\n document.body.appendChild(parentEl);\n const rects = new Map(\n Array.from(parentEl.querySelectorAll(selector))\n .map(wordEl => {\n const origRect = wordEl.getBoundingClientRect();\n return [wordEl, new Rect(\n origRect.left + window.scrollX,\n origRect.top + window.scrollY,\n origRect.width,\n origRect.height,\n )];\n })\n );\n document.body.removeChild(parentEl);\n Object.assign(parentEl.style, initals);\n return rects;\n}\n\n/**\n * @param {HTMLElement} line\n */\nfunction augmentLine(line) {\n const words = $(line).find(\"WORD\").toArray();\n return {\n ocrElement: line,\n words,\n firstWord: words[0],\n lastWord: words[words.length - 1],\n };\n}\n\n/**\n * @template TFrom, TTo\n * Generator version of map\n * @param {Iterable<TFrom>} gen\n * @param {function(TFrom): TTo} fn\n * @returns {Iterable<TTo>}\n */\nexport function* genMap(gen, fn) {\n for (const x of gen) yield fn(x);\n}\n\n/**\n * @template T\n * Generator that provides a sliding window of 3 elements,\n * prev, current, and next.\n * @param {Iterable<T>} gen\n * @returns {Iterable<[T | undefined, T, T | undefined]>}\n */\nexport function* lookAroundWindow(gen) {\n let prev = undefined;\n let cur = undefined;\n let next = undefined;\n for (const x of gen) {\n if (typeof cur !== 'undefined') {\n next = x;\n yield [prev, cur, next];\n }\n prev = cur;\n cur = x;\n next = undefined;\n }\n\n if (typeof cur !== 'undefined') {\n yield [prev, cur, next];\n }\n}\n\n/**\n * @template T1, T2\n * Lazy zip implementation to avoid importing lodash\n * Expects iterators to be of the same length\n * @param {Iterable<T1>} gen1\n * @param {Iterable<T2>} gen2\n * @returns {Iterable<[T1, T2]>}\n */\nexport function* zip(gen1, gen2) {\n const it1 = gen1[Symbol.iterator]();\n const it2 = gen2[Symbol.iterator]();\n while (true) {\n const r1 = it1.next();\n const r2 = it2.next();\n if (r1.done && r2.done) {\n return;\n }\n if (r1.done || r2.done) {\n throw new Error('zip: one of the iterators is done');\n }\n yield [r1.value, r2.value];\n }\n}\n\n/**\n * [left, bottom, right, top]\n * @param {Array<[number, number, number, number]>} bounds\n * @returns {[number, number, number, number]}\n */\nfunction determineBounds(bounds) {\n let leftMost = Infinity;\n let bottomMost = -Infinity;\n let rightMost = -Infinity;\n let topMost = Infinity;\n\n for (const [left, bottom, right, top] of bounds) {\n leftMost = Math.min(leftMost, left);\n bottomMost = Math.max(bottomMost, bottom);\n rightMost = Math.max(rightMost, right);\n topMost = Math.min(topMost, top);\n }\n\n return [leftMost, bottomMost, rightMost, topMost];\n}\n\n/**\n * Recursively traverses the XML tree and adds coords\n * which are the bounding box of all child coords\n * @param {Element} xmlEl\n */\nfunction recursivelyAddCoords(xmlEl) {\n if ($(xmlEl).attr('coords') || !xmlEl.children) {\n return;\n }\n\n const children = $(xmlEl).children().toArray();\n if (children.length === 0) {\n return;\n }\n\n for (const child of children) {\n recursivelyAddCoords(child);\n }\n\n const childCoords = [];\n\n for (const child of children) {\n if (!$(child).attr('coords')) continue;\n childCoords.push($(child).attr('coords').split(',').map(parseFloat));\n }\n\n const boundingCoords = determineBounds(childCoords);\n if (Math.abs(boundingCoords[0]) != Infinity) {\n $(xmlEl).attr('coords', boundingCoords.join(','));\n }\n}\n\n/**\n * Basically a polyfill for the native DOMRect class\n */\nclass Rect {\n /**\n * @param {number} x\n * @param {number} y\n * @param {number} width\n * @param {number} height\n */\n constructor(x, y, width, height) {\n this.x = x;\n this.y = y;\n this.width = width;\n this.height = height;\n }\n\n get right() { return this.x + this.width; }\n get bottom() { return this.y + this.height; }\n get top() { return this.y; }\n get left() { return this.x; }\n}\n","var global = require('../internals/global');\nvar fails = require('../internals/fails');\nvar uncurryThis = require('../internals/function-uncurry-this');\nvar toString = require('../internals/to-string');\nvar trim = require('../internals/string-trim').trim;\nvar whitespaces = require('../internals/whitespaces');\n\nvar charAt = uncurryThis(''.charAt);\nvar n$ParseFloat = global.parseFloat;\nvar Symbol = global.Symbol;\nvar ITERATOR = Symbol && Symbol.iterator;\nvar FORCED = 1 / n$ParseFloat(whitespaces + '-0') !== -Infinity\n // MS Edge 18- broken with boxed symbols\n || (ITERATOR && !fails(function () { n$ParseFloat(Object(ITERATOR)); }));\n\n// `parseFloat` method\n// https://tc39.es/ecma262/#sec-parsefloat-string\nmodule.exports = FORCED ? function parseFloat(string) {\n var trimmedString = trim(toString(string));\n var result = n$ParseFloat(trimmedString);\n return result === 0 && charAt(trimmedString, 0) == '-' ? -0 : result;\n} : n$ParseFloat;\n","var PROPER_FUNCTION_NAME = require('../internals/function-name').PROPER;\nvar fails = require('../internals/fails');\nvar whitespaces = require('../internals/whitespaces');\n\nvar non = '\\u200B\\u0085\\u180E';\n\n// check that a method works with the correct list\n// of whitespaces and has a correct name\nmodule.exports = function (METHOD_NAME) {\n return fails(function () {\n return !!whitespaces[METHOD_NAME]()\n || non[METHOD_NAME]() !== non\n || (PROPER_FUNCTION_NAME && whitespaces[METHOD_NAME].name !== METHOD_NAME);\n });\n};\n","var $ = require('../internals/export');\nvar $parseFloat = require('../internals/number-parse-float');\n\n// `parseFloat` method\n// https://tc39.es/ecma262/#sec-parsefloat-string\n$({ global: true, forced: parseFloat != $parseFloat }, {\n parseFloat: $parseFloat\n});\n","'use strict';\nvar $ = require('../internals/export');\nvar $trim = require('../internals/string-trim').trim;\nvar forcedStringTrimMethod = require('../internals/string-trim-forced');\n\n// `String.prototype.trim` method\n// https://tc39.es/ecma262/#sec-string.prototype.trim\n$({ target: 'String', proto: true, forced: forcedStringTrimMethod('trim') }, {\n trim: function trim() {\n return $trim(this);\n }\n});\n"],"names":["SelectionObserver","selector","handler","sel","window","getSelection","selecting","toString","target","$","anchorNode","closest","isCollapsed","this","document","addEventListener","_onSelectionChange","removeEventListener","applyVariables","template","vars","overrides","possibleFilters","APPLY_FILTERS","replace","$0","$1","split","map","x","trim","varName","filterNames","value","n","reduce","acc","cur","urlencode","encodeURIComponent","genMap","lookAroundWindow","zip","BookReader","DEFAULT_OPTIONS","enabled","fullDjvuXmlUrl","singlePageDjvuXmlUrl","jsonp","Cache","maxSize","entries","entry","length","shift","push","TextSelectionPlugin","options","optionVariables","pageProgression","type","textSelectingMode","Error","defaultMode","djvuPagesPromise","rtl","pageTextCache","maxWordRendered","selectionObserver","attach","ajax","url","dataType","cache","error","e","then","res","xmlMap","parseXML","find","index","cachedEntry","response","pageIndex","xmlDoc","result","add","undefined","XMLpagesArr","$container","event","selection","clipboardData","setData","preventDefault","textLayer","$pageContainer","style","pointerEvents","css","off","startedMouseDown","mouseIsDown","skipNextMouseup","on","is","stopPropagation","$textLayer","each","i","s","interceptCopy","pageContainer","page","getPageText","XMLpage","recursivelyAddCoords","totalWords","console","log","createDIVPageLayer","ratioW","parseFloat","width","ratioH","height","transform","setAttribute","ocrParagraphs","toArray","paragEls","p","el","renderParagraph","appendChild","paragraphRects","determineRealRects","yAdded","ocrParagraph","paragEl","ocrParagBounds","attr","realRect","get","ocrLeft","ocrRight","ocrTop","newStartMargin","right","left","newTop","top","marginTop","append","stopPageFlip","createElement","classList","paragLeft","paragBottom","paragRight","paragTop","wordHeightArr","lines","augmentLine","prevLine","line","nextLine","isLastLineOfParagraph","ocrElement","lineEl","words","wordIndex","currWord","bottom","wordHeight","lastWord","textContent","endsWith","newLeft","firstWord","wordEl","space","createTextNode","hasHyphen","lastWordEl","children","slice","sort","a","b","paragWordHeight","Math","floor","fontSize","wordRects","querySelectorAll","ocrWord","ocrWidth","diff","letterSpacing","spaceRects","ocrLines","lineEls","Array","from","ySoFar","ocrLine","xSoFar","wordRect","previousElementSibling","min","w","lineHeight","BookreaderWithTextSelection","Object","assign","plugins","textSelection","textSelectionPlugin","init","selectEvent","archiveAnalyticsSendEvent","refs","$br","removeClass","addClass","mode","constModeThumb","createTextLayer","parentEl","initals","position","visibility","body","rects","Map","origRect","getBoundingClientRect","Rect","scrollX","scrollY","removeChild","gen","fn","f","prev","next","gen1","gen2","it1","Symbol","iterator","it2","r1","r2","done","xmlEl","childCoords","child","boundingCoords","bounds","leftMost","Infinity","bottomMost","rightMost","topMost","max","determineBounds","abs","join","y","global","fails","uncurryThis","whitespaces","charAt","n$ParseFloat","ITERATOR","FORCED","module","exports","string","trimmedString","PROPER_FUNCTION_NAME","METHOD_NAME","name","$parseFloat","forced","$trim","proto","forcedStringTrimMethod"],"sourceRoot":""}
|