UNPKG

13.4 kBJavaScriptView Raw
1/**
2 * PDFObject v2.2.5
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.3";
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, 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
231 if(id){
232 embed.id = id;
233 }
234
235 if(embedType === "iframe"){
236 embed.allow = "fullscreen";
237 }
238
239 if(!omitInlineStyles){
240
241 let style = (embedType === "embed") ? "overflow: auto;" : "border: none;";
242
243 if(targetSelector && targetSelector !== document.body){
244 style += "width: " + width + "; height: " + height + ";";
245 } else {
246 style += "position: absolute; top: 0; right: 0; bottom: 0; left: 0; width: 100%; height: 100%;";
247 }
248
249 embed.style.cssText = style;
250
251 }
252
253 targetNode.classList.add("pdfobject-container");
254 targetNode.appendChild(embed);
255
256 return targetNode.getElementsByTagName(embedType)[0];
257
258 };
259
260 let embed = function(url, targetSelector, options){
261
262 //If targetSelector is not defined, convert to boolean
263 let selector = targetSelector || false;
264
265 //Ensure options object is not undefined -- enables easier error checking below
266 let opt = options || {};
267
268 //Get passed options, or set reasonable defaults
269 let id = (typeof opt.id === "string") ? opt.id : "";
270 let page = opt.page || false;
271 let pdfOpenParams = opt.pdfOpenParams || {};
272 let fallbackLink = opt.fallbackLink || true;
273 let width = opt.width || "100%";
274 let height = opt.height || "100%";
275 let assumptionMode = (typeof opt.assumptionMode === "boolean") ? opt.assumptionMode : true;
276 let forcePDFJS = (typeof opt.forcePDFJS === "boolean") ? opt.forcePDFJS : false;
277 let supportRedirect = (typeof opt.supportRedirect === "boolean") ? opt.supportRedirect : false;
278 let omitInlineStyles = (typeof opt.omitInlineStyles === "boolean") ? opt.omitInlineStyles : false;
279 let suppressConsole = (typeof opt.suppressConsole === "boolean") ? opt.suppressConsole : false;
280 let forceIframe = (typeof opt.forceIframe === "boolean") ? opt.forceIframe : false;
281 let PDFJS_URL = opt.PDFJS_URL || false;
282 let targetNode = getTargetElement(selector);
283 let fallbackHTML = "";
284 let pdfOpenFragment = "";
285 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>";
286
287 //Ensure URL is available. If not, exit now.
288 if(typeof url !== "string"){ return embedError("URL is not valid", suppressConsole); }
289
290 //If target element is specified but is not valid, exit without doing anything
291 if(!targetNode){ return embedError("Target element cannot be determined", suppressConsole); }
292
293 //page option overrides pdfOpenParams, if found
294 if(page){ pdfOpenParams.page = page; }
295
296 //Stringify optional Adobe params for opening document (as fragment identifier)
297 pdfOpenFragment = buildURLFragmentString(pdfOpenParams);
298
299
300 // --== Do the dance: Embed attempt #1 ==--
301
302 //If the forcePDFJS option is invoked, skip everything else and embed as directed
303 if(forcePDFJS && PDFJS_URL){
304 return generatePDFJSMarkup(targetNode, url, pdfOpenFragment, PDFJS_URL, id, omitInlineStyles);
305 }
306
307 // --== Embed attempt #2 ==--
308
309 //Embed PDF if traditional support is provided, or if this developer is willing to roll with assumption
310 //that modern desktop (not mobile) browsers natively support PDFs
311 if(supportsPDFs || (assumptionMode && !isMobileDevice)){
312
313 //Should we use <embed> or <iframe>? In most cases <embed>.
314 //Allow developer to force <iframe>, if desired
315 //There is an edge case where Safari does not respect 302 redirect requests for PDF files when using <embed> element.
316 //Redirect appears to work fine when using <iframe> instead of <embed> (Addresses issue #210)
317 let embedtype = (forceIframe || (supportRedirect && isSafariDesktop)) ? "iframe" : "embed";
318
319 return generatePDFObjectMarkup(embedtype, targetNode, targetSelector, url, pdfOpenFragment, width, height, id, omitInlineStyles);
320
321 }
322
323 // --== Embed attempt #3 ==--
324
325 //If everything else has failed and a PDFJS fallback is provided, try to use it
326 if(PDFJS_URL){
327 return generatePDFJSMarkup(targetNode, url, pdfOpenFragment, PDFJS_URL, id, omitInlineStyles);
328 }
329
330 // --== PDF embed not supported! Use fallback ==--
331
332 //Display the fallback link if available
333 if(fallbackLink){
334
335 fallbackHTML = (typeof fallbackLink === "string") ? fallbackLink : fallbackHTML_default;
336 targetNode.innerHTML = fallbackHTML.replace(/\[url\]/g, url);
337
338 }
339
340 return embedError("This browser does not support embedded PDFs", suppressConsole);
341
342 };
343
344 return {
345 embed: function (a,b,c){ return embed(a,b,c); },
346 pdfobjectversion: (function () { return pdfobjectversion; })(),
347 supportsPDFs: (function (){ return supportsPDFs; })()
348 };
349
350}));