├── README.md
├── composer.json
├── laraview
├── compatibility.js
├── example.local.css
├── images
│ ├── kogmbh.png
│ ├── nlnet.png
│ ├── texture.png
│ ├── toolbarButton-download.png
│ ├── toolbarButton-fullscreen.png
│ ├── toolbarButton-menuArrows.png
│ ├── toolbarButton-pageDown.png
│ ├── toolbarButton-pageUp.png
│ ├── toolbarButton-presentation.png
│ ├── toolbarButton-zoomIn.png
│ └── toolbarButton-zoomOut.png
├── index.html
├── pdf.js
├── pdf.worker.js
├── pdfjsversion.js
├── text_layer_builder.js
├── ui_utils.js
└── webodf.js
└── src
├── Facade
└── LaravelPdfViewer.php
└── LaravelPdfViewerServiceProvider.php
/README.md:
--------------------------------------------------------------------------------
1 | ## Laravel PDF VIEWER
2 |
3 | [](https://packagist.org/packages/davcpas1234/laravelpdfviewer)
4 | [](https://packagist.org/packages/davcpas1234/laravelpdfviewer)
5 | [](https://scrutinizer-ci.com/g/goodnesskay/LARAVEL-PDF-VIEWER/build-status/master)
6 |
7 | > This package is meant to help with viewing portable document file(PDF) on the web seamlessly when developing with Laravel. The package makes use of [ViewerJS](http://viewerjs.org)
8 |
9 | ## Requirement
10 |
11 | - [PHP](https://php.net) 5.6+
12 | - [Composer](https://getcomposer.org)
13 | - Pdf files
14 |
15 | ## Installation
16 | To install into your project, run the command below in your terminal.
17 |
18 | ```
19 | composer require davcpas1234/laravelpdfviewer
20 | ```
21 |
22 | Once the package is done being installed, register the service provider. Open `config/app.php` and add the following to the `providers` key.
23 |
24 | ```
25 | Davcpas1234\LaravelPdfViewer\LaravelPdfViewerServiceProvider::class,
26 | ```
27 |
28 | ## Configure
29 | Run this in your terminal:
30 | ```
31 | php artisan vendor:publish --provider="Davcpas1234\LaravelPdfViewer\LaravelPdfViewerServiceProvider"
32 | ```
33 | It will publish a folder named `laraview` to the root folder of your project.
34 |
35 | ## How it Works
36 | Simple!!! After installations and configurations have been carried out successfully, add the code below to your html file
37 | ```
38 | {{ asset('/laraview/#../folder-name/the-pdf-file.pdf') }}
39 |
40 | ```
41 | It should look like this:
42 | ```
43 |
44 | ```
45 | Then, you should have something like this:
46 |
47 | 
48 |
49 |
50 | **Note:**
51 | > After `#../` in `{{ asset('/laraview/#../folder-name/the-pdf-file.pdf') }}`, what should follow is the folder name of the pdf files in the public
52 | folder then, the pdf file name can follow.
53 |
54 |
55 |
56 | ## Contribute
57 |
58 | You can `fork` this package, `contribute` and `submit a pull request`. I will really love it.
59 |
60 |
61 | ## License
62 |
63 | MIT License (MIT).
64 |
65 |
--------------------------------------------------------------------------------
/composer.json:
--------------------------------------------------------------------------------
1 | {
2 | "name": "davcpas1234/laravelpdfviewer",
3 | "description": "A Laravel Package for viewing PDF files or documents on Web App",
4 | "version": "1.0.1",
5 | "license": "MIT",
6 | "autoload": {
7 | "psr-4": {
8 | "Davcpas1234\\LaravelPdfViewer\\": "src/"
9 | }
10 | },
11 | "keywords": ["laravel","pdf-viewer","laravel-viewerJS","ViewerJS"],
12 | "authors": [
13 | {
14 | "name": "Goodness Toluwanimi Kayode",
15 | "email": "gtkbrain@gmail.com"
16 | },
17 | {
18 | "name": "David Passmore",
19 | "email": "david.passmore@verscreative.co.uk"
20 | }
21 | ],
22 | "minimum-stability": "stable",
23 | "require": {},
24 | "extra": {
25 | "laravel": {
26 | "providers": [
27 | "Davcpas1234\\LaravelPdfViewer\\LaravelPdfViewerServiceProvider"
28 | ]
29 | }
30 | }
31 | }
32 |
--------------------------------------------------------------------------------
/laraview/compatibility.js:
--------------------------------------------------------------------------------
1 | /* -*- Mode: Java; tab-width: 2; indent-tabs-mode: nil; c-basic-offset: 2 -*- */
2 | /* vim: set shiftwidth=2 tabstop=2 autoindent cindent expandtab: */
3 | /* Copyright 2012 Mozilla Foundation
4 | *
5 | * Licensed under the Apache License, Version 2.0 (the "License");
6 | * you may not use this file except in compliance with the License.
7 | * You may obtain a copy of the License at
8 | *
9 | * http://www.apache.org/licenses/LICENSE-2.0
10 | *
11 | * Unless required by applicable law or agreed to in writing, software
12 | * distributed under the License is distributed on an "AS IS" BASIS,
13 | * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
14 | * See the License for the specific language governing permissions and
15 | * limitations under the License.
16 | */
17 | /* globals VBArray, PDFJS */
18 |
19 | 'use strict';
20 |
21 | // Initializing PDFJS global object here, it case if we need to change/disable
22 | // some PDF.js features, e.g. range requests
23 | if (typeof PDFJS === 'undefined') {
24 | (typeof window !== 'undefined' ? window : this).PDFJS = {};
25 | }
26 |
27 | // Checking if the typed arrays are supported
28 | // Support: iOS<6.0 (subarray), IE<10, Android<4.0
29 | (function checkTypedArrayCompatibility() {
30 | if (typeof Uint8Array !== 'undefined') {
31 | // Support: iOS<6.0
32 | if (typeof Uint8Array.prototype.subarray === 'undefined') {
33 | Uint8Array.prototype.subarray = function subarray(start, end) {
34 | return new Uint8Array(this.slice(start, end));
35 | };
36 | Float32Array.prototype.subarray = function subarray(start, end) {
37 | return new Float32Array(this.slice(start, end));
38 | };
39 | }
40 |
41 | // Support: Android<4.1
42 | if (typeof Float64Array === 'undefined') {
43 | window.Float64Array = Float32Array;
44 | }
45 | return;
46 | }
47 |
48 | function subarray(start, end) {
49 | return new TypedArray(this.slice(start, end));
50 | }
51 |
52 | function setArrayOffset(array, offset) {
53 | if (arguments.length < 2) {
54 | offset = 0;
55 | }
56 | for (var i = 0, n = array.length; i < n; ++i, ++offset) {
57 | this[offset] = array[i] & 0xFF;
58 | }
59 | }
60 |
61 | function TypedArray(arg1) {
62 | var result, i, n;
63 | if (typeof arg1 === 'number') {
64 | result = [];
65 | for (i = 0; i < arg1; ++i) {
66 | result[i] = 0;
67 | }
68 | } else if ('slice' in arg1) {
69 | result = arg1.slice(0);
70 | } else {
71 | result = [];
72 | for (i = 0, n = arg1.length; i < n; ++i) {
73 | result[i] = arg1[i];
74 | }
75 | }
76 |
77 | result.subarray = subarray;
78 | result.buffer = result;
79 | result.byteLength = result.length;
80 | result.set = setArrayOffset;
81 |
82 | if (typeof arg1 === 'object' && arg1.buffer) {
83 | result.buffer = arg1.buffer;
84 | }
85 | return result;
86 | }
87 |
88 | window.Uint8Array = TypedArray;
89 | window.Int8Array = TypedArray;
90 |
91 | // we don't need support for set, byteLength for 32-bit array
92 | // so we can use the TypedArray as well
93 | window.Uint32Array = TypedArray;
94 | window.Int32Array = TypedArray;
95 | window.Uint16Array = TypedArray;
96 | window.Float32Array = TypedArray;
97 | window.Float64Array = TypedArray;
98 | })();
99 |
100 | // URL = URL || webkitURL
101 | // Support: Safari<7, Android 4.2+
102 | (function normalizeURLObject() {
103 | if (!window.URL) {
104 | window.URL = window.webkitURL;
105 | }
106 | })();
107 |
108 | // Object.defineProperty()?
109 | // Support: Android<4.0, Safari<5.1
110 | (function checkObjectDefinePropertyCompatibility() {
111 | if (typeof Object.defineProperty !== 'undefined') {
112 | var definePropertyPossible = true;
113 | try {
114 | // some browsers (e.g. safari) cannot use defineProperty() on DOM objects
115 | // and thus the native version is not sufficient
116 | Object.defineProperty(new Image(), 'id', { value: 'test' });
117 | // ... another test for android gb browser for non-DOM objects
118 | var Test = function Test() {};
119 | Test.prototype = { get id() { } };
120 | Object.defineProperty(new Test(), 'id',
121 | { value: '', configurable: true, enumerable: true, writable: false });
122 | } catch (e) {
123 | definePropertyPossible = false;
124 | }
125 | if (definePropertyPossible) {
126 | return;
127 | }
128 | }
129 |
130 | Object.defineProperty = function objectDefineProperty(obj, name, def) {
131 | delete obj[name];
132 | if ('get' in def) {
133 | obj.__defineGetter__(name, def['get']);
134 | }
135 | if ('set' in def) {
136 | obj.__defineSetter__(name, def['set']);
137 | }
138 | if ('value' in def) {
139 | obj.__defineSetter__(name, function objectDefinePropertySetter(value) {
140 | this.__defineGetter__(name, function objectDefinePropertyGetter() {
141 | return value;
142 | });
143 | return value;
144 | });
145 | obj[name] = def.value;
146 | }
147 | };
148 | })();
149 |
150 |
151 | // No XMLHttpRequest#response?
152 | // Support: IE<11, Android <4.0
153 | (function checkXMLHttpRequestResponseCompatibility() {
154 | var xhrPrototype = XMLHttpRequest.prototype;
155 | var xhr = new XMLHttpRequest();
156 | if (!('overrideMimeType' in xhr)) {
157 | // IE10 might have response, but not overrideMimeType
158 | // Support: IE10
159 | Object.defineProperty(xhrPrototype, 'overrideMimeType', {
160 | value: function xmlHttpRequestOverrideMimeType(mimeType) {}
161 | });
162 | }
163 | if ('responseType' in xhr) {
164 | return;
165 | }
166 |
167 | // The worker will be using XHR, so we can save time and disable worker.
168 | PDFJS.disableWorker = true;
169 |
170 | Object.defineProperty(xhrPrototype, 'responseType', {
171 | get: function xmlHttpRequestGetResponseType() {
172 | return this._responseType || 'text';
173 | },
174 | set: function xmlHttpRequestSetResponseType(value) {
175 | if (value === 'text' || value === 'arraybuffer') {
176 | this._responseType = value;
177 | if (value === 'arraybuffer' &&
178 | typeof this.overrideMimeType === 'function') {
179 | this.overrideMimeType('text/plain; charset=x-user-defined');
180 | }
181 | }
182 | }
183 | });
184 |
185 | // Support: IE9
186 | if (typeof VBArray !== 'undefined') {
187 | Object.defineProperty(xhrPrototype, 'response', {
188 | get: function xmlHttpRequestResponseGet() {
189 | if (this.responseType === 'arraybuffer') {
190 | return new Uint8Array(new VBArray(this.responseBody).toArray());
191 | } else {
192 | return this.responseText;
193 | }
194 | }
195 | });
196 | return;
197 | }
198 |
199 | Object.defineProperty(xhrPrototype, 'response', {
200 | get: function xmlHttpRequestResponseGet() {
201 | if (this.responseType !== 'arraybuffer') {
202 | return this.responseText;
203 | }
204 | var text = this.responseText;
205 | var i, n = text.length;
206 | var result = new Uint8Array(n);
207 | for (i = 0; i < n; ++i) {
208 | result[i] = text.charCodeAt(i) & 0xFF;
209 | }
210 | return result.buffer;
211 | }
212 | });
213 | })();
214 |
215 | // window.btoa (base64 encode function) ?
216 | // Support: IE<10
217 | (function checkWindowBtoaCompatibility() {
218 | if ('btoa' in window) {
219 | return;
220 | }
221 |
222 | var digits =
223 | 'ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789+/=';
224 |
225 | window.btoa = function windowBtoa(chars) {
226 | var buffer = '';
227 | var i, n;
228 | for (i = 0, n = chars.length; i < n; i += 3) {
229 | var b1 = chars.charCodeAt(i) & 0xFF;
230 | var b2 = chars.charCodeAt(i + 1) & 0xFF;
231 | var b3 = chars.charCodeAt(i + 2) & 0xFF;
232 | var d1 = b1 >> 2, d2 = ((b1 & 3) << 4) | (b2 >> 4);
233 | var d3 = i + 1 < n ? ((b2 & 0xF) << 2) | (b3 >> 6) : 64;
234 | var d4 = i + 2 < n ? (b3 & 0x3F) : 64;
235 | buffer += (digits.charAt(d1) + digits.charAt(d2) +
236 | digits.charAt(d3) + digits.charAt(d4));
237 | }
238 | return buffer;
239 | };
240 | })();
241 |
242 | // window.atob (base64 encode function)?
243 | // Support: IE<10
244 | (function checkWindowAtobCompatibility() {
245 | if ('atob' in window) {
246 | return;
247 | }
248 |
249 | // https://github.com/davidchambers/Base64.js
250 | var digits =
251 | 'ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789+/=';
252 | window.atob = function (input) {
253 | input = input.replace(/=+$/, '');
254 | if (input.length % 4 === 1) {
255 | throw new Error('bad atob input');
256 | }
257 | for (
258 | // initialize result and counters
259 | var bc = 0, bs, buffer, idx = 0, output = '';
260 | // get next character
261 | buffer = input.charAt(idx++);
262 | // character found in table?
263 | // initialize bit storage and add its ascii value
264 | ~buffer && (bs = bc % 4 ? bs * 64 + buffer : buffer,
265 | // and if not first of each 4 characters,
266 | // convert the first 8 bits to one ascii character
267 | bc++ % 4) ? output += String.fromCharCode(255 & bs >> (-2 * bc & 6)) : 0
268 | ) {
269 | // try to find character in table (0-63, not found => -1)
270 | buffer = digits.indexOf(buffer);
271 | }
272 | return output;
273 | };
274 | })();
275 |
276 | // Function.prototype.bind?
277 | // Support: Android<4.0, iOS<6.0
278 | (function checkFunctionPrototypeBindCompatibility() {
279 | if (typeof Function.prototype.bind !== 'undefined') {
280 | return;
281 | }
282 |
283 | Function.prototype.bind = function functionPrototypeBind(obj) {
284 | var fn = this, headArgs = Array.prototype.slice.call(arguments, 1);
285 | var bound = function functionPrototypeBindBound() {
286 | var args = headArgs.concat(Array.prototype.slice.call(arguments));
287 | return fn.apply(obj, args);
288 | };
289 | return bound;
290 | };
291 | })();
292 |
293 | // HTMLElement dataset property
294 | // Support: IE<11, Safari<5.1, Android<4.0
295 | (function checkDatasetProperty() {
296 | var div = document.createElement('div');
297 | if ('dataset' in div) {
298 | return; // dataset property exists
299 | }
300 |
301 | Object.defineProperty(HTMLElement.prototype, 'dataset', {
302 | get: function() {
303 | if (this._dataset) {
304 | return this._dataset;
305 | }
306 |
307 | var dataset = {};
308 | for (var j = 0, jj = this.attributes.length; j < jj; j++) {
309 | var attribute = this.attributes[j];
310 | if (attribute.name.substring(0, 5) !== 'data-') {
311 | continue;
312 | }
313 | var key = attribute.name.substring(5).replace(/\-([a-z])/g,
314 | function(all, ch) {
315 | return ch.toUpperCase();
316 | });
317 | dataset[key] = attribute.value;
318 | }
319 |
320 | Object.defineProperty(this, '_dataset', {
321 | value: dataset,
322 | writable: false,
323 | enumerable: false
324 | });
325 | return dataset;
326 | },
327 | enumerable: true
328 | });
329 | })();
330 |
331 | // HTMLElement classList property
332 | // Support: IE<10, Android<4.0, iOS<5.0
333 | (function checkClassListProperty() {
334 | var div = document.createElement('div');
335 | if ('classList' in div) {
336 | return; // classList property exists
337 | }
338 |
339 | function changeList(element, itemName, add, remove) {
340 | var s = element.className || '';
341 | var list = s.split(/\s+/g);
342 | if (list[0] === '') {
343 | list.shift();
344 | }
345 | var index = list.indexOf(itemName);
346 | if (index < 0 && add) {
347 | list.push(itemName);
348 | }
349 | if (index >= 0 && remove) {
350 | list.splice(index, 1);
351 | }
352 | element.className = list.join(' ');
353 | return (index >= 0);
354 | }
355 |
356 | var classListPrototype = {
357 | add: function(name) {
358 | changeList(this.element, name, true, false);
359 | },
360 | contains: function(name) {
361 | return changeList(this.element, name, false, false);
362 | },
363 | remove: function(name) {
364 | changeList(this.element, name, false, true);
365 | },
366 | toggle: function(name) {
367 | changeList(this.element, name, true, true);
368 | }
369 | };
370 |
371 | Object.defineProperty(HTMLElement.prototype, 'classList', {
372 | get: function() {
373 | if (this._classList) {
374 | return this._classList;
375 | }
376 |
377 | var classList = Object.create(classListPrototype, {
378 | element: {
379 | value: this,
380 | writable: false,
381 | enumerable: true
382 | }
383 | });
384 | Object.defineProperty(this, '_classList', {
385 | value: classList,
386 | writable: false,
387 | enumerable: false
388 | });
389 | return classList;
390 | },
391 | enumerable: true
392 | });
393 | })();
394 |
395 | // Check console compatibility
396 | // In older IE versions the console object is not available
397 | // unless console is open.
398 | // Support: IE<10
399 | (function checkConsoleCompatibility() {
400 | if (!('console' in window)) {
401 | window.console = {
402 | log: function() {},
403 | error: function() {},
404 | warn: function() {}
405 | };
406 | } else if (!('bind' in console.log)) {
407 | // native functions in IE9 might not have bind
408 | console.log = (function(fn) {
409 | return function(msg) { return fn(msg); };
410 | })(console.log);
411 | console.error = (function(fn) {
412 | return function(msg) { return fn(msg); };
413 | })(console.error);
414 | console.warn = (function(fn) {
415 | return function(msg) { return fn(msg); };
416 | })(console.warn);
417 | }
418 | })();
419 |
420 | // Check onclick compatibility in Opera
421 | // Support: Opera<15
422 | (function checkOnClickCompatibility() {
423 | // workaround for reported Opera bug DSK-354448:
424 | // onclick fires on disabled buttons with opaque content
425 | function ignoreIfTargetDisabled(event) {
426 | if (isDisabled(event.target)) {
427 | event.stopPropagation();
428 | }
429 | }
430 | function isDisabled(node) {
431 | return node.disabled || (node.parentNode && isDisabled(node.parentNode));
432 | }
433 | if (navigator.userAgent.indexOf('Opera') !== -1) {
434 | // use browser detection since we cannot feature-check this bug
435 | document.addEventListener('click', ignoreIfTargetDisabled, true);
436 | }
437 | })();
438 |
439 | // Checks if possible to use URL.createObjectURL()
440 | // Support: IE
441 | (function checkOnBlobSupport() {
442 | // sometimes IE loosing the data created with createObjectURL(), see #3977
443 | if (navigator.userAgent.indexOf('Trident') >= 0) {
444 | PDFJS.disableCreateObjectURL = true;
445 | }
446 | })();
447 |
448 | // Checks if navigator.language is supported
449 | (function checkNavigatorLanguage() {
450 | if ('language' in navigator) {
451 | return;
452 | }
453 | PDFJS.locale = navigator.userLanguage || 'en-US';
454 | })();
455 |
456 | (function checkRangeRequests() {
457 | // Safari has issues with cached range requests see:
458 | // https://github.com/mozilla/pdf.js/issues/3260
459 | // Last tested with version 6.0.4.
460 | // Support: Safari 6.0+
461 | var isSafari = Object.prototype.toString.call(
462 | window.HTMLElement).indexOf('Constructor') > 0;
463 |
464 | // Older versions of Android (pre 3.0) has issues with range requests, see:
465 | // https://github.com/mozilla/pdf.js/issues/3381.
466 | // Make sure that we only match webkit-based Android browsers,
467 | // since Firefox/Fennec works as expected.
468 | // Support: Android<3.0
469 | var regex = /Android\s[0-2][^\d]/;
470 | var isOldAndroid = regex.test(navigator.userAgent);
471 |
472 | // Range requests are broken in Chrome 39 and 40, https://crbug.com/442318
473 | var isChromeWithRangeBug = /Chrome\/(39|40)\./.test(navigator.userAgent);
474 |
475 | if (isSafari || isOldAndroid || isChromeWithRangeBug) {
476 | PDFJS.disableRange = true;
477 | PDFJS.disableStream = true;
478 | }
479 | })();
480 |
481 | // Check if the browser supports manipulation of the history.
482 | // Support: IE<10, Android<4.2
483 | (function checkHistoryManipulation() {
484 | // Android 2.x has so buggy pushState support that it was removed in
485 | // Android 3.0 and restored as late as in Android 4.2.
486 | // Support: Android 2.x
487 | if (!history.pushState || navigator.userAgent.indexOf('Android 2.') >= 0) {
488 | PDFJS.disableHistory = true;
489 | }
490 | })();
491 |
492 | // Support: IE<11, Chrome<21, Android<4.4, Safari<6
493 | (function checkSetPresenceInImageData() {
494 | // IE < 11 will use window.CanvasPixelArray which lacks set function.
495 | if (window.CanvasPixelArray) {
496 | if (typeof window.CanvasPixelArray.prototype.set !== 'function') {
497 | window.CanvasPixelArray.prototype.set = function(arr) {
498 | for (var i = 0, ii = this.length; i < ii; i++) {
499 | this[i] = arr[i];
500 | }
501 | };
502 | }
503 | } else {
504 | // Old Chrome and Android use an inaccessible CanvasPixelArray prototype.
505 | // Because we cannot feature detect it, we rely on user agent parsing.
506 | var polyfill = false, versionMatch;
507 | if (navigator.userAgent.indexOf('Chrom') >= 0) {
508 | versionMatch = navigator.userAgent.match(/Chrom(e|ium)\/([0-9]+)\./);
509 | // Chrome < 21 lacks the set function.
510 | polyfill = versionMatch && parseInt(versionMatch[2]) < 21;
511 | } else if (navigator.userAgent.indexOf('Android') >= 0) {
512 | // Android < 4.4 lacks the set function.
513 | // Android >= 4.4 will contain Chrome in the user agent,
514 | // thus pass the Chrome check above and not reach this block.
515 | polyfill = /Android\s[0-4][^\d]/g.test(navigator.userAgent);
516 | } else if (navigator.userAgent.indexOf('Safari') >= 0) {
517 | versionMatch = navigator.userAgent.
518 | match(/Version\/([0-9]+)\.([0-9]+)\.([0-9]+) Safari\//);
519 | // Safari < 6 lacks the set function.
520 | polyfill = versionMatch && parseInt(versionMatch[1]) < 6;
521 | }
522 |
523 | if (polyfill) {
524 | var contextPrototype = window.CanvasRenderingContext2D.prototype;
525 | contextPrototype._createImageData = contextPrototype.createImageData;
526 | contextPrototype.createImageData = function(w, h) {
527 | var imageData = this._createImageData(w, h);
528 | imageData.data.set = function(arr) {
529 | for (var i = 0, ii = this.length; i < ii; i++) {
530 | this[i] = arr[i];
531 | }
532 | };
533 | return imageData;
534 | };
535 | }
536 | }
537 | })();
538 |
539 | // Support: IE<10, Android<4.0, iOS
540 | (function checkRequestAnimationFrame() {
541 | function fakeRequestAnimationFrame(callback) {
542 | window.setTimeout(callback, 20);
543 | }
544 |
545 | var isIOS = /(iPad|iPhone|iPod)/g.test(navigator.userAgent);
546 | if (isIOS) {
547 | // requestAnimationFrame on iOS is broken, replacing with fake one.
548 | window.requestAnimationFrame = fakeRequestAnimationFrame;
549 | return;
550 | }
551 | if ('requestAnimationFrame' in window) {
552 | return;
553 | }
554 | window.requestAnimationFrame =
555 | window.mozRequestAnimationFrame ||
556 | window.webkitRequestAnimationFrame ||
557 | fakeRequestAnimationFrame;
558 | })();
559 |
560 | (function checkCanvasSizeLimitation() {
561 | var isIOS = /(iPad|iPhone|iPod)/g.test(navigator.userAgent);
562 | var isAndroid = /Android/g.test(navigator.userAgent);
563 | if (isIOS || isAndroid) {
564 | // 5MP
565 | PDFJS.maxCanvasPixels = 5242880;
566 | }
567 | })();
568 |
569 | // Disable fullscreen support for certain problematic configurations.
570 | // Support: IE11+ (when embedded).
571 | (function checkFullscreenSupport() {
572 | var isEmbeddedIE = (navigator.userAgent.indexOf('Trident') >= 0 &&
573 | window.parent !== window);
574 | if (isEmbeddedIE) {
575 | PDFJS.disableFullscreen = true;
576 | }
577 | })();
578 |
--------------------------------------------------------------------------------
/laraview/example.local.css:
--------------------------------------------------------------------------------
1 | /* This is just a sample file with CSS rules. You should write your own @font-face declarations
2 | * to add support for your desired fonts.
3 | */
4 |
5 | @font-face {
6 | font-family: 'Novecentowide Book';
7 | src: url("/ViewerJS/fonts/Novecentowide-Bold-webfont.eot");
8 | src: url("/ViewerJS/fonts/Novecentowide-Bold-webfont.eot?#iefix") format("embedded-opentype"),
9 | url("/ViewerJS/fonts/Novecentowide-Bold-webfont.woff") format("woff"),
10 | url("/fonts/Novecentowide-Bold-webfont.ttf") format("truetype"),
11 | url("/fonts/Novecentowide-Bold-webfont.svg#NovecentowideBookBold") format("svg");
12 | font-weight: normal;
13 | font-style: normal;
14 | }
15 |
16 | @font-face {
17 | font-family: 'exotica';
18 | src: url('/ViewerJS/fonts/Exotica-webfont.eot');
19 | src: url('/ViewerJS/fonts/Exotica-webfont.eot?#iefix') format('embedded-opentype'),
20 | url('/ViewerJS/fonts/Exotica-webfont.woff') format('woff'),
21 | url('/ViewerJS/fonts/Exotica-webfont.ttf') format('truetype'),
22 | url('/ViewerJS/fonts/Exotica-webfont.svg#exoticamedium') format('svg');
23 | font-weight: normal;
24 | font-style: normal;
25 |
26 | }
27 |
28 |
--------------------------------------------------------------------------------
/laraview/images/kogmbh.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/davcpas1234/laravel-pdf-viewer/be0a3a8ff9719708cc62a12db091551ba91c2f5f/laraview/images/kogmbh.png
--------------------------------------------------------------------------------
/laraview/images/nlnet.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/davcpas1234/laravel-pdf-viewer/be0a3a8ff9719708cc62a12db091551ba91c2f5f/laraview/images/nlnet.png
--------------------------------------------------------------------------------
/laraview/images/texture.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/davcpas1234/laravel-pdf-viewer/be0a3a8ff9719708cc62a12db091551ba91c2f5f/laraview/images/texture.png
--------------------------------------------------------------------------------
/laraview/images/toolbarButton-download.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/davcpas1234/laravel-pdf-viewer/be0a3a8ff9719708cc62a12db091551ba91c2f5f/laraview/images/toolbarButton-download.png
--------------------------------------------------------------------------------
/laraview/images/toolbarButton-fullscreen.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/davcpas1234/laravel-pdf-viewer/be0a3a8ff9719708cc62a12db091551ba91c2f5f/laraview/images/toolbarButton-fullscreen.png
--------------------------------------------------------------------------------
/laraview/images/toolbarButton-menuArrows.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/davcpas1234/laravel-pdf-viewer/be0a3a8ff9719708cc62a12db091551ba91c2f5f/laraview/images/toolbarButton-menuArrows.png
--------------------------------------------------------------------------------
/laraview/images/toolbarButton-pageDown.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/davcpas1234/laravel-pdf-viewer/be0a3a8ff9719708cc62a12db091551ba91c2f5f/laraview/images/toolbarButton-pageDown.png
--------------------------------------------------------------------------------
/laraview/images/toolbarButton-pageUp.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/davcpas1234/laravel-pdf-viewer/be0a3a8ff9719708cc62a12db091551ba91c2f5f/laraview/images/toolbarButton-pageUp.png
--------------------------------------------------------------------------------
/laraview/images/toolbarButton-presentation.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/davcpas1234/laravel-pdf-viewer/be0a3a8ff9719708cc62a12db091551ba91c2f5f/laraview/images/toolbarButton-presentation.png
--------------------------------------------------------------------------------
/laraview/images/toolbarButton-zoomIn.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/davcpas1234/laravel-pdf-viewer/be0a3a8ff9719708cc62a12db091551ba91c2f5f/laraview/images/toolbarButton-zoomIn.png
--------------------------------------------------------------------------------
/laraview/images/toolbarButton-zoomOut.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/davcpas1234/laravel-pdf-viewer/be0a3a8ff9719708cc62a12db091551ba91c2f5f/laraview/images/toolbarButton-zoomOut.png
--------------------------------------------------------------------------------
/laraview/index.html:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 |
5 |
6 |
31 |
32 | ViewerJS
33 |
38 |
39 |
77 |
78 |
79 |
80 |
81 |
82 |
83 |
84 |
85 |
86 |
87 |
88 |
89 |
131 |
134 |
138 |
139 | ✖
140 |
141 |
142 |
143 |
144 |
145 |
146 |
--------------------------------------------------------------------------------
/laraview/pdfjsversion.js:
--------------------------------------------------------------------------------
1 | var /**@const{!string}*/pdfjs_version = "v1.1.114";
2 |
--------------------------------------------------------------------------------
/laraview/text_layer_builder.js:
--------------------------------------------------------------------------------
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, PDFJS */
17 |
18 | 'use strict';
19 |
20 | var MAX_TEXT_DIVS_TO_RENDER = 100000;
21 |
22 | var NonWhitespaceRegexp = /\S/;
23 |
24 | function isAllWhitespace(str) {
25 | return !NonWhitespaceRegexp.test(str);
26 | }
27 |
28 | /**
29 | * @typedef {Object} TextLayerBuilderOptions
30 | * @property {HTMLDivElement} textLayerDiv - The text layer container.
31 | * @property {number} pageIndex - The page index.
32 | * @property {PageViewport} viewport - The viewport of the text layer.
33 | * @property {PDFFindController} findController
34 | */
35 |
36 | /**
37 | * TextLayerBuilder provides text-selection functionality for the PDF.
38 | * It does this by creating overlay divs over the PDF text. These divs
39 | * contain text that matches the PDF text they are overlaying. This object
40 | * also provides a way to highlight text that is being searched for.
41 | * @class
42 | */
43 | var TextLayerBuilder = (function TextLayerBuilderClosure() {
44 | function TextLayerBuilder(options) {
45 | this.textLayerDiv = options.textLayerDiv;
46 | this.renderingDone = false;
47 | this.divContentDone = false;
48 | this.pageIdx = options.pageIndex;
49 | this.pageNumber = this.pageIdx + 1;
50 | this.matches = [];
51 | this.viewport = options.viewport;
52 | this.textDivs = [];
53 | this.findController = options.findController || null;
54 | }
55 |
56 | TextLayerBuilder.prototype = {
57 | _finishRendering: function TextLayerBuilder_finishRendering() {
58 | this.renderingDone = true;
59 |
60 | var event = document.createEvent('CustomEvent');
61 | event.initCustomEvent('textlayerrendered', true, true, {
62 | pageNumber: this.pageNumber
63 | });
64 | this.textLayerDiv.dispatchEvent(event);
65 | },
66 |
67 | renderLayer: function TextLayerBuilder_renderLayer() {
68 | var textLayerFrag = document.createDocumentFragment();
69 | var textDivs = this.textDivs;
70 | var textDivsLength = textDivs.length;
71 | var canvas = document.createElement('canvas');
72 | var ctx = canvas.getContext('2d');
73 |
74 | // No point in rendering many divs as it would make the browser
75 | // unusable even after the divs are rendered.
76 | if (textDivsLength > MAX_TEXT_DIVS_TO_RENDER) {
77 | this._finishRendering();
78 | return;
79 | }
80 |
81 | var lastFontSize;
82 | var lastFontFamily;
83 | for (var i = 0; i < textDivsLength; i++) {
84 | var textDiv = textDivs[i];
85 | if (textDiv.dataset.isWhitespace !== undefined) {
86 | continue;
87 | }
88 |
89 | var fontSize = textDiv.style.fontSize;
90 | var fontFamily = textDiv.style.fontFamily;
91 |
92 | // Only build font string and set to context if different from last.
93 | if (fontSize !== lastFontSize || fontFamily !== lastFontFamily) {
94 | ctx.font = fontSize + ' ' + fontFamily;
95 | lastFontSize = fontSize;
96 | lastFontFamily = fontFamily;
97 | }
98 |
99 | var width = ctx.measureText(textDiv.textContent).width;
100 | if (width > 0) {
101 | textLayerFrag.appendChild(textDiv);
102 | var transform;
103 | if (textDiv.dataset.canvasWidth !== undefined) {
104 | // Dataset values come of type string.
105 | var textScale = textDiv.dataset.canvasWidth / width;
106 | transform = 'scaleX(' + textScale + ')';
107 | } else {
108 | transform = '';
109 | }
110 | var rotation = textDiv.dataset.angle;
111 | if (rotation) {
112 | transform = 'rotate(' + rotation + 'deg) ' + transform;
113 | }
114 | if (transform) {
115 | CustomStyle.setProp('transform' , textDiv, transform);
116 | }
117 | }
118 | }
119 |
120 | this.textLayerDiv.appendChild(textLayerFrag);
121 | this._finishRendering();
122 | this.updateMatches();
123 | },
124 |
125 | /**
126 | * Renders the text layer.
127 | * @param {number} timeout (optional) if specified, the rendering waits
128 | * for specified amount of ms.
129 | */
130 | render: function TextLayerBuilder_render(timeout) {
131 | if (!this.divContentDone || this.renderingDone) {
132 | return;
133 | }
134 |
135 | if (this.renderTimer) {
136 | clearTimeout(this.renderTimer);
137 | this.renderTimer = null;
138 | }
139 |
140 | if (!timeout) { // Render right away
141 | this.renderLayer();
142 | } else { // Schedule
143 | var self = this;
144 | this.renderTimer = setTimeout(function() {
145 | self.renderLayer();
146 | self.renderTimer = null;
147 | }, timeout);
148 | }
149 | },
150 |
151 | appendText: function TextLayerBuilder_appendText(geom, styles) {
152 | var style = styles[geom.fontName];
153 | var textDiv = document.createElement('div');
154 | this.textDivs.push(textDiv);
155 | if (isAllWhitespace(geom.str)) {
156 | textDiv.dataset.isWhitespace = true;
157 | return;
158 | }
159 | var tx = PDFJS.Util.transform(this.viewport.transform, geom.transform);
160 | var angle = Math.atan2(tx[1], tx[0]);
161 | if (style.vertical) {
162 | angle += Math.PI / 2;
163 | }
164 | var fontHeight = Math.sqrt((tx[2] * tx[2]) + (tx[3] * tx[3]));
165 | var fontAscent = fontHeight;
166 | if (style.ascent) {
167 | fontAscent = style.ascent * fontAscent;
168 | } else if (style.descent) {
169 | fontAscent = (1 + style.descent) * fontAscent;
170 | }
171 |
172 | var left;
173 | var top;
174 | if (angle === 0) {
175 | left = tx[4];
176 | top = tx[5] - fontAscent;
177 | } else {
178 | left = tx[4] + (fontAscent * Math.sin(angle));
179 | top = tx[5] - (fontAscent * Math.cos(angle));
180 | }
181 | textDiv.style.left = left + 'px';
182 | textDiv.style.top = top + 'px';
183 | textDiv.style.fontSize = fontHeight + 'px';
184 | textDiv.style.fontFamily = style.fontFamily;
185 |
186 | textDiv.textContent = geom.str;
187 | // |fontName| is only used by the Font Inspector. This test will succeed
188 | // when e.g. the Font Inspector is off but the Stepper is on, but it's
189 | // not worth the effort to do a more accurate test.
190 | if (PDFJS.pdfBug) {
191 | textDiv.dataset.fontName = geom.fontName;
192 | }
193 | // Storing into dataset will convert number into string.
194 | if (angle !== 0) {
195 | textDiv.dataset.angle = angle * (180 / Math.PI);
196 | }
197 | // We don't bother scaling single-char text divs, because it has very
198 | // little effect on text highlighting. This makes scrolling on docs with
199 | // lots of such divs a lot faster.
200 | if (textDiv.textContent.length > 1) {
201 | if (style.vertical) {
202 | textDiv.dataset.canvasWidth = geom.height * this.viewport.scale;
203 | } else {
204 | textDiv.dataset.canvasWidth = geom.width * this.viewport.scale;
205 | }
206 | }
207 | },
208 |
209 | setTextContent: function TextLayerBuilder_setTextContent(textContent) {
210 | this.textContent = textContent;
211 |
212 | var textItems = textContent.items;
213 | for (var i = 0, len = textItems.length; i < len; i++) {
214 | this.appendText(textItems[i], textContent.styles);
215 | }
216 | this.divContentDone = true;
217 | },
218 |
219 | convertMatches: function TextLayerBuilder_convertMatches(matches) {
220 | var i = 0;
221 | var iIndex = 0;
222 | var bidiTexts = this.textContent.items;
223 | var end = bidiTexts.length - 1;
224 | var queryLen = (this.findController === null ?
225 | 0 : this.findController.state.query.length);
226 | var ret = [];
227 |
228 | for (var m = 0, len = matches.length; m < len; m++) {
229 | // Calculate the start position.
230 | var matchIdx = matches[m];
231 |
232 | // Loop over the divIdxs.
233 | while (i !== end && matchIdx >= (iIndex + bidiTexts[i].str.length)) {
234 | iIndex += bidiTexts[i].str.length;
235 | i++;
236 | }
237 |
238 | if (i === bidiTexts.length) {
239 | console.error('Could not find a matching mapping');
240 | }
241 |
242 | var match = {
243 | begin: {
244 | divIdx: i,
245 | offset: matchIdx - iIndex
246 | }
247 | };
248 |
249 | // Calculate the end position.
250 | matchIdx += queryLen;
251 |
252 | // Somewhat the same array as above, but use > instead of >= to get
253 | // the end position right.
254 | while (i !== end && matchIdx > (iIndex + bidiTexts[i].str.length)) {
255 | iIndex += bidiTexts[i].str.length;
256 | i++;
257 | }
258 |
259 | match.end = {
260 | divIdx: i,
261 | offset: matchIdx - iIndex
262 | };
263 | ret.push(match);
264 | }
265 |
266 | return ret;
267 | },
268 |
269 | renderMatches: function TextLayerBuilder_renderMatches(matches) {
270 | // Early exit if there is nothing to render.
271 | if (matches.length === 0) {
272 | return;
273 | }
274 |
275 | var bidiTexts = this.textContent.items;
276 | var textDivs = this.textDivs;
277 | var prevEnd = null;
278 | var pageIdx = this.pageIdx;
279 | var isSelectedPage = (this.findController === null ?
280 | false : (pageIdx === this.findController.selected.pageIdx));
281 | var selectedMatchIdx = (this.findController === null ?
282 | -1 : this.findController.selected.matchIdx);
283 | var highlightAll = (this.findController === null ?
284 | false : this.findController.state.highlightAll);
285 | var infinity = {
286 | divIdx: -1,
287 | offset: undefined
288 | };
289 |
290 | function beginText(begin, className) {
291 | var divIdx = begin.divIdx;
292 | textDivs[divIdx].textContent = '';
293 | appendTextToDiv(divIdx, 0, begin.offset, className);
294 | }
295 |
296 | function appendTextToDiv(divIdx, fromOffset, toOffset, className) {
297 | var div = textDivs[divIdx];
298 | var content = bidiTexts[divIdx].str.substring(fromOffset, toOffset);
299 | var node = document.createTextNode(content);
300 | if (className) {
301 | var span = document.createElement('span');
302 | span.className = className;
303 | span.appendChild(node);
304 | div.appendChild(span);
305 | return;
306 | }
307 | div.appendChild(node);
308 | }
309 |
310 | var i0 = selectedMatchIdx, i1 = i0 + 1;
311 | if (highlightAll) {
312 | i0 = 0;
313 | i1 = matches.length;
314 | } else if (!isSelectedPage) {
315 | // Not highlighting all and this isn't the selected page, so do nothing.
316 | return;
317 | }
318 |
319 | for (var i = i0; i < i1; i++) {
320 | var match = matches[i];
321 | var begin = match.begin;
322 | var end = match.end;
323 | var isSelected = (isSelectedPage && i === selectedMatchIdx);
324 | var highlightSuffix = (isSelected ? ' selected' : '');
325 |
326 | if (this.findController) {
327 | this.findController.updateMatchPosition(pageIdx, i, textDivs,
328 | begin.divIdx, end.divIdx);
329 | }
330 |
331 | // Match inside new div.
332 | if (!prevEnd || begin.divIdx !== prevEnd.divIdx) {
333 | // If there was a previous div, then add the text at the end.
334 | if (prevEnd !== null) {
335 | appendTextToDiv(prevEnd.divIdx, prevEnd.offset, infinity.offset);
336 | }
337 | // Clear the divs and set the content until the starting point.
338 | beginText(begin);
339 | } else {
340 | appendTextToDiv(prevEnd.divIdx, prevEnd.offset, begin.offset);
341 | }
342 |
343 | if (begin.divIdx === end.divIdx) {
344 | appendTextToDiv(begin.divIdx, begin.offset, end.offset,
345 | 'highlight' + highlightSuffix);
346 | } else {
347 | appendTextToDiv(begin.divIdx, begin.offset, infinity.offset,
348 | 'highlight begin' + highlightSuffix);
349 | for (var n0 = begin.divIdx + 1, n1 = end.divIdx; n0 < n1; n0++) {
350 | textDivs[n0].className = 'highlight middle' + highlightSuffix;
351 | }
352 | beginText(end, 'highlight end' + highlightSuffix);
353 | }
354 | prevEnd = end;
355 | }
356 |
357 | if (prevEnd) {
358 | appendTextToDiv(prevEnd.divIdx, prevEnd.offset, infinity.offset);
359 | }
360 | },
361 |
362 | updateMatches: function TextLayerBuilder_updateMatches() {
363 | // Only show matches when all rendering is done.
364 | if (!this.renderingDone) {
365 | return;
366 | }
367 |
368 | // Clear all matches.
369 | var matches = this.matches;
370 | var textDivs = this.textDivs;
371 | var bidiTexts = this.textContent.items;
372 | var clearedUntilDivIdx = -1;
373 |
374 | // Clear all current matches.
375 | for (var i = 0, len = matches.length; i < len; i++) {
376 | var match = matches[i];
377 | var begin = Math.max(clearedUntilDivIdx, match.begin.divIdx);
378 | for (var n = begin, end = match.end.divIdx; n <= end; n++) {
379 | var div = textDivs[n];
380 | div.textContent = bidiTexts[n].str;
381 | div.className = '';
382 | }
383 | clearedUntilDivIdx = match.end.divIdx + 1;
384 | }
385 |
386 | if (this.findController === null || !this.findController.active) {
387 | return;
388 | }
389 |
390 | // Convert the matches on the page controller into the match format
391 | // used for the textLayer.
392 | this.matches = this.convertMatches(this.findController === null ?
393 | [] : (this.findController.pageMatches[this.pageIdx] || []));
394 | this.renderMatches(this.matches);
395 | }
396 | };
397 | return TextLayerBuilder;
398 | })();
399 |
400 | /**
401 | * @constructor
402 | * @implements IPDFTextLayerFactory
403 | */
404 | function DefaultTextLayerFactory() {}
405 | DefaultTextLayerFactory.prototype = {
406 | /**
407 | * @param {HTMLDivElement} textLayerDiv
408 | * @param {number} pageIndex
409 | * @param {PageViewport} viewport
410 | * @returns {TextLayerBuilder}
411 | */
412 | createTextLayerBuilder: function (textLayerDiv, pageIndex, viewport) {
413 | return new TextLayerBuilder({
414 | textLayerDiv: textLayerDiv,
415 | pageIndex: pageIndex,
416 | viewport: viewport
417 | });
418 | }
419 | };
420 |
--------------------------------------------------------------------------------
/laraview/ui_utils.js:
--------------------------------------------------------------------------------
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 | var CSS_UNITS = 96.0 / 72.0;
20 | var DEFAULT_SCALE = 'auto';
21 | var UNKNOWN_SCALE = 0;
22 | var MAX_AUTO_SCALE = 1.25;
23 | var SCROLLBAR_PADDING = 40;
24 | var VERTICAL_PADDING = 5;
25 |
26 | // optimised CSS custom property getter/setter
27 | var CustomStyle = (function CustomStyleClosure() {
28 |
29 | // As noted on: http://www.zachstronaut.com/posts/2009/02/17/
30 | // animate-css-transforms-firefox-webkit.html
31 | // in some versions of IE9 it is critical that ms appear in this list
32 | // before Moz
33 | var prefixes = ['ms', 'Moz', 'Webkit', 'O'];
34 | var _cache = {};
35 |
36 | function CustomStyle() {}
37 |
38 | CustomStyle.getProp = function get(propName, element) {
39 | // check cache only when no element is given
40 | if (arguments.length === 1 && typeof _cache[propName] === 'string') {
41 | return _cache[propName];
42 | }
43 |
44 | element = element || document.documentElement;
45 | var style = element.style, prefixed, uPropName;
46 |
47 | // test standard property first
48 | if (typeof style[propName] === 'string') {
49 | return (_cache[propName] = propName);
50 | }
51 |
52 | // capitalize
53 | uPropName = propName.charAt(0).toUpperCase() + propName.slice(1);
54 |
55 | // test vendor specific properties
56 | for (var i = 0, l = prefixes.length; i < l; i++) {
57 | prefixed = prefixes[i] + uPropName;
58 | if (typeof style[prefixed] === 'string') {
59 | return (_cache[propName] = prefixed);
60 | }
61 | }
62 |
63 | //if all fails then set to undefined
64 | return (_cache[propName] = 'undefined');
65 | };
66 |
67 | CustomStyle.setProp = function set(propName, element, str) {
68 | var prop = this.getProp(propName);
69 | if (prop !== 'undefined') {
70 | element.style[prop] = str;
71 | }
72 | };
73 |
74 | return CustomStyle;
75 | })();
76 |
77 | function getFileName(url) {
78 | var anchor = url.indexOf('#');
79 | var query = url.indexOf('?');
80 | var end = Math.min(
81 | anchor > 0 ? anchor : url.length,
82 | query > 0 ? query : url.length);
83 | return url.substring(url.lastIndexOf('/', end) + 1, end);
84 | }
85 |
86 | /**
87 | * Returns scale factor for the canvas. It makes sense for the HiDPI displays.
88 | * @return {Object} The object with horizontal (sx) and vertical (sy)
89 | scales. The scaled property is set to false if scaling is
90 | not required, true otherwise.
91 | */
92 | function getOutputScale(ctx) {
93 | var devicePixelRatio = window.devicePixelRatio || 1;
94 | var backingStoreRatio = ctx.webkitBackingStorePixelRatio ||
95 | ctx.mozBackingStorePixelRatio ||
96 | ctx.msBackingStorePixelRatio ||
97 | ctx.oBackingStorePixelRatio ||
98 | ctx.backingStorePixelRatio || 1;
99 | var pixelRatio = devicePixelRatio / backingStoreRatio;
100 | return {
101 | sx: pixelRatio,
102 | sy: pixelRatio,
103 | scaled: pixelRatio !== 1
104 | };
105 | }
106 |
107 | /**
108 | * Scrolls specified element into view of its parent.
109 | * element {Object} The element to be visible.
110 | * spot {Object} An object with optional top and left properties,
111 | * specifying the offset from the top left edge.
112 | */
113 | function scrollIntoView(element, spot) {
114 | // Assuming offsetParent is available (it's not available when viewer is in
115 | // hidden iframe or object). We have to scroll: if the offsetParent is not set
116 | // producing the error. See also animationStartedClosure.
117 | var parent = element.offsetParent;
118 | var offsetY = element.offsetTop + element.clientTop;
119 | var offsetX = element.offsetLeft + element.clientLeft;
120 | if (!parent) {
121 | console.error('offsetParent is not set -- cannot scroll');
122 | return;
123 | }
124 | while (parent.clientHeight === parent.scrollHeight) {
125 | if (parent.dataset._scaleY) {
126 | offsetY /= parent.dataset._scaleY;
127 | offsetX /= parent.dataset._scaleX;
128 | }
129 | offsetY += parent.offsetTop;
130 | offsetX += parent.offsetLeft;
131 | parent = parent.offsetParent;
132 | if (!parent) {
133 | return; // no need to scroll
134 | }
135 | }
136 | if (spot) {
137 | if (spot.top !== undefined) {
138 | offsetY += spot.top;
139 | }
140 | if (spot.left !== undefined) {
141 | offsetX += spot.left;
142 | parent.scrollLeft = offsetX;
143 | }
144 | }
145 | parent.scrollTop = offsetY;
146 | }
147 |
148 | /**
149 | * Helper function to start monitoring the scroll event and converting them into
150 | * PDF.js friendly one: with scroll debounce and scroll direction.
151 | */
152 | function watchScroll(viewAreaElement, callback) {
153 | var debounceScroll = function debounceScroll(evt) {
154 | if (rAF) {
155 | return;
156 | }
157 | // schedule an invocation of scroll for next animation frame.
158 | rAF = window.requestAnimationFrame(function viewAreaElementScrolled() {
159 | rAF = null;
160 |
161 | var currentY = viewAreaElement.scrollTop;
162 | var lastY = state.lastY;
163 | if (currentY !== lastY) {
164 | state.down = currentY > lastY;
165 | }
166 | state.lastY = currentY;
167 | callback(state);
168 | });
169 | };
170 |
171 | var state = {
172 | down: true,
173 | lastY: viewAreaElement.scrollTop,
174 | _eventHandler: debounceScroll
175 | };
176 |
177 | var rAF = null;
178 | viewAreaElement.addEventListener('scroll', debounceScroll, true);
179 | return state;
180 | }
181 |
182 | /**
183 | * Use binary search to find the index of the first item in a given array which
184 | * passes a given condition. The items are expected to be sorted in the sense
185 | * that if the condition is true for one item in the array, then it is also true
186 | * for all following items.
187 | *
188 | * @returns {Number} Index of the first array element to pass the test,
189 | * or |items.length| if no such element exists.
190 | */
191 | function binarySearchFirstItem(items, condition) {
192 | var minIndex = 0;
193 | var maxIndex = items.length - 1;
194 |
195 | if (items.length === 0 || !condition(items[maxIndex])) {
196 | return items.length;
197 | }
198 | if (condition(items[minIndex])) {
199 | return minIndex;
200 | }
201 |
202 | while (minIndex < maxIndex) {
203 | var currentIndex = (minIndex + maxIndex) >> 1;
204 | var currentItem = items[currentIndex];
205 | if (condition(currentItem)) {
206 | maxIndex = currentIndex;
207 | } else {
208 | minIndex = currentIndex + 1;
209 | }
210 | }
211 | return minIndex; /* === maxIndex */
212 | }
213 |
214 | /**
215 | * Generic helper to find out what elements are visible within a scroll pane.
216 | */
217 | function getVisibleElements(scrollEl, views, sortByVisibility) {
218 | var top = scrollEl.scrollTop, bottom = top + scrollEl.clientHeight;
219 | var left = scrollEl.scrollLeft, right = left + scrollEl.clientWidth;
220 |
221 | function isElementBottomBelowViewTop(view) {
222 | var element = view.div;
223 | var elementBottom =
224 | element.offsetTop + element.clientTop + element.clientHeight;
225 | return elementBottom > top;
226 | }
227 |
228 | var visible = [], view, element;
229 | var currentHeight, viewHeight, hiddenHeight, percentHeight;
230 | var currentWidth, viewWidth;
231 | var firstVisibleElementInd = (views.length === 0) ? 0 :
232 | binarySearchFirstItem(views, isElementBottomBelowViewTop);
233 |
234 | for (var i = firstVisibleElementInd, ii = views.length; i < ii; i++) {
235 | view = views[i];
236 | element = view.div;
237 | currentHeight = element.offsetTop + element.clientTop;
238 | viewHeight = element.clientHeight;
239 |
240 | if (currentHeight > bottom) {
241 | break;
242 | }
243 |
244 | currentWidth = element.offsetLeft + element.clientLeft;
245 | viewWidth = element.clientWidth;
246 | if (currentWidth + viewWidth < left || currentWidth > right) {
247 | continue;
248 | }
249 | hiddenHeight = Math.max(0, top - currentHeight) +
250 | Math.max(0, currentHeight + viewHeight - bottom);
251 | percentHeight = ((viewHeight - hiddenHeight) * 100 / viewHeight) | 0;
252 |
253 | visible.push({
254 | id: view.id,
255 | x: currentWidth,
256 | y: currentHeight,
257 | view: view,
258 | percent: percentHeight
259 | });
260 | }
261 |
262 | var first = visible[0];
263 | var last = visible[visible.length - 1];
264 |
265 | if (sortByVisibility) {
266 | visible.sort(function(a, b) {
267 | var pc = a.percent - b.percent;
268 | if (Math.abs(pc) > 0.001) {
269 | return -pc;
270 | }
271 | return a.id - b.id; // ensure stability
272 | });
273 | }
274 | return {first: first, last: last, views: visible};
275 | }
276 |
277 | /**
278 | * Event handler to suppress context menu.
279 | */
280 | function noContextMenuHandler(e) {
281 | e.preventDefault();
282 | }
283 |
284 | /**
285 | * Returns the filename or guessed filename from the url (see issue 3455).
286 | * url {String} The original PDF location.
287 | * @return {String} Guessed PDF file name.
288 | */
289 | function getPDFFileNameFromURL(url) {
290 | var reURI = /^(?:([^:]+:)?\/\/[^\/]+)?([^?#]*)(\?[^#]*)?(#.*)?$/;
291 | // SCHEME HOST 1.PATH 2.QUERY 3.REF
292 | // Pattern to get last matching NAME.pdf
293 | var reFilename = /[^\/?#=]+\.pdf\b(?!.*\.pdf\b)/i;
294 | var splitURI = reURI.exec(url);
295 | var suggestedFilename = reFilename.exec(splitURI[1]) ||
296 | reFilename.exec(splitURI[2]) ||
297 | reFilename.exec(splitURI[3]);
298 | if (suggestedFilename) {
299 | suggestedFilename = suggestedFilename[0];
300 | if (suggestedFilename.indexOf('%') !== -1) {
301 | // URL-encoded %2Fpath%2Fto%2Ffile.pdf should be file.pdf
302 | try {
303 | suggestedFilename =
304 | reFilename.exec(decodeURIComponent(suggestedFilename))[0];
305 | } catch(e) { // Possible (extremely rare) errors:
306 | // URIError "Malformed URI", e.g. for "%AA.pdf"
307 | // TypeError "null has no properties", e.g. for "%2F.pdf"
308 | }
309 | }
310 | }
311 | return suggestedFilename || 'document.pdf';
312 | }
313 |
314 | var ProgressBar = (function ProgressBarClosure() {
315 |
316 | function clamp(v, min, max) {
317 | return Math.min(Math.max(v, min), max);
318 | }
319 |
320 | function ProgressBar(id, opts) {
321 | this.visible = true;
322 |
323 | // Fetch the sub-elements for later.
324 | this.div = document.querySelector(id + ' .progress');
325 |
326 | // Get the loading bar element, so it can be resized to fit the viewer.
327 | this.bar = this.div.parentNode;
328 |
329 | // Get options, with sensible defaults.
330 | this.height = opts.height || 100;
331 | this.width = opts.width || 100;
332 | this.units = opts.units || '%';
333 |
334 | // Initialize heights.
335 | this.div.style.height = this.height + this.units;
336 | this.percent = 0;
337 | }
338 |
339 | ProgressBar.prototype = {
340 |
341 | updateBar: function ProgressBar_updateBar() {
342 | if (this._indeterminate) {
343 | this.div.classList.add('indeterminate');
344 | this.div.style.width = this.width + this.units;
345 | return;
346 | }
347 |
348 | this.div.classList.remove('indeterminate');
349 | var progressSize = this.width * this._percent / 100;
350 | this.div.style.width = progressSize + this.units;
351 | },
352 |
353 | get percent() {
354 | return this._percent;
355 | },
356 |
357 | set percent(val) {
358 | this._indeterminate = isNaN(val);
359 | this._percent = clamp(val, 0, 100);
360 | this.updateBar();
361 | },
362 |
363 | setWidth: function ProgressBar_setWidth(viewer) {
364 | if (viewer) {
365 | var container = viewer.parentNode;
366 | var scrollbarWidth = container.offsetWidth - viewer.offsetWidth;
367 | if (scrollbarWidth > 0) {
368 | this.bar.setAttribute('style', 'width: calc(100% - ' +
369 | scrollbarWidth + 'px);');
370 | }
371 | }
372 | },
373 |
374 | hide: function ProgressBar_hide() {
375 | if (!this.visible) {
376 | return;
377 | }
378 | this.visible = false;
379 | this.bar.classList.add('hidden');
380 | document.body.classList.remove('loadingInProgress');
381 | },
382 |
383 | show: function ProgressBar_show() {
384 | if (this.visible) {
385 | return;
386 | }
387 | this.visible = true;
388 | document.body.classList.add('loadingInProgress');
389 | this.bar.classList.remove('hidden');
390 | }
391 | };
392 |
393 | return ProgressBar;
394 | })();
395 |
--------------------------------------------------------------------------------
/src/Facade/LaravelPdfViewer.php:
--------------------------------------------------------------------------------
1 |
7 | * (c) David Passmore
8 | *
9 | * For the full copyright and license information, please view the LICENSE
10 | * file that was distributed with this source code.
11 | */
12 |
13 | namespace Davcpas1234\LaravelPdfViewer\Facade;
14 | use Illuminate\Support\Facades\Facade;
15 |
16 | class LaravelPdfViewer extends Facade
17 | {
18 | protected static function getFacadeAccessor()
19 | {
20 | return 'laravelpdfviewer';
21 | }
22 | }
23 |
--------------------------------------------------------------------------------
/src/LaravelPdfViewerServiceProvider.php:
--------------------------------------------------------------------------------
1 |
7 | * (c) David Passmore
8 | *
9 | * For the full copyright and license information, please view the LICENSE
10 | * file that was distributed with this source code.
11 | */
12 |
13 | namespace Davcpas1234\LaravelPdfViewer;
14 |
15 | use Illuminate\Support\ServiceProvider;
16 |
17 | class LaravelPdfViewerServiceProvider extends ServiceProvider
18 | {
19 | /**
20 | * Bootstrap the application services.
21 | *
22 | * @return void
23 | */
24 | public function boot()
25 | {
26 | $this->publishes([
27 | __DIR__.DIRECTORY_SEPARATOR.'..'.DIRECTORY_SEPARATOR.'laraview' => public_path('laraview'),
28 | ], 'public');
29 | }
30 |
31 | /**
32 | * Register the application services.
33 | *
34 | * @return void
35 | */
36 | public function register()
37 | {
38 | //
39 | }
40 | }
41 |
--------------------------------------------------------------------------------