From 9a95d91b923a0622ec9ab3a6bcd58021e6922f42 Mon Sep 17 00:00:00 2001 From: Tim van der Meij Date: Sun, 4 Jun 2017 20:35:21 +0200 Subject: [PATCH] Convert the find controller to ES6 syntax Moreover, rename `FindStates` to `FindState` since enumeration names are usually not in plural, for readability and consistency with the ones in `src/shared/util.js`. --- web/pdf_find_bar.js | 10 +- web/pdf_find_controller.js | 794 ++++++++++++++++++------------------- 2 files changed, 400 insertions(+), 404 deletions(-) diff --git a/web/pdf_find_bar.js b/web/pdf_find_bar.js index c9908b807..34310b6a3 100644 --- a/web/pdf_find_bar.js +++ b/web/pdf_find_bar.js @@ -13,7 +13,7 @@ * limitations under the License. */ -import { FindStates } from './pdf_find_controller'; +import { FindState } from './pdf_find_controller'; import { NullL10n } from './ui_utils'; /** @@ -108,19 +108,19 @@ class PDFFindBar { var status = ''; switch (state) { - case FindStates.FIND_FOUND: + case FindState.FOUND: break; - case FindStates.FIND_PENDING: + case FindState.PENDING: status = 'pending'; break; - case FindStates.FIND_NOTFOUND: + case FindState.NOT_FOUND: findMsg = this.l10n.get('find_not_found', null, 'Phrase not found'); notFound = true; break; - case FindStates.FIND_WRAPPED: + case FindState.WRAPPED: if (previous) { findMsg = this.l10n.get('find_reached_top', null, 'Reached top of document, continued from bottom'); diff --git a/web/pdf_find_controller.js b/web/pdf_find_controller.js index 35da708ba..3ae4424bb 100644 --- a/web/pdf_find_controller.js +++ b/web/pdf_find_controller.js @@ -16,17 +16,18 @@ import { createPromiseCapability } from 'pdfjs-lib'; import { scrollIntoView } from './ui_utils'; -var FindStates = { - FIND_FOUND: 0, - FIND_NOTFOUND: 1, - FIND_WRAPPED: 2, - FIND_PENDING: 3, +const FindState = { + FOUND: 0, + NOT_FOUND: 1, + WRAPPED: 2, + PENDING: 3, }; -var FIND_SCROLL_OFFSET_TOP = -50; -var FIND_SCROLL_OFFSET_LEFT = -400; +const FIND_SCROLL_OFFSET_TOP = -50; +const FIND_SCROLL_OFFSET_LEFT = -400; +const FIND_TIMEOUT = 250; // ms -var CHARACTERS_TO_NORMALIZE = { +const CHARACTERS_TO_NORMALIZE = { '\u2018': '\'', // Left single quotation mark '\u2019': '\'', // Right single quotation mark '\u201A': '\'', // Single low-9 quotation mark @@ -41,12 +42,11 @@ var CHARACTERS_TO_NORMALIZE = { }; /** - * Provides "search" or "find" functionality for the PDF. - * This object actually performs the search for a given string. + * Provides search functionality to find a given string in a PDF document. */ -var PDFFindController = (function PDFFindControllerClosure() { - function PDFFindController(options) { - this.pdfViewer = options.pdfViewer || null; +class PDFFindController { + constructor({ pdfViewer, }) { + this.pdfViewer = pdfViewer; this.onUpdateResultsCount = null; this.onUpdateState = null; @@ -54,434 +54,430 @@ var PDFFindController = (function PDFFindControllerClosure() { this.reset(); // Compile the regular expression for text normalization once. - var replace = Object.keys(CHARACTERS_TO_NORMALIZE).join(''); + let replace = Object.keys(CHARACTERS_TO_NORMALIZE).join(''); this.normalizationRegex = new RegExp('[' + replace + ']', 'g'); } - PDFFindController.prototype = { - reset: function PDFFindController_reset() { - this.startedTextExtraction = false; - this.extractTextPromises = []; - this.pendingFindMatches = Object.create(null); - this.active = false; // If active, find results will be highlighted. - this.pageContents = []; // Stores the text for each page. - this.pageMatches = []; - this.pageMatchesLength = null; - this.matchCount = 0; - this.selected = { // Currently selected match. - pageIdx: -1, - matchIdx: -1, - }; - this.offset = { // Where the find algorithm currently is in the document. - pageIdx: null, - matchIdx: null, - }; - this.pagesToSearch = null; - this.resumePageIdx = null; - this.state = null; - this.dirtyMatch = false; - this.findTimeout = null; + reset() { + this.startedTextExtraction = false; + this.extractTextPromises = []; + this.pendingFindMatches = Object.create(null); + this.active = false; // If active, find results will be highlighted. + this.pageContents = []; // Stores the text for each page. + this.pageMatches = []; + this.pageMatchesLength = null; + this.matchCount = 0; + this.selected = { // Currently selected match. + pageIdx: -1, + matchIdx: -1, + }; + this.offset = { // Where the find algorithm currently is in the document. + pageIdx: null, + matchIdx: null, + }; + this.pagesToSearch = null; + this.resumePageIdx = null; + this.state = null; + this.dirtyMatch = false; + this.findTimeout = null; - this._firstPagePromise = new Promise((resolve) => { - this.resolveFirstPage = resolve; - }); - }, + this._firstPagePromise = new Promise((resolve) => { + this.resolveFirstPage = resolve; + }); + } - normalize: function PDFFindController_normalize(text) { - return text.replace(this.normalizationRegex, function (ch) { - return CHARACTERS_TO_NORMALIZE[ch]; - }); - }, + normalize(text) { + return text.replace(this.normalizationRegex, function (ch) { + return CHARACTERS_TO_NORMALIZE[ch]; + }); + } - // Helper for multiple search - fills matchesWithLength array - // and takes into account cases when one search term - // include another search term (for example, "tamed tame" or "this is"). - // Looking for intersecting terms in the 'matches' and - // leave elements with a longer match-length. + /** + * Helper for multi-term search that fills the `matchesWithLength` array + * and handles cases where one search term includes another search term (for + * example, "tamed tame" or "this is"). It looks for intersecting terms in + * the `matches` and keeps elements with a longer match length. + */ + _prepareMatches(matchesWithLength, matches, matchesLength) { + function isSubTerm(matchesWithLength, currentIndex) { + let currentElem = matchesWithLength[currentIndex]; + let nextElem = matchesWithLength[currentIndex + 1]; - _prepareMatches: function PDFFindController_prepareMatches( - matchesWithLength, matches, matchesLength) { + // Check for cases like "TAMEd TAME". + if (currentIndex < matchesWithLength.length - 1 && + currentElem.match === nextElem.match) { + currentElem.skipped = true; + return true; + } - function isSubTerm(matchesWithLength, currentIndex) { - var currentElem, prevElem, nextElem; - currentElem = matchesWithLength[currentIndex]; - nextElem = matchesWithLength[currentIndex + 1]; - // checking for cases like "TAMEd TAME" - if (currentIndex < matchesWithLength.length - 1 && - currentElem.match === nextElem.match) { + // Check for cases like "thIS IS". + for (let i = currentIndex - 1; i >= 0; i--) { + let prevElem = matchesWithLength[i]; + if (prevElem.skipped) { + continue; + } + if (prevElem.match + prevElem.matchLength < currentElem.match) { + break; + } + if (prevElem.match + prevElem.matchLength >= + currentElem.match + currentElem.matchLength) { currentElem.skipped = true; return true; } - // checking for cases like "thIS IS" - for (var i = currentIndex - 1; i >= 0; i--) { - prevElem = matchesWithLength[i]; - if (prevElem.skipped) { - continue; - } - if (prevElem.match + prevElem.matchLength < currentElem.match) { - break; - } - if (prevElem.match + prevElem.matchLength >= - currentElem.match + currentElem.matchLength) { - currentElem.skipped = true; - return true; - } - } - return false; } + return false; + } - var i, len; - // Sorting array of objects { match: , matchLength: } - // in increasing index first and then the lengths. - matchesWithLength.sort(function(a, b) { - return a.match === b.match ? - a.matchLength - b.matchLength : a.match - b.match; - }); - for (i = 0, len = matchesWithLength.length; i < len; i++) { - if (isSubTerm(matchesWithLength, i)) { - continue; - } - matches.push(matchesWithLength[i].match); - matchesLength.push(matchesWithLength[i].matchLength); + // Sort the array of `{ match: , matchLength: }` + // objects on increasing index first and on the length otherwise. + matchesWithLength.sort(function(a, b) { + return a.match === b.match ? a.matchLength - b.matchLength : + a.match - b.match; + }); + for (let i = 0, len = matchesWithLength.length; i < len; i++) { + if (isSubTerm(matchesWithLength, i)) { + continue; } - }, + matches.push(matchesWithLength[i].match); + matchesLength.push(matchesWithLength[i].matchLength); + } + } - calcFindPhraseMatch: function PDFFindController_calcFindPhraseMatch( - query, pageIndex, pageContent) { - var matches = []; - var queryLen = query.length; - var matchIdx = -queryLen; + calcFindPhraseMatch(query, pageIndex, pageContent) { + let matches = []; + let queryLen = query.length; + let matchIdx = -queryLen; + while (true) { + matchIdx = pageContent.indexOf(query, matchIdx + queryLen); + if (matchIdx === -1) { + break; + } + matches.push(matchIdx); + } + this.pageMatches[pageIndex] = matches; + } + + calcFindWordMatch(query, pageIndex, pageContent) { + let matchesWithLength = []; + // Divide the query into pieces and search for text in each piece. + let queryArray = query.match(/\S+/g); + for (let i = 0, len = queryArray.length; i < len; i++) { + let subquery = queryArray[i]; + let subqueryLen = subquery.length; + let matchIdx = -subqueryLen; while (true) { - matchIdx = pageContent.indexOf(query, matchIdx + queryLen); + matchIdx = pageContent.indexOf(subquery, matchIdx + subqueryLen); if (matchIdx === -1) { break; } - matches.push(matchIdx); - } - this.pageMatches[pageIndex] = matches; - }, - - calcFindWordMatch: function PDFFindController_calcFindWordMatch( - query, pageIndex, pageContent) { - var matchesWithLength = []; - // Divide the query into pieces and search for text on each piece. - var queryArray = query.match(/\S+/g); - var subquery, subqueryLen, matchIdx; - for (var i = 0, len = queryArray.length; i < len; i++) { - subquery = queryArray[i]; - subqueryLen = subquery.length; - matchIdx = -subqueryLen; - while (true) { - matchIdx = pageContent.indexOf(subquery, matchIdx + subqueryLen); - if (matchIdx === -1) { - break; - } - // Other searches do not, so we store the length. - matchesWithLength.push({ - match: matchIdx, - matchLength: subqueryLen, - skipped: false, - }); - } - } - // Prepare arrays for store the matches. - if (!this.pageMatchesLength) { - this.pageMatchesLength = []; - } - this.pageMatchesLength[pageIndex] = []; - this.pageMatches[pageIndex] = []; - // Sort matchesWithLength, clean up intersecting terms - // and put the result into the two arrays. - this._prepareMatches(matchesWithLength, this.pageMatches[pageIndex], - this.pageMatchesLength[pageIndex]); - }, - - calcFindMatch: function PDFFindController_calcFindMatch(pageIndex) { - var pageContent = this.normalize(this.pageContents[pageIndex]); - var query = this.normalize(this.state.query); - var caseSensitive = this.state.caseSensitive; - var phraseSearch = this.state.phraseSearch; - var queryLen = query.length; - - if (queryLen === 0) { - // Do nothing: the matches should be wiped out already. - return; - } - - if (!caseSensitive) { - pageContent = pageContent.toLowerCase(); - query = query.toLowerCase(); - } - - if (phraseSearch) { - this.calcFindPhraseMatch(query, pageIndex, pageContent); - } else { - this.calcFindWordMatch(query, pageIndex, pageContent); - } - - this.updatePage(pageIndex); - if (this.resumePageIdx === pageIndex) { - this.resumePageIdx = null; - this.nextPageMatch(); - } - - // Update the matches count - if (this.pageMatches[pageIndex].length > 0) { - this.matchCount += this.pageMatches[pageIndex].length; - this.updateUIResultsCount(); - } - }, - - extractText() { - if (this.startedTextExtraction) { - return; - } - this.startedTextExtraction = true; - this.pageContents.length = 0; - - let promise = Promise.resolve(); - for (let i = 0, ii = this.pdfViewer.pagesCount; i < ii; i++) { - let extractTextCapability = createPromiseCapability(); - this.extractTextPromises[i] = extractTextCapability.promise; - - promise = promise.then(() => { - return this.pdfViewer.getPageTextContent(i).then((textContent) => { - let textItems = textContent.items; - let strBuf = []; - - for (let j = 0, jj = textItems.length; j < jj; j++) { - strBuf.push(textItems[j].str); - } - // Store the pageContent as a string. - this.pageContents[i] = strBuf.join(''); - extractTextCapability.resolve(i); - }); + // Other searches do not, so we store the length. + matchesWithLength.push({ + match: matchIdx, + matchLength: subqueryLen, + skipped: false, }); } - }, + } - executeCommand: function PDFFindController_executeCommand(cmd, state) { - if (this.state === null || cmd !== 'findagain') { - this.dirtyMatch = true; - } - this.state = state; - this.updateUIState(FindStates.FIND_PENDING); + // Prepare arrays for storing the matches. + if (!this.pageMatchesLength) { + this.pageMatchesLength = []; + } + this.pageMatchesLength[pageIndex] = []; + this.pageMatches[pageIndex] = []; - this._firstPagePromise.then(() => { - this.extractText(); + // Sort `matchesWithLength`, remove intersecting terms and put the result + // into the two arrays. + this._prepareMatches(matchesWithLength, this.pageMatches[pageIndex], + this.pageMatchesLength[pageIndex]); + } - clearTimeout(this.findTimeout); - if (cmd === 'find') { - // Only trigger the find action after 250ms of silence. - this.findTimeout = setTimeout(this.nextMatch.bind(this), 250); - } else { - this.nextMatch(); - } - }); - }, + calcFindMatch(pageIndex) { + let pageContent = this.normalize(this.pageContents[pageIndex]); + let query = this.normalize(this.state.query); + let caseSensitive = this.state.caseSensitive; + let phraseSearch = this.state.phraseSearch; + let queryLen = query.length; - updatePage: function PDFFindController_updatePage(index) { - if (this.selected.pageIdx === index) { - // If the page is selected, scroll the page into view, which triggers - // rendering the page, which adds the textLayer. Once the textLayer is - // build, it will scroll onto the selected match. - this.pdfViewer.currentPageNumber = index + 1; - } + if (queryLen === 0) { + // Do nothing: the matches should be wiped out already. + return; + } - var page = this.pdfViewer.getPageView(index); - if (page.textLayer) { - page.textLayer.updateMatches(); - } - }, + if (!caseSensitive) { + pageContent = pageContent.toLowerCase(); + query = query.toLowerCase(); + } - nextMatch: function PDFFindController_nextMatch() { - var previous = this.state.findPrevious; - var currentPageIndex = this.pdfViewer.currentPageNumber - 1; - var numPages = this.pdfViewer.pagesCount; + if (phraseSearch) { + this.calcFindPhraseMatch(query, pageIndex, pageContent); + } else { + this.calcFindWordMatch(query, pageIndex, pageContent); + } - this.active = true; - - if (this.dirtyMatch) { - // Need to recalculate the matches, reset everything. - this.dirtyMatch = false; - this.selected.pageIdx = this.selected.matchIdx = -1; - this.offset.pageIdx = currentPageIndex; - this.offset.matchIdx = null; - this.hadMatch = false; - this.resumePageIdx = null; - this.pageMatches = []; - this.matchCount = 0; - this.pageMatchesLength = null; - - for (let i = 0; i < numPages; i++) { - // Wipe out any previous highlighted matches. - this.updatePage(i); - - // As soon as the text is extracted start finding the matches. - if (!(i in this.pendingFindMatches)) { - this.pendingFindMatches[i] = true; - this.extractTextPromises[i].then((pageIdx) => { - delete this.pendingFindMatches[pageIdx]; - this.calcFindMatch(pageIdx); - }); - } - } - } - - // If there's no query there's no point in searching. - if (this.state.query === '') { - this.updateUIState(FindStates.FIND_FOUND); - return; - } - - // If we're waiting on a page, we return since we can't do anything else. - if (this.resumePageIdx) { - return; - } - - var offset = this.offset; - // Keep track of how many pages we should maximally iterate through. - this.pagesToSearch = numPages; - // If there's already a matchIdx that means we are iterating through a - // page's matches. - if (offset.matchIdx !== null) { - var numPageMatches = this.pageMatches[offset.pageIdx].length; - if ((!previous && offset.matchIdx + 1 < numPageMatches) || - (previous && offset.matchIdx > 0)) { - // The simple case; we just have advance the matchIdx to select - // the next match on the page. - this.hadMatch = true; - offset.matchIdx = (previous ? offset.matchIdx - 1 : - offset.matchIdx + 1); - this.updateMatch(true); - return; - } - // We went beyond the current page's matches, so we advance to - // the next page. - this.advanceOffsetPage(previous); - } - // Start searching through the page. + this.updatePage(pageIndex); + if (this.resumePageIdx === pageIndex) { + this.resumePageIdx = null; this.nextPageMatch(); - }, + } - matchesReady: function PDFFindController_matchesReady(matches) { - var offset = this.offset; - var numMatches = matches.length; - var previous = this.state.findPrevious; + // Update the match count. + if (this.pageMatches[pageIndex].length > 0) { + this.matchCount += this.pageMatches[pageIndex].length; + this.updateUIResultsCount(); + } + } - if (numMatches) { - // There were matches for the page, so initialize the matchIdx. + extractText() { + if (this.startedTextExtraction) { + return; + } + this.startedTextExtraction = true; + this.pageContents.length = 0; + + let promise = Promise.resolve(); + for (let i = 0, ii = this.pdfViewer.pagesCount; i < ii; i++) { + let extractTextCapability = createPromiseCapability(); + this.extractTextPromises[i] = extractTextCapability.promise; + + promise = promise.then(() => { + return this.pdfViewer.getPageTextContent(i).then((textContent) => { + let textItems = textContent.items; + let strBuf = []; + + for (let j = 0, jj = textItems.length; j < jj; j++) { + strBuf.push(textItems[j].str); + } + // Store the pageContent as a string. + this.pageContents[i] = strBuf.join(''); + extractTextCapability.resolve(i); + }); + }); + } + } + + executeCommand(cmd, state) { + if (this.state === null || cmd !== 'findagain') { + this.dirtyMatch = true; + } + this.state = state; + this.updateUIState(FindState.PENDING); + + this._firstPagePromise.then(() => { + this.extractText(); + + clearTimeout(this.findTimeout); + if (cmd === 'find') { + // Trigger the find action with a small delay to avoid starting the + // search when the user is still typing (saving resources). + this.findTimeout = setTimeout(this.nextMatch.bind(this), FIND_TIMEOUT); + } else { + this.nextMatch(); + } + }); + } + + updatePage(index) { + if (this.selected.pageIdx === index) { + // If the page is selected, scroll the page into view, which triggers + // rendering the page, which adds the textLayer. Once the textLayer is + // build, it will scroll onto the selected match. + this.pdfViewer.currentPageNumber = index + 1; + } + + let page = this.pdfViewer.getPageView(index); + if (page.textLayer) { + page.textLayer.updateMatches(); + } + } + + nextMatch() { + let previous = this.state.findPrevious; + let currentPageIndex = this.pdfViewer.currentPageNumber - 1; + let numPages = this.pdfViewer.pagesCount; + + this.active = true; + + if (this.dirtyMatch) { + // Need to recalculate the matches, reset everything. + this.dirtyMatch = false; + this.selected.pageIdx = this.selected.matchIdx = -1; + this.offset.pageIdx = currentPageIndex; + this.offset.matchIdx = null; + this.hadMatch = false; + this.resumePageIdx = null; + this.pageMatches = []; + this.matchCount = 0; + this.pageMatchesLength = null; + + for (let i = 0; i < numPages; i++) { + // Wipe out any previously highlighted matches. + this.updatePage(i); + + // Start finding the matches as soon as the text is extracted. + if (!(i in this.pendingFindMatches)) { + this.pendingFindMatches[i] = true; + this.extractTextPromises[i].then((pageIdx) => { + delete this.pendingFindMatches[pageIdx]; + this.calcFindMatch(pageIdx); + }); + } + } + } + + // If there's no query there's no point in searching. + if (this.state.query === '') { + this.updateUIState(FindState.FOUND); + return; + } + + // If we're waiting on a page, we return since we can't do anything else. + if (this.resumePageIdx) { + return; + } + + let offset = this.offset; + // Keep track of how many pages we should maximally iterate through. + this.pagesToSearch = numPages; + // If there's already a `matchIdx` that means we are iterating through a + // page's matches. + if (offset.matchIdx !== null) { + let numPageMatches = this.pageMatches[offset.pageIdx].length; + if ((!previous && offset.matchIdx + 1 < numPageMatches) || + (previous && offset.matchIdx > 0)) { + // The simple case; we just have advance the matchIdx to select + // the next match on the page. this.hadMatch = true; - offset.matchIdx = (previous ? numMatches - 1 : 0); + offset.matchIdx = (previous ? offset.matchIdx - 1 : + offset.matchIdx + 1); this.updateMatch(true); + return; + } + // We went beyond the current page's matches, so we advance to + // the next page. + this.advanceOffsetPage(previous); + } + // Start searching through the page. + this.nextPageMatch(); + } + + matchesReady(matches) { + let offset = this.offset; + let numMatches = matches.length; + let previous = this.state.findPrevious; + + if (numMatches) { + // There were matches for the page, so initialize `matchIdx`. + this.hadMatch = true; + offset.matchIdx = (previous ? numMatches - 1 : 0); + this.updateMatch(true); + return true; + } + // No matches, so attempt to search the next page. + this.advanceOffsetPage(previous); + if (offset.wrapped) { + offset.matchIdx = null; + if (this.pagesToSearch < 0) { + // No point in wrapping again, there were no matches. + this.updateMatch(false); + // While matches were not found, searching for a page + // with matches should nevertheless halt. return true; } - // No matches, so attempt to search the next page. - this.advanceOffsetPage(previous); - if (offset.wrapped) { - offset.matchIdx = null; - if (this.pagesToSearch < 0) { - // No point in wrapping again, there were no matches. - this.updateMatch(false); - // while matches were not found, searching for a page - // with matches should nevertheless halt. - return true; - } + } + // Matches were not found (and searching is not done). + return false; + } + + /** + * Called from the text layer when match presentation is updated. + * + * @param {number} pageIndex - The index of the page. + * @param {number} matchIndex - The index of the match. + * @param {Array} elements - Text layer `div` elements. + * @param {number} beginIdx - Start index of the `div` array for the match. + */ + updateMatchPosition(pageIndex, matchIndex, elements, beginIdx) { + if (this.selected.matchIdx === matchIndex && + this.selected.pageIdx === pageIndex) { + let spot = { + top: FIND_SCROLL_OFFSET_TOP, + left: FIND_SCROLL_OFFSET_LEFT, + }; + scrollIntoView(elements[beginIdx], spot, + /* skipOverflowHiddenElements = */ true); + } + } + + nextPageMatch() { + if (this.resumePageIdx !== null) { + console.error('There can only be one pending page.'); + } + + let matches = null; + do { + let pageIdx = this.offset.pageIdx; + matches = this.pageMatches[pageIdx]; + if (!matches) { + // The matches don't exist yet for processing by `matchesReady`, + // so set a resume point for when they do exist. + this.resumePageIdx = pageIdx; + break; } - // Matches were not found (and searching is not done). - return false; - }, + } while (!this.matchesReady(matches)); + } - /** - * The method is called back from the text layer when match presentation - * is updated. - * @param {number} pageIndex - page index. - * @param {number} index - match index. - * @param {Array} elements - text layer div elements array. - * @param {number} beginIdx - start index of the div array for the match. - */ - updateMatchPosition: function PDFFindController_updateMatchPosition( - pageIndex, index, elements, beginIdx) { - if (this.selected.matchIdx === index && - this.selected.pageIdx === pageIndex) { - var spot = { - top: FIND_SCROLL_OFFSET_TOP, - left: FIND_SCROLL_OFFSET_LEFT, - }; - scrollIntoView(elements[beginIdx], spot, - /* skipOverflowHiddenElements = */ true); + advanceOffsetPage(previous) { + let offset = this.offset; + let numPages = this.extractTextPromises.length; + offset.pageIdx = (previous ? offset.pageIdx - 1 : offset.pageIdx + 1); + offset.matchIdx = null; + + this.pagesToSearch--; + + if (offset.pageIdx >= numPages || offset.pageIdx < 0) { + offset.pageIdx = (previous ? numPages - 1 : 0); + offset.wrapped = true; + } + } + + updateMatch(found = false) { + let state = FindState.NOT_FOUND; + let wrapped = this.offset.wrapped; + this.offset.wrapped = false; + + if (found) { + let previousPage = this.selected.pageIdx; + this.selected.pageIdx = this.offset.pageIdx; + this.selected.matchIdx = this.offset.matchIdx; + state = (wrapped ? FindState.WRAPPED : FindState.FOUND); + + // Update the currently selected page to wipe out any selected matches. + if (previousPage !== -1 && previousPage !== this.selected.pageIdx) { + this.updatePage(previousPage); } - }, + } - nextPageMatch: function PDFFindController_nextPageMatch() { - if (this.resumePageIdx !== null) { - console.error('There can only be one pending page.'); - } - do { - var pageIdx = this.offset.pageIdx; - var matches = this.pageMatches[pageIdx]; - if (!matches) { - // The matches don't exist yet for processing by "matchesReady", - // so set a resume point for when they do exist. - this.resumePageIdx = pageIdx; - break; - } - } while (!this.matchesReady(matches)); - }, + this.updateUIState(state, this.state.findPrevious); + if (this.selected.pageIdx !== -1) { + this.updatePage(this.selected.pageIdx); + } + } - advanceOffsetPage: function PDFFindController_advanceOffsetPage(previous) { - var offset = this.offset; - var numPages = this.extractTextPromises.length; - offset.pageIdx = (previous ? offset.pageIdx - 1 : offset.pageIdx + 1); - offset.matchIdx = null; + updateUIResultsCount() { + if (this.onUpdateResultsCount) { + this.onUpdateResultsCount(this.matchCount); + } + } - this.pagesToSearch--; - - if (offset.pageIdx >= numPages || offset.pageIdx < 0) { - offset.pageIdx = (previous ? numPages - 1 : 0); - offset.wrapped = true; - } - }, - - updateMatch: function PDFFindController_updateMatch(found) { - var state = FindStates.FIND_NOTFOUND; - var wrapped = this.offset.wrapped; - this.offset.wrapped = false; - - if (found) { - var previousPage = this.selected.pageIdx; - this.selected.pageIdx = this.offset.pageIdx; - this.selected.matchIdx = this.offset.matchIdx; - state = (wrapped ? FindStates.FIND_WRAPPED : FindStates.FIND_FOUND); - // Update the currently selected page to wipe out any selected matches. - if (previousPage !== -1 && previousPage !== this.selected.pageIdx) { - this.updatePage(previousPage); - } - } - - this.updateUIState(state, this.state.findPrevious); - if (this.selected.pageIdx !== -1) { - this.updatePage(this.selected.pageIdx); - } - }, - - updateUIResultsCount: - function PDFFindController_updateUIResultsCount() { - if (this.onUpdateResultsCount) { - this.onUpdateResultsCount(this.matchCount); - } - }, - - updateUIState: function PDFFindController_updateUIState(state, previous) { - if (this.onUpdateState) { - this.onUpdateState(state, previous, this.matchCount); - } - }, - }; - return PDFFindController; -})(); + updateUIState(state, previous) { + if (this.onUpdateState) { + this.onUpdateState(state, previous, this.matchCount); + } + } +} export { - FindStates, + FindState, PDFFindController, };