@ -16,17 +16,18 @@
@@ -16,17 +16,18 @@
import { createPromiseCapability } from 'pdfjs-lib' ;
import { scrollIntoView } from './ui_utils' ;
var FindStates = {
FIND _F OUND : 0 ,
FIND _NOT FOUND: 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 = {
@@ -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() {
@@ -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 ( text ) {
return text . replace ( this . normalizationRegex , function ( ch ) {
return CHARACTERS _TO _NORMALIZE [ ch ] ;
} ) ;
}
normalize : function PDFFindController _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.
_prepareMatches : function PDFFindController _prepareMatches (
matchesWithLength , matches , matchesLength ) {
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 ) {
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 ;
/ * *
* 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 ] ;
// Check for cases like "TAMEd TAME".
if ( currentIndex < matchesWithLength . length - 1 &&
currentElem . match === nextElem . match ) {
currentElem . skipped = true ;
return true ;
}
var i , len ;
// Sorting array of objects { match: <match>, matchLength: <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 ) ) {
// Check for cases like "thIS IS".
for ( let i = currentIndex - 1 ; i >= 0 ; i -- ) {
let prevElem = matchesWithLength [ i ] ;
if ( prevElem . skipped ) {
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 ;
while ( true ) {
matchIdx = pageContent . indexOf ( query , matchIdx + queryLen ) ;
if ( matchIdx === - 1 ) {
if ( prevElem . match + prevElem . matchLength < currentElem . match ) {
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 ,
} ) ;
if ( prevElem . match + prevElem . matchLength >=
currentElem . match + currentElem . matchLength ) {
currentElem . skipped = true ;
return true ;
}
}
// 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 ;
return false ;
}
// Sort the array of `{ match: <match>, matchLength: <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 ) ;
}
}
if ( ! caseSensitive ) {
pageContent = pageContent . toLowerCase ( ) ;
query = query . toLowerCase ( ) ;
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 ;
}
if ( phraseSearch ) {
this . calcFindPhraseMatch ( query , pageIndex , pageContent ) ;
} else {
this . calcFindWordMatch ( query , pageIndex , pageContent ) ;
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 ( 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 storing the matches.
if ( ! this . pageMatchesLength ) {
this . pageMatchesLength = [ ] ;
}
this . pageMatchesLength [ pageIndex ] = [ ] ;
this . pageMatches [ pageIndex ] = [ ] ;
// Sort `matchesWithLength`, remove intersecting terms and put the result
// into the two arrays.
this . _prepareMatches ( matchesWithLength , this . pageMatches [ pageIndex ] ,
this . pageMatchesLength [ pageIndex ] ) ;
}
this . updatePage ( pageIndex ) ;
if ( this . resumePageIdx === pageIndex ) {
this . resumePageIdx = null ;
this . nextPageMatch ( ) ;
}
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 ;
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 ( ) ;
}
} ,
// Update the match 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 ) ;
} ) ;
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 : function PDFFindController _executeCommand ( cmd , state ) {
if ( this . state === null || cmd !== 'findagain' ) {
this . dirtyMatch = true ;
}
this . state = state ;
this . updateUIState ( FindStates . FIND _PENDING ) ;
this . _firstPagePromise . then ( ( ) => {
this . extractText ( ) ;
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 ( ) ;
}
} ) ;
} ,
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 ;
}
}
}
var page = this . pdfViewer . getPageView ( index ) ;
if ( page . textLayer ) {
page . textLayer . updateMatches ( ) ;
}
} ,
nextMatch : function PDFFindController _nextMatch ( ) {
var previous = this . state . findPrevious ;
var currentPageIndex = this . pdfViewer . currentPageNumber - 1 ;
var 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 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 ) ;
} ) ;
}
}
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 ( ) ;
}
} ) ;
}
// If there's no query there's no point in searching.
if ( this . state . query === '' ) {
this . updateUIState ( FindStates . FIND _FOUND ) ;
return ;
}
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 ( ) ;
}
}
// If we're waiting on a page, we return since we can't do anything else.
if ( this . resumePageIdx ) {
return ;
}
nextMatch ( ) {
let previous = this . state . findPrevious ;
let currentPageIndex = this . pdfViewer . currentPageNumber - 1 ;
let numPages = this . pdfViewer . pagesCount ;
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 . nextPageMatch ( ) ;
} ,
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 ;
matchesReady : function PDFFindController _matchesReady ( matches ) {
var offset = this . offset ;
var numMatches = matches . length ;
var previous = this . state . findPrevious ;
for ( let i = 0 ; i < numPages ; i ++ ) {
// Wipe out any previously highlighted matches.
this . updatePage ( i ) ;
if ( numMatches ) {
// There were matches for the page, so initialize the matchIdx.
// 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 true ;
return ;
}
// No matches, so attempt to search the next page.
// We went beyond the current page's matches, so we advance to
// 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 ;
} ,
/ * *
* 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 ) ;
}
// 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 ;
}
} ,
}
// 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 : function PDFFindController _nextPageMatch ( ) {
if ( this . resumePageIdx !== null ) {
console . error ( 'There can only be one pending page.' ) ;
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 ;
}
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 ) ) ;
} ,
} while ( ! this . matchesReady ( matches ) ) ;
}
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 ;
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 -- ;
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 ) ;
}
}
if ( offset . pageIdx >= numPages || offset . pageIdx < 0 ) {
offset . pageIdx = ( previous ? numPages - 1 : 0 ) ;
offset . wrapped = true ;
}
}
this . updateUIState ( state , this . state . findPrevious ) ;
if ( this . selected . pageIdx !== - 1 ) {
this . updatePage ( this . selected . pageIdx ) ;
}
} ,
updateMatch ( found = false ) {
let state = FindState . NOT _FOUND ;
let wrapped = this . offset . wrapped ;
this . offset . wrapped = false ;
updateUIResultsCount :
function PDFFindController _updateUIResultsCount ( ) {
if ( this . onUpdateResultsCount ) {
this . onUpdateResultsCount ( this . matchCount ) ;
}
} ,
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 ) ;
updateUIState : function PDFFindController _updateUIState ( state , previous ) {
if ( this . onUpdateState ) {
this . onUpdateState ( state , previous , this . matchCount ) ;
// Update the currently selected page to wipe out any selected matches.
if ( previousPage !== - 1 && previousPage !== this . selected . pageIdx ) {
this . updatePage ( previousPage ) ;
}
} ,
} ;
return PDFFindController ;
} ) ( ) ;
}
this . updateUIState ( state , this . state . findPrevious ) ;
if ( this . selected . pageIdx !== - 1 ) {
this . updatePage ( this . selected . pageIdx ) ;
}
}
updateUIResultsCount ( ) {
if ( this . onUpdateResultsCount ) {
this . onUpdateResultsCount ( this . matchCount ) ;
}
}
updateUIState ( state , previous ) {
if ( this . onUpdateState ) {
this . onUpdateState ( state , previous , this . matchCount ) ;
}
}
}
export {
FindStates ,
FindState ,
PDFFindController ,
} ;