viewerjs-rails 0.0.1 → 0.0.2

Sign up to get free protection for your applications and to get access to all the features.
@@ -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