@internetarchive/bookreader 5.0.0-46-alpha2 → 5.0.0-46-no-right-click-2
Sign up to get free protection for your applications and to get access to all the features.
- package/BookReader/BookReader.js +2 -33352
- package/BookReader/BookReader.js.map +1 -1
- package/BookReader/ia-bookreader-bundle.js +31 -31
- package/BookReader/ia-bookreader-bundle.js.map +1 -1
- package/BookReader/jquery-1.10.1.js +2 -0
- package/BookReader/jquery-1.10.1.js.LICENSE.txt +24 -0
- package/BookReader/plugins/plugin.search.js +1 -1
- package/BookReader/plugins/plugin.search.js.map +1 -1
- package/BookReaderDemo/IADemoBr.js +13 -17
- package/BookReaderDemo/demo-advanced.html +1 -1
- package/BookReaderDemo/demo-autoplay.html +1 -1
- package/BookReaderDemo/demo-embed-iframe-src.html +1 -1
- package/BookReaderDemo/demo-fullscreen-mobile.html +1 -1
- package/BookReaderDemo/demo-fullscreen.html +1 -1
- package/BookReaderDemo/demo-iiif.html +1 -1
- package/BookReaderDemo/demo-internetarchive.html +1 -1
- package/BookReaderDemo/demo-multiple.html +1 -1
- package/BookReaderDemo/demo-preview-pages.html +1 -1
- package/BookReaderDemo/demo-simple.html +1 -1
- package/BookReaderDemo/demo-vendor-fullscreen.html +1 -1
- package/BookReaderDemo/immersion-1up.html +1 -1
- package/BookReaderDemo/immersion-mode.html +1 -1
- package/BookReaderDemo/toggle_controls.html +1 -1
- package/BookReaderDemo/view_mode.html +1 -1
- package/BookReaderDemo/viewmode-cycle.html +1 -1
- package/CHANGELOG.md +0 -12
- package/package.json +7 -7
- package/src/BookNavigator/bookmarks/ia-bookmarks.js +1 -15
- package/src/BookNavigator/search/a-search-result.js +4 -12
- package/src/plugins/search/view.js +5 -10
- package/src/util/manifestGenerator.js +0 -0
- package/tests/jest/BookNavigator/search/search-results.test.js +1 -33
- package/tests/jest/plugins/search/plugin.search.view.test.js +0 -29
- package/webpack.config.js +1 -1
- package/BookReader/jquery-3.js +0 -2
- package/BookReader/jquery-3.js.LICENSE.txt +0 -24
@@ -1 +1 @@
|
|
1
|
-
{"version":3,"file":"plugins/plugin.search.js","mappings":"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","sources":["webpack://@internetarchive/bookreader/./src/plugins/search/plugin.search.js","webpack://@internetarchive/bookreader/./src/plugins/search/view.js","webpack://@internetarchive/bookreader/./node_modules/core-js/internals/number-parse-float.js","webpack://@internetarchive/bookreader/./node_modules/core-js/modules/es.object.entries.js","webpack://@internetarchive/bookreader/./node_modules/core-js/modules/es.parse-float.js"],"sourcesContent":["// @ts-check\n/* global BookReader */\n/**\n * Plugin for Archive.org book search\n * NOTE: This script must be loaded AFTER `plugin.mobile_nav.js`\n * as it mutates mobile nav drawer\n *\n * Events fired at various points throughout search processing are published\n * on the document DOM element. These can be subscribed to using jQuery's event\n * binding method `$.fn.on`. All of the events are prefixed with a BookReader\n * namespace. The events are:\n *\n * @event BookReader:SearchStarted - When a search form is submitted, immediately\n * before an AJAX call is made to request search results\n * @event BookReader:SearchCallback - When the search AJAX call is returned and at\n * least one result is returned. The event callback receives an object\n * with the `results`, plugin `options`, and the BookReader `instance`\n * @event BookReader:SearchCallbackError - When the AJAX request returns an error.\n * Receives the `results` and `instance`\n * @event BookReader:SearchCallbackNotIndexed - When a message is received that\n * the book has not had OCR text indexed yet. Receives `instance`\n * @event BookReader:SearchCallbackEmpty - When no results found. Receives\n * `instance`\n * @event BookReader:SearchCanceled - When no results found. Receives\n * `instance`\n */\nimport { poll } from '../../BookReader/utils.js';\nimport { renderBoxesInPageContainerLayer } from '../../BookReader/PageContainer.js';\nimport SearchView from './view.js';\n/** @typedef {import('../../BookReader/PageContainer').PageContainer} PageContainer */\n/** @typedef {import('../../BookReader/BookModel').PageIndex} PageIndex */\n/** @typedef {import('../../BookReader/BookModel').LeafNum} LeafNum */\n/** @typedef {import('../../BookReader/BookModel').PageNumString} PageNumString */\n\njQuery.extend(BookReader.defaultOptions, {\n server: 'ia600609.us.archive.org',\n bookId: '',\n subPrefix: '',\n bookPath: '',\n enableSearch: true,\n searchInsideUrl: '/fulltext/inside.php',\n initialSearchTerm: null,\n});\n\n/** @override */\nBookReader.prototype.setup = (function (super_) {\n return function (options) {\n super_.call(this, options);\n\n this.searchTerm = '';\n this.searchResults = null;\n this.searchInsideUrl = options.searchInsideUrl;\n this.enableSearch = options.enableSearch;\n\n // Base server used by some api calls\n this.bookId = options.bookId;\n this.server = options.server;\n this.subPrefix = options.subPrefix;\n this.bookPath = options.bookPath;\n\n this.searchXHR = null;\n this._cancelSearch.bind(this);\n this.cancelSearchRequest.bind(this);\n\n /** @type { {[pageIndex: number]: SearchInsideMatchBox[]} } */\n this._searchBoxesByIndex = {};\n\n this.searchView = undefined;\n };\n})(BookReader.prototype.setup);\n\n/** @override */\nBookReader.prototype.init = (function (super_) {\n return function () {\n super_.call(this);\n // give SearchView the most complete bookreader state\n this.searchView = new SearchView({\n br: this,\n searchCancelledCallback: () => {\n this._cancelSearch();\n this.trigger('SearchCanceled', { term: this.searchTerm, instance: this });\n }\n });\n if (this.options.enableSearch && this.options.initialSearchTerm) {\n /**\n * this.search() take two parameter\n * 1. this.options.initialSearchTerm - search term\n * 2. {\n * goToFirstResult: this.options.goToFirstResult,\n * suppressFragmentChange: false // always want to change fragment in URL\n * }\n */\n this.search(\n this.options.initialSearchTerm,\n { goToFirstResult: this.options.goToFirstResult, suppressFragmentChange: false }\n );\n }\n };\n})(BookReader.prototype.init);\n\n/** @override */\nBookReader.prototype.buildToolbarElement = (function (super_) {\n return function () {\n const $el = super_.call(this);\n if (!this.enableSearch) { return; }\n if (this.searchView.dom.toolbarSearch) {\n $el.find('.BRtoolbarSectionInfo').after(this.searchView.dom.toolbarSearch);\n }\n return $el;\n };\n})(BookReader.prototype.buildToolbarElement);\n\n/** @override */\nBookReader.prototype._createPageContainer = (function (super_) {\n return function (index) {\n const pageContainer = super_.call(this, index);\n if (this.enableSearch && pageContainer.page && index in this._searchBoxesByIndex) {\n const pageIndex = pageContainer.page.index;\n const boxes = this._searchBoxesByIndex[pageIndex];\n renderBoxesInPageContainerLayer(\n 'searchHiliteLayer',\n boxes,\n pageContainer.page,\n pageContainer.$container[0],\n boxes.map(b => `match-index-${b.matchIndex}`),\n );\n }\n return pageContainer;\n };\n})(BookReader.prototype._createPageContainer);\n\n/**\n * @typedef {object} SearchOptions\n * @property {boolean} goToFirstResult\n * @property {boolean} disablePopup\n * @property {(null|function)} error - @deprecated at v.5.0\n * @property {(null|function)} success - @deprecated at v.5.0\n */\n\n/**\n * Submits search request\n *\n * @param {string} term\n * @param {SearchOptions} overrides\n */\nBookReader.prototype.search = async function(term = '', overrides = {}) {\n /** @type {SearchOptions} */\n const defaultOptions = {\n goToFirstResult: false, /* jump to the first result (default=false) */\n disablePopup: false, /* don't show the modal progress (default=false) */\n suppressFragmentChange: false, /* don't change the URL on initial load */\n error: null, /* optional error handler (default=null) */\n success: null, /* optional success handler (default=null) */\n\n };\n const options = jQuery.extend({}, defaultOptions, overrides);\n this.suppressFragmentChange = options.suppressFragmentChange;\n this.searchCancelled = false;\n\n // strip slashes, since this goes in the url\n this.searchTerm = term.replace(/\\//g, ' ');\n\n if (!options.suppressFragmentChange) {\n this.trigger(BookReader.eventNames.fragmentChange);\n }\n\n // Add quotes to the term. This is to compenstate for the backends default OR query\n // term = term.replace(/['\"]+/g, '');\n // term = '\"' + term + '\"';\n\n // Remove the port and userdir\n const serverPath = this.server.replace(/:.+/, '');\n const baseUrl = `https://${serverPath}${this.searchInsideUrl}?`;\n\n // Remove subPrefix from end of path\n let path = this.bookPath;\n const subPrefixWithSlash = `/${this.subPrefix}`;\n if (this.bookPath.length - this.bookPath.lastIndexOf(subPrefixWithSlash) == subPrefixWithSlash.length) {\n path = this.bookPath.substr(0, this.bookPath.length - subPrefixWithSlash.length);\n }\n\n const urlParams = {\n item_id: this.bookId,\n doc: this.subPrefix,\n path,\n q: term,\n };\n\n // NOTE that the API does not expect / (slashes) to be encoded. (%2F) won't work\n const paramStr = $.param(urlParams).replace(/%2F/g, '/');\n\n const url = `${baseUrl}${paramStr}`;\n\n const callSearchResultsCallback = (searchInsideResults) => {\n if (this.searchCancelled) {\n return;\n }\n const responseHasError = searchInsideResults.error || !searchInsideResults.matches.length;\n const hasCustomError = typeof options.error === 'function';\n const hasCustomSuccess = typeof options.success === 'function';\n\n if (responseHasError) {\n hasCustomError\n ? options.error.call(this, searchInsideResults, options)\n : this.BRSearchCallbackError(searchInsideResults, options);\n } else {\n hasCustomSuccess\n ? options.success.call(this, searchInsideResults, options)\n : this.BRSearchCallback(searchInsideResults, options);\n }\n };\n\n this.trigger('SearchStarted', { term: this.searchTerm, instance: this });\n callSearchResultsCallback(await $.ajax({\n url: url,\n dataType: 'jsonp',\n cache: true,\n beforeSend: xhr => { this.searchXHR = xhr; },\n }));\n};\n\n/**\n * cancels AJAX Call\n * emits custom event\n */\nBookReader.prototype._cancelSearch = function () {\n this.searchXHR?.abort();\n this.searchView.clearSearchFieldAndResults(false);\n this.searchTerm = '';\n this.searchXHR = null;\n this.searchCancelled = true;\n this.searchResults = [];\n};\n\n/**\n * External function to cancel search\n * checks for term & xhr in flight before running\n */\nBookReader.prototype.cancelSearchRequest = function () {\n this.searchCancelled = true;\n if (this.searchXHR !== null) {\n this._cancelSearch();\n this.searchView.toggleSearchPending();\n this.trigger('SearchCanceled', { term: this.searchTerm, instance: this });\n }\n};\n\n/**\n * @typedef {object} SearchInsideMatchBox\n * @property {number} page\n * @property {number} r\n * @property {number} l\n * @property {number} b\n * @property {number} t\n * @property {HTMLDivElement} [div]\n * @property {number} matchIndex This is a fake field! not part of the API response. The index of the match that contains this box in total search results matches.\n */\n\n/**\n * @typedef {object} SearchInsideMatch\n * @property {number} matchIndex This is a fake field! Not part of the API response. It is added by the JS.\n * @property {string} displayPageNumber (fake field) The page number as it should be displayed in the UI.\n * @property {string} text\n * @property {Array<{ page: number, boxes: SearchInsideMatchBox[] }>} par\n */\n\n/**\n * @typedef {object} SearchInsideResults\n * @property {string} error\n * @property {SearchInsideMatch[]} matches\n * @property {boolean} indexed\n */\n\n/**\n * Attach some fields to search inside results\n * @param {SearchInsideResults} results\n * @param {(pageNum: LeafNum) => PageNumString} displayPageNumberFn\n */\nexport function marshallSearchResults(results, displayPageNumberFn) {\n // Attach matchIndex to a few things to make it easier to identify\n // an active/selected match\n for (const [index, match] of results.matches.entries()) {\n match.matchIndex = index;\n match.displayPageNumber = displayPageNumberFn(match.par[0].page);\n for (const par of match.par) {\n for (const box of par.boxes) {\n box.matchIndex = index;\n }\n }\n }\n}\n\n/**\n * Search Results return handler\n * @param {SearchInsideResults} results\n * @param {object} options\n * @param {boolean} options.goToFirstResult\n */\nBookReader.prototype.BRSearchCallback = function(results, options) {\n marshallSearchResults(results, pageNum => this.getPageNum(this.leafNumToIndex(pageNum)));\n this.searchResults = results || [];\n\n this.updateSearchHilites();\n this.removeProgressPopup();\n if (options.goToFirstResult) {\n this._searchPluginGoToResult(0);\n }\n this.trigger('SearchCallback', { results, options, instance: this });\n};\n\n/**\n * Main search results error handler\n * @callback\n * @param {SearchInsideResults} results\n */\nBookReader.prototype.BRSearchCallbackError = function(results) {\n this._BRSearchCallbackError(results);\n};\n\n/**\n * @private draws search results error\n * @callback\n * @param {SearchInsideResults} results\n * @param {jQuery} $el\n * @param {boolean} fade\n */\nBookReader.prototype._BRSearchCallbackError = function(results) {\n this.searchResults = results;\n const basePayload = {\n term: this.searchTerm,\n instance: this,\n };\n if (results.error) {\n const payload = Object.assign({}, basePayload, { results });\n this.trigger('SearchCallbackError', payload);\n } else if (0 == results.matches.length) {\n if (false === results.indexed) {\n this.trigger('SearchCallbackBookNotIndexed', basePayload);\n return;\n }\n this.trigger('SearchCallbackEmpty', basePayload);\n }\n};\n\n/**\n * updates search on-page highlights controller\n */\nBookReader.prototype.updateSearchHilites = function() {\n /** @type {SearchInsideMatch[]} */\n const matches = this.searchResults?.matches || [];\n /** @type { {[pageIndex: number]: SearchInsideMatchBox[]} } */\n const boxesByIndex = {};\n\n // Clear any existing svg layers\n this.removeSearchHilites();\n\n // Group by pageIndex\n for (const match of matches) {\n for (const box of match.par[0].boxes) {\n const pageIndex = this.leafNumToIndex(box.page);\n const pageBoxes = boxesByIndex[pageIndex] || (boxesByIndex[pageIndex] = []);\n pageBoxes.push(box);\n }\n }\n\n // update any already created pages\n for (const [pageIndexString, boxes] of Object.entries(boxesByIndex)) {\n const pageIndex = parseFloat(pageIndexString);\n const page = this._models.book.getPage(pageIndex);\n const pageContainers = this.getActivePageContainerElementsForIndex(pageIndex);\n for (const container of pageContainers) {\n renderBoxesInPageContainerLayer('searchHiliteLayer', boxes, page, container, boxes.map(b => `match-index-${b.matchIndex}`));\n }\n }\n\n this._searchBoxesByIndex = boxesByIndex;\n};\n\n/**\n * remove search highlights\n */\nBookReader.prototype.removeSearchHilites = function() {\n $(this.getActivePageContainerElements()).find('.searchHiliteLayer').remove();\n};\n\n/**\n * @private\n * Goes to the page specified. If the page is not viewable, tries to load the page\n * FIXME Most of this logic is IA specific, and should be less integrated into here\n * or at least more configurable.\n * @param {number} matchIndex\n */\nBookReader.prototype._searchPluginGoToResult = async function (matchIndex) {\n const match = this.searchResults?.matches[matchIndex];\n const pageIndex = this.leafNumToIndex(match.par[0].page);\n const { book } = this._models;\n const page = book.getPage(pageIndex);\n const onNearbyPage = Math.abs(this.currentIndex() - pageIndex) < 3;\n let makeUnviewableAtEnd = false;\n if (!page.isViewable) {\n const resp = await fetch('/services/bookreader/request_page?' + new URLSearchParams({\n id: this.options.bookId,\n subprefix: this.options.subPrefix,\n leafNum: page.leafNum,\n })).then(r => r.json());\n\n for (const leafNum of resp.value) {\n book.getPage(book.leafNumToIndex(leafNum)).makeViewable();\n }\n\n // not able to show page; make the page viewable anyways so that it can\n // actually open. On IA, it has a fallback to a special error page.\n if (!resp.value.length) {\n book.getPage(pageIndex).makeViewable();\n makeUnviewableAtEnd = true;\n }\n }\n /* this updates the URL */\n if (!this._isIndexDisplayed(pageIndex)) {\n this.suppressFragmentChange = false;\n this.jumpToIndex(pageIndex);\n }\n\n // Reset it to unviewable if it wasn't resolved\n if (makeUnviewableAtEnd) {\n book.getPage(pageIndex).makeViewable(false);\n }\n\n // Scroll/flash in the ui\n const $boxes = await poll(() => $(`rect.match-index-${match.matchIndex}`), { until: result => result.length > 0 });\n if ($boxes.length) {\n $boxes.css('animation', 'none');\n $boxes[0].scrollIntoView({\n // Only vertically center the highlight if we're in 1up or in full screen. In\n // 2up, if we're not fullscreen, the whole body gets scrolled around to try to\n // center the highlight 🙄 See:\n // https://stackoverflow.com/questions/11039885/scrollintoview-causing-the-whole-page-to-move/11041376\n // Note: nearest doesn't quite work great, because the ReadAloud toolbar is now\n // full-width, and covers up the last line of the highlight.\n block: this.constMode1up == this.mode || this.isFullscreenActive ? 'center' : 'nearest',\n inline: 'center',\n behavior: onNearbyPage ? 'smooth' : 'auto',\n });\n // wait for animation to start\n await new Promise(resolve => setTimeout(resolve, 100));\n $boxes.removeAttr(\"style\");\n }\n};\n\n/**\n * Removes all search pins\n */\nBookReader.prototype.removeSearchResults = function(suppressFragmentChange = false) {\n this.removeSearchHilites(); //be sure to set all box.divs to null\n this.searchTerm = null;\n this.searchResults = null;\n if (!suppressFragmentChange) {\n this.trigger(BookReader.eventNames.fragmentChange);\n }\n};\n\n/**\n * Returns true if a search highlight is currently being displayed\n * @returns {boolean}\n */\nBookReader.prototype.searchHighlightVisible = function() {\n const results = this.searchResults;\n let visiblePages = [];\n if (null == results) return false;\n\n if (this.constMode2up == this.mode) {\n visiblePages = [this.twoPage.currentIndexL, this.twoPage.currentIndexR];\n } else if (this.constMode1up == this.mode) {\n visiblePages = [this.currentIndex()];\n } else {\n return false;\n }\n\n results.matches.some(match => {\n return match.par[0].boxes.some(box => {\n const pageIndex = this.leafNumToIndex(box.page);\n if (jQuery.inArray(pageIndex, visiblePages) >= 0) {\n return true;\n }\n });\n });\n\n return false;\n};\n","import { escapeHTML } from \"../../BookReader/utils.js\";\n\nclass SearchView {\n /**\n * @param {object} params\n * @param {object} params.br The BookReader instance\n * @param {function} params.cancelSearch callback when a user wants to cancel search\n *\n * @event BookReader:SearchResultsCleared - when the search results nav gets cleared\n * @event BookReader:ToggleSearchMenu - when search results menu should toggle\n */\n constructor({ br, searchCancelledCallback = () => {} }) {\n this.br = br;\n\n // Search results are returned as a text blob with the hits wrapped in\n // triple mustaches. Hits occasionally include text beyond the search\n // term, so everything within the staches is captured and wrapped.\n this.matcher = new RegExp('{{{(.+?)}}}', 'gs');\n this.matches = [];\n this.cacheDOMElements();\n this.bindEvents();\n this.cancelSearch = searchCancelledCallback;\n }\n\n cacheDOMElements() {\n this.dom = {};\n // Search input within the top toolbar. Will be removed once the mobile menu is replaced.\n this.dom.toolbarSearch = this.buildToolbarSearch();\n }\n\n /**\n * @param {string} query\n */\n setQuery(query) {\n this.br.$('[name=\"query\"]').val(query);\n }\n\n emptyMatches() {\n this.matches = [];\n }\n\n removeResultPins() {\n this.br.$('.BRnavpos .BRsearch').remove();\n }\n\n clearSearchFieldAndResults(dispatchEventWhenComplete = true) {\n this.br.removeSearchResults();\n this.removeResultPins();\n this.emptyMatches();\n this.setQuery('');\n this.teardownSearchNavigation();\n if (dispatchEventWhenComplete) {\n this.br.trigger('SearchResultsCleared');\n }\n }\n\n toggleSidebar() {\n this.br.trigger('ToggleSearchMenu');\n }\n\n renderSearchNavigation() {\n const selector = 'BRsearch-navigation';\n $('.BRnav').before(`\n <div class=\"${selector}\">\n <button class=\"toggle-sidebar\">\n <h4>\n <span class=\"icon icon-search\"></span> Results\n </h4>\n </button>\n <div class=\"pagination\">\n <button class=\"prev\" title=\"Previous result\"><span class=\"icon icon-chevron hflip\"></span></button>\n <span data-id=\"resultsCount\">${this.resultsPosition()}</span>\n <button class=\"next\" title=\"Next result\"><span class=\"icon icon-chevron\"></button>\n </div>\n <button class=\"clear\" title=\"Clear search results\">\n <span class=\"icon icon-close\"></span>\n </button>\n </div>\n `);\n this.dom.searchNavigation = $(`.${selector}`);\n }\n\n resultsPosition() {\n let positionMessage = `${this.matches.length} result${this.matches.length === 1 ? '' : 's'}`;\n if (~this.currentMatchIndex) {\n positionMessage = `${this.currentMatchIndex + 1} / ${this.matches.length}`;\n }\n return positionMessage;\n }\n\n bindSearchNavigationEvents() {\n if (!this.dom.searchNavigation) { return; }\n const namespace = 'searchNavigation';\n\n this.dom.searchNavigation\n .on(`click.${namespace}`, '.clear', this.clearSearchFieldAndResults.bind(this))\n .on(`click.${namespace}`, '.prev', this.showPrevResult.bind(this))\n .on(`click.${namespace}`, '.next', this.showNextResult.bind(this))\n .on(`click.${namespace}`, '.toggle-sidebar', this.toggleSidebar.bind(this))\n .on(`click.${namespace}`, false);\n }\n\n showPrevResult() {\n if (this.currentMatchIndex === 0) { return; }\n if (this.br.mode === this.br.constModeThumb) { this.br.switchMode(this.br.constMode1up); }\n if (!~this.currentMatchIndex) {\n this.currentMatchIndex = this.getClosestMatchIndex((start, end, comparator) => end[0] > comparator) + 1;\n }\n this.br.$('.BRnavline .BRsearch').eq(--this.currentMatchIndex).click();\n this.updateResultsPosition();\n this.updateSearchNavigationButtons();\n }\n\n showNextResult() {\n if (this.currentMatchIndex + 1 === this.matches.length) { return; }\n if (this.br.mode === this.br.constModeThumb) { this.br.switchMode(this.br.constMode1up); }\n if (!~this.currentMatchIndex) {\n this.currentMatchIndex = this.getClosestMatchIndex((start, end, comparator) => start[start.length - 1] > comparator) - 1;\n }\n this.br.$('.BRnavline .BRsearch').eq(++this.currentMatchIndex).click();\n this.updateResultsPosition();\n this.updateSearchNavigationButtons();\n }\n\n /**\n * Obtains closest match based on the logical comparison function passed in.\n * When the comparison function returns true, the starting (left) half of the\n * matches array is used in the binary split, else the ending (right) half is\n * used. A recursive call is made to perform the same split and comparison\n * on the winning half of the matches. This is traditionally known as binary\n * search (https://en.wikipedia.org/wiki/Binary_search_algorithm), and in\n * most cases (medium to large search result arrays) should outperform\n * traversing the array from start to finish. In the case of small arrays,\n * the speed difference is negligible.\n *\n * @param {function} comparisonFn\n * @return {number} matchIndex\n */\n getClosestMatchIndex(comparisonFn) {\n const matchPages = this.matches.map((m) => m.par[0].page);\n const currentPage = this.br.currentIndex() + 1;\n const closestTo = (pool, comparator) => {\n if (pool.length === 1) { return pool[0]; }\n const start = pool.slice(0, pool.length / 2);\n const end = pool.slice(pool.length / 2);\n return closestTo((comparisonFn(start, end, comparator) ? start : end), comparator);\n };\n\n const closestPage = closestTo(matchPages, currentPage);\n return this.matches.indexOf(this.matches.find((m) => m.par[0].page === closestPage));\n }\n\n updateResultsPosition() {\n if (!this.dom.searchNavigation) return;\n this.dom.searchNavigation.find('[data-id=resultsCount]').text(this.resultsPosition());\n }\n\n updateSearchNavigationButtons() {\n if (!this.dom.searchNavigation) return;\n this.dom.searchNavigation.find('.prev').attr('disabled', !this.currentMatchIndex);\n this.dom.searchNavigation.find('.next').attr('disabled', this.currentMatchIndex + 1 === this.matches.length);\n }\n\n teardownSearchNavigation() {\n if (!this.dom.searchNavigation) {\n this.dom.searchNavigation = $('.BRsearch-navigation');\n }\n if (!this.dom.searchNavigation.length) { return; }\n\n this.dom.searchNavigation.off('.searchNavigation').remove();\n this.dom.searchNavigation = null;\n this.br.resize();\n }\n\n setCurrentMatchIndex() {\n let matchingSearchResult;\n if (this.br.mode === this.br.constModeThumb) {\n this.currentMatchIndex = -1;\n return;\n }\n if (this.br.mode === this.br.constMode2up) {\n matchingSearchResult = this.find2upMatchingSearchResult();\n }\n else {\n matchingSearchResult = this.find1upMatchingSearchResult();\n }\n this.currentMatchIndex = this.matches.indexOf(matchingSearchResult);\n }\n\n find1upMatchingSearchResult() {\n return this.matches.find((m) => this.br.currentIndex() === m.par[0].page - 1);\n }\n\n find2upMatchingSearchResult() {\n return this.matches.find((m) => this.br._isIndexDisplayed(m.par[0].page - 1));\n }\n\n updateSearchNavigation() {\n if (!this.matches.length) { return; }\n\n this.setCurrentMatchIndex();\n this.updateResultsPosition();\n this.updateSearchNavigationButtons();\n }\n\n /**\n * @param {boolean} bool\n */\n togglePinsFor(bool) {\n const pinsVisibleState = bool ? 'visible' : 'hidden';\n this.br.refs.$BRfooter.find('.BRsearch').css({ visibility: pinsVisibleState });\n }\n\n buildToolbarSearch() {\n const toolbarSearch = document.createElement('span');\n toolbarSearch.classList.add('BRtoolbarSection', 'BRtoolbarSectionSearch');\n toolbarSearch.innerHTML = `\n <form class=\"BRbooksearch desktop\">\n <input type=\"search\" name=\"query\" class=\"BRsearchInput\" value=\"\" placeholder=\"Search inside\"/>\n <button type=\"submit\" class=\"BRsearchSubmit\">\n <img src=\"${this.br.imagesBaseURL}icon_search_button.svg\" />\n </button>\n </form>\n `;\n return toolbarSearch;\n }\n\n /**\n * @param {array} matches\n */\n renderPins(matches) {\n matches.forEach((match) => {\n const queryString = match.text;\n const pageIndex = this.br.leafNumToIndex(match.par[0].page);\n const uiStringSearch = \"Search result\"; // i18n\n\n const percentThrough = this.br.constructor.util.cssPercentage(pageIndex, this.br.getNumLeafs() - 1);\n\n const escapedQueryString = escapeHTML(queryString);\n const queryStringWithB = escapedQueryString.replace(this.matcher, '<b>$1</b>');\n\n let queryStringWithBTruncated = '';\n\n if (queryString.length > 100) {\n queryStringWithBTruncated = queryString.replace(/^(.{100}[^\\s]*).*/, \"$1\");\n\n // If truncating, we must escape *after* truncation occurs (but before wrapping in <b>)\n queryStringWithBTruncated = escapeHTML(queryStringWithBTruncated)\n .replace(this.matcher, '<b>$1</b>')\n + '...';\n }\n\n // draw marker\n $('<div>')\n .addClass('BRsearch')\n .css({\n left: percentThrough,\n })\n .attr('title', uiStringSearch)\n .append(`\n <div class=\"BRquery\">\n <div>${queryStringWithBTruncated || queryStringWithB}</div>\n <div>Page ${match.displayPageNumber}</div>\n </div>\n `)\n .appendTo(this.br.$('.BRnavline'))\n .on(\"mouseenter\", (event) => {\n // remove from other markers then turn on just for this\n // XXX should be done when nav slider moves\n const marker = event.currentTarget;\n const tooltip = marker.querySelector('.BRquery');\n const tooltipOffset = tooltip.getBoundingClientRect();\n const targetOffset = marker.getBoundingClientRect();\n const boxSizeAdjust = parseInt(getComputedStyle(tooltip).paddingLeft) * 2;\n if (tooltipOffset.x - boxSizeAdjust < 0) {\n tooltip.style.setProperty('transform', `translateX(-${targetOffset.left - boxSizeAdjust}px)`);\n }\n $('.BRsearch,.BRchapter').removeClass('front');\n $(event.target).addClass('front');\n })\n .on(\"mouseleave\", (event) => $(event.target).removeClass('front'))\n .on(\"click\", () => { this.br._searchPluginGoToResult(match.matchIndex); });\n });\n }\n\n /**\n * @param {boolean} bool\n */\n toggleSearchPending(bool) {\n if (bool) {\n this.br.showProgressPopup(\"Search results will appear below...\", () => this.progressPopupClosed());\n }\n else {\n this.br.removeProgressPopup();\n }\n }\n\n /**\n * Primary callback when user cancels search popup\n */\n progressPopupClosed() {\n this.toggleSearchPending();\n this.cancelSearch();\n }\n\n renderErrorModal(textIsProcessing = false) {\n const errorDetails = `${!textIsProcessing ? 'The text may still be processing. ' : ''}Please try again.`;\n this.renderModalMessage(`\n Sorry, there was an error with your search.\n <br />\n ${errorDetails}\n `);\n this.delayModalRemovalFor(4000);\n }\n\n renderBookNotIndexedModal() {\n this.renderModalMessage(`\n <p>\n This book hasn't been indexed for searching yet.\n We've just started indexing it, so search should be available soon.\n <br />\n Please try again later. Thanks!\n </p>\n `);\n this.delayModalRemovalFor(5000);\n }\n\n renderResultsEmptyModal() {\n this.renderModalMessage('No matches were found.');\n this.delayModalRemovalFor(2000);\n }\n\n /**\n * @param {string} messageHTML The innerHTML string used to popupate the modal contents\n */\n renderModalMessage(messageHTML) {\n const modal = document.createElement('div');\n modal.classList.add('BRprogresspopup', 'search_modal');\n modal.innerHTML = messageHTML;\n document.querySelector(this.br.el).append(modal);\n }\n\n /**\n * @param {number} timeoutMS\n */\n delayModalRemovalFor(timeoutMS) {\n setTimeout(this.br.removeProgressPopup.bind(this.br), timeoutMS);\n }\n\n /**\n * @param {Event} e\n */\n submitHandler(e) {\n e.preventDefault();\n const query = e.target.querySelector('[name=\"query\"]').value;\n if (!query.length) { return false; }\n this.br.search(query);\n this.emptyMatches();\n this.toggleSearchPending(true);\n return false;\n }\n\n /**\n * @param {Event} e\n * @param {object} properties\n * @param {object} properties.results\n * @param {object} properties.options\n */\n handleSearchCallback(e, { results, options }) {\n this.matches = results.matches;\n this.setCurrentMatchIndex();\n this.teardownSearchNavigation();\n this.renderSearchNavigation();\n this.bindSearchNavigationEvents();\n this.renderPins(results.matches);\n this.toggleSearchPending(false);\n if (options.goToFirstResult) {\n $(document).one('BookReader:pageChanged', () => {\n this.br.resize();\n });\n } else {\n this.br.resize();\n }\n }\n\n /**\n * @param {Event} e\n */\n handleNavToggledCallback(e) {\n const is_visible = this.br.navigationIsVisible();\n this.togglePinsFor(is_visible);\n }\n\n handleSearchStarted() {\n this.emptyMatches();\n this.br.removeSearchHilites();\n this.removeResultPins();\n this.toggleSearchPending(true);\n this.teardownSearchNavigation();\n this.setQuery(this.br.searchTerm);\n }\n\n /**\n * Event listener for: `BookReader:SearchCallbackError`\n * @param {CustomEvent} event\n */\n handleSearchCallbackError(event = {}) {\n this.toggleSearchPending(false);\n const isIndexed = event?.detail?.props?.results?.indexed;\n this.renderErrorModal(isIndexed);\n }\n\n handleSearchCallbackBookNotIndexed() {\n this.toggleSearchPending(false);\n this.renderBookNotIndexedModal();\n }\n\n handleSearchCallbackEmpty() {\n this.toggleSearchPending(false);\n this.renderResultsEmptyModal();\n }\n\n bindEvents() {\n const namespace = 'BookReader:';\n\n window.addEventListener(`${namespace}SearchCallbackError`, this.handleSearchCallbackError.bind(this));\n $(document).on(`${namespace}SearchCallback`, this.handleSearchCallback.bind(this))\n .on(`${namespace}navToggled`, this.handleNavToggledCallback.bind(this))\n .on(`${namespace}SearchStarted`, this.handleSearchStarted.bind(this))\n .on(`${namespace}SearchCallbackBookNotIndexed`, this.handleSearchCallbackBookNotIndexed.bind(this))\n .on(`${namespace}SearchCallbackEmpty`, this.handleSearchCallbackEmpty.bind(this))\n .on(`${namespace}pageChanged`, this.updateSearchNavigation.bind(this));\n\n this.dom.toolbarSearch.querySelector('form').addEventListener('submit', this.submitHandler.bind(this));\n }\n}\n\nexport default SearchView;\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 $ = require('../internals/export');\nvar $entries = require('../internals/object-to-array').entries;\n\n// `Object.entries` method\n// https://tc39.es/ecma262/#sec-object.entries\n$({ target: 'Object', stat: true }, {\n entries: function entries(O) {\n return $entries(O);\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"],"names":["super_","SearchView","br","searchCancelledCallback","this","matcher","RegExp","matches","cacheDOMElements","bindEvents","cancelSearch","dom","toolbarSearch","buildToolbarSearch","query","$","val","remove","dispatchEventWhenComplete","removeSearchResults","removeResultPins","emptyMatches","setQuery","teardownSearchNavigation","trigger","selector","before","resultsPosition","searchNavigation","positionMessage","length","currentMatchIndex","namespace","on","clearSearchFieldAndResults","bind","showPrevResult","showNextResult","toggleSidebar","mode","constModeThumb","switchMode","constMode1up","getClosestMatchIndex","start","end","comparator","eq","click","updateResultsPosition","updateSearchNavigationButtons","comparisonFn","closestPage","closestTo","pool","slice","map","m","par","page","currentIndex","indexOf","find","text","attr","off","resize","matchingSearchResult","constMode2up","find2upMatchingSearchResult","find1upMatchingSearchResult","_isIndexDisplayed","setCurrentMatchIndex","bool","pinsVisibleState","refs","$BRfooter","css","visibility","document","createElement","classList","add","innerHTML","imagesBaseURL","forEach","match","queryString","pageIndex","leafNumToIndex","percentThrough","constructor","util","cssPercentage","getNumLeafs","queryStringWithB","escapeHTML","replace","queryStringWithBTruncated","addClass","left","append","displayPageNumber","appendTo","event","marker","currentTarget","tooltip","querySelector","tooltipOffset","getBoundingClientRect","targetOffset","boxSizeAdjust","parseInt","getComputedStyle","paddingLeft","x","style","setProperty","removeClass","target","_searchPluginGoToResult","matchIndex","showProgressPopup","progressPopupClosed","removeProgressPopup","toggleSearchPending","textIsProcessing","errorDetails","renderModalMessage","delayModalRemovalFor","messageHTML","modal","el","timeoutMS","setTimeout","e","preventDefault","value","search","results","options","renderSearchNavigation","bindSearchNavigationEvents","renderPins","goToFirstResult","one","is_visible","navigationIsVisible","togglePinsFor","removeSearchHilites","searchTerm","isIndexed","detail","props","indexed","renderErrorModal","renderBookNotIndexedModal","renderResultsEmptyModal","window","addEventListener","handleSearchCallbackError","handleSearchCallback","handleNavToggledCallback","handleSearchStarted","handleSearchCallbackBookNotIndexed","handleSearchCallbackEmpty","updateSearchNavigation","submitHandler","jQuery","extend","BookReader","defaultOptions","server","bookId","subPrefix","bookPath","enableSearch","searchInsideUrl","initialSearchTerm","prototype","setup","call","searchResults","searchXHR","_cancelSearch","cancelSearchRequest","_searchBoxesByIndex","searchView","undefined","init","term","instance","suppressFragmentChange","buildToolbarElement","$el","after","_createPageContainer","index","pageContainer","boxes","renderBoxesInPageContainerLayer","$container","b","overrides","disablePopup","error","success","searchCancelled","eventNames","fragmentChange","serverPath","baseUrl","path","subPrefixWithSlash","lastIndexOf","substr","urlParams","item_id","doc","q","paramStr","param","url","callSearchResultsCallback","searchInsideResults","responseHasError","hasCustomError","hasCustomSuccess","BRSearchCallbackError","BRSearchCallback","ajax","dataType","cache","beforeSend","xhr","abort","displayPageNumberFn","pageNum","entries","getPageNum","marshallSearchResults","updateSearchHilites","_BRSearchCallbackError","basePayload","payload","Object","assign","boxesByIndex","box","push","pageIndexString","parseFloat","_models","book","getPage","getActivePageContainerElementsForIndex","container","getActivePageContainerElements","onNearbyPage","Math","abs","makeUnviewableAtEnd","isViewable","fetch","URLSearchParams","id","subprefix","leafNum","then","r","json","resp","makeViewable","jumpToIndex","poll","until","result","$boxes","scrollIntoView","block","isFullscreenActive","inline","behavior","Promise","resolve","removeAttr","searchHighlightVisible","visiblePages","twoPage","currentIndexL","currentIndexR","some","inArray","global","fails","uncurryThis","toString","trim","whitespaces","charAt","n$ParseFloat","Symbol","ITERATOR","iterator","FORCED","module","exports","string","trimmedString","$entries","stat","O","$parseFloat","forced"],"sourceRoot":""}
|
1
|
+
{"version":3,"file":"plugins/plugin.search.js","mappings":"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","sources":["webpack://@internetarchive/bookreader/./src/plugins/search/plugin.search.js","webpack://@internetarchive/bookreader/./src/plugins/search/view.js","webpack://@internetarchive/bookreader/./node_modules/core-js/internals/number-parse-float.js","webpack://@internetarchive/bookreader/./node_modules/core-js/modules/es.object.entries.js","webpack://@internetarchive/bookreader/./node_modules/core-js/modules/es.parse-float.js"],"sourcesContent":["// @ts-check\n/* global BookReader */\n/**\n * Plugin for Archive.org book search\n * NOTE: This script must be loaded AFTER `plugin.mobile_nav.js`\n * as it mutates mobile nav drawer\n *\n * Events fired at various points throughout search processing are published\n * on the document DOM element. These can be subscribed to using jQuery's event\n * binding method `$.fn.on`. All of the events are prefixed with a BookReader\n * namespace. The events are:\n *\n * @event BookReader:SearchStarted - When a search form is submitted, immediately\n * before an AJAX call is made to request search results\n * @event BookReader:SearchCallback - When the search AJAX call is returned and at\n * least one result is returned. The event callback receives an object\n * with the `results`, plugin `options`, and the BookReader `instance`\n * @event BookReader:SearchCallbackError - When the AJAX request returns an error.\n * Receives the `results` and `instance`\n * @event BookReader:SearchCallbackNotIndexed - When a message is received that\n * the book has not had OCR text indexed yet. Receives `instance`\n * @event BookReader:SearchCallbackEmpty - When no results found. Receives\n * `instance`\n * @event BookReader:SearchCanceled - When no results found. Receives\n * `instance`\n */\nimport { poll } from '../../BookReader/utils.js';\nimport { renderBoxesInPageContainerLayer } from '../../BookReader/PageContainer.js';\nimport SearchView from './view.js';\n/** @typedef {import('../../BookReader/PageContainer').PageContainer} PageContainer */\n/** @typedef {import('../../BookReader/BookModel').PageIndex} PageIndex */\n/** @typedef {import('../../BookReader/BookModel').LeafNum} LeafNum */\n/** @typedef {import('../../BookReader/BookModel').PageNumString} PageNumString */\n\njQuery.extend(BookReader.defaultOptions, {\n server: 'ia600609.us.archive.org',\n bookId: '',\n subPrefix: '',\n bookPath: '',\n enableSearch: true,\n searchInsideUrl: '/fulltext/inside.php',\n initialSearchTerm: null,\n});\n\n/** @override */\nBookReader.prototype.setup = (function (super_) {\n return function (options) {\n super_.call(this, options);\n\n this.searchTerm = '';\n this.searchResults = null;\n this.searchInsideUrl = options.searchInsideUrl;\n this.enableSearch = options.enableSearch;\n\n // Base server used by some api calls\n this.bookId = options.bookId;\n this.server = options.server;\n this.subPrefix = options.subPrefix;\n this.bookPath = options.bookPath;\n\n this.searchXHR = null;\n this._cancelSearch.bind(this);\n this.cancelSearchRequest.bind(this);\n\n /** @type { {[pageIndex: number]: SearchInsideMatchBox[]} } */\n this._searchBoxesByIndex = {};\n\n this.searchView = undefined;\n };\n})(BookReader.prototype.setup);\n\n/** @override */\nBookReader.prototype.init = (function (super_) {\n return function () {\n super_.call(this);\n // give SearchView the most complete bookreader state\n this.searchView = new SearchView({\n br: this,\n searchCancelledCallback: () => {\n this._cancelSearch();\n this.trigger('SearchCanceled', { term: this.searchTerm, instance: this });\n }\n });\n if (this.options.enableSearch && this.options.initialSearchTerm) {\n /**\n * this.search() take two parameter\n * 1. this.options.initialSearchTerm - search term\n * 2. {\n * goToFirstResult: this.options.goToFirstResult,\n * suppressFragmentChange: false // always want to change fragment in URL\n * }\n */\n this.search(\n this.options.initialSearchTerm,\n { goToFirstResult: this.options.goToFirstResult, suppressFragmentChange: false }\n );\n }\n };\n})(BookReader.prototype.init);\n\n/** @override */\nBookReader.prototype.buildToolbarElement = (function (super_) {\n return function () {\n const $el = super_.call(this);\n if (!this.enableSearch) { return; }\n if (this.searchView.dom.toolbarSearch) {\n $el.find('.BRtoolbarSectionInfo').after(this.searchView.dom.toolbarSearch);\n }\n return $el;\n };\n})(BookReader.prototype.buildToolbarElement);\n\n/** @override */\nBookReader.prototype._createPageContainer = (function (super_) {\n return function (index) {\n const pageContainer = super_.call(this, index);\n if (this.enableSearch && pageContainer.page && index in this._searchBoxesByIndex) {\n const pageIndex = pageContainer.page.index;\n const boxes = this._searchBoxesByIndex[pageIndex];\n renderBoxesInPageContainerLayer(\n 'searchHiliteLayer',\n boxes,\n pageContainer.page,\n pageContainer.$container[0],\n boxes.map(b => `match-index-${b.matchIndex}`),\n );\n }\n return pageContainer;\n };\n})(BookReader.prototype._createPageContainer);\n\n/**\n * @typedef {object} SearchOptions\n * @property {boolean} goToFirstResult\n * @property {boolean} disablePopup\n * @property {(null|function)} error - @deprecated at v.5.0\n * @property {(null|function)} success - @deprecated at v.5.0\n */\n\n/**\n * Submits search request\n *\n * @param {string} term\n * @param {SearchOptions} overrides\n */\nBookReader.prototype.search = async function(term = '', overrides = {}) {\n /** @type {SearchOptions} */\n const defaultOptions = {\n goToFirstResult: false, /* jump to the first result (default=false) */\n disablePopup: false, /* don't show the modal progress (default=false) */\n suppressFragmentChange: false, /* don't change the URL on initial load */\n error: null, /* optional error handler (default=null) */\n success: null, /* optional success handler (default=null) */\n\n };\n const options = jQuery.extend({}, defaultOptions, overrides);\n this.suppressFragmentChange = options.suppressFragmentChange;\n this.searchCancelled = false;\n\n // strip slashes, since this goes in the url\n this.searchTerm = term.replace(/\\//g, ' ');\n\n if (!options.suppressFragmentChange) {\n this.trigger(BookReader.eventNames.fragmentChange);\n }\n\n // Add quotes to the term. This is to compenstate for the backends default OR query\n // term = term.replace(/['\"]+/g, '');\n // term = '\"' + term + '\"';\n\n // Remove the port and userdir\n const serverPath = this.server.replace(/:.+/, '');\n const baseUrl = `https://${serverPath}${this.searchInsideUrl}?`;\n\n // Remove subPrefix from end of path\n let path = this.bookPath;\n const subPrefixWithSlash = `/${this.subPrefix}`;\n if (this.bookPath.length - this.bookPath.lastIndexOf(subPrefixWithSlash) == subPrefixWithSlash.length) {\n path = this.bookPath.substr(0, this.bookPath.length - subPrefixWithSlash.length);\n }\n\n const urlParams = {\n item_id: this.bookId,\n doc: this.subPrefix,\n path,\n q: term,\n };\n\n // NOTE that the API does not expect / (slashes) to be encoded. (%2F) won't work\n const paramStr = $.param(urlParams).replace(/%2F/g, '/');\n\n const url = `${baseUrl}${paramStr}`;\n\n const callSearchResultsCallback = (searchInsideResults) => {\n if (this.searchCancelled) {\n return;\n }\n const responseHasError = searchInsideResults.error || !searchInsideResults.matches.length;\n const hasCustomError = typeof options.error === 'function';\n const hasCustomSuccess = typeof options.success === 'function';\n\n if (responseHasError) {\n hasCustomError\n ? options.error.call(this, searchInsideResults, options)\n : this.BRSearchCallbackError(searchInsideResults, options);\n } else {\n hasCustomSuccess\n ? options.success.call(this, searchInsideResults, options)\n : this.BRSearchCallback(searchInsideResults, options);\n }\n };\n\n this.trigger('SearchStarted', { term: this.searchTerm, instance: this });\n callSearchResultsCallback(await $.ajax({\n url: url,\n dataType: 'jsonp',\n cache: true,\n beforeSend: xhr => { this.searchXHR = xhr; },\n }));\n};\n\n/**\n * cancels AJAX Call\n * emits custom event\n */\nBookReader.prototype._cancelSearch = function () {\n this.searchXHR?.abort();\n this.searchView.clearSearchFieldAndResults(false);\n this.searchTerm = '';\n this.searchXHR = null;\n this.searchCancelled = true;\n this.searchResults = [];\n};\n\n/**\n * External function to cancel search\n * checks for term & xhr in flight before running\n */\nBookReader.prototype.cancelSearchRequest = function () {\n this.searchCancelled = true;\n if (this.searchXHR !== null) {\n this._cancelSearch();\n this.searchView.toggleSearchPending();\n this.trigger('SearchCanceled', { term: this.searchTerm, instance: this });\n }\n};\n\n/**\n * @typedef {object} SearchInsideMatchBox\n * @property {number} page\n * @property {number} r\n * @property {number} l\n * @property {number} b\n * @property {number} t\n * @property {HTMLDivElement} [div]\n * @property {number} matchIndex This is a fake field! not part of the API response. The index of the match that contains this box in total search results matches.\n */\n\n/**\n * @typedef {object} SearchInsideMatch\n * @property {number} matchIndex This is a fake field! Not part of the API response. It is added by the JS.\n * @property {string} displayPageNumber (fake field) The page number as it should be displayed in the UI.\n * @property {string} text\n * @property {Array<{ page: number, boxes: SearchInsideMatchBox[] }>} par\n */\n\n/**\n * @typedef {object} SearchInsideResults\n * @property {string} error\n * @property {SearchInsideMatch[]} matches\n * @property {boolean} indexed\n */\n\n/**\n * Attach some fields to search inside results\n * @param {SearchInsideResults} results\n * @param {(pageNum: LeafNum) => PageNumString} displayPageNumberFn\n */\nexport function marshallSearchResults(results, displayPageNumberFn) {\n // Attach matchIndex to a few things to make it easier to identify\n // an active/selected match\n for (const [index, match] of results.matches.entries()) {\n match.matchIndex = index;\n match.displayPageNumber = displayPageNumberFn(match.par[0].page);\n for (const par of match.par) {\n for (const box of par.boxes) {\n box.matchIndex = index;\n }\n }\n }\n}\n\n/**\n * Search Results return handler\n * @param {SearchInsideResults} results\n * @param {object} options\n * @param {boolean} options.goToFirstResult\n */\nBookReader.prototype.BRSearchCallback = function(results, options) {\n marshallSearchResults(results, pageNum => this.getPageNum(this.leafNumToIndex(pageNum)));\n this.searchResults = results || [];\n\n this.updateSearchHilites();\n this.removeProgressPopup();\n if (options.goToFirstResult) {\n this._searchPluginGoToResult(0);\n }\n this.trigger('SearchCallback', { results, options, instance: this });\n};\n\n/**\n * Main search results error handler\n * @callback\n * @param {SearchInsideResults} results\n */\nBookReader.prototype.BRSearchCallbackError = function(results) {\n this._BRSearchCallbackError(results);\n};\n\n/**\n * @private draws search results error\n * @callback\n * @param {SearchInsideResults} results\n * @param {jQuery} $el\n * @param {boolean} fade\n */\nBookReader.prototype._BRSearchCallbackError = function(results) {\n this.searchResults = results;\n const basePayload = {\n term: this.searchTerm,\n instance: this,\n };\n if (results.error) {\n const payload = Object.assign({}, basePayload, { results });\n this.trigger('SearchCallbackError', payload);\n } else if (0 == results.matches.length) {\n if (false === results.indexed) {\n this.trigger('SearchCallbackBookNotIndexed', basePayload);\n return;\n }\n this.trigger('SearchCallbackEmpty', basePayload);\n }\n};\n\n/**\n * updates search on-page highlights controller\n */\nBookReader.prototype.updateSearchHilites = function() {\n /** @type {SearchInsideMatch[]} */\n const matches = this.searchResults?.matches || [];\n /** @type { {[pageIndex: number]: SearchInsideMatchBox[]} } */\n const boxesByIndex = {};\n\n // Clear any existing svg layers\n this.removeSearchHilites();\n\n // Group by pageIndex\n for (const match of matches) {\n for (const box of match.par[0].boxes) {\n const pageIndex = this.leafNumToIndex(box.page);\n const pageBoxes = boxesByIndex[pageIndex] || (boxesByIndex[pageIndex] = []);\n pageBoxes.push(box);\n }\n }\n\n // update any already created pages\n for (const [pageIndexString, boxes] of Object.entries(boxesByIndex)) {\n const pageIndex = parseFloat(pageIndexString);\n const page = this._models.book.getPage(pageIndex);\n const pageContainers = this.getActivePageContainerElementsForIndex(pageIndex);\n for (const container of pageContainers) {\n renderBoxesInPageContainerLayer('searchHiliteLayer', boxes, page, container, boxes.map(b => `match-index-${b.matchIndex}`));\n }\n }\n\n this._searchBoxesByIndex = boxesByIndex;\n};\n\n/**\n * remove search highlights\n */\nBookReader.prototype.removeSearchHilites = function() {\n $(this.getActivePageContainerElements()).find('.searchHiliteLayer').remove();\n};\n\n/**\n * @private\n * Goes to the page specified. If the page is not viewable, tries to load the page\n * FIXME Most of this logic is IA specific, and should be less integrated into here\n * or at least more configurable.\n * @param {number} matchIndex\n */\nBookReader.prototype._searchPluginGoToResult = async function (matchIndex) {\n const match = this.searchResults?.matches[matchIndex];\n const pageIndex = this.leafNumToIndex(match.par[0].page);\n const { book } = this._models;\n const page = book.getPage(pageIndex);\n const onNearbyPage = Math.abs(this.currentIndex() - pageIndex) < 3;\n let makeUnviewableAtEnd = false;\n if (!page.isViewable) {\n const resp = await fetch('/services/bookreader/request_page?' + new URLSearchParams({\n id: this.options.bookId,\n subprefix: this.options.subPrefix,\n leafNum: page.leafNum,\n })).then(r => r.json());\n\n for (const leafNum of resp.value) {\n book.getPage(book.leafNumToIndex(leafNum)).makeViewable();\n }\n\n // not able to show page; make the page viewable anyways so that it can\n // actually open. On IA, it has a fallback to a special error page.\n if (!resp.value.length) {\n book.getPage(pageIndex).makeViewable();\n makeUnviewableAtEnd = true;\n }\n }\n /* this updates the URL */\n if (!this._isIndexDisplayed(pageIndex)) {\n this.suppressFragmentChange = false;\n this.jumpToIndex(pageIndex);\n }\n\n // Reset it to unviewable if it wasn't resolved\n if (makeUnviewableAtEnd) {\n book.getPage(pageIndex).makeViewable(false);\n }\n\n // Scroll/flash in the ui\n const $boxes = await poll(() => $(`rect.match-index-${match.matchIndex}`), { until: result => result.length > 0 });\n if ($boxes.length) {\n $boxes.css('animation', 'none');\n $boxes[0].scrollIntoView({\n // Only vertically center the highlight if we're in 1up or in full screen. In\n // 2up, if we're not fullscreen, the whole body gets scrolled around to try to\n // center the highlight 🙄 See:\n // https://stackoverflow.com/questions/11039885/scrollintoview-causing-the-whole-page-to-move/11041376\n // Note: nearest doesn't quite work great, because the ReadAloud toolbar is now\n // full-width, and covers up the last line of the highlight.\n block: this.constMode1up == this.mode || this.isFullscreenActive ? 'center' : 'nearest',\n inline: 'center',\n behavior: onNearbyPage ? 'smooth' : 'auto',\n });\n // wait for animation to start\n await new Promise(resolve => setTimeout(resolve, 100));\n $boxes.removeAttr(\"style\");\n }\n};\n\n/**\n * Removes all search pins\n */\nBookReader.prototype.removeSearchResults = function(suppressFragmentChange = false) {\n this.removeSearchHilites(); //be sure to set all box.divs to null\n this.searchTerm = null;\n this.searchResults = null;\n if (!suppressFragmentChange) {\n this.trigger(BookReader.eventNames.fragmentChange);\n }\n};\n\n/**\n * Returns true if a search highlight is currently being displayed\n * @returns {boolean}\n */\nBookReader.prototype.searchHighlightVisible = function() {\n const results = this.searchResults;\n let visiblePages = [];\n if (null == results) return false;\n\n if (this.constMode2up == this.mode) {\n visiblePages = [this.twoPage.currentIndexL, this.twoPage.currentIndexR];\n } else if (this.constMode1up == this.mode) {\n visiblePages = [this.currentIndex()];\n } else {\n return false;\n }\n\n results.matches.some(match => {\n return match.par[0].boxes.some(box => {\n const pageIndex = this.leafNumToIndex(box.page);\n if (jQuery.inArray(pageIndex, visiblePages) >= 0) {\n return true;\n }\n });\n });\n\n return false;\n};\n","class SearchView {\n /**\n * @param {object} params\n * @param {object} params.br The BookReader instance\n * @param {function} params.cancelSearch callback when a user wants to cancel search\n *\n * @event BookReader:SearchResultsCleared - when the search results nav gets cleared\n * @event BookReader:ToggleSearchMenu - when search results menu should toggle\n */\n constructor({ br, searchCancelledCallback = () => {} }) {\n this.br = br;\n\n // Search results are returned as a text blob with the hits wrapped in\n // triple mustaches. Hits occasionally include text beyond the search\n // term, so everything within the staches is captured and wrapped.\n this.matcher = new RegExp('{{{(.+?)}}}', 'g');\n this.matches = [];\n this.cacheDOMElements();\n this.bindEvents();\n this.cancelSearch = searchCancelledCallback;\n }\n\n cacheDOMElements() {\n this.dom = {};\n // Search input within the top toolbar. Will be removed once the mobile menu is replaced.\n this.dom.toolbarSearch = this.buildToolbarSearch();\n }\n\n /**\n * @param {string} query\n */\n setQuery(query) {\n this.br.$('[name=\"query\"]').val(query);\n }\n\n emptyMatches() {\n this.matches = [];\n }\n\n removeResultPins() {\n this.br.$('.BRnavpos .BRsearch').remove();\n }\n\n clearSearchFieldAndResults(dispatchEventWhenComplete = true) {\n this.br.removeSearchResults();\n this.removeResultPins();\n this.emptyMatches();\n this.setQuery('');\n this.teardownSearchNavigation();\n if (dispatchEventWhenComplete) {\n this.br.trigger('SearchResultsCleared');\n }\n }\n\n toggleSidebar() {\n this.br.trigger('ToggleSearchMenu');\n }\n\n renderSearchNavigation() {\n const selector = 'BRsearch-navigation';\n $('.BRnav').before(`\n <div class=\"${selector}\">\n <button class=\"toggle-sidebar\">\n <h4>\n <span class=\"icon icon-search\"></span> Results\n </h4>\n </button>\n <div class=\"pagination\">\n <button class=\"prev\" title=\"Previous result\"><span class=\"icon icon-chevron hflip\"></span></button>\n <span data-id=\"resultsCount\">${this.resultsPosition()}</span>\n <button class=\"next\" title=\"Next result\"><span class=\"icon icon-chevron\"></button>\n </div>\n <button class=\"clear\" title=\"Clear search results\">\n <span class=\"icon icon-close\"></span>\n </button>\n </div>\n `);\n this.dom.searchNavigation = $(`.${selector}`);\n }\n\n resultsPosition() {\n let positionMessage = `${this.matches.length} result${this.matches.length === 1 ? '' : 's'}`;\n if (~this.currentMatchIndex) {\n positionMessage = `${this.currentMatchIndex + 1} / ${this.matches.length}`;\n }\n return positionMessage;\n }\n\n bindSearchNavigationEvents() {\n if (!this.dom.searchNavigation) { return; }\n const namespace = 'searchNavigation';\n\n this.dom.searchNavigation\n .on(`click.${namespace}`, '.clear', this.clearSearchFieldAndResults.bind(this))\n .on(`click.${namespace}`, '.prev', this.showPrevResult.bind(this))\n .on(`click.${namespace}`, '.next', this.showNextResult.bind(this))\n .on(`click.${namespace}`, '.toggle-sidebar', this.toggleSidebar.bind(this))\n .on(`click.${namespace}`, false);\n }\n\n showPrevResult() {\n if (this.currentMatchIndex === 0) { return; }\n if (this.br.mode === this.br.constModeThumb) { this.br.switchMode(this.br.constMode1up); }\n if (!~this.currentMatchIndex) {\n this.currentMatchIndex = this.getClosestMatchIndex((start, end, comparator) => end[0] > comparator) + 1;\n }\n this.br.$('.BRnavline .BRsearch').eq(--this.currentMatchIndex).click();\n this.updateResultsPosition();\n this.updateSearchNavigationButtons();\n }\n\n showNextResult() {\n if (this.currentMatchIndex + 1 === this.matches.length) { return; }\n if (this.br.mode === this.br.constModeThumb) { this.br.switchMode(this.br.constMode1up); }\n if (!~this.currentMatchIndex) {\n this.currentMatchIndex = this.getClosestMatchIndex((start, end, comparator) => start[start.length - 1] > comparator) - 1;\n }\n this.br.$('.BRnavline .BRsearch').eq(++this.currentMatchIndex).click();\n this.updateResultsPosition();\n this.updateSearchNavigationButtons();\n }\n\n /**\n * Obtains closest match based on the logical comparison function passed in.\n * When the comparison function returns true, the starting (left) half of the\n * matches array is used in the binary split, else the ending (right) half is\n * used. A recursive call is made to perform the same split and comparison\n * on the winning half of the matches. This is traditionally known as binary\n * search (https://en.wikipedia.org/wiki/Binary_search_algorithm), and in\n * most cases (medium to large search result arrays) should outperform\n * traversing the array from start to finish. In the case of small arrays,\n * the speed difference is negligible.\n *\n * @param {function} comparisonFn\n * @return {number} matchIndex\n */\n getClosestMatchIndex(comparisonFn) {\n const matchPages = this.matches.map((m) => m.par[0].page);\n const currentPage = this.br.currentIndex() + 1;\n const closestTo = (pool, comparator) => {\n if (pool.length === 1) { return pool[0]; }\n const start = pool.slice(0, pool.length / 2);\n const end = pool.slice(pool.length / 2);\n return closestTo((comparisonFn(start, end, comparator) ? start : end), comparator);\n };\n\n const closestPage = closestTo(matchPages, currentPage);\n return this.matches.indexOf(this.matches.find((m) => m.par[0].page === closestPage));\n }\n\n updateResultsPosition() {\n if (!this.dom.searchNavigation) return;\n this.dom.searchNavigation.find('[data-id=resultsCount]').text(this.resultsPosition());\n }\n\n updateSearchNavigationButtons() {\n if (!this.dom.searchNavigation) return;\n this.dom.searchNavigation.find('.prev').attr('disabled', !this.currentMatchIndex);\n this.dom.searchNavigation.find('.next').attr('disabled', this.currentMatchIndex + 1 === this.matches.length);\n }\n\n teardownSearchNavigation() {\n if (!this.dom.searchNavigation) {\n this.dom.searchNavigation = $('.BRsearch-navigation');\n }\n if (!this.dom.searchNavigation.length) { return; }\n\n this.dom.searchNavigation.off('.searchNavigation').remove();\n this.dom.searchNavigation = null;\n this.br.resize();\n }\n\n setCurrentMatchIndex() {\n let matchingSearchResult;\n if (this.br.mode === this.br.constModeThumb) {\n this.currentMatchIndex = -1;\n return;\n }\n if (this.br.mode === this.br.constMode2up) {\n matchingSearchResult = this.find2upMatchingSearchResult();\n }\n else {\n matchingSearchResult = this.find1upMatchingSearchResult();\n }\n this.currentMatchIndex = this.matches.indexOf(matchingSearchResult);\n }\n\n find1upMatchingSearchResult() {\n return this.matches.find((m) => this.br.currentIndex() === m.par[0].page - 1);\n }\n\n find2upMatchingSearchResult() {\n return this.matches.find((m) => this.br._isIndexDisplayed(m.par[0].page - 1));\n }\n\n updateSearchNavigation() {\n if (!this.matches.length) { return; }\n\n this.setCurrentMatchIndex();\n this.updateResultsPosition();\n this.updateSearchNavigationButtons();\n }\n\n /**\n * @param {boolean} bool\n */\n togglePinsFor(bool) {\n const pinsVisibleState = bool ? 'visible' : 'hidden';\n this.br.refs.$BRfooter.find('.BRsearch').css({ visibility: pinsVisibleState });\n }\n\n buildToolbarSearch() {\n const toolbarSearch = document.createElement('span');\n toolbarSearch.classList.add('BRtoolbarSection', 'BRtoolbarSectionSearch');\n toolbarSearch.innerHTML = `\n <form class=\"BRbooksearch desktop\">\n <input type=\"search\" name=\"query\" class=\"BRsearchInput\" value=\"\" placeholder=\"Search inside\"/>\n <button type=\"submit\" class=\"BRsearchSubmit\">\n <img src=\"${this.br.imagesBaseURL}icon_search_button.svg\" />\n </button>\n </form>\n `;\n return toolbarSearch;\n }\n\n /**\n * @param {array} matches\n */\n renderPins(matches) {\n matches.forEach((match) => {\n const queryString = match.text;\n const pageIndex = this.br.leafNumToIndex(match.par[0].page);\n const uiStringSearch = \"Search result\"; // i18n\n\n const percentThrough = this.br.constructor.util.cssPercentage(pageIndex, this.br.getNumLeafs() - 1);\n\n const queryStringWithB = queryString.replace(this.matcher, '<b>$1</b>');\n\n let queryStringWithBTruncated = '';\n\n if (queryString.length > 100) {\n queryStringWithBTruncated = queryString\n .replace(/^(.{100}[^\\s]*).*/, \"$1\")\n .replace(this.matcher, '<b>$1</b>')\n + '...';\n }\n\n // draw marker\n $('<div>')\n .addClass('BRsearch')\n .css({\n left: percentThrough,\n })\n .attr('title', uiStringSearch)\n .append(`\n <div class=\"BRquery\">\n <div>${queryStringWithBTruncated || queryStringWithB}</div>\n <div>Page ${match.displayPageNumber}</div>\n </div>\n `)\n .appendTo(this.br.$('.BRnavline'))\n .on(\"mouseenter\", (event) => {\n // remove from other markers then turn on just for this\n // XXX should be done when nav slider moves\n const marker = event.currentTarget;\n const tooltip = marker.querySelector('.BRquery');\n const tooltipOffset = tooltip.getBoundingClientRect();\n const targetOffset = marker.getBoundingClientRect();\n const boxSizeAdjust = parseInt(getComputedStyle(tooltip).paddingLeft) * 2;\n if (tooltipOffset.x - boxSizeAdjust < 0) {\n tooltip.style.setProperty('transform', `translateX(-${targetOffset.left - boxSizeAdjust}px)`);\n }\n $('.BRsearch,.BRchapter').removeClass('front');\n $(event.target).addClass('front');\n })\n .on(\"mouseleave\", (event) => $(event.target).removeClass('front'))\n .on(\"click\", () => { this.br._searchPluginGoToResult(match.matchIndex); });\n });\n }\n\n /**\n * @param {boolean} bool\n */\n toggleSearchPending(bool) {\n if (bool) {\n this.br.showProgressPopup(\"Search results will appear below...\", () => this.progressPopupClosed());\n }\n else {\n this.br.removeProgressPopup();\n }\n }\n\n /**\n * Primary callback when user cancels search popup\n */\n progressPopupClosed() {\n this.toggleSearchPending();\n this.cancelSearch();\n }\n\n renderErrorModal(textIsProcessing = false) {\n const errorDetails = `${!textIsProcessing ? 'The text may still be processing. ' : ''}Please try again.`;\n this.renderModalMessage(`\n Sorry, there was an error with your search.\n <br />\n ${errorDetails}\n `);\n this.delayModalRemovalFor(4000);\n }\n\n renderBookNotIndexedModal() {\n this.renderModalMessage(`\n <p>\n This book hasn't been indexed for searching yet.\n We've just started indexing it, so search should be available soon.\n <br />\n Please try again later. Thanks!\n </p>\n `);\n this.delayModalRemovalFor(5000);\n }\n\n renderResultsEmptyModal() {\n this.renderModalMessage('No matches were found.');\n this.delayModalRemovalFor(2000);\n }\n\n /**\n * @param {string} messageHTML The innerHTML string used to popupate the modal contents\n */\n renderModalMessage(messageHTML) {\n const modal = document.createElement('div');\n modal.classList.add('BRprogresspopup', 'search_modal');\n modal.innerHTML = messageHTML;\n document.querySelector(this.br.el).append(modal);\n }\n\n /**\n * @param {number} timeoutMS\n */\n delayModalRemovalFor(timeoutMS) {\n setTimeout(this.br.removeProgressPopup.bind(this.br), timeoutMS);\n }\n\n /**\n * @param {Event} e\n */\n submitHandler(e) {\n e.preventDefault();\n const query = e.target.querySelector('[name=\"query\"]').value;\n if (!query.length) { return false; }\n this.br.search(query);\n this.emptyMatches();\n this.toggleSearchPending(true);\n return false;\n }\n\n /**\n * @param {Event} e\n * @param {object} properties\n * @param {object} properties.results\n * @param {object} properties.options\n */\n handleSearchCallback(e, { results, options }) {\n this.matches = results.matches;\n this.setCurrentMatchIndex();\n this.teardownSearchNavigation();\n this.renderSearchNavigation();\n this.bindSearchNavigationEvents();\n this.renderPins(results.matches);\n this.toggleSearchPending(false);\n if (options.goToFirstResult) {\n $(document).one('BookReader:pageChanged', () => {\n this.br.resize();\n });\n } else {\n this.br.resize();\n }\n }\n\n /**\n * @param {Event} e\n */\n handleNavToggledCallback(e) {\n const is_visible = this.br.navigationIsVisible();\n this.togglePinsFor(is_visible);\n }\n\n handleSearchStarted() {\n this.emptyMatches();\n this.br.removeSearchHilites();\n this.removeResultPins();\n this.toggleSearchPending(true);\n this.teardownSearchNavigation();\n this.setQuery(this.br.searchTerm);\n }\n\n /**\n * Event listener for: `BookReader:SearchCallbackError`\n * @param {CustomEvent} event\n */\n handleSearchCallbackError(event = {}) {\n this.toggleSearchPending(false);\n const isIndexed = event?.detail?.props?.results?.indexed;\n this.renderErrorModal(isIndexed);\n }\n\n handleSearchCallbackBookNotIndexed() {\n this.toggleSearchPending(false);\n this.renderBookNotIndexedModal();\n }\n\n handleSearchCallbackEmpty() {\n this.toggleSearchPending(false);\n this.renderResultsEmptyModal();\n }\n\n bindEvents() {\n const namespace = 'BookReader:';\n\n window.addEventListener(`${namespace}SearchCallbackError`, this.handleSearchCallbackError.bind(this));\n $(document).on(`${namespace}SearchCallback`, this.handleSearchCallback.bind(this))\n .on(`${namespace}navToggled`, this.handleNavToggledCallback.bind(this))\n .on(`${namespace}SearchStarted`, this.handleSearchStarted.bind(this))\n .on(`${namespace}SearchCallbackBookNotIndexed`, this.handleSearchCallbackBookNotIndexed.bind(this))\n .on(`${namespace}SearchCallbackEmpty`, this.handleSearchCallbackEmpty.bind(this))\n .on(`${namespace}pageChanged`, this.updateSearchNavigation.bind(this));\n\n this.dom.toolbarSearch.querySelector('form').addEventListener('submit', this.submitHandler.bind(this));\n }\n}\n\nexport default SearchView;\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 $ = require('../internals/export');\nvar $entries = require('../internals/object-to-array').entries;\n\n// `Object.entries` method\n// https://tc39.es/ecma262/#sec-object.entries\n$({ target: 'Object', stat: true }, {\n entries: function entries(O) {\n return $entries(O);\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"],"names":["super_","SearchView","br","searchCancelledCallback","this","matcher","RegExp","matches","cacheDOMElements","bindEvents","cancelSearch","dom","toolbarSearch","buildToolbarSearch","query","$","val","remove","dispatchEventWhenComplete","removeSearchResults","removeResultPins","emptyMatches","setQuery","teardownSearchNavigation","trigger","selector","before","resultsPosition","searchNavigation","positionMessage","length","currentMatchIndex","namespace","on","clearSearchFieldAndResults","bind","showPrevResult","showNextResult","toggleSidebar","mode","constModeThumb","switchMode","constMode1up","getClosestMatchIndex","start","end","comparator","eq","click","updateResultsPosition","updateSearchNavigationButtons","comparisonFn","closestPage","closestTo","pool","slice","map","m","par","page","currentIndex","indexOf","find","text","attr","off","resize","matchingSearchResult","constMode2up","find2upMatchingSearchResult","find1upMatchingSearchResult","_isIndexDisplayed","setCurrentMatchIndex","bool","pinsVisibleState","refs","$BRfooter","css","visibility","document","createElement","classList","add","innerHTML","imagesBaseURL","forEach","match","queryString","pageIndex","leafNumToIndex","percentThrough","constructor","util","cssPercentage","getNumLeafs","queryStringWithB","replace","queryStringWithBTruncated","addClass","left","append","displayPageNumber","appendTo","event","marker","currentTarget","tooltip","querySelector","tooltipOffset","getBoundingClientRect","targetOffset","boxSizeAdjust","parseInt","getComputedStyle","paddingLeft","x","style","setProperty","removeClass","target","_searchPluginGoToResult","matchIndex","showProgressPopup","progressPopupClosed","removeProgressPopup","toggleSearchPending","textIsProcessing","errorDetails","renderModalMessage","delayModalRemovalFor","messageHTML","modal","el","timeoutMS","setTimeout","e","preventDefault","value","search","results","options","renderSearchNavigation","bindSearchNavigationEvents","renderPins","goToFirstResult","one","is_visible","navigationIsVisible","togglePinsFor","removeSearchHilites","searchTerm","isIndexed","detail","props","indexed","renderErrorModal","renderBookNotIndexedModal","renderResultsEmptyModal","window","addEventListener","handleSearchCallbackError","handleSearchCallback","handleNavToggledCallback","handleSearchStarted","handleSearchCallbackBookNotIndexed","handleSearchCallbackEmpty","updateSearchNavigation","submitHandler","jQuery","extend","BookReader","defaultOptions","server","bookId","subPrefix","bookPath","enableSearch","searchInsideUrl","initialSearchTerm","prototype","setup","call","searchResults","searchXHR","_cancelSearch","cancelSearchRequest","_searchBoxesByIndex","searchView","undefined","init","term","instance","suppressFragmentChange","buildToolbarElement","$el","after","_createPageContainer","index","pageContainer","boxes","renderBoxesInPageContainerLayer","$container","b","overrides","disablePopup","error","success","searchCancelled","eventNames","fragmentChange","serverPath","baseUrl","path","subPrefixWithSlash","lastIndexOf","substr","urlParams","item_id","doc","q","paramStr","param","url","callSearchResultsCallback","searchInsideResults","responseHasError","hasCustomError","hasCustomSuccess","BRSearchCallbackError","BRSearchCallback","ajax","dataType","cache","beforeSend","xhr","abort","displayPageNumberFn","pageNum","entries","getPageNum","marshallSearchResults","updateSearchHilites","_BRSearchCallbackError","basePayload","payload","Object","assign","boxesByIndex","box","push","pageIndexString","parseFloat","_models","book","getPage","getActivePageContainerElementsForIndex","container","getActivePageContainerElements","onNearbyPage","Math","abs","makeUnviewableAtEnd","isViewable","fetch","URLSearchParams","id","subprefix","leafNum","then","r","json","resp","makeViewable","jumpToIndex","poll","until","result","$boxes","scrollIntoView","block","isFullscreenActive","inline","behavior","Promise","resolve","removeAttr","searchHighlightVisible","visiblePages","twoPage","currentIndexL","currentIndexR","some","inArray","global","fails","uncurryThis","toString","trim","whitespaces","charAt","n$ParseFloat","Symbol","ITERATOR","iterator","FORCED","module","exports","string","trimmedString","$entries","stat","O","$parseFloat","forced"],"sourceRoot":""}
|
@@ -114,23 +114,19 @@ const fetchBookManifestAndInitializeBookreader = async (iaMetadata) => {
|
|
114
114
|
document.querySelector('input[name="itemMD"]').checked = true;
|
115
115
|
iaBookReader.item = iaMetadata;
|
116
116
|
|
117
|
-
const
|
118
|
-
|
119
|
-
|
120
|
-
|
121
|
-
|
122
|
-
|
123
|
-
|
124
|
-
|
125
|
-
|
126
|
-
|
127
|
-
|
128
|
-
|
129
|
-
|
130
|
-
new URLSearchParams(jsiaParams)
|
131
|
-
}`;
|
132
|
-
|
133
|
-
const manifest = await fetch(iaManifestUrl).then(response => response.json());
|
117
|
+
const {
|
118
|
+
metadata: {
|
119
|
+
identifier
|
120
|
+
},
|
121
|
+
} = iaMetadata;
|
122
|
+
|
123
|
+
const locator = `https://archive.org/bookreader/BookReaderJSLocate.php?format=json&subPrefix=&id=${identifier}`;
|
124
|
+
// Todo: move from `locator` to create `iaManifestUrl` url from `iaMetadata`
|
125
|
+
// so we can support multiple volumes
|
126
|
+
// const iaManifestUrl = `https://${server}/BookReader/BookReaderJSIA.php?format=jsonp&itemPath=${dir}&id=${identifier}`;
|
127
|
+
|
128
|
+
const manifest = await fetch(locator)
|
129
|
+
.then(response => response.json());
|
134
130
|
document.querySelector('input[name="bookManifest"]').checked = true;
|
135
131
|
|
136
132
|
initializeBookReader(manifest);
|
@@ -9,7 +9,7 @@
|
|
9
9
|
<link rel="stylesheet" href="../BookReader/BookReader.css"/>
|
10
10
|
|
11
11
|
<script src="../BookReader/webcomponents-bundle.js"></script>
|
12
|
-
<script src="../BookReader/jquery-
|
12
|
+
<script src="../BookReader/jquery-1.10.1.js"></script>
|
13
13
|
|
14
14
|
|
15
15
|
<script src="../BookReader/BookReader.js"></script>
|
@@ -8,7 +8,7 @@
|
|
8
8
|
|
9
9
|
<!-- JS dependencies -->
|
10
10
|
<script src="../BookReader/webcomponents-bundle.js"></script>
|
11
|
-
<script src="../BookReader/jquery-
|
11
|
+
<script src="../BookReader/jquery-1.10.1.js"></script>
|
12
12
|
|
13
13
|
<!-- BookReader and plugins -->
|
14
14
|
<link rel="stylesheet" href="../BookReader/BookReader.css"/>
|
package/CHANGELOG.md
CHANGED
@@ -1,15 +1,3 @@
|
|
1
|
-
# 5.0.0-47
|
2
|
-
- Fix: XSS vulnerability in search results @latonv
|
3
|
-
- Dev: Update jQuery to v3 **BREAKING** @cdrini
|
4
|
-
- If you were importing `BookReader/jquery-1.10.1.js` you will need to change it to `BookReader/jquery-3.js`
|
5
|
-
- Also ensure if other code was using this jquery that it works with jQuery 3!
|
6
|
-
- Dev: Update testing dependencies (jest, testcafe) @renovate
|
7
|
-
|
8
|
-
# 5.0.0-46
|
9
|
-
Fix: Leaf positioning during RTL fliip animation @latonv
|
10
|
-
Dev: dependency updates @renovate
|
11
|
-
Fix: Disable contextmenu for restricted books @iisa
|
12
|
-
|
13
1
|
# 5.0.0-45
|
14
2
|
# 5.0.0-44
|
15
3
|
Fix: dynamic `q=<term>` url parameter @iisa
|
package/package.json
CHANGED
@@ -1,6 +1,6 @@
|
|
1
1
|
{
|
2
2
|
"name": "@internetarchive/bookreader",
|
3
|
-
"version": "5.0.0-46-
|
3
|
+
"version": "5.0.0-46-no-right-click-2",
|
4
4
|
"description": "The Internet Archive BookReader.",
|
5
5
|
"repository": {
|
6
6
|
"type": "git",
|
@@ -47,11 +47,11 @@
|
|
47
47
|
"@babel/plugin-proposal-decorators": "7.17.9",
|
48
48
|
"@babel/preset-env": "7.16.11",
|
49
49
|
"@open-wc/testing-helpers": "^2.1.3",
|
50
|
-
"@types/jest": "^
|
50
|
+
"@types/jest": "^27.5.1",
|
51
51
|
"@webcomponents/webcomponentsjs": "^2.6.0",
|
52
52
|
"babel-loader": "8.2.5",
|
53
53
|
"codecov": "^3.8.3",
|
54
|
-
"concurrently": "7.
|
54
|
+
"concurrently": "7.2.2",
|
55
55
|
"core-js": "3.22.3",
|
56
56
|
"cpx2": "4.2.0",
|
57
57
|
"eslint": "^7.32.0",
|
@@ -60,9 +60,9 @@
|
|
60
60
|
"hammerjs": "^2.0.8",
|
61
61
|
"http-server": "14.1.1",
|
62
62
|
"iso-language-codes": "1.1.0",
|
63
|
-
"jest": "^
|
64
|
-
"jest-environment-jsdom": "^
|
65
|
-
"jquery": "
|
63
|
+
"jest": "^28.1.0",
|
64
|
+
"jest-environment-jsdom": "^28.1.0",
|
65
|
+
"jquery": "1.12.4",
|
66
66
|
"jquery-colorbox": "1.6.4",
|
67
67
|
"jquery-ui": "1.12.1",
|
68
68
|
"jquery-ui-touch-punch": "0.2.3",
|
@@ -75,7 +75,7 @@
|
|
75
75
|
"sinon": "^14.0.0",
|
76
76
|
"soundmanager2": "2.97.20170602",
|
77
77
|
"svgo": "2.8.0",
|
78
|
-
"testcafe": "^
|
78
|
+
"testcafe": "^1.19.0",
|
79
79
|
"testcafe-browser-provider-browserstack": "^1.13.2-alpha.1",
|
80
80
|
"webpack": "5.51.1",
|
81
81
|
"webpack-cli": "4.9.2"
|
@@ -137,8 +137,7 @@ class IABookmarks extends LitElement {
|
|
137
137
|
}
|
138
138
|
|
139
139
|
setup() {
|
140
|
-
|
141
|
-
this.api.identifier = this.getIdentifier();
|
140
|
+
this.api.identifier = this.bookreader.bookId;
|
142
141
|
if (this.displayMode === 'login') {
|
143
142
|
return;
|
144
143
|
}
|
@@ -146,19 +145,6 @@ class IABookmarks extends LitElement {
|
|
146
145
|
this.setBREventListeners();
|
147
146
|
}
|
148
147
|
|
149
|
-
/**
|
150
|
-
* get identifier for current book including sub-files
|
151
|
-
*
|
152
|
-
* @returns Identifer
|
153
|
-
*/
|
154
|
-
getIdentifier() {
|
155
|
-
if (this.bookreader.bookId !== this.bookreader.subPrefix) {
|
156
|
-
return `${this.bookreader.bookId}/${this.bookreader.subPrefix}`;
|
157
|
-
}
|
158
|
-
|
159
|
-
return this.bookreader.bookId;
|
160
|
-
}
|
161
|
-
|
162
148
|
updateDisplay() {
|
163
149
|
if (this.displayMode === 'bookmarks') {
|
164
150
|
this.fetchUserBookmarks();
|
@@ -1,4 +1,3 @@
|
|
1
|
-
import { escapeHTML } from '../../BookReader/utils.js';
|
2
1
|
import { html, LitElement, nothing } from 'lit';
|
3
2
|
import { unsafeHTML } from 'lit/directives/unsafe-html.js';
|
4
3
|
/** @typedef {import('@/src/plugins/search/plugin.search.js').SearchInsideMatch} SearchInsideMatch */
|
@@ -13,24 +12,17 @@ export class BookSearchResult extends LitElement {
|
|
13
12
|
constructor() {
|
14
13
|
super();
|
15
14
|
|
16
|
-
this.matchRegex = new RegExp('{{{(.+?)}}}', '
|
15
|
+
this.matchRegex = new RegExp('{{{(.+?)}}}', 'g');
|
17
16
|
}
|
18
17
|
|
19
18
|
createRenderRoot() {
|
20
19
|
return this;
|
21
20
|
}
|
22
21
|
|
23
|
-
/**
|
24
|
-
* Converts the search hit to a `<p>` template containing the full search result with all of
|
25
|
-
* its `{{{triple-brace-delimited}}}` matches replaced by `<mark>HTML mark tags</mark>`.
|
26
|
-
*
|
27
|
-
* This approach safely avoids the use of `unsafeHTML` and leaves any existing HTML tags
|
28
|
-
* in the snippets intact (as inert text), rather than stripping them away with DOMPurify.
|
29
|
-
*/
|
30
22
|
highlightedHit(hit) {
|
31
|
-
return html
|
32
|
-
|
33
|
-
|
23
|
+
return html`
|
24
|
+
<p>${unsafeHTML(hit.replace(this.matchRegex, '<mark>$1</mark>'))}</p>
|
25
|
+
`;
|
34
26
|
}
|
35
27
|
|
36
28
|
resultSelected() {
|