viewerjs-rails 0.0.1 → 0.0.2

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
@@ -27,149 +27,151 @@
27
27
  */
28
28
  var PDFFindBar = {
29
29
 
30
- opened: false,
31
- bar: null,
32
- toggleButton: null,
33
- findField: null,
34
- highlightAll: null,
35
- caseSensitive: null,
36
- findMsg: null,
37
- findStatusIcon: null,
38
- findPreviousButton: null,
39
- findNextButton: null,
40
-
41
- initialize: function(options) {
42
- if(typeof PDFFindController === 'undefined' || PDFFindController === null) {
43
- throw 'PDFFindBar cannot be initialized ' +
44
- 'without a PDFFindController instance.';
45
- }
30
+ opened: false,
31
+ bar: null,
32
+ toggleButton: null,
33
+ findField: null,
34
+ highlightAll: null,
35
+ caseSensitive: null,
36
+ findMsg: null,
37
+ findStatusIcon: null,
38
+ findPreviousButton: null,
39
+ findNextButton: null,
40
+
41
+ initialize: function (options) {
42
+ if (typeof PDFFindController === 'undefined' || PDFFindController === null) {
43
+ throw 'PDFFindBar cannot be initialized ' +
44
+ 'without a PDFFindController instance.';
45
+ }
46
46
 
47
- this.bar = options.bar;
48
- this.toggleButton = options.toggleButton;
49
- this.findField = options.findField;
50
- this.highlightAll = options.highlightAllCheckbox;
51
- this.caseSensitive = options.caseSensitiveCheckbox;
52
- this.findMsg = options.findMsg;
53
- this.findStatusIcon = options.findStatusIcon;
54
- this.findPreviousButton = options.findPreviousButton;
55
- this.findNextButton = options.findNextButton;
56
-
57
- var self = this;
58
- this.toggleButton.addEventListener('click', function() {
59
- self.toggle();
60
- });
61
-
62
- this.findField.addEventListener('input', function() {
63
- self.dispatchEvent('');
64
- });
65
-
66
- this.bar.addEventListener('keydown', function(evt) {
67
- switch (evt.keyCode) {
68
- case 13: // Enter
69
- if (evt.target === self.findField) {
70
- self.dispatchEvent('again', evt.shiftKey);
71
- }
72
- break;
73
- case 27: // Escape
74
- self.close();
75
- break;
76
- }
77
- });
78
-
79
- this.findPreviousButton.addEventListener('click',
80
- function() { self.dispatchEvent('again', true); }
81
- );
82
-
83
- this.findNextButton.addEventListener('click', function() {
84
- self.dispatchEvent('again', false);
85
- });
86
-
87
- this.highlightAll.addEventListener('click', function() {
88
- self.dispatchEvent('highlightallchange');
89
- });
90
-
91
- this.caseSensitive.addEventListener('click', function() {
92
- self.dispatchEvent('casesensitivitychange');
93
- });
94
- },
95
-
96
- dispatchEvent: function(aType, aFindPrevious) {
97
- var event = document.createEvent('CustomEvent');
98
- event.initCustomEvent('find' + aType, true, true, {
99
- query: this.findField.value,
100
- caseSensitive: this.caseSensitive.checked,
101
- highlightAll: this.highlightAll.checked,
102
- findPrevious: aFindPrevious
103
- });
104
- return window.dispatchEvent(event);
105
- },
106
-
107
- updateUIState: function(state, previous) {
108
- var notFound = false;
109
- var findMsg = '';
110
- var status = '';
111
-
112
- switch (state) {
113
- case FindStates.FIND_FOUND:
114
- break;
115
-
116
- case FindStates.FIND_PENDING:
117
- status = 'pending';
118
- break;
119
-
120
- case FindStates.FIND_NOTFOUND:
121
- findMsg = mozL10n.get('find_not_found', null, 'Phrase not found');
122
- notFound = true;
123
- break;
124
-
125
- case FindStates.FIND_WRAPPED:
126
- if (previous) {
127
- findMsg = mozL10n.get('find_reached_top', null,
128
- 'Reached top of document, continued from bottom');
129
- } else {
130
- findMsg = mozL10n.get('find_reached_bottom', null,
131
- 'Reached end of document, continued from top');
47
+ this.bar = options.bar;
48
+ this.toggleButton = options.toggleButton;
49
+ this.findField = options.findField;
50
+ this.highlightAll = options.highlightAllCheckbox;
51
+ this.caseSensitive = options.caseSensitiveCheckbox;
52
+ this.findMsg = options.findMsg;
53
+ this.findStatusIcon = options.findStatusIcon;
54
+ this.findPreviousButton = options.findPreviousButton;
55
+ this.findNextButton = options.findNextButton;
56
+
57
+ var self = this;
58
+ this.toggleButton.addEventListener('click', function () {
59
+ self.toggle();
60
+ });
61
+
62
+ this.findField.addEventListener('input', function () {
63
+ self.dispatchEvent('');
64
+ });
65
+
66
+ this.bar.addEventListener('keydown', function (evt) {
67
+ switch (evt.keyCode) {
68
+ case 13: // Enter
69
+ if (evt.target === self.findField) {
70
+ self.dispatchEvent('again', evt.shiftKey);
71
+ }
72
+ break;
73
+ case 27: // Escape
74
+ self.close();
75
+ break;
76
+ }
77
+ });
78
+
79
+ this.findPreviousButton.addEventListener('click',
80
+ function () {
81
+ self.dispatchEvent('again', true);
82
+ }
83
+ );
84
+
85
+ this.findNextButton.addEventListener('click', function () {
86
+ self.dispatchEvent('again', false);
87
+ });
88
+
89
+ this.highlightAll.addEventListener('click', function () {
90
+ self.dispatchEvent('highlightallchange');
91
+ });
92
+
93
+ this.caseSensitive.addEventListener('click', function () {
94
+ self.dispatchEvent('casesensitivitychange');
95
+ });
96
+ },
97
+
98
+ dispatchEvent: function (aType, aFindPrevious) {
99
+ var event = document.createEvent('CustomEvent');
100
+ event.initCustomEvent('find' + aType, true, true, {
101
+ query: this.findField.value,
102
+ caseSensitive: this.caseSensitive.checked,
103
+ highlightAll: this.highlightAll.checked,
104
+ findPrevious: aFindPrevious
105
+ });
106
+ return window.dispatchEvent(event);
107
+ },
108
+
109
+ updateUIState: function (state, previous) {
110
+ var notFound = false;
111
+ var findMsg = '';
112
+ var status = '';
113
+
114
+ switch (state) {
115
+ case FindStates.FIND_FOUND:
116
+ break;
117
+
118
+ case FindStates.FIND_PENDING:
119
+ status = 'pending';
120
+ break;
121
+
122
+ case FindStates.FIND_NOTFOUND:
123
+ findMsg = mozL10n.get('find_not_found', null, 'Phrase not found');
124
+ notFound = true;
125
+ break;
126
+
127
+ case FindStates.FIND_WRAPPED:
128
+ if (previous) {
129
+ findMsg = mozL10n.get('find_reached_top', null,
130
+ 'Reached top of document, continued from bottom');
131
+ } else {
132
+ findMsg = mozL10n.get('find_reached_bottom', null,
133
+ 'Reached end of document, continued from top');
134
+ }
135
+ break;
132
136
  }
133
- break;
134
- }
135
137
 
136
- if (notFound) {
137
- this.findField.classList.add('notFound');
138
- } else {
139
- this.findField.classList.remove('notFound');
140
- }
138
+ if (notFound) {
139
+ this.findField.classList.add('notFound');
140
+ } else {
141
+ this.findField.classList.remove('notFound');
142
+ }
141
143
 
142
- this.findField.setAttribute('data-status', status);
143
- this.findMsg.textContent = findMsg;
144
- },
144
+ this.findField.setAttribute('data-status', status);
145
+ this.findMsg.textContent = findMsg;
146
+ },
145
147
 
146
- open: function() {
147
- if (!this.opened) {
148
- this.opened = true;
149
- this.toggleButton.classList.add('toggled');
150
- this.bar.classList.remove('hidden');
151
- }
148
+ open: function () {
149
+ if (!this.opened) {
150
+ this.opened = true;
151
+ this.toggleButton.classList.add('toggled');
152
+ this.bar.classList.remove('hidden');
153
+ }
152
154
 
153
- this.findField.select();
154
- this.findField.focus();
155
- },
155
+ this.findField.select();
156
+ this.findField.focus();
157
+ },
156
158
 
157
- close: function() {
158
- if (!this.opened) return;
159
+ close: function () {
160
+ if (!this.opened) return;
159
161
 
160
- this.opened = false;
161
- this.toggleButton.classList.remove('toggled');
162
- this.bar.classList.add('hidden');
162
+ this.opened = false;
163
+ this.toggleButton.classList.remove('toggled');
164
+ this.bar.classList.add('hidden');
163
165
 
164
- PDFFindController.active = false;
165
- },
166
+ PDFFindController.active = false;
167
+ },
166
168
 
167
- toggle: function() {
168
- if (this.opened) {
169
- this.close();
170
- } else {
171
- this.open();
169
+ toggle: function () {
170
+ if (this.opened) {
171
+ this.close();
172
+ } else {
173
+ this.open();
174
+ }
172
175
  }
173
- }
174
176
  };
175
177
 
@@ -24,332 +24,334 @@
24
24
  */
25
25
 
26
26
  var PDFFindController = {
27
- startedTextExtraction: false,
27
+ startedTextExtraction: false,
28
28
 
29
- extractTextPromises: [],
29
+ extractTextPromises: [],
30
30
 
31
- pendingFindMatches: {},
31
+ pendingFindMatches: {},
32
32
 
33
- // If active, find results will be highlighted.
34
- active: false,
33
+ // If active, find results will be highlighted.
34
+ active: false,
35
35
 
36
- // Stores the text for each page.
37
- pageContents: [],
36
+ // Stores the text for each page.
37
+ pageContents: [],
38
38
 
39
- pageMatches: [],
39
+ pageMatches: [],
40
40
 
41
- // Currently selected match.
42
- selected: {
43
- pageIdx: -1,
44
- matchIdx: -1
45
- },
41
+ // Currently selected match.
42
+ selected: {
43
+ pageIdx: -1,
44
+ matchIdx: -1
45
+ },
46
46
 
47
- // Where find algorithm currently is in the document.
48
- offset: {
49
- pageIdx: null,
50
- matchIdx: null
51
- },
47
+ // Where find algorithm currently is in the document.
48
+ offset: {
49
+ pageIdx: null,
50
+ matchIdx: null
51
+ },
52
52
 
53
- resumePageIdx: null,
53
+ resumePageIdx: null,
54
54
 
55
- state: null,
55
+ state: null,
56
56
 
57
- dirtyMatch: false,
57
+ dirtyMatch: false,
58
58
 
59
- findTimeout: null,
59
+ findTimeout: null,
60
60
 
61
- pdfPageSource: null,
61
+ pdfPageSource: null,
62
62
 
63
- integratedFind: false,
63
+ integratedFind: false,
64
64
 
65
- initialize: function(options) {
66
- if(typeof PDFFindBar === 'undefined' || PDFFindBar === null) {
67
- throw 'PDFFindController cannot be initialized ' +
68
- 'without a PDFFindController instance';
69
- }
65
+ initialize: function (options) {
66
+ if (typeof PDFFindBar === 'undefined' || PDFFindBar === null) {
67
+ throw 'PDFFindController cannot be initialized ' +
68
+ 'without a PDFFindController instance';
69
+ }
70
70
 
71
- this.pdfPageSource = options.pdfPageSource;
72
- this.integratedFind = options.integratedFind;
71
+ this.pdfPageSource = options.pdfPageSource;
72
+ this.integratedFind = options.integratedFind;
73
73
 
74
- var events = [
75
- 'find',
76
- 'findagain',
77
- 'findhighlightallchange',
78
- 'findcasesensitivitychange'
79
- ];
74
+ var events = [
75
+ 'find',
76
+ 'findagain',
77
+ 'findhighlightallchange',
78
+ 'findcasesensitivitychange'
79
+ ];
80
80
 
81
- this.firstPagePromise = new Promise(function (resolve) {
82
- this.resolveFirstPage = resolve;
83
- }.bind(this));
84
- this.handleEvent = this.handleEvent.bind(this);
81
+ this.firstPagePromise = new Promise(function (resolve) {
82
+ this.resolveFirstPage = resolve;
83
+ }.bind(this));
84
+ this.handleEvent = this.handleEvent.bind(this);
85
85
 
86
- for (var i = 0; i < events.length; i++) {
87
- window.addEventListener(events[i], this.handleEvent);
88
- }
89
- },
90
-
91
- reset: function pdfFindControllerReset() {
92
- this.startedTextExtraction = false;
93
- this.extractTextPromises = [];
94
- this.active = false;
95
- },
96
-
97
- calcFindMatch: function(pageIndex) {
98
- var pageContent = this.pageContents[pageIndex];
99
- var query = this.state.query;
100
- var caseSensitive = this.state.caseSensitive;
101
- var queryLen = query.length;
102
-
103
- if (queryLen === 0) {
104
- // Do nothing the matches should be wiped out already.
105
- return;
106
- }
86
+ for (var i = 0; i < events.length; i++) {
87
+ window.addEventListener(events[i], this.handleEvent);
88
+ }
89
+ },
90
+
91
+ reset: function pdfFindControllerReset() {
92
+ this.startedTextExtraction = false;
93
+ this.extractTextPromises = [];
94
+ this.active = false;
95
+ },
96
+
97
+ calcFindMatch: function (pageIndex) {
98
+ var pageContent = this.pageContents[pageIndex];
99
+ var query = this.state.query;
100
+ var caseSensitive = this.state.caseSensitive;
101
+ var queryLen = query.length;
102
+
103
+ if (queryLen === 0) {
104
+ // Do nothing the matches should be wiped out already.
105
+ return;
106
+ }
107
107
 
108
- if (!caseSensitive) {
109
- pageContent = pageContent.toLowerCase();
110
- query = query.toLowerCase();
111
- }
108
+ if (!caseSensitive) {
109
+ pageContent = pageContent.toLowerCase();
110
+ query = query.toLowerCase();
111
+ }
112
112
 
113
- var matches = [];
113
+ var matches = [];
114
114
 
115
- var matchIdx = -queryLen;
116
- while (true) {
117
- matchIdx = pageContent.indexOf(query, matchIdx + queryLen);
118
- if (matchIdx === -1) {
119
- break;
120
- }
115
+ var matchIdx = -queryLen;
116
+ while (true) {
117
+ matchIdx = pageContent.indexOf(query, matchIdx + queryLen);
118
+ if (matchIdx === -1) {
119
+ break;
120
+ }
121
121
 
122
- matches.push(matchIdx);
123
- }
124
- this.pageMatches[pageIndex] = matches;
125
- this.updatePage(pageIndex);
126
- if (this.resumePageIdx === pageIndex) {
127
- this.resumePageIdx = null;
128
- this.nextPageMatch();
129
- }
130
- },
122
+ matches.push(matchIdx);
123
+ }
124
+ this.pageMatches[pageIndex] = matches;
125
+ this.updatePage(pageIndex);
126
+ if (this.resumePageIdx === pageIndex) {
127
+ this.resumePageIdx = null;
128
+ this.nextPageMatch();
129
+ }
130
+ },
131
131
 
132
- extractText: function() {
133
- if (this.startedTextExtraction) {
134
- return;
135
- }
136
- this.startedTextExtraction = true;
137
-
138
- this.pageContents = [];
139
- var extractTextPromisesResolves = [];
140
- for (var i = 0, ii = this.pdfPageSource.pdfDocument.numPages; i < ii; i++) {
141
- this.extractTextPromises.push(new Promise(function (resolve) {
142
- extractTextPromisesResolves.push(resolve);
143
- }));
144
- }
132
+ extractText: function () {
133
+ if (this.startedTextExtraction) {
134
+ return;
135
+ }
136
+ this.startedTextExtraction = true;
137
+
138
+ this.pageContents = [];
139
+ var extractTextPromisesResolves = [];
140
+ for (var i = 0, ii = this.pdfPageSource.pdfDocument.numPages; i < ii; i++) {
141
+ this.extractTextPromises.push(new Promise(function (resolve) {
142
+ extractTextPromisesResolves.push(resolve);
143
+ }));
144
+ }
145
+
146
+ var self = this;
145
147
 
146
- var self = this;
147
- function extractPageText(pageIndex) {
148
- self.pdfPageSource.pages[pageIndex].getTextContent().then(
149
- function textContentResolved(bidiTexts) {
150
- var str = '';
148
+ function extractPageText(pageIndex) {
149
+ self.pdfPageSource.pages[pageIndex].getTextContent().then(
150
+ function textContentResolved(bidiTexts) {
151
+ var str = '';
151
152
 
152
- for (var i = 0; i < bidiTexts.length; i++) {
153
- str += bidiTexts[i].str;
154
- }
153
+ for (var i = 0; i < bidiTexts.length; i++) {
154
+ str += bidiTexts[i].str;
155
+ }
155
156
 
156
- // Store the pageContent as a string.
157
- self.pageContents.push(str);
157
+ // Store the pageContent as a string.
158
+ self.pageContents.push(str);
158
159
 
159
- extractTextPromisesResolves[pageIndex](pageIndex);
160
- if ((pageIndex + 1) < self.pdfPageSource.pages.length)
161
- extractPageText(pageIndex + 1);
160
+ extractTextPromisesResolves[pageIndex](pageIndex);
161
+ if ((pageIndex + 1) < self.pdfPageSource.pages.length)
162
+ extractPageText(pageIndex + 1);
163
+ }
164
+ );
162
165
  }
163
- );
164
- }
165
- extractPageText(0);
166
- },
167
166
 
168
- handleEvent: function(e) {
169
- if (this.state === null || e.type !== 'findagain') {
170
- this.dirtyMatch = true;
171
- }
172
- this.state = e.detail;
173
- this.updateUIState(FindStates.FIND_PENDING);
174
-
175
- this.firstPagePromise.then(function() {
176
- this.extractText();
177
-
178
- clearTimeout(this.findTimeout);
179
- if (e.type === 'find') {
180
- // Only trigger the find action after 250ms of silence.
181
- this.findTimeout = setTimeout(this.nextMatch.bind(this), 250);
182
- } else {
183
- this.nextMatch();
184
- }
185
- }.bind(this));
186
- },
187
-
188
- updatePage: function(idx) {
189
- var page = this.pdfPageSource.pages[idx];
190
-
191
- if (this.selected.pageIdx === idx) {
192
- // If the page is selected, scroll the page into view, which triggers
193
- // rendering the page, which adds the textLayer. Once the textLayer is
194
- // build, it will scroll onto the selected match.
195
- page.scrollIntoView();
196
- }
167
+ extractPageText(0);
168
+ },
197
169
 
198
- if (page.textLayer) {
199
- page.textLayer.updateMatches();
200
- }
201
- },
202
-
203
- nextMatch: function() {
204
- var previous = this.state.findPrevious;
205
- var currentPageIndex = this.pdfPageSource.page - 1;
206
- var numPages = this.pdfPageSource.pages.length;
207
-
208
- this.active = true;
209
-
210
- if (this.dirtyMatch) {
211
- // Need to recalculate the matches, reset everything.
212
- this.dirtyMatch = false;
213
- this.selected.pageIdx = this.selected.matchIdx = -1;
214
- this.offset.pageIdx = currentPageIndex;
215
- this.offset.matchIdx = null;
216
- this.hadMatch = false;
217
- this.resumePageIdx = null;
218
- this.pageMatches = [];
219
- var self = this;
220
-
221
- for (var i = 0; i < numPages; i++) {
222
- // Wipe out any previous highlighted matches.
223
- this.updatePage(i);
224
-
225
- // As soon as the text is extracted start finding the matches.
226
- if (!(i in this.pendingFindMatches)) {
227
- this.pendingFindMatches[i] = true;
228
- this.extractTextPromises[i].then(function(pageIdx) {
229
- delete self.pendingFindMatches[pageIdx];
230
- self.calcFindMatch(pageIdx);
231
- });
170
+ handleEvent: function (e) {
171
+ if (this.state === null || e.type !== 'findagain') {
172
+ this.dirtyMatch = true;
173
+ }
174
+ this.state = e.detail;
175
+ this.updateUIState(FindStates.FIND_PENDING);
176
+
177
+ this.firstPagePromise.then(function () {
178
+ this.extractText();
179
+
180
+ clearTimeout(this.findTimeout);
181
+ if (e.type === 'find') {
182
+ // Only trigger the find action after 250ms of silence.
183
+ this.findTimeout = setTimeout(this.nextMatch.bind(this), 250);
184
+ } else {
185
+ this.nextMatch();
186
+ }
187
+ }.bind(this));
188
+ },
189
+
190
+ updatePage: function (idx) {
191
+ var page = this.pdfPageSource.pages[idx];
192
+
193
+ if (this.selected.pageIdx === idx) {
194
+ // If the page is selected, scroll the page into view, which triggers
195
+ // rendering the page, which adds the textLayer. Once the textLayer is
196
+ // build, it will scroll onto the selected match.
197
+ page.scrollIntoView();
232
198
  }
233
- }
234
- }
235
199
 
236
- // If there's no query there's no point in searching.
237
- if (this.state.query === '') {
238
- this.updateUIState(FindStates.FIND_FOUND);
239
- return;
240
- }
200
+ if (page.textLayer) {
201
+ page.textLayer.updateMatches();
202
+ }
203
+ },
204
+
205
+ nextMatch: function () {
206
+ var previous = this.state.findPrevious;
207
+ var currentPageIndex = this.pdfPageSource.page - 1;
208
+ var numPages = this.pdfPageSource.pages.length;
209
+
210
+ this.active = true;
211
+
212
+ if (this.dirtyMatch) {
213
+ // Need to recalculate the matches, reset everything.
214
+ this.dirtyMatch = false;
215
+ this.selected.pageIdx = this.selected.matchIdx = -1;
216
+ this.offset.pageIdx = currentPageIndex;
217
+ this.offset.matchIdx = null;
218
+ this.hadMatch = false;
219
+ this.resumePageIdx = null;
220
+ this.pageMatches = [];
221
+ var self = this;
222
+
223
+ for (var i = 0; i < numPages; i++) {
224
+ // Wipe out any previous highlighted matches.
225
+ this.updatePage(i);
226
+
227
+ // As soon as the text is extracted start finding the matches.
228
+ if (!(i in this.pendingFindMatches)) {
229
+ this.pendingFindMatches[i] = true;
230
+ this.extractTextPromises[i].then(function (pageIdx) {
231
+ delete self.pendingFindMatches[pageIdx];
232
+ self.calcFindMatch(pageIdx);
233
+ });
234
+ }
235
+ }
236
+ }
241
237
 
242
- // If we're waiting on a page, we return since we can't do anything else.
243
- if (this.resumePageIdx) {
244
- return;
245
- }
238
+ // If there's no query there's no point in searching.
239
+ if (this.state.query === '') {
240
+ this.updateUIState(FindStates.FIND_FOUND);
241
+ return;
242
+ }
246
243
 
247
- var offset = this.offset;
248
- // If there's already a matchIdx that means we are iterating through a
249
- // page's matches.
250
- if (offset.matchIdx !== null) {
251
- var numPageMatches = this.pageMatches[offset.pageIdx].length;
252
- if ((!previous && offset.matchIdx + 1 < numPageMatches) ||
253
- (previous && offset.matchIdx > 0)) {
254
- // The simple case, we just have advance the matchIdx to select the next
255
- // match on the page.
256
- this.hadMatch = true;
257
- offset.matchIdx = previous ? offset.matchIdx - 1 : offset.matchIdx + 1;
258
- this.updateMatch(true);
259
- return;
260
- }
261
- // We went beyond the current page's matches, so we advance to the next
262
- // page.
263
- this.advanceOffsetPage(previous);
264
- }
265
- // Start searching through the page.
266
- this.nextPageMatch();
267
- },
268
-
269
- matchesReady: function(matches) {
270
- var offset = this.offset;
271
- var numMatches = matches.length;
272
- var previous = this.state.findPrevious;
273
- if (numMatches) {
274
- // There were matches for the page, so initialize the matchIdx.
275
- this.hadMatch = true;
276
- offset.matchIdx = previous ? numMatches - 1 : 0;
277
- this.updateMatch(true);
278
- // matches were found
279
- return true;
280
- } else {
281
- // No matches attempt to search the next page.
282
- this.advanceOffsetPage(previous);
283
- if (offset.wrapped) {
284
- offset.matchIdx = null;
285
- if (!this.hadMatch) {
286
- // No point in wrapping there were no matches.
287
- this.updateMatch(false);
288
- // while matches were not found, searching for a page
289
- // with matches should nevertheless halt.
290
- return true;
244
+ // If we're waiting on a page, we return since we can't do anything else.
245
+ if (this.resumePageIdx) {
246
+ return;
291
247
  }
292
- }
293
- // matches were not found (and searching is not done)
294
- return false;
295
- }
296
- },
297
248
 
298
- nextPageMatch: function() {
299
- if (this.resumePageIdx !== null) {
300
- console.error('There can only be one pending page.');
301
- }
302
- do {
303
- var pageIdx = this.offset.pageIdx;
304
- var matches = this.pageMatches[pageIdx];
305
- if (!matches) {
306
- // The matches don't exist yet for processing by "matchesReady",
307
- // so set a resume point for when they do exist.
308
- this.resumePageIdx = pageIdx;
309
- break;
310
- }
311
- } while (!this.matchesReady(matches));
312
- },
313
-
314
- advanceOffsetPage: function(previous) {
315
- var offset = this.offset;
316
- var numPages = this.extractTextPromises.length;
317
- offset.pageIdx = previous ? offset.pageIdx - 1 : offset.pageIdx + 1;
318
- offset.matchIdx = null;
319
- if (offset.pageIdx >= numPages || offset.pageIdx < 0) {
320
- offset.pageIdx = previous ? numPages - 1 : 0;
321
- offset.wrapped = true;
322
- return;
323
- }
324
- },
325
-
326
- updateMatch: function(found) {
327
- var state = FindStates.FIND_NOTFOUND;
328
- var wrapped = this.offset.wrapped;
329
- this.offset.wrapped = false;
330
- if (found) {
331
- var previousPage = this.selected.pageIdx;
332
- this.selected.pageIdx = this.offset.pageIdx;
333
- this.selected.matchIdx = this.offset.matchIdx;
334
- state = wrapped ? FindStates.FIND_WRAPPED : FindStates.FIND_FOUND;
335
- // Update the currently selected page to wipe out any selected matches.
336
- if (previousPage !== -1 && previousPage !== this.selected.pageIdx) {
337
- this.updatePage(previousPage);
338
- }
339
- }
340
- this.updateUIState(state, this.state.findPrevious);
341
- if (this.selected.pageIdx !== -1) {
342
- this.updatePage(this.selected.pageIdx, true);
343
- }
344
- },
249
+ var offset = this.offset;
250
+ // If there's already a matchIdx that means we are iterating through a
251
+ // page's matches.
252
+ if (offset.matchIdx !== null) {
253
+ var numPageMatches = this.pageMatches[offset.pageIdx].length;
254
+ if ((!previous && offset.matchIdx + 1 < numPageMatches) ||
255
+ (previous && offset.matchIdx > 0)) {
256
+ // The simple case, we just have advance the matchIdx to select the next
257
+ // match on the page.
258
+ this.hadMatch = true;
259
+ offset.matchIdx = previous ? offset.matchIdx - 1 : offset.matchIdx + 1;
260
+ this.updateMatch(true);
261
+ return;
262
+ }
263
+ // We went beyond the current page's matches, so we advance to the next
264
+ // page.
265
+ this.advanceOffsetPage(previous);
266
+ }
267
+ // Start searching through the page.
268
+ this.nextPageMatch();
269
+ },
270
+
271
+ matchesReady: function (matches) {
272
+ var offset = this.offset;
273
+ var numMatches = matches.length;
274
+ var previous = this.state.findPrevious;
275
+ if (numMatches) {
276
+ // There were matches for the page, so initialize the matchIdx.
277
+ this.hadMatch = true;
278
+ offset.matchIdx = previous ? numMatches - 1 : 0;
279
+ this.updateMatch(true);
280
+ // matches were found
281
+ return true;
282
+ } else {
283
+ // No matches attempt to search the next page.
284
+ this.advanceOffsetPage(previous);
285
+ if (offset.wrapped) {
286
+ offset.matchIdx = null;
287
+ if (!this.hadMatch) {
288
+ // No point in wrapping there were no matches.
289
+ this.updateMatch(false);
290
+ // while matches were not found, searching for a page
291
+ // with matches should nevertheless halt.
292
+ return true;
293
+ }
294
+ }
295
+ // matches were not found (and searching is not done)
296
+ return false;
297
+ }
298
+ },
345
299
 
346
- updateUIState: function(state, previous) {
347
- if (this.integratedFind) {
348
- FirefoxCom.request('updateFindControlState',
349
- {result: state, findPrevious: previous});
350
- return;
300
+ nextPageMatch: function () {
301
+ if (this.resumePageIdx !== null) {
302
+ console.error('There can only be one pending page.');
303
+ }
304
+ do {
305
+ var pageIdx = this.offset.pageIdx;
306
+ var matches = this.pageMatches[pageIdx];
307
+ if (!matches) {
308
+ // The matches don't exist yet for processing by "matchesReady",
309
+ // so set a resume point for when they do exist.
310
+ this.resumePageIdx = pageIdx;
311
+ break;
312
+ }
313
+ } while (!this.matchesReady(matches));
314
+ },
315
+
316
+ advanceOffsetPage: function (previous) {
317
+ var offset = this.offset;
318
+ var numPages = this.extractTextPromises.length;
319
+ offset.pageIdx = previous ? offset.pageIdx - 1 : offset.pageIdx + 1;
320
+ offset.matchIdx = null;
321
+ if (offset.pageIdx >= numPages || offset.pageIdx < 0) {
322
+ offset.pageIdx = previous ? numPages - 1 : 0;
323
+ offset.wrapped = true;
324
+ return;
325
+ }
326
+ },
327
+
328
+ updateMatch: function (found) {
329
+ var state = FindStates.FIND_NOTFOUND;
330
+ var wrapped = this.offset.wrapped;
331
+ this.offset.wrapped = false;
332
+ if (found) {
333
+ var previousPage = this.selected.pageIdx;
334
+ this.selected.pageIdx = this.offset.pageIdx;
335
+ this.selected.matchIdx = this.offset.matchIdx;
336
+ state = wrapped ? FindStates.FIND_WRAPPED : FindStates.FIND_FOUND;
337
+ // Update the currently selected page to wipe out any selected matches.
338
+ if (previousPage !== -1 && previousPage !== this.selected.pageIdx) {
339
+ this.updatePage(previousPage);
340
+ }
341
+ }
342
+ this.updateUIState(state, this.state.findPrevious);
343
+ if (this.selected.pageIdx !== -1) {
344
+ this.updatePage(this.selected.pageIdx, true);
345
+ }
346
+ },
347
+
348
+ updateUIState: function (state, previous) {
349
+ if (this.integratedFind) {
350
+ FirefoxCom.request('updateFindControlState',
351
+ {result: state, findPrevious: previous});
352
+ return;
353
+ }
354
+ PDFFindBar.updateUIState(state, previous);
351
355
  }
352
- PDFFindBar.updateUIState(state, previous);
353
- }
354
356
  };
355
357