diff --git a/extensions/chromium/extension-router.js b/extensions/chromium/extension-router.js index d9a0c23e1..e4ff6f426 100644 --- a/extensions/chromium/extension-router.js +++ b/extensions/chromium/extension-router.js @@ -27,6 +27,8 @@ limitations under the License. 'ftp', 'file', 'chrome-extension', + 'blob', + 'data', // Chromium OS 'filesystem', // Chromium OS, shorthand for filesystem:/external/ diff --git a/extensions/chromium/manifest.json b/extensions/chromium/manifest.json index 230bb762a..78eff2515 100644 --- a/extensions/chromium/manifest.json +++ b/extensions/chromium/manifest.json @@ -63,6 +63,8 @@ "ftp:/*", "file:/*", "chrome-extension:/*", + "blob:*", + "data:*", "filesystem:/*", "drive:*" ] diff --git a/web/app.js b/web/app.js index 5c236c355..3922750f3 100644 --- a/web/app.js +++ b/web/app.js @@ -574,14 +574,17 @@ var PDFViewerApplication = { setTitleUsingUrl: function pdfViewSetTitleUsingUrl(url) { this.url = url; this.baseUrl = url.split('#')[0]; - try { - this.setTitle(decodeURIComponent( - pdfjsLib.getFilenameFromUrl(url)) || url); - } catch (e) { - // decodeURIComponent may throw URIError, - // fall back to using the unprocessed url in that case - this.setTitle(url); + var title = getPDFFileNameFromURL(url, ''); + if (!title) { + try { + title = decodeURIComponent(pdfjsLib.getFilenameFromUrl(url)) || url; + } catch (e) { + // decodeURIComponent may throw URIError, + // fall back to using the unprocessed url in that case + title = url; + } } + this.setTitle(title); }, setTitle: function pdfViewSetTitle(title) { @@ -742,7 +745,9 @@ var PDFViewerApplication = { } var url = this.baseUrl; - var filename = getPDFFileNameFromURL(url); + // Use this.url instead of this.baseUrl to perform filename detection based + // on the reference fragment as ultimate fallback if needed. + var filename = getPDFFileNameFromURL(this.url); var downloadManager = this.downloadManager; downloadManager.onerror = function (err) { // This error won't really be helpful because it's likely the diff --git a/web/pdf_attachment_viewer.js b/web/pdf_attachment_viewer.js index dbfda4b3d..4b3e16f28 100644 --- a/web/pdf_attachment_viewer.js +++ b/web/pdf_attachment_viewer.js @@ -86,6 +86,38 @@ var PDFAttachmentViewer = (function PDFAttachmentViewerClosure() { this._renderedCapability.resolve(); }, + /** + * @private + */ + _bindPdfLink: + function PDFAttachmentViewer_bindPdfLink(button, content, filename) { + var blobUrl; + button.onclick = function() { + if (!blobUrl) { + blobUrl = pdfjsLib.createObjectURL( + content, 'application/pdf', pdfjsLib.PDFJS.disableCreateObjectURL); + } + var viewerUrl; + if (typeof PDFJSDev === 'undefined' || PDFJSDev.test('GENERIC')) { + // The current URL is the viewer, let's use it and append the file. + viewerUrl = '?file=' + encodeURIComponent(blobUrl + '#' + filename); + } else if (PDFJSDev.test('CHROME')) { + // In the Chrome extension, the URL is rewritten using the history API + // in viewer.js, so an absolute URL must be generated. + // eslint-disable-next-line no-undef + viewerUrl = chrome.runtime.getURL('/content/web/viewer.html') + + '?file=' + encodeURIComponent(blobUrl + '#' + filename); + } else { + // Let Firefox's content handler catch the URL and display the PDF. + // In Firefox PDFJS.disableCreateObjectURL is always false, so + // blobUrl is always a blob:-URL and never a data:-URL. + viewerUrl = blobUrl + '?' + encodeURIComponent(filename); + } + window.open(viewerUrl); + return false; + }; + }, + /** * @private */ @@ -124,11 +156,18 @@ var PDFAttachmentViewer = (function PDFAttachmentViewerClosure() { for (var i = 0; i < attachmentsCount; i++) { var item = attachments[names[i]]; var filename = pdfjsLib.getFilenameFromUrl(item.filename); + filename = pdfjsLib.removeNullCharacters(filename); + var div = document.createElement('div'); div.className = 'attachmentsItem'; var button = document.createElement('button'); - this._bindLink(button, item.content, filename); - button.textContent = pdfjsLib.removeNullCharacters(filename); + button.textContent = filename; + if (/\.pdf$/i.test(filename)) { + this._bindPdfLink(button, item.content, filename); + } else { + this._bindLink(button, item.content, filename); + } + div.appendChild(button); this.container.appendChild(div); } diff --git a/web/ui_utils.js b/web/ui_utils.js index fd925d1ba..54b4d9226 100644 --- a/web/ui_utils.js +++ b/web/ui_utils.js @@ -368,11 +368,15 @@ function noContextMenuHandler(e) { /** * Returns the filename or guessed filename from the url (see issue 3455). * url {String} The original PDF location. + * defaultFilename {string} The value to return if the file name is unknown. * @return {String} Guessed PDF file name. */ -function getPDFFileNameFromURL(url) { - var reURI = /^(?:([^:]+:)?\/\/[^\/]+)?([^?#]*)(\?[^#]*)?(#.*)?$/; - // SCHEME HOST 1.PATH 2.QUERY 3.REF +function getPDFFileNameFromURL(url, defaultFilename) { + if (typeof defaultFilename === 'undefined') { + defaultFilename = 'document.pdf'; + } + var reURI = /^(?:(?:[^:]+:)?\/\/[^\/]+)?([^?#]*)(\?[^#]*)?(#.*)?$/; + // SCHEME HOST 1.PATH 2.QUERY 3.REF // Pattern to get last matching NAME.pdf var reFilename = /[^\/?#=]+\.pdf\b(?!.*\.pdf\b)/i; var splitURI = reURI.exec(url); @@ -392,7 +396,7 @@ function getPDFFileNameFromURL(url) { } } } - return suggestedFilename || 'document.pdf'; + return suggestedFilename || defaultFilename; } function normalizeWheelEventDelta(evt) {