|
|
|
@ -875,6 +875,7 @@ exports.binarySearchFirstItem = binarySearchFirstItem;
@@ -875,6 +875,7 @@ exports.binarySearchFirstItem = binarySearchFirstItem;
|
|
|
|
|
var event = document.createEvent('CustomEvent'); |
|
|
|
|
event.initCustomEvent('find' + e.type, true, true, { |
|
|
|
|
query: e.query, |
|
|
|
|
phraseSearch: e.phraseSearch, |
|
|
|
|
caseSensitive: e.caseSensitive, |
|
|
|
|
highlightAll: e.highlightAll, |
|
|
|
|
findPrevious: e.findPrevious |
|
|
|
@ -999,6 +1000,7 @@ var PDFFindController = (function PDFFindControllerClosure() {
@@ -999,6 +1000,7 @@ var PDFFindController = (function PDFFindControllerClosure() {
|
|
|
|
|
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, |
|
|
|
@ -1025,10 +1027,114 @@ var PDFFindController = (function PDFFindControllerClosure() {
@@ -1025,10 +1027,114 @@ var PDFFindController = (function PDFFindControllerClosure() {
|
|
|
|
|
}); |
|
|
|
|
}, |
|
|
|
|
|
|
|
|
|
// 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; |
|
|
|
|
} |
|
|
|
|
|
|
|
|
|
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)) { |
|
|
|
|
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) { |
|
|
|
|
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) { |
|
|
|
@ -1041,16 +1147,12 @@ var PDFFindController = (function PDFFindControllerClosure() {
@@ -1041,16 +1147,12 @@ var PDFFindController = (function PDFFindControllerClosure() {
|
|
|
|
|
query = query.toLowerCase(); |
|
|
|
|
} |
|
|
|
|
|
|
|
|
|
var matches = []; |
|
|
|
|
var matchIdx = -queryLen; |
|
|
|
|
while (true) { |
|
|
|
|
matchIdx = pageContent.indexOf(query, matchIdx + queryLen); |
|
|
|
|
if (matchIdx === -1) { |
|
|
|
|
break; |
|
|
|
|
} |
|
|
|
|
matches.push(matchIdx); |
|
|
|
|
if (phraseSearch) { |
|
|
|
|
this.calcFindPhraseMatch(query, pageIndex, pageContent); |
|
|
|
|
} else { |
|
|
|
|
this.calcFindWordMatch(query, pageIndex, pageContent); |
|
|
|
|
} |
|
|
|
|
this.pageMatches[pageIndex] = matches; |
|
|
|
|
|
|
|
|
|
this.updatePage(pageIndex); |
|
|
|
|
if (this.resumePageIdx === pageIndex) { |
|
|
|
|
this.resumePageIdx = null; |
|
|
|
@ -1058,8 +1160,8 @@ var PDFFindController = (function PDFFindControllerClosure() {
@@ -1058,8 +1160,8 @@ var PDFFindController = (function PDFFindControllerClosure() {
|
|
|
|
|
} |
|
|
|
|
|
|
|
|
|
// Update the matches count
|
|
|
|
|
if (matches.length > 0) { |
|
|
|
|
this.matchCount += matches.length; |
|
|
|
|
if (this.pageMatches[pageIndex].length > 0) { |
|
|
|
|
this.matchCount += this.pageMatches[pageIndex].length; |
|
|
|
|
this.updateUIResultsCount(); |
|
|
|
|
} |
|
|
|
|
}, |
|
|
|
@ -1154,6 +1256,7 @@ var PDFFindController = (function PDFFindControllerClosure() {
@@ -1154,6 +1256,7 @@ var PDFFindController = (function PDFFindControllerClosure() {
|
|
|
|
|
this.resumePageIdx = null; |
|
|
|
|
this.pageMatches = []; |
|
|
|
|
this.matchCount = 0; |
|
|
|
|
this.pageMatchesLength = null; |
|
|
|
|
var self = this; |
|
|
|
|
|
|
|
|
|
for (var i = 0; i < numPages; i++) { |
|
|
|
@ -1901,6 +2004,13 @@ var PDFLinkService = (function () {
@@ -1901,6 +2004,13 @@ var PDFLinkService = (function () {
|
|
|
|
|
setHash: function PDFLinkService_setHash(hash) { |
|
|
|
|
if (hash.indexOf('=') >= 0) { |
|
|
|
|
var params = parseQueryString(hash); |
|
|
|
|
if ('search' in params) { |
|
|
|
|
this.eventBus.dispatch('findfromurlhash', { |
|
|
|
|
source: this, |
|
|
|
|
query: params['search'].replace(/"/g, ''), |
|
|
|
|
phraseSearch: (params['phrase'] === 'true') |
|
|
|
|
}); |
|
|
|
|
} |
|
|
|
|
// borrowing syntax from "Parameters for Opening PDF Files"
|
|
|
|
|
if ('nameddest' in params) { |
|
|
|
|
if (this.pdfHistory) { |
|
|
|
@ -2749,7 +2859,8 @@ var TextLayerBuilder = (function TextLayerBuilderClosure() {
@@ -2749,7 +2859,8 @@ var TextLayerBuilder = (function TextLayerBuilderClosure() {
|
|
|
|
|
this.divContentDone = true; |
|
|
|
|
}, |
|
|
|
|
|
|
|
|
|
convertMatches: function TextLayerBuilder_convertMatches(matches) { |
|
|
|
|
convertMatches: function TextLayerBuilder_convertMatches(matches, |
|
|
|
|
matchesLength) { |
|
|
|
|
var i = 0; |
|
|
|
|
var iIndex = 0; |
|
|
|
|
var bidiTexts = this.textContent.items; |
|
|
|
@ -2757,7 +2868,9 @@ var TextLayerBuilder = (function TextLayerBuilderClosure() {
@@ -2757,7 +2868,9 @@ var TextLayerBuilder = (function TextLayerBuilderClosure() {
|
|
|
|
|
var queryLen = (this.findController === null ? |
|
|
|
|
0 : this.findController.state.query.length); |
|
|
|
|
var ret = []; |
|
|
|
|
|
|
|
|
|
if (!matches) { |
|
|
|
|
return ret; |
|
|
|
|
} |
|
|
|
|
for (var m = 0, len = matches.length; m < len; m++) { |
|
|
|
|
// Calculate the start position.
|
|
|
|
|
var matchIdx = matches[m]; |
|
|
|
@ -2780,7 +2893,11 @@ var TextLayerBuilder = (function TextLayerBuilderClosure() {
@@ -2780,7 +2893,11 @@ var TextLayerBuilder = (function TextLayerBuilderClosure() {
|
|
|
|
|
}; |
|
|
|
|
|
|
|
|
|
// Calculate the end position.
|
|
|
|
|
matchIdx += queryLen; |
|
|
|
|
if (matchesLength) { // multiterm search
|
|
|
|
|
matchIdx += matchesLength[m]; |
|
|
|
|
} else { // phrase search
|
|
|
|
|
matchIdx += queryLen; |
|
|
|
|
} |
|
|
|
|
|
|
|
|
|
// Somewhat the same array as above, but use > instead of >= to get
|
|
|
|
|
// the end position right.
|
|
|
|
@ -2922,8 +3039,14 @@ var TextLayerBuilder = (function TextLayerBuilderClosure() {
@@ -2922,8 +3039,14 @@ var TextLayerBuilder = (function TextLayerBuilderClosure() {
|
|
|
|
|
|
|
|
|
|
// Convert the matches on the page controller into the match format
|
|
|
|
|
// used for the textLayer.
|
|
|
|
|
this.matches = this.convertMatches(this.findController === null ? |
|
|
|
|
[] : (this.findController.pageMatches[this.pageIdx] || [])); |
|
|
|
|
var pageMatches, pageMatchesLength; |
|
|
|
|
if (this.findController !== null) { |
|
|
|
|
pageMatches = this.findController.pageMatches[this.pageIdx] || null; |
|
|
|
|
pageMatchesLength = (this.findController.pageMatchesLength) ? |
|
|
|
|
this.findController.pageMatchesLength[this.pageIdx] || null : null; |
|
|
|
|
} |
|
|
|
|
|
|
|
|
|
this.matches = this.convertMatches(pageMatches, pageMatchesLength); |
|
|
|
|
this.renderMatches(this.matches); |
|
|
|
|
}, |
|
|
|
|
|
|
|
|
|