|
|
@ -16,17 +16,18 @@ |
|
|
|
import { createPromiseCapability } from 'pdfjs-lib'; |
|
|
|
import { createPromiseCapability } from 'pdfjs-lib'; |
|
|
|
import { scrollIntoView } from './ui_utils'; |
|
|
|
import { scrollIntoView } from './ui_utils'; |
|
|
|
|
|
|
|
|
|
|
|
var FindStates = { |
|
|
|
const FindState = { |
|
|
|
FIND_FOUND: 0, |
|
|
|
FOUND: 0, |
|
|
|
FIND_NOTFOUND: 1, |
|
|
|
NOT_FOUND: 1, |
|
|
|
FIND_WRAPPED: 2, |
|
|
|
WRAPPED: 2, |
|
|
|
FIND_PENDING: 3, |
|
|
|
PENDING: 3, |
|
|
|
}; |
|
|
|
}; |
|
|
|
|
|
|
|
|
|
|
|
var FIND_SCROLL_OFFSET_TOP = -50; |
|
|
|
const FIND_SCROLL_OFFSET_TOP = -50; |
|
|
|
var FIND_SCROLL_OFFSET_LEFT = -400; |
|
|
|
const FIND_SCROLL_OFFSET_LEFT = -400; |
|
|
|
|
|
|
|
const FIND_TIMEOUT = 250; // ms
|
|
|
|
|
|
|
|
|
|
|
|
var CHARACTERS_TO_NORMALIZE = { |
|
|
|
const CHARACTERS_TO_NORMALIZE = { |
|
|
|
'\u2018': '\'', // Left single quotation mark
|
|
|
|
'\u2018': '\'', // Left single quotation mark
|
|
|
|
'\u2019': '\'', // Right single quotation mark
|
|
|
|
'\u2019': '\'', // Right single quotation mark
|
|
|
|
'\u201A': '\'', // Single low-9 quotation mark
|
|
|
|
'\u201A': '\'', // Single low-9 quotation mark
|
|
|
@ -41,12 +42,11 @@ var CHARACTERS_TO_NORMALIZE = { |
|
|
|
}; |
|
|
|
}; |
|
|
|
|
|
|
|
|
|
|
|
/** |
|
|
|
/** |
|
|
|
* Provides "search" or "find" functionality for the PDF. |
|
|
|
* Provides search functionality to find a given string in a PDF document. |
|
|
|
* This object actually performs the search for a given string. |
|
|
|
|
|
|
|
*/ |
|
|
|
*/ |
|
|
|
var PDFFindController = (function PDFFindControllerClosure() { |
|
|
|
class PDFFindController { |
|
|
|
function PDFFindController(options) { |
|
|
|
constructor({ pdfViewer, }) { |
|
|
|
this.pdfViewer = options.pdfViewer || null; |
|
|
|
this.pdfViewer = pdfViewer; |
|
|
|
|
|
|
|
|
|
|
|
this.onUpdateResultsCount = null; |
|
|
|
this.onUpdateResultsCount = null; |
|
|
|
this.onUpdateState = null; |
|
|
|
this.onUpdateState = null; |
|
|
@ -54,12 +54,11 @@ var PDFFindController = (function PDFFindControllerClosure() { |
|
|
|
this.reset(); |
|
|
|
this.reset(); |
|
|
|
|
|
|
|
|
|
|
|
// Compile the regular expression for text normalization once.
|
|
|
|
// 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'); |
|
|
|
this.normalizationRegex = new RegExp('[' + replace + ']', 'g'); |
|
|
|
} |
|
|
|
} |
|
|
|
|
|
|
|
|
|
|
|
PDFFindController.prototype = { |
|
|
|
reset() { |
|
|
|
reset: function PDFFindController_reset() { |
|
|
|
|
|
|
|
this.startedTextExtraction = false; |
|
|
|
this.startedTextExtraction = false; |
|
|
|
this.extractTextPromises = []; |
|
|
|
this.extractTextPromises = []; |
|
|
|
this.pendingFindMatches = Object.create(null); |
|
|
|
this.pendingFindMatches = Object.create(null); |
|
|
@ -85,36 +84,35 @@ var PDFFindController = (function PDFFindControllerClosure() { |
|
|
|
this._firstPagePromise = new Promise((resolve) => { |
|
|
|
this._firstPagePromise = new Promise((resolve) => { |
|
|
|
this.resolveFirstPage = resolve; |
|
|
|
this.resolveFirstPage = resolve; |
|
|
|
}); |
|
|
|
}); |
|
|
|
}, |
|
|
|
} |
|
|
|
|
|
|
|
|
|
|
|
normalize: function PDFFindController_normalize(text) { |
|
|
|
normalize(text) { |
|
|
|
return text.replace(this.normalizationRegex, function (ch) { |
|
|
|
return text.replace(this.normalizationRegex, function (ch) { |
|
|
|
return CHARACTERS_TO_NORMALIZE[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.
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
_prepareMatches: function PDFFindController_prepareMatches( |
|
|
|
|
|
|
|
matchesWithLength, matches, matchesLength) { |
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
/** |
|
|
|
|
|
|
|
* 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) { |
|
|
|
function isSubTerm(matchesWithLength, currentIndex) { |
|
|
|
var currentElem, prevElem, nextElem; |
|
|
|
let currentElem = matchesWithLength[currentIndex]; |
|
|
|
currentElem = matchesWithLength[currentIndex]; |
|
|
|
let nextElem = matchesWithLength[currentIndex + 1]; |
|
|
|
nextElem = matchesWithLength[currentIndex + 1]; |
|
|
|
|
|
|
|
// checking for cases like "TAMEd TAME"
|
|
|
|
// Check for cases like "TAMEd TAME".
|
|
|
|
if (currentIndex < matchesWithLength.length - 1 && |
|
|
|
if (currentIndex < matchesWithLength.length - 1 && |
|
|
|
currentElem.match === nextElem.match) { |
|
|
|
currentElem.match === nextElem.match) { |
|
|
|
currentElem.skipped = true; |
|
|
|
currentElem.skipped = true; |
|
|
|
return true; |
|
|
|
return true; |
|
|
|
} |
|
|
|
} |
|
|
|
// checking for cases like "thIS IS"
|
|
|
|
|
|
|
|
for (var i = currentIndex - 1; i >= 0; i--) { |
|
|
|
// Check for cases like "thIS IS".
|
|
|
|
prevElem = matchesWithLength[i]; |
|
|
|
for (let i = currentIndex - 1; i >= 0; i--) { |
|
|
|
|
|
|
|
let prevElem = matchesWithLength[i]; |
|
|
|
if (prevElem.skipped) { |
|
|
|
if (prevElem.skipped) { |
|
|
|
continue; |
|
|
|
continue; |
|
|
|
} |
|
|
|
} |
|
|
@ -130,27 +128,25 @@ var PDFFindController = (function PDFFindControllerClosure() { |
|
|
|
return false; |
|
|
|
return false; |
|
|
|
} |
|
|
|
} |
|
|
|
|
|
|
|
|
|
|
|
var i, len; |
|
|
|
// Sort the array of `{ match: <match>, matchLength: <matchLength> }`
|
|
|
|
// Sorting array of objects { match: <match>, matchLength: <matchLength> }
|
|
|
|
// objects on increasing index first and on the length otherwise.
|
|
|
|
// in increasing index first and then the lengths.
|
|
|
|
|
|
|
|
matchesWithLength.sort(function(a, b) { |
|
|
|
matchesWithLength.sort(function(a, b) { |
|
|
|
return a.match === b.match ? |
|
|
|
return a.match === b.match ? a.matchLength - b.matchLength : |
|
|
|
a.matchLength - b.matchLength : a.match - b.match; |
|
|
|
a.match - b.match; |
|
|
|
}); |
|
|
|
}); |
|
|
|
for (i = 0, len = matchesWithLength.length; i < len; i++) { |
|
|
|
for (let i = 0, len = matchesWithLength.length; i < len; i++) { |
|
|
|
if (isSubTerm(matchesWithLength, i)) { |
|
|
|
if (isSubTerm(matchesWithLength, i)) { |
|
|
|
continue; |
|
|
|
continue; |
|
|
|
} |
|
|
|
} |
|
|
|
matches.push(matchesWithLength[i].match); |
|
|
|
matches.push(matchesWithLength[i].match); |
|
|
|
matchesLength.push(matchesWithLength[i].matchLength); |
|
|
|
matchesLength.push(matchesWithLength[i].matchLength); |
|
|
|
} |
|
|
|
} |
|
|
|
}, |
|
|
|
} |
|
|
|
|
|
|
|
|
|
|
|
calcFindPhraseMatch: function PDFFindController_calcFindPhraseMatch( |
|
|
|
calcFindPhraseMatch(query, pageIndex, pageContent) { |
|
|
|
query, pageIndex, pageContent) { |
|
|
|
let matches = []; |
|
|
|
var matches = []; |
|
|
|
let queryLen = query.length; |
|
|
|
var queryLen = query.length; |
|
|
|
let matchIdx = -queryLen; |
|
|
|
var matchIdx = -queryLen; |
|
|
|
|
|
|
|
while (true) { |
|
|
|
while (true) { |
|
|
|
matchIdx = pageContent.indexOf(query, matchIdx + queryLen); |
|
|
|
matchIdx = pageContent.indexOf(query, matchIdx + queryLen); |
|
|
|
if (matchIdx === -1) { |
|
|
|
if (matchIdx === -1) { |
|
|
@ -159,18 +155,16 @@ var PDFFindController = (function PDFFindControllerClosure() { |
|
|
|
matches.push(matchIdx); |
|
|
|
matches.push(matchIdx); |
|
|
|
} |
|
|
|
} |
|
|
|
this.pageMatches[pageIndex] = matches; |
|
|
|
this.pageMatches[pageIndex] = matches; |
|
|
|
}, |
|
|
|
} |
|
|
|
|
|
|
|
|
|
|
|
calcFindWordMatch: function PDFFindController_calcFindWordMatch( |
|
|
|
calcFindWordMatch(query, pageIndex, pageContent) { |
|
|
|
query, pageIndex, pageContent) { |
|
|
|
let matchesWithLength = []; |
|
|
|
var matchesWithLength = []; |
|
|
|
// Divide the query into pieces and search for text in each piece.
|
|
|
|
// Divide the query into pieces and search for text on each piece.
|
|
|
|
let queryArray = query.match(/\S+/g); |
|
|
|
var queryArray = query.match(/\S+/g); |
|
|
|
for (let i = 0, len = queryArray.length; i < len; i++) { |
|
|
|
var subquery, subqueryLen, matchIdx; |
|
|
|
let subquery = queryArray[i]; |
|
|
|
for (var i = 0, len = queryArray.length; i < len; i++) { |
|
|
|
let subqueryLen = subquery.length; |
|
|
|
subquery = queryArray[i]; |
|
|
|
let matchIdx = -subqueryLen; |
|
|
|
subqueryLen = subquery.length; |
|
|
|
|
|
|
|
matchIdx = -subqueryLen; |
|
|
|
|
|
|
|
while (true) { |
|
|
|
while (true) { |
|
|
|
matchIdx = pageContent.indexOf(subquery, matchIdx + subqueryLen); |
|
|
|
matchIdx = pageContent.indexOf(subquery, matchIdx + subqueryLen); |
|
|
|
if (matchIdx === -1) { |
|
|
|
if (matchIdx === -1) { |
|
|
@ -184,24 +178,26 @@ var PDFFindController = (function PDFFindControllerClosure() { |
|
|
|
}); |
|
|
|
}); |
|
|
|
} |
|
|
|
} |
|
|
|
} |
|
|
|
} |
|
|
|
// Prepare arrays for store the matches.
|
|
|
|
|
|
|
|
|
|
|
|
// Prepare arrays for storing the matches.
|
|
|
|
if (!this.pageMatchesLength) { |
|
|
|
if (!this.pageMatchesLength) { |
|
|
|
this.pageMatchesLength = []; |
|
|
|
this.pageMatchesLength = []; |
|
|
|
} |
|
|
|
} |
|
|
|
this.pageMatchesLength[pageIndex] = []; |
|
|
|
this.pageMatchesLength[pageIndex] = []; |
|
|
|
this.pageMatches[pageIndex] = []; |
|
|
|
this.pageMatches[pageIndex] = []; |
|
|
|
// Sort matchesWithLength, clean up intersecting terms
|
|
|
|
|
|
|
|
// and put the result into the two arrays.
|
|
|
|
// Sort `matchesWithLength`, remove intersecting terms and put the result
|
|
|
|
|
|
|
|
// into the two arrays.
|
|
|
|
this._prepareMatches(matchesWithLength, this.pageMatches[pageIndex], |
|
|
|
this._prepareMatches(matchesWithLength, this.pageMatches[pageIndex], |
|
|
|
this.pageMatchesLength[pageIndex]); |
|
|
|
this.pageMatchesLength[pageIndex]); |
|
|
|
}, |
|
|
|
} |
|
|
|
|
|
|
|
|
|
|
|
calcFindMatch: function PDFFindController_calcFindMatch(pageIndex) { |
|
|
|
calcFindMatch(pageIndex) { |
|
|
|
var pageContent = this.normalize(this.pageContents[pageIndex]); |
|
|
|
let pageContent = this.normalize(this.pageContents[pageIndex]); |
|
|
|
var query = this.normalize(this.state.query); |
|
|
|
let query = this.normalize(this.state.query); |
|
|
|
var caseSensitive = this.state.caseSensitive; |
|
|
|
let caseSensitive = this.state.caseSensitive; |
|
|
|
var phraseSearch = this.state.phraseSearch; |
|
|
|
let phraseSearch = this.state.phraseSearch; |
|
|
|
var queryLen = query.length; |
|
|
|
let queryLen = query.length; |
|
|
|
|
|
|
|
|
|
|
|
if (queryLen === 0) { |
|
|
|
if (queryLen === 0) { |
|
|
|
// Do nothing: the matches should be wiped out already.
|
|
|
|
// Do nothing: the matches should be wiped out already.
|
|
|
@ -225,12 +221,12 @@ var PDFFindController = (function PDFFindControllerClosure() { |
|
|
|
this.nextPageMatch(); |
|
|
|
this.nextPageMatch(); |
|
|
|
} |
|
|
|
} |
|
|
|
|
|
|
|
|
|
|
|
// Update the matches count
|
|
|
|
// Update the match count.
|
|
|
|
if (this.pageMatches[pageIndex].length > 0) { |
|
|
|
if (this.pageMatches[pageIndex].length > 0) { |
|
|
|
this.matchCount += this.pageMatches[pageIndex].length; |
|
|
|
this.matchCount += this.pageMatches[pageIndex].length; |
|
|
|
this.updateUIResultsCount(); |
|
|
|
this.updateUIResultsCount(); |
|
|
|
} |
|
|
|
} |
|
|
|
}, |
|
|
|
} |
|
|
|
|
|
|
|
|
|
|
|
extractText() { |
|
|
|
extractText() { |
|
|
|
if (this.startedTextExtraction) { |
|
|
|
if (this.startedTextExtraction) { |
|
|
@ -258,29 +254,30 @@ var PDFFindController = (function PDFFindControllerClosure() { |
|
|
|
}); |
|
|
|
}); |
|
|
|
}); |
|
|
|
}); |
|
|
|
} |
|
|
|
} |
|
|
|
}, |
|
|
|
} |
|
|
|
|
|
|
|
|
|
|
|
executeCommand: function PDFFindController_executeCommand(cmd, state) { |
|
|
|
executeCommand(cmd, state) { |
|
|
|
if (this.state === null || cmd !== 'findagain') { |
|
|
|
if (this.state === null || cmd !== 'findagain') { |
|
|
|
this.dirtyMatch = true; |
|
|
|
this.dirtyMatch = true; |
|
|
|
} |
|
|
|
} |
|
|
|
this.state = state; |
|
|
|
this.state = state; |
|
|
|
this.updateUIState(FindStates.FIND_PENDING); |
|
|
|
this.updateUIState(FindState.PENDING); |
|
|
|
|
|
|
|
|
|
|
|
this._firstPagePromise.then(() => { |
|
|
|
this._firstPagePromise.then(() => { |
|
|
|
this.extractText(); |
|
|
|
this.extractText(); |
|
|
|
|
|
|
|
|
|
|
|
clearTimeout(this.findTimeout); |
|
|
|
clearTimeout(this.findTimeout); |
|
|
|
if (cmd === 'find') { |
|
|
|
if (cmd === 'find') { |
|
|
|
// Only trigger the find action after 250ms of silence.
|
|
|
|
// Trigger the find action with a small delay to avoid starting the
|
|
|
|
this.findTimeout = setTimeout(this.nextMatch.bind(this), 250); |
|
|
|
// search when the user is still typing (saving resources).
|
|
|
|
|
|
|
|
this.findTimeout = setTimeout(this.nextMatch.bind(this), FIND_TIMEOUT); |
|
|
|
} else { |
|
|
|
} else { |
|
|
|
this.nextMatch(); |
|
|
|
this.nextMatch(); |
|
|
|
} |
|
|
|
} |
|
|
|
}); |
|
|
|
}); |
|
|
|
}, |
|
|
|
} |
|
|
|
|
|
|
|
|
|
|
|
updatePage: function PDFFindController_updatePage(index) { |
|
|
|
updatePage(index) { |
|
|
|
if (this.selected.pageIdx === index) { |
|
|
|
if (this.selected.pageIdx === index) { |
|
|
|
// If the page is selected, scroll the page into view, which triggers
|
|
|
|
// If the page is selected, scroll the page into view, which triggers
|
|
|
|
// rendering the page, which adds the textLayer. Once the textLayer is
|
|
|
|
// rendering the page, which adds the textLayer. Once the textLayer is
|
|
|
@ -288,16 +285,16 @@ var PDFFindController = (function PDFFindControllerClosure() { |
|
|
|
this.pdfViewer.currentPageNumber = index + 1; |
|
|
|
this.pdfViewer.currentPageNumber = index + 1; |
|
|
|
} |
|
|
|
} |
|
|
|
|
|
|
|
|
|
|
|
var page = this.pdfViewer.getPageView(index); |
|
|
|
let page = this.pdfViewer.getPageView(index); |
|
|
|
if (page.textLayer) { |
|
|
|
if (page.textLayer) { |
|
|
|
page.textLayer.updateMatches(); |
|
|
|
page.textLayer.updateMatches(); |
|
|
|
} |
|
|
|
} |
|
|
|
}, |
|
|
|
} |
|
|
|
|
|
|
|
|
|
|
|
nextMatch: function PDFFindController_nextMatch() { |
|
|
|
nextMatch() { |
|
|
|
var previous = this.state.findPrevious; |
|
|
|
let previous = this.state.findPrevious; |
|
|
|
var currentPageIndex = this.pdfViewer.currentPageNumber - 1; |
|
|
|
let currentPageIndex = this.pdfViewer.currentPageNumber - 1; |
|
|
|
var numPages = this.pdfViewer.pagesCount; |
|
|
|
let numPages = this.pdfViewer.pagesCount; |
|
|
|
|
|
|
|
|
|
|
|
this.active = true; |
|
|
|
this.active = true; |
|
|
|
|
|
|
|
|
|
|
@ -314,10 +311,10 @@ var PDFFindController = (function PDFFindControllerClosure() { |
|
|
|
this.pageMatchesLength = null; |
|
|
|
this.pageMatchesLength = null; |
|
|
|
|
|
|
|
|
|
|
|
for (let i = 0; i < numPages; i++) { |
|
|
|
for (let i = 0; i < numPages; i++) { |
|
|
|
// Wipe out any previous highlighted matches.
|
|
|
|
// Wipe out any previously highlighted matches.
|
|
|
|
this.updatePage(i); |
|
|
|
this.updatePage(i); |
|
|
|
|
|
|
|
|
|
|
|
// As soon as the text is extracted start finding the matches.
|
|
|
|
// Start finding the matches as soon as the text is extracted.
|
|
|
|
if (!(i in this.pendingFindMatches)) { |
|
|
|
if (!(i in this.pendingFindMatches)) { |
|
|
|
this.pendingFindMatches[i] = true; |
|
|
|
this.pendingFindMatches[i] = true; |
|
|
|
this.extractTextPromises[i].then((pageIdx) => { |
|
|
|
this.extractTextPromises[i].then((pageIdx) => { |
|
|
@ -330,7 +327,7 @@ var PDFFindController = (function PDFFindControllerClosure() { |
|
|
|
|
|
|
|
|
|
|
|
// If there's no query there's no point in searching.
|
|
|
|
// If there's no query there's no point in searching.
|
|
|
|
if (this.state.query === '') { |
|
|
|
if (this.state.query === '') { |
|
|
|
this.updateUIState(FindStates.FIND_FOUND); |
|
|
|
this.updateUIState(FindState.FOUND); |
|
|
|
return; |
|
|
|
return; |
|
|
|
} |
|
|
|
} |
|
|
|
|
|
|
|
|
|
|
@ -339,13 +336,13 @@ var PDFFindController = (function PDFFindControllerClosure() { |
|
|
|
return; |
|
|
|
return; |
|
|
|
} |
|
|
|
} |
|
|
|
|
|
|
|
|
|
|
|
var offset = this.offset; |
|
|
|
let offset = this.offset; |
|
|
|
// Keep track of how many pages we should maximally iterate through.
|
|
|
|
// Keep track of how many pages we should maximally iterate through.
|
|
|
|
this.pagesToSearch = numPages; |
|
|
|
this.pagesToSearch = numPages; |
|
|
|
// If there's already a matchIdx that means we are iterating through a
|
|
|
|
// If there's already a `matchIdx` that means we are iterating through a
|
|
|
|
// page's matches.
|
|
|
|
// page's matches.
|
|
|
|
if (offset.matchIdx !== null) { |
|
|
|
if (offset.matchIdx !== null) { |
|
|
|
var numPageMatches = this.pageMatches[offset.pageIdx].length; |
|
|
|
let numPageMatches = this.pageMatches[offset.pageIdx].length; |
|
|
|
if ((!previous && offset.matchIdx + 1 < numPageMatches) || |
|
|
|
if ((!previous && offset.matchIdx + 1 < numPageMatches) || |
|
|
|
(previous && offset.matchIdx > 0)) { |
|
|
|
(previous && offset.matchIdx > 0)) { |
|
|
|
// The simple case; we just have advance the matchIdx to select
|
|
|
|
// The simple case; we just have advance the matchIdx to select
|
|
|
@ -362,15 +359,15 @@ var PDFFindController = (function PDFFindControllerClosure() { |
|
|
|
} |
|
|
|
} |
|
|
|
// Start searching through the page.
|
|
|
|
// Start searching through the page.
|
|
|
|
this.nextPageMatch(); |
|
|
|
this.nextPageMatch(); |
|
|
|
}, |
|
|
|
} |
|
|
|
|
|
|
|
|
|
|
|
matchesReady: function PDFFindController_matchesReady(matches) { |
|
|
|
matchesReady(matches) { |
|
|
|
var offset = this.offset; |
|
|
|
let offset = this.offset; |
|
|
|
var numMatches = matches.length; |
|
|
|
let numMatches = matches.length; |
|
|
|
var previous = this.state.findPrevious; |
|
|
|
let previous = this.state.findPrevious; |
|
|
|
|
|
|
|
|
|
|
|
if (numMatches) { |
|
|
|
if (numMatches) { |
|
|
|
// There were matches for the page, so initialize the matchIdx.
|
|
|
|
// There were matches for the page, so initialize `matchIdx`.
|
|
|
|
this.hadMatch = true; |
|
|
|
this.hadMatch = true; |
|
|
|
offset.matchIdx = (previous ? numMatches - 1 : 0); |
|
|
|
offset.matchIdx = (previous ? numMatches - 1 : 0); |
|
|
|
this.updateMatch(true); |
|
|
|
this.updateMatch(true); |
|
|
@ -383,55 +380,56 @@ var PDFFindController = (function PDFFindControllerClosure() { |
|
|
|
if (this.pagesToSearch < 0) { |
|
|
|
if (this.pagesToSearch < 0) { |
|
|
|
// No point in wrapping again, there were no matches.
|
|
|
|
// No point in wrapping again, there were no matches.
|
|
|
|
this.updateMatch(false); |
|
|
|
this.updateMatch(false); |
|
|
|
// while matches were not found, searching for a page
|
|
|
|
// While matches were not found, searching for a page
|
|
|
|
// with matches should nevertheless halt.
|
|
|
|
// with matches should nevertheless halt.
|
|
|
|
return true; |
|
|
|
return true; |
|
|
|
} |
|
|
|
} |
|
|
|
} |
|
|
|
} |
|
|
|
// Matches were not found (and searching is not done).
|
|
|
|
// Matches were not found (and searching is not done).
|
|
|
|
return false; |
|
|
|
return false; |
|
|
|
}, |
|
|
|
} |
|
|
|
|
|
|
|
|
|
|
|
/** |
|
|
|
/** |
|
|
|
* The method is called back from the text layer when match presentation |
|
|
|
* Called from the text layer when match presentation is updated. |
|
|
|
* is updated. |
|
|
|
* |
|
|
|
* @param {number} pageIndex - page index. |
|
|
|
* @param {number} pageIndex - The index of the page. |
|
|
|
* @param {number} index - match index. |
|
|
|
* @param {number} matchIndex - The index of the match. |
|
|
|
* @param {Array} elements - text layer div elements array. |
|
|
|
* @param {Array} elements - Text layer `div` elements. |
|
|
|
* @param {number} beginIdx - start index of the div array for the match. |
|
|
|
* @param {number} beginIdx - Start index of the `div` array for the match. |
|
|
|
*/ |
|
|
|
*/ |
|
|
|
updateMatchPosition: function PDFFindController_updateMatchPosition( |
|
|
|
updateMatchPosition(pageIndex, matchIndex, elements, beginIdx) { |
|
|
|
pageIndex, index, elements, beginIdx) { |
|
|
|
if (this.selected.matchIdx === matchIndex && |
|
|
|
if (this.selected.matchIdx === index && |
|
|
|
|
|
|
|
this.selected.pageIdx === pageIndex) { |
|
|
|
this.selected.pageIdx === pageIndex) { |
|
|
|
var spot = { |
|
|
|
let spot = { |
|
|
|
top: FIND_SCROLL_OFFSET_TOP, |
|
|
|
top: FIND_SCROLL_OFFSET_TOP, |
|
|
|
left: FIND_SCROLL_OFFSET_LEFT, |
|
|
|
left: FIND_SCROLL_OFFSET_LEFT, |
|
|
|
}; |
|
|
|
}; |
|
|
|
scrollIntoView(elements[beginIdx], spot, |
|
|
|
scrollIntoView(elements[beginIdx], spot, |
|
|
|
/* skipOverflowHiddenElements = */ true); |
|
|
|
/* skipOverflowHiddenElements = */ true); |
|
|
|
} |
|
|
|
} |
|
|
|
}, |
|
|
|
} |
|
|
|
|
|
|
|
|
|
|
|
nextPageMatch: function PDFFindController_nextPageMatch() { |
|
|
|
nextPageMatch() { |
|
|
|
if (this.resumePageIdx !== null) { |
|
|
|
if (this.resumePageIdx !== null) { |
|
|
|
console.error('There can only be one pending page.'); |
|
|
|
console.error('There can only be one pending page.'); |
|
|
|
} |
|
|
|
} |
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
let matches = null; |
|
|
|
do { |
|
|
|
do { |
|
|
|
var pageIdx = this.offset.pageIdx; |
|
|
|
let pageIdx = this.offset.pageIdx; |
|
|
|
var matches = this.pageMatches[pageIdx]; |
|
|
|
matches = this.pageMatches[pageIdx]; |
|
|
|
if (!matches) { |
|
|
|
if (!matches) { |
|
|
|
// The matches don't exist yet for processing by "matchesReady",
|
|
|
|
// The matches don't exist yet for processing by `matchesReady`,
|
|
|
|
// so set a resume point for when they do exist.
|
|
|
|
// so set a resume point for when they do exist.
|
|
|
|
this.resumePageIdx = pageIdx; |
|
|
|
this.resumePageIdx = pageIdx; |
|
|
|
break; |
|
|
|
break; |
|
|
|
} |
|
|
|
} |
|
|
|
} while (!this.matchesReady(matches)); |
|
|
|
} while (!this.matchesReady(matches)); |
|
|
|
}, |
|
|
|
} |
|
|
|
|
|
|
|
|
|
|
|
advanceOffsetPage: function PDFFindController_advanceOffsetPage(previous) { |
|
|
|
advanceOffsetPage(previous) { |
|
|
|
var offset = this.offset; |
|
|
|
let offset = this.offset; |
|
|
|
var numPages = this.extractTextPromises.length; |
|
|
|
let numPages = this.extractTextPromises.length; |
|
|
|
offset.pageIdx = (previous ? offset.pageIdx - 1 : offset.pageIdx + 1); |
|
|
|
offset.pageIdx = (previous ? offset.pageIdx - 1 : offset.pageIdx + 1); |
|
|
|
offset.matchIdx = null; |
|
|
|
offset.matchIdx = null; |
|
|
|
|
|
|
|
|
|
|
@ -441,18 +439,19 @@ var PDFFindController = (function PDFFindControllerClosure() { |
|
|
|
offset.pageIdx = (previous ? numPages - 1 : 0); |
|
|
|
offset.pageIdx = (previous ? numPages - 1 : 0); |
|
|
|
offset.wrapped = true; |
|
|
|
offset.wrapped = true; |
|
|
|
} |
|
|
|
} |
|
|
|
}, |
|
|
|
} |
|
|
|
|
|
|
|
|
|
|
|
updateMatch: function PDFFindController_updateMatch(found) { |
|
|
|
updateMatch(found = false) { |
|
|
|
var state = FindStates.FIND_NOTFOUND; |
|
|
|
let state = FindState.NOT_FOUND; |
|
|
|
var wrapped = this.offset.wrapped; |
|
|
|
let wrapped = this.offset.wrapped; |
|
|
|
this.offset.wrapped = false; |
|
|
|
this.offset.wrapped = false; |
|
|
|
|
|
|
|
|
|
|
|
if (found) { |
|
|
|
if (found) { |
|
|
|
var previousPage = this.selected.pageIdx; |
|
|
|
let previousPage = this.selected.pageIdx; |
|
|
|
this.selected.pageIdx = this.offset.pageIdx; |
|
|
|
this.selected.pageIdx = this.offset.pageIdx; |
|
|
|
this.selected.matchIdx = this.offset.matchIdx; |
|
|
|
this.selected.matchIdx = this.offset.matchIdx; |
|
|
|
state = (wrapped ? FindStates.FIND_WRAPPED : FindStates.FIND_FOUND); |
|
|
|
state = (wrapped ? FindState.WRAPPED : FindState.FOUND); |
|
|
|
|
|
|
|
|
|
|
|
// Update the currently selected page to wipe out any selected matches.
|
|
|
|
// Update the currently selected page to wipe out any selected matches.
|
|
|
|
if (previousPage !== -1 && previousPage !== this.selected.pageIdx) { |
|
|
|
if (previousPage !== -1 && previousPage !== this.selected.pageIdx) { |
|
|
|
this.updatePage(previousPage); |
|
|
|
this.updatePage(previousPage); |
|
|
@ -463,25 +462,22 @@ var PDFFindController = (function PDFFindControllerClosure() { |
|
|
|
if (this.selected.pageIdx !== -1) { |
|
|
|
if (this.selected.pageIdx !== -1) { |
|
|
|
this.updatePage(this.selected.pageIdx); |
|
|
|
this.updatePage(this.selected.pageIdx); |
|
|
|
} |
|
|
|
} |
|
|
|
}, |
|
|
|
} |
|
|
|
|
|
|
|
|
|
|
|
updateUIResultsCount: |
|
|
|
updateUIResultsCount() { |
|
|
|
function PDFFindController_updateUIResultsCount() { |
|
|
|
|
|
|
|
if (this.onUpdateResultsCount) { |
|
|
|
if (this.onUpdateResultsCount) { |
|
|
|
this.onUpdateResultsCount(this.matchCount); |
|
|
|
this.onUpdateResultsCount(this.matchCount); |
|
|
|
} |
|
|
|
} |
|
|
|
}, |
|
|
|
} |
|
|
|
|
|
|
|
|
|
|
|
updateUIState: function PDFFindController_updateUIState(state, previous) { |
|
|
|
updateUIState(state, previous) { |
|
|
|
if (this.onUpdateState) { |
|
|
|
if (this.onUpdateState) { |
|
|
|
this.onUpdateState(state, previous, this.matchCount); |
|
|
|
this.onUpdateState(state, previous, this.matchCount); |
|
|
|
} |
|
|
|
} |
|
|
|
}, |
|
|
|
} |
|
|
|
}; |
|
|
|
} |
|
|
|
return PDFFindController; |
|
|
|
|
|
|
|
})(); |
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
export { |
|
|
|
export { |
|
|
|
FindStates, |
|
|
|
FindState, |
|
|
|
PDFFindController, |
|
|
|
PDFFindController, |
|
|
|
}; |
|
|
|
}; |
|
|
|