viewerjs-rails 0.0.1
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 +7 -0
- data/.gitignore +14 -0
- data/Gemfile +4 -0
- data/LICENSE.txt +22 -0
- data/README.md +65 -0
- data/Rakefile +2 -0
- data/app/assets/AGPL-3.0.txt +661 -0
- data/app/assets/images/kogmbh.png +0 -0
- data/app/assets/images/nlnet.png +0 -0
- data/app/assets/images/texture.png +0 -0
- data/app/assets/images/toolbarButton-download.png +0 -0
- data/app/assets/images/toolbarButton-fullscreen.png +0 -0
- data/app/assets/images/toolbarButton-menuArrows.png +0 -0
- data/app/assets/images/toolbarButton-pageDown.png +0 -0
- data/app/assets/images/toolbarButton-pageUp.png +0 -0
- data/app/assets/images/toolbarButton-presentation.png +0 -0
- data/app/assets/images/toolbarButton-zoomIn.png +0 -0
- data/app/assets/images/toolbarButton-zoomOut.png +0 -0
- data/app/assets/javascripts/pdf.worker.js +39900 -0
- data/app/assets/javascripts/viewerjs/ODFViewerPlugin.js +219 -0
- data/app/assets/javascripts/viewerjs/PDFViewerPlugin.js.erb +348 -0
- data/app/assets/javascripts/viewerjs/PluginLoader.js +47 -0
- data/app/assets/javascripts/viewerjs/compatibility.js +491 -0
- data/app/assets/javascripts/viewerjs/pdf.js +7651 -0
- data/app/assets/javascripts/viewerjs/pdf_find_bar.js +175 -0
- data/app/assets/javascripts/viewerjs/pdf_find_controller.js +355 -0
- data/app/assets/javascripts/viewerjs/pdfjsversion.js +1 -0
- data/app/assets/javascripts/viewerjs/text_layer_builder.js +385 -0
- data/app/assets/javascripts/viewerjs/ui_utils.js +270 -0
- data/app/assets/javascripts/viewerjs/viewer.js +230 -0
- data/app/assets/javascripts/viewerjs/webodf.js +631 -0
- data/app/assets/javascripts/viewerjs_rails.js +22 -0
- data/app/assets/stylesheets/ODFViewerPlugin.css.scss +29 -0
- data/app/assets/stylesheets/PDFViewerPlugin.css.scss +36 -0
- data/app/assets/stylesheets/example.local.css.scss +27 -0
- data/app/assets/stylesheets/viewer.css.scss +816 -0
- data/app/assets/stylesheets/viewerjs_rails.css +15 -0
- data/lib/viewerjs/rails.rb +19 -0
- data/lib/viewerjs/rails/version.rb +5 -0
- data/lib/viewerjs/view_helpers.rb +75 -0
- data/viewerjs-rails.gemspec +23 -0
- metadata +113 -0
@@ -0,0 +1 @@
|
|
1
|
+
var /**@const{!string}*/pdfjs_version = "d45d7bc";
|
@@ -0,0 +1,385 @@
|
|
1
|
+
/* -*- Mode: Java; tab-width: 2; indent-tabs-mode: nil; c-basic-offset: 2 -*- */
|
2
|
+
/* Copyright 2012 Mozilla Foundation
|
3
|
+
*
|
4
|
+
* Licensed under the Apache License, Version 2.0 (the "License");
|
5
|
+
* you may not use this file except in compliance with the License.
|
6
|
+
* You may obtain a copy of the License at
|
7
|
+
*
|
8
|
+
* http://www.apache.org/licenses/LICENSE-2.0
|
9
|
+
*
|
10
|
+
* Unless required by applicable law or agreed to in writing, software
|
11
|
+
* distributed under the License is distributed on an "AS IS" BASIS,
|
12
|
+
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
13
|
+
* See the License for the specific language governing permissions and
|
14
|
+
* limitations under the License.
|
15
|
+
*/
|
16
|
+
/* globals CustomStyle, PDFFindController, scrollIntoView */
|
17
|
+
|
18
|
+
'use strict';
|
19
|
+
|
20
|
+
var FIND_SCROLL_OFFSET_TOP = -50;
|
21
|
+
var FIND_SCROLL_OFFSET_LEFT = -400;
|
22
|
+
|
23
|
+
/**
|
24
|
+
* TextLayerBuilder provides text-selection
|
25
|
+
* functionality for the PDF. It does this
|
26
|
+
* by creating overlay divs over the PDF
|
27
|
+
* text. This divs contain text that matches
|
28
|
+
* the PDF text they are overlaying. This
|
29
|
+
* object also provides for a way to highlight
|
30
|
+
* text that is being searched for.
|
31
|
+
*/
|
32
|
+
var TextLayerBuilder = function textLayerBuilder(options) {
|
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;
|
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
|
+
}
|
94
|
+
}
|
95
|
+
|
96
|
+
textLayerDiv.appendChild(textLayerFrag);
|
97
|
+
this.renderingDone = true;
|
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;
|
171
|
+
}
|
172
|
+
|
173
|
+
this.setupRenderLayoutTimer();
|
174
|
+
};
|
175
|
+
|
176
|
+
this.setTextContent = function textLayerBuilderSetTextContent(textContent) {
|
177
|
+
this.textContent = textContent;
|
178
|
+
this.insertDivContent();
|
179
|
+
};
|
180
|
+
|
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
|
+
}
|
233
|
+
|
234
|
+
return ret;
|
235
|
+
};
|
236
|
+
|
237
|
+
this.renderMatches = function textLayerBuilder_renderMatches(matches) {
|
238
|
+
// Early exit if there is nothing to render.
|
239
|
+
if (matches.length === 0) {
|
240
|
+
return;
|
241
|
+
}
|
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);
|
277
|
+
}
|
278
|
+
|
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
|
+
}
|
294
|
+
|
295
|
+
function highlightDiv(divIdx, className) {
|
296
|
+
textDivs[divIdx].className = className;
|
297
|
+
}
|
298
|
+
|
299
|
+
var i0 = selectedMatchIdx, i1 = i0 + 1, i;
|
300
|
+
|
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
|
+
};
|
385
|
+
|
@@ -0,0 +1,270 @@
|
|
1
|
+
/* -*- Mode: Java; tab-width: 2; indent-tabs-mode: nil; c-basic-offset: 2 -*- */
|
2
|
+
/* Copyright 2012 Mozilla Foundation
|
3
|
+
*
|
4
|
+
* Licensed under the Apache License, Version 2.0 (the "License");
|
5
|
+
* you may not use this file except in compliance with the License.
|
6
|
+
* You may obtain a copy of the License at
|
7
|
+
*
|
8
|
+
* http://www.apache.org/licenses/LICENSE-2.0
|
9
|
+
*
|
10
|
+
* Unless required by applicable law or agreed to in writing, software
|
11
|
+
* distributed under the License is distributed on an "AS IS" BASIS,
|
12
|
+
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
13
|
+
* See the License for the specific language governing permissions and
|
14
|
+
* limitations under the License.
|
15
|
+
*/
|
16
|
+
|
17
|
+
'use strict';
|
18
|
+
|
19
|
+
// optimised CSS custom property getter/setter
|
20
|
+
var CustomStyle = (function CustomStyleClosure() {
|
21
|
+
|
22
|
+
// As noted on: http://www.zachstronaut.com/posts/2009/02/17/
|
23
|
+
// animate-css-transforms-firefox-webkit.html
|
24
|
+
// in some versions of IE9 it is critical that ms appear in this list
|
25
|
+
// before Moz
|
26
|
+
var prefixes = ['ms', 'Moz', 'Webkit', 'O'];
|
27
|
+
var _cache = { };
|
28
|
+
|
29
|
+
function CustomStyle() {
|
30
|
+
}
|
31
|
+
|
32
|
+
CustomStyle.getProp = function get(propName, element) {
|
33
|
+
// check cache only when no element is given
|
34
|
+
if (arguments.length == 1 && typeof _cache[propName] == 'string') {
|
35
|
+
return _cache[propName];
|
36
|
+
}
|
37
|
+
|
38
|
+
element = element || document.documentElement;
|
39
|
+
var style = element.style, prefixed, uPropName;
|
40
|
+
|
41
|
+
// test standard property first
|
42
|
+
if (typeof style[propName] == 'string') {
|
43
|
+
return (_cache[propName] = propName);
|
44
|
+
}
|
45
|
+
|
46
|
+
// capitalize
|
47
|
+
uPropName = propName.charAt(0).toUpperCase() + propName.slice(1);
|
48
|
+
|
49
|
+
// test vendor specific properties
|
50
|
+
for (var i = 0, l = prefixes.length; i < l; i++) {
|
51
|
+
prefixed = prefixes[i] + uPropName;
|
52
|
+
if (typeof style[prefixed] == 'string') {
|
53
|
+
return (_cache[propName] = prefixed);
|
54
|
+
}
|
55
|
+
}
|
56
|
+
|
57
|
+
//if all fails then set to undefined
|
58
|
+
return (_cache[propName] = 'undefined');
|
59
|
+
};
|
60
|
+
|
61
|
+
CustomStyle.setProp = function set(propName, element, str) {
|
62
|
+
var prop = this.getProp(propName);
|
63
|
+
if (prop != 'undefined')
|
64
|
+
element.style[prop] = str;
|
65
|
+
};
|
66
|
+
|
67
|
+
return CustomStyle;
|
68
|
+
})();
|
69
|
+
|
70
|
+
function getFileName(url) {
|
71
|
+
var anchor = url.indexOf('#');
|
72
|
+
var query = url.indexOf('?');
|
73
|
+
var end = Math.min(
|
74
|
+
anchor > 0 ? anchor : url.length,
|
75
|
+
query > 0 ? query : url.length);
|
76
|
+
return url.substring(url.lastIndexOf('/', end) + 1, end);
|
77
|
+
}
|
78
|
+
|
79
|
+
/**
|
80
|
+
* Returns scale factor for the canvas. It makes sense for the HiDPI displays.
|
81
|
+
* @return {Object} The object with horizontal (sx) and vertical (sy)
|
82
|
+
scales. The scaled property is set to false if scaling is
|
83
|
+
not required, true otherwise.
|
84
|
+
*/
|
85
|
+
function getOutputScale(ctx) {
|
86
|
+
var devicePixelRatio = window.devicePixelRatio || 1;
|
87
|
+
var backingStoreRatio = ctx.webkitBackingStorePixelRatio ||
|
88
|
+
ctx.mozBackingStorePixelRatio ||
|
89
|
+
ctx.msBackingStorePixelRatio ||
|
90
|
+
ctx.oBackingStorePixelRatio ||
|
91
|
+
ctx.backingStorePixelRatio || 1;
|
92
|
+
var pixelRatio = devicePixelRatio / backingStoreRatio;
|
93
|
+
return {
|
94
|
+
sx: pixelRatio,
|
95
|
+
sy: pixelRatio,
|
96
|
+
scaled: pixelRatio != 1
|
97
|
+
};
|
98
|
+
}
|
99
|
+
|
100
|
+
/**
|
101
|
+
* Scrolls specified element into view of its parent.
|
102
|
+
* element {Object} The element to be visible.
|
103
|
+
* spot {Object} An object with optional top and left properties,
|
104
|
+
* specifying the offset from the top left edge.
|
105
|
+
*/
|
106
|
+
function scrollIntoView(element, spot) {
|
107
|
+
// Assuming offsetParent is available (it's not available when viewer is in
|
108
|
+
// hidden iframe or object). We have to scroll: if the offsetParent is not set
|
109
|
+
// producing the error. See also animationStartedClosure.
|
110
|
+
var parent = element.offsetParent;
|
111
|
+
var offsetY = element.offsetTop + element.clientTop;
|
112
|
+
var offsetX = element.offsetLeft + element.clientLeft;
|
113
|
+
if (!parent) {
|
114
|
+
console.error('offsetParent is not set -- cannot scroll');
|
115
|
+
return;
|
116
|
+
}
|
117
|
+
while (parent.clientHeight === parent.scrollHeight) {
|
118
|
+
if (parent.dataset._scaleY) {
|
119
|
+
offsetY /= parent.dataset._scaleY;
|
120
|
+
offsetX /= parent.dataset._scaleX;
|
121
|
+
}
|
122
|
+
offsetY += parent.offsetTop;
|
123
|
+
offsetX += parent.offsetLeft;
|
124
|
+
parent = parent.offsetParent;
|
125
|
+
if (!parent) {
|
126
|
+
return; // no need to scroll
|
127
|
+
}
|
128
|
+
}
|
129
|
+
if (spot) {
|
130
|
+
if (spot.top !== undefined) {
|
131
|
+
offsetY += spot.top;
|
132
|
+
}
|
133
|
+
if (spot.left !== undefined) {
|
134
|
+
offsetX += spot.left;
|
135
|
+
parent.scrollLeft = offsetX;
|
136
|
+
}
|
137
|
+
}
|
138
|
+
parent.scrollTop = offsetY;
|
139
|
+
}
|
140
|
+
|
141
|
+
/**
|
142
|
+
* Event handler to suppress context menu.
|
143
|
+
*/
|
144
|
+
function noContextMenuHandler(e) {
|
145
|
+
e.preventDefault();
|
146
|
+
}
|
147
|
+
|
148
|
+
/**
|
149
|
+
* Returns the filename or guessed filename from the url (see issue 3455).
|
150
|
+
* url {String} The original PDF location.
|
151
|
+
* @return {String} Guessed PDF file name.
|
152
|
+
*/
|
153
|
+
function getPDFFileNameFromURL(url) {
|
154
|
+
var reURI = /^(?:([^:]+:)?\/\/[^\/]+)?([^?#]*)(\?[^#]*)?(#.*)?$/;
|
155
|
+
// SCHEME HOST 1.PATH 2.QUERY 3.REF
|
156
|
+
// Pattern to get last matching NAME.pdf
|
157
|
+
var reFilename = /[^\/?#=]+\.pdf\b(?!.*\.pdf\b)/i;
|
158
|
+
var splitURI = reURI.exec(url);
|
159
|
+
var suggestedFilename = reFilename.exec(splitURI[1]) ||
|
160
|
+
reFilename.exec(splitURI[2]) ||
|
161
|
+
reFilename.exec(splitURI[3]);
|
162
|
+
if (suggestedFilename) {
|
163
|
+
suggestedFilename = suggestedFilename[0];
|
164
|
+
if (suggestedFilename.indexOf('%') != -1) {
|
165
|
+
// URL-encoded %2Fpath%2Fto%2Ffile.pdf should be file.pdf
|
166
|
+
try {
|
167
|
+
suggestedFilename =
|
168
|
+
reFilename.exec(decodeURIComponent(suggestedFilename))[0];
|
169
|
+
} catch(e) { // Possible (extremely rare) errors:
|
170
|
+
// URIError "Malformed URI", e.g. for "%AA.pdf"
|
171
|
+
// TypeError "null has no properties", e.g. for "%2F.pdf"
|
172
|
+
}
|
173
|
+
}
|
174
|
+
}
|
175
|
+
return suggestedFilename || 'document.pdf';
|
176
|
+
}
|
177
|
+
|
178
|
+
var ProgressBar = (function ProgressBarClosure() {
|
179
|
+
|
180
|
+
function clamp(v, min, max) {
|
181
|
+
return Math.min(Math.max(v, min), max);
|
182
|
+
}
|
183
|
+
|
184
|
+
function ProgressBar(id, opts) {
|
185
|
+
|
186
|
+
// Fetch the sub-elements for later.
|
187
|
+
this.div = document.querySelector(id + ' .progress');
|
188
|
+
|
189
|
+
// Get the loading bar element, so it can be resized to fit the viewer.
|
190
|
+
this.bar = this.div.parentNode;
|
191
|
+
|
192
|
+
// Get options, with sensible defaults.
|
193
|
+
this.height = opts.height || 100;
|
194
|
+
this.width = opts.width || 100;
|
195
|
+
this.units = opts.units || '%';
|
196
|
+
|
197
|
+
// Initialize heights.
|
198
|
+
this.div.style.height = this.height + this.units;
|
199
|
+
this.percent = 0;
|
200
|
+
}
|
201
|
+
|
202
|
+
ProgressBar.prototype = {
|
203
|
+
|
204
|
+
updateBar: function ProgressBar_updateBar() {
|
205
|
+
if (this._indeterminate) {
|
206
|
+
this.div.classList.add('indeterminate');
|
207
|
+
this.div.style.width = this.width + this.units;
|
208
|
+
return;
|
209
|
+
}
|
210
|
+
|
211
|
+
this.div.classList.remove('indeterminate');
|
212
|
+
var progressSize = this.width * this._percent / 100;
|
213
|
+
this.div.style.width = progressSize + this.units;
|
214
|
+
},
|
215
|
+
|
216
|
+
get percent() {
|
217
|
+
return this._percent;
|
218
|
+
},
|
219
|
+
|
220
|
+
set percent(val) {
|
221
|
+
this._indeterminate = isNaN(val);
|
222
|
+
this._percent = clamp(val, 0, 100);
|
223
|
+
this.updateBar();
|
224
|
+
},
|
225
|
+
|
226
|
+
setWidth: function ProgressBar_setWidth(viewer) {
|
227
|
+
if (viewer) {
|
228
|
+
var container = viewer.parentNode;
|
229
|
+
var scrollbarWidth = container.offsetWidth - viewer.offsetWidth;
|
230
|
+
if (scrollbarWidth > 0) {
|
231
|
+
this.bar.setAttribute('style', 'width: calc(100% - ' +
|
232
|
+
scrollbarWidth + 'px);');
|
233
|
+
}
|
234
|
+
}
|
235
|
+
},
|
236
|
+
|
237
|
+
hide: function ProgressBar_hide() {
|
238
|
+
this.bar.classList.add('hidden');
|
239
|
+
this.bar.removeAttribute('style');
|
240
|
+
}
|
241
|
+
};
|
242
|
+
|
243
|
+
return ProgressBar;
|
244
|
+
})();
|
245
|
+
|
246
|
+
var Cache = function cacheCache(size) {
|
247
|
+
var data = [];
|
248
|
+
this.push = function cachePush(view) {
|
249
|
+
var i = data.indexOf(view);
|
250
|
+
if (i >= 0)
|
251
|
+
data.splice(i);
|
252
|
+
data.push(view);
|
253
|
+
if (data.length > size)
|
254
|
+
data.shift().destroy();
|
255
|
+
};
|
256
|
+
};
|
257
|
+
|
258
|
+
//#if !(FIREFOX || MOZCENTRAL || B2G)
|
259
|
+
var isLocalStorageEnabled = (function isLocalStorageEnabledClosure() {
|
260
|
+
// Feature test as per http://diveintohtml5.info/storage.html
|
261
|
+
// The additional localStorage call is to get around a FF quirk, see
|
262
|
+
// bug #495747 in bugzilla
|
263
|
+
try {
|
264
|
+
return ('localStorage' in window && window['localStorage'] !== null &&
|
265
|
+
localStorage);
|
266
|
+
} catch (e) {
|
267
|
+
return false;
|
268
|
+
}
|
269
|
+
})();
|
270
|
+
//#endif
|