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.
- checksums.yaml +4 -4
- data/README.md +4 -1
- data/app/assets/javascripts/pdf.worker.js +85404 -39091
- data/app/assets/javascripts/viewerjs/ODFViewerPlugin.js +7 -6
- data/app/assets/javascripts/viewerjs/PDFViewerPlugin.js.erb +1 -1
- data/app/assets/javascripts/viewerjs/PluginLoader.js +0 -1
- data/app/assets/javascripts/viewerjs/compatibility.js +403 -383
- data/app/assets/javascripts/viewerjs/pdf.js +7202 -7216
- data/app/assets/javascripts/viewerjs/pdf_find_bar.js +135 -133
- data/app/assets/javascripts/viewerjs/pdf_find_controller.js +291 -289
- data/app/assets/javascripts/viewerjs/text_layer_builder.js +327 -327
- data/app/assets/javascripts/viewerjs/ui_utils.js +181 -181
- data/app/assets/javascripts/viewerjs/{viewer.js → viewer.js.erb} +19 -19
- data/app/assets/javascripts/viewerjs/webodf.js +11863 -606
- data/app/assets/stylesheets/ODFViewerPlugin.css.scss +1 -1
- data/app/assets/stylesheets/PDFViewerPlugin.css.scss +18 -13
- data/app/assets/stylesheets/example.local.css.scss +6 -12
- data/app/assets/stylesheets/viewer.css.scss +36 -36
- data/lib/viewerjs/rails/version.rb +1 -1
- data/lib/viewerjs/view_helpers.rb +63 -54
- metadata +2 -2
@@ -30,356 +30,356 @@ var FIND_SCROLL_OFFSET_LEFT = -400;
|
|
30
30
|
* text that is being searched for.
|
31
31
|
*/
|
32
32
|
var TextLayerBuilder = function textLayerBuilder(options) {
|
33
|
-
|
34
|
-
|
35
|
-
|
36
|
-
|
37
|
-
|
38
|
-
|
39
|
-
|
40
|
-
|
41
|
-
|
42
|
-
|
43
|
-
|
44
|
-
|
45
|
-
|
46
|
-
}
|
47
|
-
|
48
|
-
if(typeof this.lastScrollSource === 'undefined') {
|
49
|
-
this.lastScrollSource = null;
|
50
|
-
}
|
51
|
-
|
52
|
-
this.beginLayout = function textLayerBuilderBeginLayout() {
|
53
|
-
this.textDivs = [];
|
54
|
-
this.renderingDone = false;
|
55
|
-
};
|
56
|
-
|
57
|
-
this.endLayout = function textLayerBuilderEndLayout() {
|
58
|
-
this.layoutDone = true;
|
59
|
-
this.insertDivContent();
|
60
|
-
};
|
61
|
-
|
62
|
-
this.renderLayer = function textLayerBuilderRenderLayer() {
|
63
|
-
var self = this;
|
64
|
-
var textDivs = this.textDivs;
|
65
|
-
var bidiTexts = this.textContent;
|
66
|
-
var textLayerDiv = this.textLayerDiv;
|
67
|
-
var canvas = document.createElement('canvas');
|
68
|
-
var ctx = canvas.getContext('2d');
|
69
|
-
|
70
|
-
// No point in rendering so many divs as it'd make the browser unusable
|
71
|
-
// even after the divs are rendered
|
72
|
-
var MAX_TEXT_DIVS_TO_RENDER = 100000;
|
73
|
-
if (textDivs.length > MAX_TEXT_DIVS_TO_RENDER)
|
74
|
-
return;
|
75
|
-
|
76
|
-
for (var i = 0, ii = textDivs.length; i < ii; i++) {
|
77
|
-
var textDiv = textDivs[i];
|
78
|
-
if ('isWhitespace' in textDiv.dataset) {
|
79
|
-
continue;
|
80
|
-
}
|
81
|
-
|
82
|
-
ctx.font = textDiv.style.fontSize + ' ' + textDiv.style.fontFamily;
|
83
|
-
var width = ctx.measureText(textDiv.textContent).width;
|
84
|
-
|
85
|
-
if (width > 0) {
|
86
|
-
textLayerFrag.appendChild(textDiv);
|
87
|
-
var textScale = textDiv.dataset.canvasWidth / width;
|
88
|
-
var rotation = textDiv.dataset.angle;
|
89
|
-
var transform = 'scale(' + textScale + ', 1)';
|
90
|
-
transform = 'rotate(' + rotation + 'deg) ' + transform;
|
91
|
-
CustomStyle.setProp('transform' , textDiv, transform);
|
92
|
-
CustomStyle.setProp('transformOrigin' , textDiv, '0% 0%');
|
93
|
-
}
|
33
|
+
var textLayerFrag = document.createDocumentFragment();
|
34
|
+
|
35
|
+
this.textLayerDiv = options.textLayerDiv;
|
36
|
+
this.layoutDone = false;
|
37
|
+
this.divContentDone = false;
|
38
|
+
this.pageIdx = options.pageIndex;
|
39
|
+
this.matches = [];
|
40
|
+
this.lastScrollSource = options.lastScrollSource;
|
41
|
+
this.viewport = options.viewport;
|
42
|
+
this.isViewerInPresentationMode = options.isViewerInPresentationMode;
|
43
|
+
|
44
|
+
if (typeof PDFFindController === 'undefined') {
|
45
|
+
window.PDFFindController = null;
|
94
46
|
}
|
95
47
|
|
96
|
-
|
97
|
-
|
98
|
-
this.updateMatches();
|
99
|
-
};
|
100
|
-
|
101
|
-
this.setupRenderLayoutTimer = function textLayerSetupRenderLayoutTimer() {
|
102
|
-
// Schedule renderLayout() if user has been scrolling, otherwise
|
103
|
-
// run it right away
|
104
|
-
var RENDER_DELAY = 200; // in ms
|
105
|
-
var self = this;
|
106
|
-
var lastScroll = this.lastScrollSource === null ?
|
107
|
-
0 : this.lastScrollSource.lastScroll;
|
108
|
-
|
109
|
-
if (Date.now() - lastScroll > RENDER_DELAY) {
|
110
|
-
// Render right away
|
111
|
-
this.renderLayer();
|
112
|
-
} else {
|
113
|
-
// Schedule
|
114
|
-
if (this.renderTimer)
|
115
|
-
clearTimeout(this.renderTimer);
|
116
|
-
this.renderTimer = setTimeout(function() {
|
117
|
-
self.setupRenderLayoutTimer();
|
118
|
-
}, RENDER_DELAY);
|
119
|
-
}
|
120
|
-
};
|
121
|
-
|
122
|
-
this.appendText = function textLayerBuilderAppendText(geom) {
|
123
|
-
var textDiv = document.createElement('div');
|
124
|
-
|
125
|
-
// vScale and hScale already contain the scaling to pixel units
|
126
|
-
var fontHeight = geom.fontSize * Math.abs(geom.vScale);
|
127
|
-
textDiv.dataset.canvasWidth = geom.canvasWidth * Math.abs(geom.hScale);
|
128
|
-
textDiv.dataset.fontName = geom.fontName;
|
129
|
-
textDiv.dataset.angle = geom.angle * (180 / Math.PI);
|
130
|
-
|
131
|
-
textDiv.style.fontSize = fontHeight + 'px';
|
132
|
-
textDiv.style.fontFamily = geom.fontFamily;
|
133
|
-
var fontAscent = geom.ascent ? geom.ascent * fontHeight :
|
134
|
-
geom.descent ? (1 + geom.descent) * fontHeight : fontHeight;
|
135
|
-
textDiv.style.left = (geom.x + (fontAscent * Math.sin(geom.angle))) + 'px';
|
136
|
-
textDiv.style.top = (geom.y - (fontAscent * Math.cos(geom.angle))) + 'px';
|
137
|
-
|
138
|
-
// The content of the div is set in the `setTextContent` function.
|
139
|
-
|
140
|
-
this.textDivs.push(textDiv);
|
141
|
-
};
|
142
|
-
|
143
|
-
this.insertDivContent = function textLayerUpdateTextContent() {
|
144
|
-
// Only set the content of the divs once layout has finished, the content
|
145
|
-
// for the divs is available and content is not yet set on the divs.
|
146
|
-
if (!this.layoutDone || this.divContentDone || !this.textContent)
|
147
|
-
return;
|
148
|
-
|
149
|
-
this.divContentDone = true;
|
150
|
-
|
151
|
-
var textDivs = this.textDivs;
|
152
|
-
var bidiTexts = this.textContent;
|
153
|
-
|
154
|
-
for (var i = 0; i < bidiTexts.length; i++) {
|
155
|
-
var bidiText = bidiTexts[i];
|
156
|
-
var textDiv = textDivs[i];
|
157
|
-
if (!/\S/.test(bidiText.str)) {
|
158
|
-
textDiv.dataset.isWhitespace = true;
|
159
|
-
continue;
|
160
|
-
}
|
161
|
-
|
162
|
-
textDiv.textContent = bidiText.str;
|
163
|
-
// TODO refactor text layer to use text content position
|
164
|
-
/**
|
165
|
-
* var arr = this.viewport.convertToViewportPoint(bidiText.x, bidiText.y);
|
166
|
-
* textDiv.style.left = arr[0] + 'px';
|
167
|
-
* textDiv.style.top = arr[1] + 'px';
|
168
|
-
*/
|
169
|
-
// bidiText.dir may be 'ttb' for vertical texts.
|
170
|
-
textDiv.dir = bidiText.dir;
|
48
|
+
if (typeof this.lastScrollSource === 'undefined') {
|
49
|
+
this.lastScrollSource = null;
|
171
50
|
}
|
172
51
|
|
173
|
-
this.
|
174
|
-
|
175
|
-
|
176
|
-
|
177
|
-
|
178
|
-
this.
|
179
|
-
|
180
|
-
|
181
|
-
|
182
|
-
|
183
|
-
|
184
|
-
|
185
|
-
|
186
|
-
|
187
|
-
|
188
|
-
|
189
|
-
|
190
|
-
|
191
|
-
|
192
|
-
|
193
|
-
|
194
|
-
|
195
|
-
|
196
|
-
|
197
|
-
|
198
|
-
|
199
|
-
|
200
|
-
|
201
|
-
|
202
|
-
|
203
|
-
|
204
|
-
|
205
|
-
|
206
|
-
|
207
|
-
|
208
|
-
|
209
|
-
|
210
|
-
|
211
|
-
|
212
|
-
|
213
|
-
|
52
|
+
this.beginLayout = function textLayerBuilderBeginLayout() {
|
53
|
+
this.textDivs = [];
|
54
|
+
this.renderingDone = false;
|
55
|
+
};
|
56
|
+
|
57
|
+
this.endLayout = function textLayerBuilderEndLayout() {
|
58
|
+
this.layoutDone = true;
|
59
|
+
this.insertDivContent();
|
60
|
+
};
|
61
|
+
|
62
|
+
this.renderLayer = function textLayerBuilderRenderLayer() {
|
63
|
+
var self = this;
|
64
|
+
var textDivs = this.textDivs;
|
65
|
+
var bidiTexts = this.textContent;
|
66
|
+
var textLayerDiv = this.textLayerDiv;
|
67
|
+
var canvas = document.createElement('canvas');
|
68
|
+
var ctx = canvas.getContext('2d');
|
69
|
+
|
70
|
+
// No point in rendering so many divs as it'd make the browser unusable
|
71
|
+
// even after the divs are rendered
|
72
|
+
var MAX_TEXT_DIVS_TO_RENDER = 100000;
|
73
|
+
if (textDivs.length > MAX_TEXT_DIVS_TO_RENDER)
|
74
|
+
return;
|
75
|
+
|
76
|
+
for (var i = 0, ii = textDivs.length; i < ii; i++) {
|
77
|
+
var textDiv = textDivs[i];
|
78
|
+
if ('isWhitespace' in textDiv.dataset) {
|
79
|
+
continue;
|
80
|
+
}
|
81
|
+
|
82
|
+
ctx.font = textDiv.style.fontSize + ' ' + textDiv.style.fontFamily;
|
83
|
+
var width = ctx.measureText(textDiv.textContent).width;
|
84
|
+
|
85
|
+
if (width > 0) {
|
86
|
+
textLayerFrag.appendChild(textDiv);
|
87
|
+
var textScale = textDiv.dataset.canvasWidth / width;
|
88
|
+
var rotation = textDiv.dataset.angle;
|
89
|
+
var transform = 'scale(' + textScale + ', 1)';
|
90
|
+
transform = 'rotate(' + rotation + 'deg) ' + transform;
|
91
|
+
CustomStyle.setProp('transform', textDiv, transform);
|
92
|
+
CustomStyle.setProp('transformOrigin', textDiv, '0% 0%');
|
93
|
+
}
|
214
94
|
}
|
215
|
-
};
|
216
|
-
|
217
|
-
// # Calculate the end position.
|
218
|
-
matchIdx += queryLen;
|
219
|
-
|
220
|
-
// Somewhat same array as above, but use a > instead of >= to get the end
|
221
|
-
// position right.
|
222
|
-
while (i !== end && matchIdx > (iIndex + bidiTexts[i].str.length)) {
|
223
|
-
iIndex += bidiTexts[i].str.length;
|
224
|
-
i++;
|
225
|
-
}
|
226
|
-
|
227
|
-
match.end = {
|
228
|
-
divIdx: i,
|
229
|
-
offset: matchIdx - iIndex
|
230
|
-
};
|
231
|
-
ret.push(match);
|
232
|
-
}
|
233
95
|
|
234
|
-
|
235
|
-
|
96
|
+
textLayerDiv.appendChild(textLayerFrag);
|
97
|
+
this.renderingDone = true;
|
98
|
+
this.updateMatches();
|
99
|
+
};
|
236
100
|
|
237
|
-
|
238
|
-
|
239
|
-
|
240
|
-
|
241
|
-
|
101
|
+
this.setupRenderLayoutTimer = function textLayerSetupRenderLayoutTimer() {
|
102
|
+
// Schedule renderLayout() if user has been scrolling, otherwise
|
103
|
+
// run it right away
|
104
|
+
var RENDER_DELAY = 200; // in ms
|
105
|
+
var self = this;
|
106
|
+
var lastScroll = this.lastScrollSource === null ?
|
107
|
+
0 : this.lastScrollSource.lastScroll;
|
108
|
+
|
109
|
+
if (Date.now() - lastScroll > RENDER_DELAY) {
|
110
|
+
// Render right away
|
111
|
+
this.renderLayer();
|
112
|
+
} else {
|
113
|
+
// Schedule
|
114
|
+
if (this.renderTimer)
|
115
|
+
clearTimeout(this.renderTimer);
|
116
|
+
this.renderTimer = setTimeout(function () {
|
117
|
+
self.setupRenderLayoutTimer();
|
118
|
+
}, RENDER_DELAY);
|
119
|
+
}
|
120
|
+
};
|
242
121
|
|
243
|
-
|
244
|
-
|
245
|
-
var prevEnd = null;
|
246
|
-
var isSelectedPage = PDFFindController === null ?
|
247
|
-
false : (this.pageIdx === PDFFindController.selected.pageIdx);
|
122
|
+
this.appendText = function textLayerBuilderAppendText(geom) {
|
123
|
+
var textDiv = document.createElement('div');
|
248
124
|
|
249
|
-
|
250
|
-
|
125
|
+
// vScale and hScale already contain the scaling to pixel units
|
126
|
+
var fontHeight = geom.fontSize * Math.abs(geom.vScale);
|
127
|
+
textDiv.dataset.canvasWidth = geom.canvasWidth * Math.abs(geom.hScale);
|
128
|
+
textDiv.dataset.fontName = geom.fontName;
|
129
|
+
textDiv.dataset.angle = geom.angle * (180 / Math.PI);
|
251
130
|
|
252
|
-
|
253
|
-
|
131
|
+
textDiv.style.fontSize = fontHeight + 'px';
|
132
|
+
textDiv.style.fontFamily = geom.fontFamily;
|
133
|
+
var fontAscent = geom.ascent ? geom.ascent * fontHeight :
|
134
|
+
geom.descent ? (1 + geom.descent) * fontHeight : fontHeight;
|
135
|
+
textDiv.style.left = (geom.x + (fontAscent * Math.sin(geom.angle))) + 'px';
|
136
|
+
textDiv.style.top = (geom.y - (fontAscent * Math.cos(geom.angle))) + 'px';
|
254
137
|
|
255
|
-
|
256
|
-
|
257
|
-
|
138
|
+
// The content of the div is set in the `setTextContent` function.
|
139
|
+
|
140
|
+
this.textDivs.push(textDiv);
|
258
141
|
};
|
259
142
|
|
260
|
-
function
|
261
|
-
|
262
|
-
|
263
|
-
|
264
|
-
|
265
|
-
|
266
|
-
|
267
|
-
|
268
|
-
var
|
269
|
-
|
270
|
-
|
271
|
-
|
272
|
-
|
273
|
-
|
274
|
-
|
275
|
-
|
276
|
-
|
277
|
-
|
143
|
+
this.insertDivContent = function textLayerUpdateTextContent() {
|
144
|
+
// Only set the content of the divs once layout has finished, the content
|
145
|
+
// for the divs is available and content is not yet set on the divs.
|
146
|
+
if (!this.layoutDone || this.divContentDone || !this.textContent)
|
147
|
+
return;
|
148
|
+
|
149
|
+
this.divContentDone = true;
|
150
|
+
|
151
|
+
var textDivs = this.textDivs;
|
152
|
+
var bidiTexts = this.textContent;
|
153
|
+
|
154
|
+
for (var i = 0; i < bidiTexts.length; i++) {
|
155
|
+
var bidiText = bidiTexts[i];
|
156
|
+
var textDiv = textDivs[i];
|
157
|
+
if (!/\S/.test(bidiText.str)) {
|
158
|
+
textDiv.dataset.isWhitespace = true;
|
159
|
+
continue;
|
160
|
+
}
|
161
|
+
|
162
|
+
textDiv.textContent = bidiText.str;
|
163
|
+
// TODO refactor text layer to use text content position
|
164
|
+
/**
|
165
|
+
* var arr = this.viewport.convertToViewportPoint(bidiText.x, bidiText.y);
|
166
|
+
* textDiv.style.left = arr[0] + 'px';
|
167
|
+
* textDiv.style.top = arr[1] + 'px';
|
168
|
+
*/
|
169
|
+
// bidiText.dir may be 'ttb' for vertical texts.
|
170
|
+
textDiv.dir = bidiText.dir;
|
171
|
+
}
|
278
172
|
|
279
|
-
|
280
|
-
|
281
|
-
var div = textDivs[divIdx];
|
282
|
-
|
283
|
-
var content = bidiTexts[divIdx].str.substring(from.offset, to.offset);
|
284
|
-
var node = document.createTextNode(content);
|
285
|
-
if (className) {
|
286
|
-
var span = document.createElement('span');
|
287
|
-
span.className = className;
|
288
|
-
span.appendChild(node);
|
289
|
-
div.appendChild(span);
|
290
|
-
return;
|
291
|
-
}
|
292
|
-
div.appendChild(node);
|
293
|
-
}
|
173
|
+
this.setupRenderLayoutTimer();
|
174
|
+
};
|
294
175
|
|
295
|
-
function
|
296
|
-
|
297
|
-
|
176
|
+
this.setTextContent = function textLayerBuilderSetTextContent(textContent) {
|
177
|
+
this.textContent = textContent;
|
178
|
+
this.insertDivContent();
|
179
|
+
};
|
298
180
|
|
299
|
-
|
181
|
+
this.convertMatches = function textLayerBuilderConvertMatches(matches) {
|
182
|
+
var i = 0;
|
183
|
+
var iIndex = 0;
|
184
|
+
var bidiTexts = this.textContent;
|
185
|
+
var end = bidiTexts.length - 1;
|
186
|
+
var queryLen = PDFFindController === null ?
|
187
|
+
0 : PDFFindController.state.query.length;
|
188
|
+
|
189
|
+
var lastDivIdx = -1;
|
190
|
+
var pos;
|
191
|
+
|
192
|
+
var ret = [];
|
193
|
+
|
194
|
+
// Loop over all the matches.
|
195
|
+
for (var m = 0; m < matches.length; m++) {
|
196
|
+
var matchIdx = matches[m];
|
197
|
+
// # Calculate the begin position.
|
198
|
+
|
199
|
+
// Loop over the divIdxs.
|
200
|
+
while (i !== end && matchIdx >= (iIndex + bidiTexts[i].str.length)) {
|
201
|
+
iIndex += bidiTexts[i].str.length;
|
202
|
+
i++;
|
203
|
+
}
|
204
|
+
|
205
|
+
// TODO: Do proper handling here if something goes wrong.
|
206
|
+
if (i == bidiTexts.length) {
|
207
|
+
console.error('Could not find matching mapping');
|
208
|
+
}
|
209
|
+
|
210
|
+
var match = {
|
211
|
+
begin: {
|
212
|
+
divIdx: i,
|
213
|
+
offset: matchIdx - iIndex
|
214
|
+
}
|
215
|
+
};
|
216
|
+
|
217
|
+
// # Calculate the end position.
|
218
|
+
matchIdx += queryLen;
|
219
|
+
|
220
|
+
// Somewhat same array as above, but use a > instead of >= to get the end
|
221
|
+
// position right.
|
222
|
+
while (i !== end && matchIdx > (iIndex + bidiTexts[i].str.length)) {
|
223
|
+
iIndex += bidiTexts[i].str.length;
|
224
|
+
i++;
|
225
|
+
}
|
226
|
+
|
227
|
+
match.end = {
|
228
|
+
divIdx: i,
|
229
|
+
offset: matchIdx - iIndex
|
230
|
+
};
|
231
|
+
ret.push(match);
|
232
|
+
}
|
300
233
|
|
301
|
-
|
302
|
-
|
303
|
-
i1 = matches.length;
|
304
|
-
} else if (!isSelectedPage) {
|
305
|
-
// Not highlighting all and this isn't the selected page, so do nothing.
|
306
|
-
return;
|
307
|
-
}
|
234
|
+
return ret;
|
235
|
+
};
|
308
236
|
|
309
|
-
|
310
|
-
|
311
|
-
|
312
|
-
|
313
|
-
|
314
|
-
var isSelected = isSelectedPage && i === selectedMatchIdx;
|
315
|
-
var highlightSuffix = (isSelected ? ' selected' : '');
|
316
|
-
if (isSelected && !this.isViewerInPresentationMode) {
|
317
|
-
scrollIntoView(textDivs[begin.divIdx], { top: FIND_SCROLL_OFFSET_TOP,
|
318
|
-
left: FIND_SCROLL_OFFSET_LEFT });
|
319
|
-
}
|
320
|
-
|
321
|
-
// Match inside new div.
|
322
|
-
if (!prevEnd || begin.divIdx !== prevEnd.divIdx) {
|
323
|
-
// If there was a previous div, then add the text at the end
|
324
|
-
if (prevEnd !== null) {
|
325
|
-
appendText(prevEnd, infty);
|
237
|
+
this.renderMatches = function textLayerBuilder_renderMatches(matches) {
|
238
|
+
// Early exit if there is nothing to render.
|
239
|
+
if (matches.length === 0) {
|
240
|
+
return;
|
326
241
|
}
|
327
|
-
|
328
|
-
|
329
|
-
|
330
|
-
|
331
|
-
|
332
|
-
|
333
|
-
|
334
|
-
|
335
|
-
|
336
|
-
|
337
|
-
|
338
|
-
|
242
|
+
|
243
|
+
var bidiTexts = this.textContent;
|
244
|
+
var textDivs = this.textDivs;
|
245
|
+
var prevEnd = null;
|
246
|
+
var isSelectedPage = PDFFindController === null ?
|
247
|
+
false : (this.pageIdx === PDFFindController.selected.pageIdx);
|
248
|
+
|
249
|
+
var selectedMatchIdx = PDFFindController === null ?
|
250
|
+
-1 : PDFFindController.selected.matchIdx;
|
251
|
+
|
252
|
+
var highlightAll = PDFFindController === null ?
|
253
|
+
false : PDFFindController.state.highlightAll;
|
254
|
+
|
255
|
+
var infty = {
|
256
|
+
divIdx: -1,
|
257
|
+
offset: undefined
|
258
|
+
};
|
259
|
+
|
260
|
+
function beginText(begin, className) {
|
261
|
+
var divIdx = begin.divIdx;
|
262
|
+
var div = textDivs[divIdx];
|
263
|
+
div.textContent = '';
|
264
|
+
|
265
|
+
var content = bidiTexts[divIdx].str.substring(0, begin.offset);
|
266
|
+
var node = document.createTextNode(content);
|
267
|
+
if (className) {
|
268
|
+
var isSelected = isSelectedPage &&
|
269
|
+
divIdx === selectedMatchIdx;
|
270
|
+
var span = document.createElement('span');
|
271
|
+
span.className = className + (isSelected ? ' selected' : '');
|
272
|
+
span.appendChild(node);
|
273
|
+
div.appendChild(span);
|
274
|
+
return;
|
275
|
+
}
|
276
|
+
div.appendChild(node);
|
339
277
|
}
|
340
|
-
beginText(end, 'highlight end' + highlightSuffix);
|
341
|
-
}
|
342
|
-
prevEnd = end;
|
343
|
-
}
|
344
278
|
|
345
|
-
|
346
|
-
|
347
|
-
|
348
|
-
|
349
|
-
|
350
|
-
|
351
|
-
|
352
|
-
|
353
|
-
|
354
|
-
|
355
|
-
|
356
|
-
|
357
|
-
|
358
|
-
|
359
|
-
|
360
|
-
|
361
|
-
// Clear out all current matches.
|
362
|
-
for (var i = 0; i < matches.length; i++) {
|
363
|
-
var match = matches[i];
|
364
|
-
var begin = Math.max(clearedUntilDivIdx, match.begin.divIdx);
|
365
|
-
for (var n = begin; n <= match.end.divIdx; n++) {
|
366
|
-
var div = textDivs[n];
|
367
|
-
div.textContent = bidiTexts[n].str;
|
368
|
-
div.className = '';
|
369
|
-
}
|
370
|
-
clearedUntilDivIdx = match.end.divIdx + 1;
|
371
|
-
}
|
279
|
+
function appendText(from, to, className) {
|
280
|
+
var divIdx = from.divIdx;
|
281
|
+
var div = textDivs[divIdx];
|
282
|
+
|
283
|
+
var content = bidiTexts[divIdx].str.substring(from.offset, to.offset);
|
284
|
+
var node = document.createTextNode(content);
|
285
|
+
if (className) {
|
286
|
+
var span = document.createElement('span');
|
287
|
+
span.className = className;
|
288
|
+
span.appendChild(node);
|
289
|
+
div.appendChild(span);
|
290
|
+
return;
|
291
|
+
}
|
292
|
+
div.appendChild(node);
|
293
|
+
}
|
372
294
|
|
373
|
-
|
374
|
-
|
295
|
+
function highlightDiv(divIdx, className) {
|
296
|
+
textDivs[divIdx].className = className;
|
297
|
+
}
|
375
298
|
|
376
|
-
|
377
|
-
// for the textLayer.
|
378
|
-
this.matches = matches =
|
379
|
-
this.convertMatches(PDFFindController === null ?
|
380
|
-
[] : (PDFFindController.pageMatches[this.pageIdx] || []));
|
299
|
+
var i0 = selectedMatchIdx, i1 = i0 + 1, i;
|
381
300
|
|
382
|
-
|
383
|
-
|
301
|
+
if (highlightAll) {
|
302
|
+
i0 = 0;
|
303
|
+
i1 = matches.length;
|
304
|
+
} else if (!isSelectedPage) {
|
305
|
+
// Not highlighting all and this isn't the selected page, so do nothing.
|
306
|
+
return;
|
307
|
+
}
|
308
|
+
|
309
|
+
for (i = i0; i < i1; i++) {
|
310
|
+
var match = matches[i];
|
311
|
+
var begin = match.begin;
|
312
|
+
var end = match.end;
|
313
|
+
|
314
|
+
var isSelected = isSelectedPage && i === selectedMatchIdx;
|
315
|
+
var highlightSuffix = (isSelected ? ' selected' : '');
|
316
|
+
if (isSelected && !this.isViewerInPresentationMode) {
|
317
|
+
scrollIntoView(textDivs[begin.divIdx], { top: FIND_SCROLL_OFFSET_TOP,
|
318
|
+
left: FIND_SCROLL_OFFSET_LEFT });
|
319
|
+
}
|
320
|
+
|
321
|
+
// Match inside new div.
|
322
|
+
if (!prevEnd || begin.divIdx !== prevEnd.divIdx) {
|
323
|
+
// If there was a previous div, then add the text at the end
|
324
|
+
if (prevEnd !== null) {
|
325
|
+
appendText(prevEnd, infty);
|
326
|
+
}
|
327
|
+
// clears the divs and set the content until the begin point.
|
328
|
+
beginText(begin);
|
329
|
+
} else {
|
330
|
+
appendText(prevEnd, begin);
|
331
|
+
}
|
332
|
+
|
333
|
+
if (begin.divIdx === end.divIdx) {
|
334
|
+
appendText(begin, end, 'highlight' + highlightSuffix);
|
335
|
+
} else {
|
336
|
+
appendText(begin, infty, 'highlight begin' + highlightSuffix);
|
337
|
+
for (var n = begin.divIdx + 1; n < end.divIdx; n++) {
|
338
|
+
highlightDiv(n, 'highlight middle' + highlightSuffix);
|
339
|
+
}
|
340
|
+
beginText(end, 'highlight end' + highlightSuffix);
|
341
|
+
}
|
342
|
+
prevEnd = end;
|
343
|
+
}
|
344
|
+
|
345
|
+
if (prevEnd) {
|
346
|
+
appendText(prevEnd, infty);
|
347
|
+
}
|
348
|
+
};
|
349
|
+
|
350
|
+
this.updateMatches = function textLayerUpdateMatches() {
|
351
|
+
// Only show matches, once all rendering is done.
|
352
|
+
if (!this.renderingDone)
|
353
|
+
return;
|
354
|
+
|
355
|
+
// Clear out all matches.
|
356
|
+
var matches = this.matches;
|
357
|
+
var textDivs = this.textDivs;
|
358
|
+
var bidiTexts = this.textContent;
|
359
|
+
var clearedUntilDivIdx = -1;
|
360
|
+
|
361
|
+
// Clear out all current matches.
|
362
|
+
for (var i = 0; i < matches.length; i++) {
|
363
|
+
var match = matches[i];
|
364
|
+
var begin = Math.max(clearedUntilDivIdx, match.begin.divIdx);
|
365
|
+
for (var n = begin; n <= match.end.divIdx; n++) {
|
366
|
+
var div = textDivs[n];
|
367
|
+
div.textContent = bidiTexts[n].str;
|
368
|
+
div.className = '';
|
369
|
+
}
|
370
|
+
clearedUntilDivIdx = match.end.divIdx + 1;
|
371
|
+
}
|
372
|
+
|
373
|
+
if (PDFFindController === null || !PDFFindController.active)
|
374
|
+
return;
|
375
|
+
|
376
|
+
// Convert the matches on the page controller into the match format used
|
377
|
+
// for the textLayer.
|
378
|
+
this.matches = matches =
|
379
|
+
this.convertMatches(PDFFindController === null ?
|
380
|
+
[] : (PDFFindController.pageMatches[this.pageIdx] || []));
|
381
|
+
|
382
|
+
this.renderMatches(this.matches);
|
383
|
+
};
|
384
384
|
};
|
385
385
|
|