Added multiple term search functionality (with default phrase search)
This commit is contained in:
		
							parent
							
								
									7ac48ef4d5
								
							
						
					
					
						commit
						0a347ec04d
					
				
							
								
								
									
										13
									
								
								web/app.js
									
									
									
									
									
								
							
							
						
						
									
										13
									
								
								web/app.js
									
									
									
									
									
								
							| @ -1251,6 +1251,7 @@ var PDFViewerApplication = { | |||||||
|     eventBus.on('rotateccw', webViewerRotateCcw); |     eventBus.on('rotateccw', webViewerRotateCcw); | ||||||
|     eventBus.on('documentproperties', webViewerDocumentProperties); |     eventBus.on('documentproperties', webViewerDocumentProperties); | ||||||
|     eventBus.on('find', webViewerFind); |     eventBus.on('find', webViewerFind); | ||||||
|  |     eventBus.on('findfromurlhash', webViewerFindFromUrlHash); | ||||||
| //#if GENERIC
 | //#if GENERIC
 | ||||||
|     eventBus.on('fileinputchange', webViewerFileInputChange); |     eventBus.on('fileinputchange', webViewerFileInputChange); | ||||||
| //#endif
 | //#endif
 | ||||||
| @ -1906,12 +1907,23 @@ function webViewerDocumentProperties() { | |||||||
| function webViewerFind(e) { | function webViewerFind(e) { | ||||||
|   PDFViewerApplication.findController.executeCommand('find' + e.type, { |   PDFViewerApplication.findController.executeCommand('find' + e.type, { | ||||||
|     query: e.query, |     query: e.query, | ||||||
|  |     phraseSearch: e.phraseSearch, | ||||||
|     caseSensitive: e.caseSensitive, |     caseSensitive: e.caseSensitive, | ||||||
|     highlightAll: e.highlightAll, |     highlightAll: e.highlightAll, | ||||||
|     findPrevious: e.findPrevious |     findPrevious: e.findPrevious | ||||||
|   }); |   }); | ||||||
| } | } | ||||||
| 
 | 
 | ||||||
|  | function webViewerFindFromUrlHash(e) { | ||||||
|  |   PDFViewerApplication.findController.executeCommand('find', { | ||||||
|  |     query: e.query, | ||||||
|  |     phraseSearch: e.phraseSearch, | ||||||
|  |     caseSensitive: false, | ||||||
|  |     highlightAll: true, | ||||||
|  |     findPrevious: false | ||||||
|  |   }); | ||||||
|  | } | ||||||
|  | 
 | ||||||
| function webViewerScaleChanging(e) { | function webViewerScaleChanging(e) { | ||||||
|   var appConfig = PDFViewerApplication.appConfig; |   var appConfig = PDFViewerApplication.appConfig; | ||||||
|   appConfig.toolbar.zoomOut.disabled = (e.scale === MIN_SCALE); |   appConfig.toolbar.zoomOut.disabled = (e.scale === MIN_SCALE); | ||||||
| @ -2055,6 +2067,7 @@ window.addEventListener('keydown', function keydown(evt) { | |||||||
|           if (findState) { |           if (findState) { | ||||||
|             PDFViewerApplication.findController.executeCommand('findagain', { |             PDFViewerApplication.findController.executeCommand('findagain', { | ||||||
|               query: findState.query, |               query: findState.query, | ||||||
|  |               phraseSearch: findState.phraseSearch, | ||||||
|               caseSensitive: findState.caseSensitive, |               caseSensitive: findState.caseSensitive, | ||||||
|               highlightAll: findState.highlightAll, |               highlightAll: findState.highlightAll, | ||||||
|               findPrevious: cmd === 5 || cmd === 12 |               findPrevious: cmd === 5 || cmd === 12 | ||||||
|  | |||||||
| @ -88,6 +88,7 @@ | |||||||
|       var event = document.createEvent('CustomEvent'); |       var event = document.createEvent('CustomEvent'); | ||||||
|       event.initCustomEvent('find' + e.type, true, true, { |       event.initCustomEvent('find' + e.type, true, true, { | ||||||
|         query: e.query, |         query: e.query, | ||||||
|  |         phraseSearch: e.phraseSearch, | ||||||
|         caseSensitive: e.caseSensitive, |         caseSensitive: e.caseSensitive, | ||||||
|         highlightAll: e.highlightAll, |         highlightAll: e.highlightAll, | ||||||
|         findPrevious: e.findPrevious |         findPrevious: e.findPrevious | ||||||
|  | |||||||
| @ -163,6 +163,7 @@ Preferences._readFromStorage = function (prefObj) { | |||||||
|       source: window, |       source: window, | ||||||
|       type: evt.type.substring('find'.length), |       type: evt.type.substring('find'.length), | ||||||
|       query: evt.detail.query, |       query: evt.detail.query, | ||||||
|  |       phraseSearch: true, | ||||||
|       caseSensitive: !!evt.detail.caseSensitive, |       caseSensitive: !!evt.detail.caseSensitive, | ||||||
|       highlightAll: !!evt.detail.highlightAll, |       highlightAll: !!evt.detail.highlightAll, | ||||||
|       findPrevious: !!evt.detail.findPrevious |       findPrevious: !!evt.detail.findPrevious | ||||||
|  | |||||||
| @ -109,6 +109,7 @@ var PDFFindBar = (function PDFFindBarClosure() { | |||||||
|         type: type, |         type: type, | ||||||
|         query: this.findField.value, |         query: this.findField.value, | ||||||
|         caseSensitive: this.caseSensitive.checked, |         caseSensitive: this.caseSensitive.checked, | ||||||
|  |         phraseSearch: true, | ||||||
|         highlightAll: this.highlightAll.checked, |         highlightAll: this.highlightAll.checked, | ||||||
|         findPrevious: findPrev |         findPrevious: findPrev | ||||||
|       }); |       }); | ||||||
|  | |||||||
| @ -78,6 +78,7 @@ var PDFFindController = (function PDFFindControllerClosure() { | |||||||
|       this.active = false; // If active, find results will be highlighted.
 |       this.active = false; // If active, find results will be highlighted.
 | ||||||
|       this.pageContents = []; // Stores the text for each page.
 |       this.pageContents = []; // Stores the text for each page.
 | ||||||
|       this.pageMatches = []; |       this.pageMatches = []; | ||||||
|  |       this.pageMatchesLength = null; | ||||||
|       this.matchCount = 0; |       this.matchCount = 0; | ||||||
|       this.selected = { // Currently selected match.
 |       this.selected = { // Currently selected match.
 | ||||||
|         pageIdx: -1, |         pageIdx: -1, | ||||||
| @ -104,10 +105,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) { |     calcFindMatch: function PDFFindController_calcFindMatch(pageIndex) { | ||||||
|       var pageContent = this.normalize(this.pageContents[pageIndex]); |       var pageContent = this.normalize(this.pageContents[pageIndex]); | ||||||
|       var query = this.normalize(this.state.query); |       var query = this.normalize(this.state.query); | ||||||
|       var caseSensitive = this.state.caseSensitive; |       var caseSensitive = this.state.caseSensitive; | ||||||
|  |       var phraseSearch = this.state.phraseSearch; | ||||||
|       var queryLen = query.length; |       var queryLen = query.length; | ||||||
| 
 | 
 | ||||||
|       if (queryLen === 0) { |       if (queryLen === 0) { | ||||||
| @ -120,16 +225,12 @@ var PDFFindController = (function PDFFindControllerClosure() { | |||||||
|         query = query.toLowerCase(); |         query = query.toLowerCase(); | ||||||
|       } |       } | ||||||
| 
 | 
 | ||||||
|       var matches = []; |       if (phraseSearch) { | ||||||
|       var matchIdx = -queryLen; |         this.calcFindPhraseMatch(query, pageIndex, pageContent); | ||||||
|       while (true) { |       } else { | ||||||
|         matchIdx = pageContent.indexOf(query, matchIdx + queryLen); |         this.calcFindWordMatch(query, pageIndex, pageContent); | ||||||
|         if (matchIdx === -1) { |  | ||||||
|           break; |  | ||||||
|         } |  | ||||||
|         matches.push(matchIdx); |  | ||||||
|       } |       } | ||||||
|       this.pageMatches[pageIndex] = matches; | 
 | ||||||
|       this.updatePage(pageIndex); |       this.updatePage(pageIndex); | ||||||
|       if (this.resumePageIdx === pageIndex) { |       if (this.resumePageIdx === pageIndex) { | ||||||
|         this.resumePageIdx = null; |         this.resumePageIdx = null; | ||||||
| @ -137,8 +238,8 @@ var PDFFindController = (function PDFFindControllerClosure() { | |||||||
|       } |       } | ||||||
| 
 | 
 | ||||||
|       // Update the matches count
 |       // Update the matches count
 | ||||||
|       if (matches.length > 0) { |       if (this.pageMatches[pageIndex].length > 0) { | ||||||
|         this.matchCount += matches.length; |         this.matchCount += this.pageMatches[pageIndex].length; | ||||||
|         this.updateUIResultsCount(); |         this.updateUIResultsCount(); | ||||||
|       } |       } | ||||||
|     }, |     }, | ||||||
| @ -233,6 +334,7 @@ var PDFFindController = (function PDFFindControllerClosure() { | |||||||
|         this.resumePageIdx = null; |         this.resumePageIdx = null; | ||||||
|         this.pageMatches = []; |         this.pageMatches = []; | ||||||
|         this.matchCount = 0; |         this.matchCount = 0; | ||||||
|  |         this.pageMatchesLength = null; | ||||||
|         var self = this; |         var self = this; | ||||||
| 
 | 
 | ||||||
|         for (var i = 0; i < numPages; i++) { |         for (var i = 0; i < numPages; i++) { | ||||||
|  | |||||||
| @ -194,6 +194,13 @@ var PDFLinkService = (function () { | |||||||
|     setHash: function PDFLinkService_setHash(hash) { |     setHash: function PDFLinkService_setHash(hash) { | ||||||
|       if (hash.indexOf('=') >= 0) { |       if (hash.indexOf('=') >= 0) { | ||||||
|         var params = parseQueryString(hash); |         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"
 |         // borrowing syntax from "Parameters for Opening PDF Files"
 | ||||||
|         if ('nameddest' in params) { |         if ('nameddest' in params) { | ||||||
|           if (this.pdfHistory) { |           if (this.pdfHistory) { | ||||||
|  | |||||||
| @ -116,7 +116,8 @@ var TextLayerBuilder = (function TextLayerBuilderClosure() { | |||||||
|       this.divContentDone = true; |       this.divContentDone = true; | ||||||
|     }, |     }, | ||||||
| 
 | 
 | ||||||
|     convertMatches: function TextLayerBuilder_convertMatches(matches) { |     convertMatches: function TextLayerBuilder_convertMatches(matches, | ||||||
|  |                                                              matchesLength) { | ||||||
|       var i = 0; |       var i = 0; | ||||||
|       var iIndex = 0; |       var iIndex = 0; | ||||||
|       var bidiTexts = this.textContent.items; |       var bidiTexts = this.textContent.items; | ||||||
| @ -124,7 +125,9 @@ var TextLayerBuilder = (function TextLayerBuilderClosure() { | |||||||
|       var queryLen = (this.findController === null ? |       var queryLen = (this.findController === null ? | ||||||
|                       0 : this.findController.state.query.length); |                       0 : this.findController.state.query.length); | ||||||
|       var ret = []; |       var ret = []; | ||||||
| 
 |       if (!matches) { | ||||||
|  |         return ret; | ||||||
|  |       } | ||||||
|       for (var m = 0, len = matches.length; m < len; m++) { |       for (var m = 0, len = matches.length; m < len; m++) { | ||||||
|         // Calculate the start position.
 |         // Calculate the start position.
 | ||||||
|         var matchIdx = matches[m]; |         var matchIdx = matches[m]; | ||||||
| @ -147,7 +150,11 @@ var TextLayerBuilder = (function TextLayerBuilderClosure() { | |||||||
|         }; |         }; | ||||||
| 
 | 
 | ||||||
|         // Calculate the end position.
 |         // 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
 |         // Somewhat the same array as above, but use > instead of >= to get
 | ||||||
|         // the end position right.
 |         // the end position right.
 | ||||||
| @ -289,8 +296,14 @@ var TextLayerBuilder = (function TextLayerBuilderClosure() { | |||||||
| 
 | 
 | ||||||
|       // Convert the matches on the page controller into the match format
 |       // Convert the matches on the page controller into the match format
 | ||||||
|       // used for the textLayer.
 |       // used for the textLayer.
 | ||||||
|       this.matches = this.convertMatches(this.findController === null ? |       var pageMatches, pageMatchesLength; | ||||||
|         [] : (this.findController.pageMatches[this.pageIdx] || [])); |       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); |       this.renderMatches(this.matches); | ||||||
|     }, |     }, | ||||||
| 
 | 
 | ||||||
|  | |||||||
		Loading…
	
	
			
			x
			
			
		
	
		Reference in New Issue
	
	Block a user