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('documentproperties', webViewerDocumentProperties); | ||||
|     eventBus.on('find', webViewerFind); | ||||
|     eventBus.on('findfromurlhash', webViewerFindFromUrlHash); | ||||
| //#if GENERIC
 | ||||
|     eventBus.on('fileinputchange', webViewerFileInputChange); | ||||
| //#endif
 | ||||
| @ -1906,12 +1907,23 @@ function webViewerDocumentProperties() { | ||||
| function webViewerFind(e) { | ||||
|   PDFViewerApplication.findController.executeCommand('find' + e.type, { | ||||
|     query: e.query, | ||||
|     phraseSearch: e.phraseSearch, | ||||
|     caseSensitive: e.caseSensitive, | ||||
|     highlightAll: e.highlightAll, | ||||
|     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) { | ||||
|   var appConfig = PDFViewerApplication.appConfig; | ||||
|   appConfig.toolbar.zoomOut.disabled = (e.scale === MIN_SCALE); | ||||
| @ -2055,6 +2067,7 @@ window.addEventListener('keydown', function keydown(evt) { | ||||
|           if (findState) { | ||||
|             PDFViewerApplication.findController.executeCommand('findagain', { | ||||
|               query: findState.query, | ||||
|               phraseSearch: findState.phraseSearch, | ||||
|               caseSensitive: findState.caseSensitive, | ||||
|               highlightAll: findState.highlightAll, | ||||
|               findPrevious: cmd === 5 || cmd === 12 | ||||
|  | ||||
| @ -88,6 +88,7 @@ | ||||
|       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 | ||||
|  | ||||
| @ -163,6 +163,7 @@ Preferences._readFromStorage = function (prefObj) { | ||||
|       source: window, | ||||
|       type: evt.type.substring('find'.length), | ||||
|       query: evt.detail.query, | ||||
|       phraseSearch: true, | ||||
|       caseSensitive: !!evt.detail.caseSensitive, | ||||
|       highlightAll: !!evt.detail.highlightAll, | ||||
|       findPrevious: !!evt.detail.findPrevious | ||||
|  | ||||
| @ -109,6 +109,7 @@ var PDFFindBar = (function PDFFindBarClosure() { | ||||
|         type: type, | ||||
|         query: this.findField.value, | ||||
|         caseSensitive: this.caseSensitive.checked, | ||||
|         phraseSearch: true, | ||||
|         highlightAll: this.highlightAll.checked, | ||||
|         findPrevious: findPrev | ||||
|       }); | ||||
|  | ||||
| @ -78,6 +78,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, | ||||
| @ -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) { | ||||
|       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) { | ||||
| @ -120,16 +225,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; | ||||
|       if (phraseSearch) { | ||||
|         this.calcFindPhraseMatch(query, pageIndex, pageContent); | ||||
|       } else { | ||||
|         this.calcFindWordMatch(query, pageIndex, pageContent); | ||||
|       } | ||||
|         matches.push(matchIdx); | ||||
|       } | ||||
|       this.pageMatches[pageIndex] = matches; | ||||
| 
 | ||||
|       this.updatePage(pageIndex); | ||||
|       if (this.resumePageIdx === pageIndex) { | ||||
|         this.resumePageIdx = null; | ||||
| @ -137,8 +238,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(); | ||||
|       } | ||||
|     }, | ||||
| @ -233,6 +334,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++) { | ||||
|  | ||||
| @ -194,6 +194,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) { | ||||
|  | ||||
| @ -116,7 +116,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; | ||||
| @ -124,7 +125,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]; | ||||
| @ -147,7 +150,11 @@ var TextLayerBuilder = (function TextLayerBuilderClosure() { | ||||
|         }; | ||||
| 
 | ||||
|         // Calculate the end position.
 | ||||
|         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.
 | ||||
| @ -289,8 +296,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); | ||||
|     }, | ||||
| 
 | ||||
|  | ||||
		Loading…
	
	
			
			x
			
			
		
	
		Reference in New Issue
	
	Block a user