UNPKG

13.5 kBJavaScriptView Raw
1/**
2 * PDFObject v2.2.6
3 * https://github.com/pipwerks/PDFObject
4 * @license
5 * Copyright (c) 2008-2021 Philip Hutchison
6 * MIT-style license: http://pipwerks.mit-license.org/
7 * UMD module pattern from https://github.com/umdjs/umd/blob/master/templates/returnExports.js
8 */
9
10(function (root, factory) {
11 if (typeof define === "function" && define.amd) {
12 // AMD. Register as an anonymous module.
13 define([], factory);
14 } else if (typeof module === "object" && module.exports) {
15 // Node. Does not work with strict CommonJS, but
16 // only CommonJS-like environments that support module.exports,
17 // like Node.
18 module.exports = factory();
19 } else {
20 // Browser globals (root is window)
21 root.PDFObject = factory();
22 }
23}(this, function () {
24
25 "use strict";
26
27 //PDFObject is designed for client-side (browsers), not server-side (node)
28 //Will choke on undefined navigator and window vars when run on server
29 //Return boolean false and exit function when running server-side
30
31 if( typeof window === "undefined" ||
32 window.navigator === undefined ||
33 window.navigator.userAgent === undefined ||
34 window.navigator.mimeTypes === undefined){
35 return false;
36 }
37
38 let pdfobjectversion = "2.2.6";
39 let nav = window.navigator;
40 let ua = window.navigator.userAgent;
41
42 //Time to jump through hoops -- browser vendors do not make it easy to detect PDF support.
43
44 /*
45 IE11 still uses ActiveX for Adobe Reader, but IE 11 doesn't expose window.ActiveXObject the same way
46 previous versions of IE did. window.ActiveXObject will evaluate to false in IE 11, but "ActiveXObject"
47 in window evaluates to true.
48
49 MS Edge does not support ActiveX so this test will evaluate false
50 */
51 let isIE = ("ActiveXObject" in window);
52
53 /*
54 There is a coincidental correlation between implementation of window.promises and native PDF support in desktop browsers
55 We use this to assume if the browser supports promises it supports embedded PDFs
56 Is this fragile? Sort of. But browser vendors removed mimetype detection, so we're left to improvise
57 */
58 let isModernBrowser = (window.Promise !== undefined);
59
60 //Older browsers still expose the mimeType
61 let supportsPdfMimeType = (nav.mimeTypes["application/pdf"] !== undefined);
62
63 //Safari on iPadOS doesn't report as 'mobile' when requesting desktop site, yet still fails to embed PDFs
64 let isSafariIOSDesktopMode = ( nav.platform !== undefined &&
65 nav.platform === "MacIntel" &&
66 nav.maxTouchPoints !== undefined &&
67 nav.maxTouchPoints > 1 );
68
69 //Quick test for mobile devices.
70 let isMobileDevice = (isSafariIOSDesktopMode || /Mobi|Tablet|Android|iPad|iPhone/.test(ua));
71
72 //Safari desktop requires special handling
73 let isSafariDesktop = ( !isMobileDevice &&
74 nav.vendor !== undefined &&
75 /Apple/.test(nav.vendor) &&
76 /Safari/.test(ua) );
77
78 //Firefox started shipping PDF.js in Firefox 19. If this is Firefox 19 or greater, assume PDF.js is available
79 let isFirefoxWithPDFJS = (!isMobileDevice && /irefox/.test(ua) && ua.split("rv:").length > 1) ? (parseInt(ua.split("rv:")[1].split(".")[0], 10) > 18) : false;
80
81
82 /* ----------------------------------------------------
83 Supporting functions
84 ---------------------------------------------------- */
85
86 let createAXO = function (type){
87 var ax;
88 try {
89 ax = new ActiveXObject(type);
90 } catch (e) {
91 ax = null; //ensure ax remains null
92 }
93 return ax;
94 };
95
96 //If either ActiveX support for "AcroPDF.PDF" or "PDF.PdfCtrl" are found, return true
97 //Constructed as a method (not a prop) to avoid unneccesarry overhead -- will only be evaluated if needed
98 let supportsPdfActiveX = function (){ return !!(createAXO("AcroPDF.PDF") || createAXO("PDF.PdfCtrl")); };
99
100 //Determines whether PDF support is available
101 let supportsPDFs = (
102 //As of Sept 2020 no mobile browsers properly support PDF embeds
103 !isMobileDevice && (
104 //We're moving into the age of MIME-less browsers. They mostly all support PDF rendering without plugins.
105 isModernBrowser ||
106 //Modern versions of Firefox come bundled with PDFJS
107 isFirefoxWithPDFJS ||
108 //Browsers that still support the original MIME type check
109 supportsPdfMimeType ||
110 //Pity the poor souls still using IE
111 (isIE && supportsPdfActiveX())
112 )
113 );
114
115 //Create a fragment identifier for using PDF Open parameters when embedding PDF
116 let buildURLFragmentString = function(pdfParams){
117
118 let string = "";
119 let prop;
120
121 if(pdfParams){
122
123 for (prop in pdfParams) {
124 if (pdfParams.hasOwnProperty(prop)) {
125 string += encodeURIComponent(prop) + "=" + encodeURIComponent(pdfParams[prop]) + "&";
126 }
127 }
128
129 //The string will be empty if no PDF Params found
130 if(string){
131
132 string = "#" + string;
133
134 //Remove last ampersand
135 string = string.slice(0, string.length - 1);
136
137 }
138
139 }
140
141 return string;
142
143 };
144
145 let embedError = function (msg, suppressConsole){
146 if(!suppressConsole){
147 console.log("[PDFObject] " + msg);
148 }
149 return false;
150 };
151
152 let emptyNodeContents = function (node){
153 while(node.firstChild){
154 node.removeChild(node.firstChild);
155 }
156 };
157
158 let getTargetElement = function (targetSelector){
159
160 //Default to body for full-browser PDF
161 let targetNode = document.body;
162
163 //If a targetSelector is specified, check to see whether
164 //it's passing a selector, jQuery object, or an HTML element
165
166 if(typeof targetSelector === "string"){
167
168 //Is CSS selector
169 targetNode = document.querySelector(targetSelector);
170
171 } else if (window.jQuery !== undefined && targetSelector instanceof jQuery && targetSelector.length) {
172
173 //Is jQuery element. Extract HTML node
174 targetNode = targetSelector.get(0);
175
176 } else if (targetSelector.nodeType !== undefined && targetSelector.nodeType === 1){
177
178 //Is HTML element
179 targetNode = targetSelector;
180
181 }
182
183 return targetNode;
184
185 };
186
187 let generatePDFJSMarkup = function (targetNode, url, pdfOpenFragment, PDFJS_URL, id, omitInlineStyles){
188
189 //Ensure target element is empty first
190 emptyNodeContents(targetNode);
191
192 let fullURL = PDFJS_URL + "?file=" + encodeURIComponent(url) + pdfOpenFragment;
193 let div = document.createElement("div");
194 let iframe = document.createElement("iframe");
195
196 iframe.src = fullURL;
197 iframe.className = "pdfobject";
198 iframe.type = "application/pdf";
199 iframe.frameborder = "0";
200 iframe.allow = "fullscreen";
201
202 if(id){
203 iframe.id = id;
204 }
205
206 if(!omitInlineStyles){
207 div.style.cssText = "position: absolute; top: 0; right: 0; bottom: 0; left: 0;";
208 iframe.style.cssText = "border: none; width: 100%; height: 100%;";
209 targetNode.style.position = "relative";
210 targetNode.style.overflow = "auto";
211 }
212
213 div.appendChild(iframe);
214 targetNode.appendChild(div);
215 targetNode.classList.add("pdfobject-container");
216
217 return targetNode.getElementsByTagName("iframe")[0];
218
219 };
220
221 let generatePDFObjectMarkup = function (embedType, targetNode, targetSelector, url, pdfOpenFragment, width, height, id, title, omitInlineStyles){
222
223 //Ensure target element is empty first
224 emptyNodeContents(targetNode);
225
226 let embed = document.createElement(embedType);
227 embed.src = url + pdfOpenFragment;
228 embed.className = "pdfobject";
229 embed.type = "application/pdf";
230 embed.title = title;
231
232 if(id){
233 embed.id = id;
234 }
235
236 if(embedType === "iframe"){
237 embed.allow = "fullscreen";
238 }
239
240 if(!omitInlineStyles){
241
242 let style = (embedType === "embed") ? "overflow: auto;" : "border: none;";
243
244 if(targetSelector && targetSelector !== document.body){
245 style += "width: " + width + "; height: " + height + ";";
246 } else {
247 style += "position: absolute; top: 0; right: 0; bottom: 0; left: 0; width: 100%; height: 100%;";
248 }
249
250 embed.style.cssText = style;
251
252 }
253
254 targetNode.classList.add("pdfobject-container");
255 targetNode.appendChild(embed);
256
257 return targetNode.getElementsByTagName(embedType)[0];
258
259 };
260
261 let embed = function(url, targetSelector, options){
262
263 //If targetSelector is not defined, convert to boolean
264 let selector = targetSelector || false;
265
266 //Ensure options object is not undefined -- enables easier error checking below
267 let opt = options || {};
268
269 //Get passed options, or set reasonable defaults
270 let id = (typeof opt.id === "string") ? opt.id : "";
271 let page = opt.page || false;
272 let pdfOpenParams = opt.pdfOpenParams || {};
273 let fallbackLink = opt.fallbackLink || true;
274 let width = opt.width || "100%";
275 let height = opt.height || "100%";
276 let title = opt.title || "Embedded PDF";
277 let assumptionMode = (typeof opt.assumptionMode === "boolean") ? opt.assumptionMode : true;
278 let forcePDFJS = (typeof opt.forcePDFJS === "boolean") ? opt.forcePDFJS : false;
279 let supportRedirect = (typeof opt.supportRedirect === "boolean") ? opt.supportRedirect : false;
280 let omitInlineStyles = (typeof opt.omitInlineStyles === "boolean") ? opt.omitInlineStyles : false;
281 let suppressConsole = (typeof opt.suppressConsole === "boolean") ? opt.suppressConsole : false;
282 let forceIframe = (typeof opt.forceIframe === "boolean") ? opt.forceIframe : false;
283 let PDFJS_URL = opt.PDFJS_URL || false;
284 let targetNode = getTargetElement(selector);
285 let fallbackHTML = "";
286 let pdfOpenFragment = "";
287 let fallbackHTML_default = "<p>This browser does not support inline PDFs. Please download the PDF to view it: <a href='[url]'>Download PDF</a></p>";
288
289 //Ensure URL is available. If not, exit now.
290 if(typeof url !== "string"){ return embedError("URL is not valid", suppressConsole); }
291
292 //If target element is specified but is not valid, exit without doing anything
293 if(!targetNode){ return embedError("Target element cannot be determined", suppressConsole); }
294
295 //page option overrides pdfOpenParams, if found
296 if(page){ pdfOpenParams.page = page; }
297
298 //Stringify optional Adobe params for opening document (as fragment identifier)
299 pdfOpenFragment = buildURLFragmentString(pdfOpenParams);
300
301
302 // --== Do the dance: Embed attempt #1 ==--
303
304 //If the forcePDFJS option is invoked, skip everything else and embed as directed
305 if(forcePDFJS && PDFJS_URL){
306 return generatePDFJSMarkup(targetNode, url, pdfOpenFragment, PDFJS_URL, id, omitInlineStyles);
307 }
308
309 // --== Embed attempt #2 ==--
310
311 //Embed PDF if traditional support is provided, or if this developer is willing to roll with assumption
312 //that modern desktop (not mobile) browsers natively support PDFs
313 if(supportsPDFs || (assumptionMode && !isMobileDevice)){
314
315 //Should we use <embed> or <iframe>? In most cases <embed>.
316 //Allow developer to force <iframe>, if desired
317 //There is an edge case where Safari does not respect 302 redirect requests for PDF files when using <embed> element.
318 //Redirect appears to work fine when using <iframe> instead of <embed> (Addresses issue #210)
319 //Forcing Safari desktop to use iframe due to freezing bug in macOS 11 (Big Sur)
320 let embedtype = (forceIframe || supportRedirect || isSafariDesktop) ? "iframe" : "embed";
321
322 return generatePDFObjectMarkup(embedtype, targetNode, targetSelector, url, pdfOpenFragment, width, height, id, title, omitInlineStyles);
323
324 }
325
326 // --== Embed attempt #3 ==--
327
328 //If everything else has failed and a PDFJS fallback is provided, try to use it
329 if(PDFJS_URL){
330 return generatePDFJSMarkup(targetNode, url, pdfOpenFragment, PDFJS_URL, id, omitInlineStyles);
331 }
332
333 // --== PDF embed not supported! Use fallback ==--
334
335 //Display the fallback link if available
336 if(fallbackLink){
337
338 fallbackHTML = (typeof fallbackLink === "string") ? fallbackLink : fallbackHTML_default;
339 targetNode.innerHTML = fallbackHTML.replace(/\[url\]/g, url);
340
341 }
342
343 return embedError("This browser does not support embedded PDFs", suppressConsole);
344
345 };
346
347 return {
348 embed: function (a,b,c){ return embed(a,b,c); },
349 pdfobjectversion: (function () { return pdfobjectversion; })(),
350 supportsPDFs: (function (){ return supportsPDFs; })()
351 };
352
353}));