1 |
|
2 |
|
3 |
|
4 |
|
5 |
|
6 |
|
7 |
|
8 |
|
9 |
|
10 |
|
11 |
|
12 |
|
13 |
|
14 |
|
15 |
|
16 |
|
17 |
|
18 |
|
19 |
|
20 |
|
21 |
|
22 | 'use strict';
|
23 |
|
24 | Object.defineProperty(exports, "__esModule", {
|
25 | value: true
|
26 | });
|
27 | exports.PDFFindController = exports.FindState = undefined;
|
28 |
|
29 | var _createClass = function () { function defineProperties(target, props) { for (var i = 0; i < props.length; i++) { var descriptor = props[i]; descriptor.enumerable = descriptor.enumerable || false; descriptor.configurable = true; if ("value" in descriptor) descriptor.writable = true; Object.defineProperty(target, descriptor.key, descriptor); } } return function (Constructor, protoProps, staticProps) { if (protoProps) defineProperties(Constructor.prototype, protoProps); if (staticProps) defineProperties(Constructor, staticProps); return Constructor; }; }();
|
30 |
|
31 | var _pdf = require('../pdf');
|
32 |
|
33 | var _ui_utils = require('./ui_utils');
|
34 |
|
35 | function _classCallCheck(instance, Constructor) { if (!(instance instanceof Constructor)) { throw new TypeError("Cannot call a class as a function"); } }
|
36 |
|
37 | var FindState = {
|
38 | FOUND: 0,
|
39 | NOT_FOUND: 1,
|
40 | WRAPPED: 2,
|
41 | PENDING: 3
|
42 | };
|
43 | var FIND_SCROLL_OFFSET_TOP = -50;
|
44 | var FIND_SCROLL_OFFSET_LEFT = -400;
|
45 | var FIND_TIMEOUT = 250;
|
46 | var CHARACTERS_TO_NORMALIZE = {
|
47 | '\u2018': '\'',
|
48 | '\u2019': '\'',
|
49 | '\u201A': '\'',
|
50 | '\u201B': '\'',
|
51 | '\u201C': '"',
|
52 | '\u201D': '"',
|
53 | '\u201E': '"',
|
54 | '\u201F': '"',
|
55 | '\xBC': '1/4',
|
56 | '\xBD': '1/2',
|
57 | '\xBE': '3/4'
|
58 | };
|
59 |
|
60 | var PDFFindController = function () {
|
61 | function PDFFindController(_ref) {
|
62 | var pdfViewer = _ref.pdfViewer;
|
63 |
|
64 | _classCallCheck(this, PDFFindController);
|
65 |
|
66 | this.pdfViewer = pdfViewer;
|
67 | this.onUpdateResultsCount = null;
|
68 | this.onUpdateState = null;
|
69 | this.reset();
|
70 | var replace = Object.keys(CHARACTERS_TO_NORMALIZE).join('');
|
71 | this.normalizationRegex = new RegExp('[' + replace + ']', 'g');
|
72 | }
|
73 |
|
74 | _createClass(PDFFindController, [{
|
75 | key: 'reset',
|
76 | value: function reset() {
|
77 | var _this = this;
|
78 |
|
79 | this.startedTextExtraction = false;
|
80 | this.extractTextPromises = [];
|
81 | this.pendingFindMatches = Object.create(null);
|
82 | this.active = false;
|
83 | this.pageContents = [];
|
84 | this.pageMatches = [];
|
85 | this.pageMatchesLength = null;
|
86 | this.matchCount = 0;
|
87 | this.selected = {
|
88 | pageIdx: -1,
|
89 | matchIdx: -1
|
90 | };
|
91 | this.offset = {
|
92 | pageIdx: null,
|
93 | matchIdx: null
|
94 | };
|
95 | this.pagesToSearch = null;
|
96 | this.resumePageIdx = null;
|
97 | this.state = null;
|
98 | this.dirtyMatch = false;
|
99 | this.findTimeout = null;
|
100 | this._firstPagePromise = new Promise(function (resolve) {
|
101 | _this.resolveFirstPage = resolve;
|
102 | });
|
103 | }
|
104 | }, {
|
105 | key: 'executeCommand',
|
106 | value: function executeCommand(cmd, state) {
|
107 | var _this2 = this;
|
108 |
|
109 | if (this.state === null || cmd !== 'findagain') {
|
110 | this.dirtyMatch = true;
|
111 | }
|
112 | this.state = state;
|
113 | this._updateUIState(FindState.PENDING);
|
114 | this._firstPagePromise.then(function () {
|
115 | _this2._extractText();
|
116 | clearTimeout(_this2.findTimeout);
|
117 | if (cmd === 'find') {
|
118 | _this2.findTimeout = setTimeout(_this2._nextMatch.bind(_this2), FIND_TIMEOUT);
|
119 | } else {
|
120 | _this2._nextMatch();
|
121 | }
|
122 | });
|
123 | }
|
124 | }, {
|
125 | key: 'updateMatchPosition',
|
126 | value: function updateMatchPosition(pageIndex, matchIndex, elements, beginIdx) {
|
127 | if (this.selected.matchIdx === matchIndex && this.selected.pageIdx === pageIndex) {
|
128 | var spot = {
|
129 | top: FIND_SCROLL_OFFSET_TOP,
|
130 | left: FIND_SCROLL_OFFSET_LEFT
|
131 | };
|
132 | (0, _ui_utils.scrollIntoView)(elements[beginIdx], spot, true);
|
133 | }
|
134 | }
|
135 | }, {
|
136 | key: '_normalize',
|
137 | value: function _normalize(text) {
|
138 | return text.replace(this.normalizationRegex, function (ch) {
|
139 | return CHARACTERS_TO_NORMALIZE[ch];
|
140 | });
|
141 | }
|
142 | }, {
|
143 | key: '_prepareMatches',
|
144 | value: function _prepareMatches(matchesWithLength, matches, matchesLength) {
|
145 | function isSubTerm(matchesWithLength, currentIndex) {
|
146 | var currentElem = matchesWithLength[currentIndex];
|
147 | var nextElem = matchesWithLength[currentIndex + 1];
|
148 | if (currentIndex < matchesWithLength.length - 1 && currentElem.match === nextElem.match) {
|
149 | currentElem.skipped = true;
|
150 | return true;
|
151 | }
|
152 | for (var i = currentIndex - 1; i >= 0; i--) {
|
153 | var prevElem = matchesWithLength[i];
|
154 | if (prevElem.skipped) {
|
155 | continue;
|
156 | }
|
157 | if (prevElem.match + prevElem.matchLength < currentElem.match) {
|
158 | break;
|
159 | }
|
160 | if (prevElem.match + prevElem.matchLength >= currentElem.match + currentElem.matchLength) {
|
161 | currentElem.skipped = true;
|
162 | return true;
|
163 | }
|
164 | }
|
165 | return false;
|
166 | }
|
167 | matchesWithLength.sort(function (a, b) {
|
168 | return a.match === b.match ? a.matchLength - b.matchLength : a.match - b.match;
|
169 | });
|
170 | for (var i = 0, len = matchesWithLength.length; i < len; i++) {
|
171 | if (isSubTerm(matchesWithLength, i)) {
|
172 | continue;
|
173 | }
|
174 | matches.push(matchesWithLength[i].match);
|
175 | matchesLength.push(matchesWithLength[i].matchLength);
|
176 | }
|
177 | }
|
178 | }, {
|
179 | key: '_calculatePhraseMatch',
|
180 | value: function _calculatePhraseMatch(query, pageIndex, pageContent) {
|
181 | var matches = [];
|
182 | var queryLen = query.length;
|
183 | var matchIdx = -queryLen;
|
184 | while (true) {
|
185 | matchIdx = pageContent.indexOf(query, matchIdx + queryLen);
|
186 | if (matchIdx === -1) {
|
187 | break;
|
188 | }
|
189 | matches.push(matchIdx);
|
190 | }
|
191 | this.pageMatches[pageIndex] = matches;
|
192 | }
|
193 | }, {
|
194 | key: '_calculateWordMatch',
|
195 | value: function _calculateWordMatch(query, pageIndex, pageContent) {
|
196 | var matchesWithLength = [];
|
197 | var queryArray = query.match(/\S+/g);
|
198 | for (var i = 0, len = queryArray.length; i < len; i++) {
|
199 | var subquery = queryArray[i];
|
200 | var subqueryLen = subquery.length;
|
201 | var matchIdx = -subqueryLen;
|
202 | while (true) {
|
203 | matchIdx = pageContent.indexOf(subquery, matchIdx + subqueryLen);
|
204 | if (matchIdx === -1) {
|
205 | break;
|
206 | }
|
207 | matchesWithLength.push({
|
208 | match: matchIdx,
|
209 | matchLength: subqueryLen,
|
210 | skipped: false
|
211 | });
|
212 | }
|
213 | }
|
214 | if (!this.pageMatchesLength) {
|
215 | this.pageMatchesLength = [];
|
216 | }
|
217 | this.pageMatchesLength[pageIndex] = [];
|
218 | this.pageMatches[pageIndex] = [];
|
219 | this._prepareMatches(matchesWithLength, this.pageMatches[pageIndex], this.pageMatchesLength[pageIndex]);
|
220 | }
|
221 | }, {
|
222 | key: '_calculateMatch',
|
223 | value: function _calculateMatch(pageIndex) {
|
224 | var pageContent = this._normalize(this.pageContents[pageIndex]);
|
225 | var query = this._normalize(this.state.query);
|
226 | var caseSensitive = this.state.caseSensitive;
|
227 | var phraseSearch = this.state.phraseSearch;
|
228 | var queryLen = query.length;
|
229 | if (queryLen === 0) {
|
230 | return;
|
231 | }
|
232 | if (!caseSensitive) {
|
233 | pageContent = pageContent.toLowerCase();
|
234 | query = query.toLowerCase();
|
235 | }
|
236 | if (phraseSearch) {
|
237 | this._calculatePhraseMatch(query, pageIndex, pageContent);
|
238 | } else {
|
239 | this._calculateWordMatch(query, pageIndex, pageContent);
|
240 | }
|
241 | this._updatePage(pageIndex);
|
242 | if (this.resumePageIdx === pageIndex) {
|
243 | this.resumePageIdx = null;
|
244 | this._nextPageMatch();
|
245 | }
|
246 | if (this.pageMatches[pageIndex].length > 0) {
|
247 | this.matchCount += this.pageMatches[pageIndex].length;
|
248 | this._updateUIResultsCount();
|
249 | }
|
250 | }
|
251 | }, {
|
252 | key: '_extractText',
|
253 | value: function _extractText() {
|
254 | var _this3 = this;
|
255 |
|
256 | if (this.startedTextExtraction) {
|
257 | return;
|
258 | }
|
259 | this.startedTextExtraction = true;
|
260 | this.pageContents.length = 0;
|
261 | var promise = Promise.resolve();
|
262 |
|
263 | var _loop = function _loop(i, ii) {
|
264 | var extractTextCapability = (0, _pdf.createPromiseCapability)();
|
265 | _this3.extractTextPromises[i] = extractTextCapability.promise;
|
266 | promise = promise.then(function () {
|
267 | return _this3.pdfViewer.getPageTextContent(i).then(function (textContent) {
|
268 | var textItems = textContent.items;
|
269 | var strBuf = [];
|
270 | for (var j = 0, jj = textItems.length; j < jj; j++) {
|
271 | strBuf.push(textItems[j].str);
|
272 | }
|
273 | _this3.pageContents[i] = strBuf.join('');
|
274 | extractTextCapability.resolve(i);
|
275 | }, function (reason) {
|
276 | console.error('Unable to get page ' + (i + 1) + ' text content', reason);
|
277 | _this3.pageContents[i] = '';
|
278 | extractTextCapability.resolve(i);
|
279 | });
|
280 | });
|
281 | };
|
282 |
|
283 | for (var i = 0, ii = this.pdfViewer.pagesCount; i < ii; i++) {
|
284 | _loop(i, ii);
|
285 | }
|
286 | }
|
287 | }, {
|
288 | key: '_updatePage',
|
289 | value: function _updatePage(index) {
|
290 | if (this.selected.pageIdx === index) {
|
291 | this.pdfViewer.currentPageNumber = index + 1;
|
292 | }
|
293 | var page = this.pdfViewer.getPageView(index);
|
294 | if (page.textLayer) {
|
295 | page.textLayer.updateMatches();
|
296 | }
|
297 | }
|
298 | }, {
|
299 | key: '_nextMatch',
|
300 | value: function _nextMatch() {
|
301 | var _this4 = this;
|
302 |
|
303 | var previous = this.state.findPrevious;
|
304 | var currentPageIndex = this.pdfViewer.currentPageNumber - 1;
|
305 | var numPages = this.pdfViewer.pagesCount;
|
306 | this.active = true;
|
307 | if (this.dirtyMatch) {
|
308 | this.dirtyMatch = false;
|
309 | this.selected.pageIdx = this.selected.matchIdx = -1;
|
310 | this.offset.pageIdx = currentPageIndex;
|
311 | this.offset.matchIdx = null;
|
312 | this.hadMatch = false;
|
313 | this.resumePageIdx = null;
|
314 | this.pageMatches = [];
|
315 | this.matchCount = 0;
|
316 | this.pageMatchesLength = null;
|
317 | for (var i = 0; i < numPages; i++) {
|
318 | this._updatePage(i);
|
319 | if (!(i in this.pendingFindMatches)) {
|
320 | this.pendingFindMatches[i] = true;
|
321 | this.extractTextPromises[i].then(function (pageIdx) {
|
322 | delete _this4.pendingFindMatches[pageIdx];
|
323 | _this4._calculateMatch(pageIdx);
|
324 | });
|
325 | }
|
326 | }
|
327 | }
|
328 | if (this.state.query === '') {
|
329 | this._updateUIState(FindState.FOUND);
|
330 | return;
|
331 | }
|
332 | if (this.resumePageIdx) {
|
333 | return;
|
334 | }
|
335 | var offset = this.offset;
|
336 | this.pagesToSearch = numPages;
|
337 | if (offset.matchIdx !== null) {
|
338 | var numPageMatches = this.pageMatches[offset.pageIdx].length;
|
339 | if (!previous && offset.matchIdx + 1 < numPageMatches || previous && offset.matchIdx > 0) {
|
340 | this.hadMatch = true;
|
341 | offset.matchIdx = previous ? offset.matchIdx - 1 : offset.matchIdx + 1;
|
342 | this._updateMatch(true);
|
343 | return;
|
344 | }
|
345 | this._advanceOffsetPage(previous);
|
346 | }
|
347 | this._nextPageMatch();
|
348 | }
|
349 | }, {
|
350 | key: '_matchesReady',
|
351 | value: function _matchesReady(matches) {
|
352 | var offset = this.offset;
|
353 | var numMatches = matches.length;
|
354 | var previous = this.state.findPrevious;
|
355 | if (numMatches) {
|
356 | this.hadMatch = true;
|
357 | offset.matchIdx = previous ? numMatches - 1 : 0;
|
358 | this._updateMatch(true);
|
359 | return true;
|
360 | }
|
361 | this._advanceOffsetPage(previous);
|
362 | if (offset.wrapped) {
|
363 | offset.matchIdx = null;
|
364 | if (this.pagesToSearch < 0) {
|
365 | this._updateMatch(false);
|
366 | return true;
|
367 | }
|
368 | }
|
369 | return false;
|
370 | }
|
371 | }, {
|
372 | key: '_nextPageMatch',
|
373 | value: function _nextPageMatch() {
|
374 | if (this.resumePageIdx !== null) {
|
375 | console.error('There can only be one pending page.');
|
376 | }
|
377 | var matches = null;
|
378 | do {
|
379 | var pageIdx = this.offset.pageIdx;
|
380 | matches = this.pageMatches[pageIdx];
|
381 | if (!matches) {
|
382 | this.resumePageIdx = pageIdx;
|
383 | break;
|
384 | }
|
385 | } while (!this._matchesReady(matches));
|
386 | }
|
387 | }, {
|
388 | key: '_advanceOffsetPage',
|
389 | value: function _advanceOffsetPage(previous) {
|
390 | var offset = this.offset;
|
391 | var numPages = this.extractTextPromises.length;
|
392 | offset.pageIdx = previous ? offset.pageIdx - 1 : offset.pageIdx + 1;
|
393 | offset.matchIdx = null;
|
394 | this.pagesToSearch--;
|
395 | if (offset.pageIdx >= numPages || offset.pageIdx < 0) {
|
396 | offset.pageIdx = previous ? numPages - 1 : 0;
|
397 | offset.wrapped = true;
|
398 | }
|
399 | }
|
400 | }, {
|
401 | key: '_updateMatch',
|
402 | value: function _updateMatch() {
|
403 | var found = arguments.length > 0 && arguments[0] !== undefined ? arguments[0] : false;
|
404 |
|
405 | var state = FindState.NOT_FOUND;
|
406 | var wrapped = this.offset.wrapped;
|
407 | this.offset.wrapped = false;
|
408 | if (found) {
|
409 | var previousPage = this.selected.pageIdx;
|
410 | this.selected.pageIdx = this.offset.pageIdx;
|
411 | this.selected.matchIdx = this.offset.matchIdx;
|
412 | state = wrapped ? FindState.WRAPPED : FindState.FOUND;
|
413 | if (previousPage !== -1 && previousPage !== this.selected.pageIdx) {
|
414 | this._updatePage(previousPage);
|
415 | }
|
416 | }
|
417 | this._updateUIState(state, this.state.findPrevious);
|
418 | if (this.selected.pageIdx !== -1) {
|
419 | this._updatePage(this.selected.pageIdx);
|
420 | }
|
421 | }
|
422 | }, {
|
423 | key: '_updateUIResultsCount',
|
424 | value: function _updateUIResultsCount() {
|
425 | if (this.onUpdateResultsCount) {
|
426 | this.onUpdateResultsCount(this.matchCount);
|
427 | }
|
428 | }
|
429 | }, {
|
430 | key: '_updateUIState',
|
431 | value: function _updateUIState(state, previous) {
|
432 | if (this.onUpdateState) {
|
433 | this.onUpdateState(state, previous, this.matchCount);
|
434 | }
|
435 | }
|
436 | }]);
|
437 |
|
438 | return PDFFindController;
|
439 | }();
|
440 |
|
441 | exports.FindState = FindState;
|
442 | exports.PDFFindController = PDFFindController; |
\ | No newline at end of file |