|
40 | 40 | let isModernBrowser = function (){
|
41 | 41 |
|
42 | 42 | /*
|
43 |
| - userAgent sniffing is not the ideal path, but most browsers revoked the ability to check navigator.mimeTypes |
| 43 | + userAgent sniffing is not the ideal path, but most browsers revoked the ability to check navigator.mimeTypes |
44 | 44 | for security purposes. As of 2023, browsers have begun implementing navigator.pdfViewerEnabled, but older versions
|
45 |
| - do not have navigator.pdfViewerEnabled or the ability to check navigator.mimeTypes. We're left with basic browser |
| 45 | + do not have navigator.pdfViewerEnabled or the ability to check navigator.mimeTypes. We're left with basic browser |
46 | 46 | sniffing and assumptions of PDF support based on browser vendor.
|
47 | 47 | */
|
48 | 48 |
|
|
52 | 52 | //Note that MS Edge opts to use a different PDF rendering engine. As of 2024, Edge uses a version of Adobe's Reader
|
53 | 53 | let isChromium = (win.chrome !== undefined);
|
54 | 54 |
|
55 |
| - //Safari on macOS has provided native PDF support since 2009. |
| 55 | + //Safari on macOS has provided native PDF support since 2009. |
56 | 56 | //This code snippet also detects the DuckDuckGo browser, which uses Safari/Webkit under the hood.
|
57 | 57 | let isSafari = (win.safari !== undefined || (nav.vendor !== undefined && /Apple/.test(nav.vendor) && /Safari/.test(ua)));
|
58 | 58 |
|
59 | 59 | //Firefox has provided PDF support via PDFJS since 2013.
|
60 | 60 | let isFirefox = (win.Mozilla !== undefined || /irefox/.test(ua));
|
61 | 61 |
|
62 |
| - return isChromium || isSafari || isFirefox; |
| 62 | + return isChromium || isSafari || isFirefox; |
63 | 63 |
|
64 | 64 | };
|
65 | 65 |
|
66 | 66 | /*
|
67 | 67 | Special handling for Internet Explorer 11.
|
68 | 68 | Check for ActiveX support, then whether "AcroPDF.PDF" or "PDF.PdfCtrl" are valid.
|
69 |
| - IE11 uses ActiveX for Adobe Reader and other PDF plugins, but window.ActiveXObject will evaluate to false. |
| 69 | + IE11 uses ActiveX for Adobe Reader and other PDF plugins, but window.ActiveXObject will evaluate to false. |
70 | 70 | ("ActiveXObject" in window) evaluates to true.
|
71 | 71 | MS Edge does not support ActiveX so this test will evaluate false for MS Edge.
|
72 | 72 | */
|
|
92 | 92 |
|
93 | 93 | //As of June 2023, no mobile browsers properly support inline PDFs. If mobile, just say no.
|
94 | 94 | if(isMobileDevice){ return false; }
|
95 |
| - |
| 95 | + |
96 | 96 | //Modern browsers began supporting navigator.pdfViewerEnabled in late 2022 and early 2023.
|
97 | 97 | let supportsPDFVE = (typeof nav.pdfViewerEnabled === "boolean");
|
98 | 98 |
|
|
113 | 113 | let prop;
|
114 | 114 | let paramArray = [];
|
115 | 115 | let fdf = "";
|
116 |
| - |
117 |
| - //The comment, viewrect, and highlight parameters require page to be set first. |
| 116 | + |
| 117 | + //The comment, viewrect, and highlight parameters require page to be set first. |
118 | 118 |
|
119 | 119 | //Check to ensure page is used if comment, viewrect, or highlight are specified
|
120 | 120 | if(pdfParams.comment || pdfParams.viewrect || pdfParams.highlight){
|
121 | 121 |
|
122 | 122 | if(!pdfParams.page){
|
123 |
| - |
| 123 | + |
124 | 124 | //If page is not set, use the first page
|
125 | 125 | pdfParams.page = 1;
|
126 |
| - |
| 126 | + |
127 | 127 | //Inform user that page needs to be set properly
|
128 | 128 | embedError("The comment, viewrect, and highlight parameters require a page parameter, but none was specified. Defaulting to page 1.");
|
129 |
| - |
| 129 | + |
130 | 130 | }
|
131 | 131 |
|
132 | 132 | }
|
|
142 | 142 | fdf = pdfParams.fdf;
|
143 | 143 | delete pdfParams.fdf;
|
144 | 144 | }
|
145 |
| - |
| 145 | + |
146 | 146 | //Add all other parameters, as needed
|
147 | 147 | if(pdfParams){
|
148 | 148 |
|
|
225 | 225 | xhr.onload = function() {
|
226 | 226 |
|
227 | 227 | if (xhr.status === 200) {
|
228 |
| - |
| 228 | + |
229 | 229 | var blob = xhr.response;
|
230 | 230 | var link = document.createElement('a');
|
231 | 231 | link.innerText = "Download PDF";
|
|
238 | 238 | };
|
239 | 239 |
|
240 | 240 | xhr.send();
|
241 |
| - |
| 241 | + |
242 | 242 | }
|
243 | 243 |
|
244 | 244 | };
|
|
251 | 251 |
|
252 | 252 | let source = url;
|
253 | 253 |
|
254 |
| - if(embedType === "pdfjs"){ |
| 254 | + if(embedType === "pdfjs"){ |
255 | 255 | //If PDFJS_URL already contains a ?, assume querystring is in place, and use an ampersand to append PDFJS's file parameter
|
256 |
| - let connector = (PDFJS_URL.indexOf("?") !== -1) ? "&" : "?"; |
| 256 | + let connector = (PDFJS_URL.indexOf("?") !== -1) ? "&" : "?"; |
257 | 257 | source = PDFJS_URL + connector + "file=" + encodeURIComponent(url) + pdfOpenFragment;
|
258 | 258 | } else {
|
259 | 259 | source += pdfOpenFragment;
|
|
280 | 280 | style += "position: absolute; top: 0; right: 0; bottom: 0; left: 0; width: 100%; height: 100%;";
|
281 | 281 | }
|
282 | 282 |
|
283 |
| - el.style.cssText = style; |
| 283 | + el.style.cssText = style; |
284 | 284 |
|
285 | 285 | }
|
286 | 286 |
|
|
320 | 320 | let targetNode = getTargetElement(selector);
|
321 | 321 | let pdfOpenFragment = "";
|
322 | 322 | let customAttribute = opt.customAttribute || {};
|
| 323 | + let fallbackFileNameForBase64 = opt.fallbackFileNameForBase64; |
323 | 324 | let fallbackHTML_default = "<p>This browser does not support inline PDFs. Please download the PDF to view it: [pdflink]</p>";
|
324 | 325 |
|
325 | 326 | //Ensure URL is available. If not, exit now.
|
|
341 | 342 | if(forcePDFJS && PDFJS_URL){
|
342 | 343 | return generatePDFObjectMarkup("pdfjs", targetNode, url, pdfOpenFragment, width, height, id, title, omitInlineStyles, customAttribute, PDFJS_URL);
|
343 | 344 | }
|
344 |
| - |
| 345 | + |
345 | 346 | // --== Embed attempt #2 ==--
|
346 | 347 |
|
347 |
| - //Embed PDF if support is detected, or if this is a relatively modern browser |
| 348 | + //Embed PDF if support is detected, or if this is a relatively modern browser |
348 | 349 | if(supportsPDFs){
|
349 | 350 | return generatePDFObjectMarkup("iframe", targetNode, url, pdfOpenFragment, width, height, id, title, omitInlineStyles, customAttribute);
|
350 | 351 | }
|
351 |
| - |
| 352 | + |
352 | 353 | // --== Embed attempt #3 ==--
|
353 |
| - |
| 354 | + |
354 | 355 | //If everything else has failed and a PDFJS fallback is provided, try to use it
|
355 | 356 | if(PDFJS_URL){
|
356 | 357 | return generatePDFObjectMarkup("pdfjs", targetNode, url, pdfOpenFragment, width, height, id, title, omitInlineStyles, customAttribute, PDFJS_URL);
|
357 | 358 | }
|
358 |
| - |
359 |
| - // --== PDF embed not supported! Use fallback ==-- |
| 359 | + |
| 360 | + // --== PDF embed not supported! Use fallback ==-- |
360 | 361 |
|
361 | 362 | //Display the fallback link if available
|
362 | 363 | if(fallbackLink){
|
|
370 | 371 | } else {
|
371 | 372 |
|
372 | 373 | //If the PDF is a base64 string, convert it to a downloadable link
|
373 |
| - if(url.indexOf("data:application/pdf;base64") !== -1){ |
| 374 | + const match = url.match(/data:application\/pdf;(?:.*filename=([^;]+);)?.*base64,/i); |
| 375 | + if(match){ |
| 376 | + |
| 377 | + fallbackFileNameForBase64 = |
| 378 | + fallbackFileNameForBase64 // from options |
| 379 | + || match[1] // from data URI metadata |
| 380 | + || "file.pdf"; // default |
374 | 381 |
|
375 | 382 | //Asynchronously append the link to the targetNode
|
376 |
| - convertBase64ToDownloadableLink(url, "file.pdf", targetNode, fallbackHTML_default); |
377 |
| - |
| 383 | + convertBase64ToDownloadableLink(url, fallbackFileNameForBase64, targetNode, fallbackHTML_default); |
| 384 | + |
378 | 385 | } else {
|
379 | 386 |
|
380 | 387 | //Use default fallback link
|
|
0 commit comments