From 4ffc408512590369ae965b86c9d4bb132fe69de4 Mon Sep 17 00:00:00 2001 From: Rob Wu Date: Tue, 2 Jul 2013 17:15:32 +0200 Subject: [PATCH] Download PDF from cache for non-Firefox add-on This feature relies on URL.createObjectURL, which is supported by - Firefox 4 - Chrome 8 - Opera 15 - Internet Explorer 10 If the feature is missing, it falls back to downloading from the server. The environment-specific code are put in ifdef's. Two methods are defined: - noData This function is used as a fallback in case of failure, it triggers a download directly from the server. - triggerSaveAs(String url, optional String blob) This function attempts to show a Save As dialog for a given URL. It attempts to use the a.download attribute, if available, and falls back to window.open(, '_parent') if unavailable. See also http://caniuse.com/download --- web/viewer.js | 105 +++++++++++++++++++++++++++----------------------- 1 file changed, 57 insertions(+), 48 deletions(-) diff --git a/web/viewer.js b/web/viewer.js index 9ac2f5a95..106164e19 100644 --- a/web/viewer.js +++ b/web/viewer.js @@ -914,59 +914,55 @@ var PDFView = { }, download: function pdfViewDownload() { - function noData() { - FirefoxCom.request('download', { originalUrl: url }); - } var url = this.url.split('#')[0]; //#if !(FIREFOX || MOZCENTRAL) - - var a = document.createElement('a'); - - // If _parent == self, then opening an identical URL with different - // location hash will only cause a navigation, not a download. - if (window.top === window && !('download' in a) && - url === window.location.href.split('#')[0]) { - url += url.indexOf('?') === -1 ? '?' : '&'; + function noData() { + triggerSaveAs(url + '#pdfjs.action=download'); } + function triggerSaveAs(url, blobUrl) { + // If blobUrl is not specified, fall back to non-blob url. + if (!blobUrl) blobUrl = url; - url += '#pdfjs.action=download'; - if (a.click) { - // Use a.click() if available. Otherwise, Chrome might show - // "Unsafe JavaScript attempt to initiate a navigation change - // for frame with URL" and not open the PDF at all. - // Supported by (not mentioned = untested): - // - Firefox 6 - 19 (4- does not support a.click, 5 ignores a.click) - // - Chrome 19 - 26 (18- does not support a.click) - // - Opera 9 - 12.15 - // - Internet Explorer 6 - 10 - // - Safari 6 (5.1- does not support a.click) - a.href = url; - a.target = '_parent'; - // Use a.download if available. This increases the likelihood that - // the file is downloaded instead of opened by another PDF plugin. - if ('download' in a) { - var filename = url.match(/([^\/?#=]+\.pdf)/i); - a.download = filename ? filename[1] : 'file.pdf'; + var a = document.createElement('a'); + if (a.click) { + // Use a.click() if available. Otherwise, Chrome might show + // "Unsafe JavaScript attempt to initiate a navigation change + // for frame with URL" and not open the PDF at all. + // Supported by (not mentioned = untested): + // - Firefox 6 - 19 (4- does not support a.click, 5 ignores a.click) + // - Chrome 19 - 26 (18- does not support a.click) + // - Opera 9 - 12.15 + // - Internet Explorer 6 - 10 + // - Safari 6 (5.1- does not support a.click) + a.href = blobUrl; + a.target = '_parent'; + // Use a.download if available. This increases the likelihood that + // the file is downloaded instead of opened by another PDF plugin. + if ('download' in a) { + var filename = url.match(/([^\/?#=]+\.pdf\b)(?!.*\.pdf\b)/i); + a.download = filename ? filename[1] : 'document.pdf'; + } + // must be in the document for IE and recent Firefox versions. + // (otherwise .click() is ignored) + (document.body || document.documentElement).appendChild(a); + a.click(); + a.parentNode.removeChild(a); + } else { + if (window.top === window && + blobUrl.split('#')[0] === window.location.href.split('#')[0]) { + // If _parent == self, then opening an identical URL with different + // location hash will only cause a navigation, not a download. + var padCharacter = blobUrl.indexOf('?') === -1 ? '?' : '&'; + blobUrl = blobUrl.replace(/#|$/, padCharacter + '$&'); + } + window.open(blobUrl, '_parent'); } - // must be in the document for IE and recent Firefox versions. - // (otherwise .click() is ignored) - (document.body || document.documentElement).appendChild(a); - a.click(); - a.parentNode.removeChild(a); - } else { - window.open(url, '_parent'); } //#else -// // Document isn't ready just try to download with the url. -// if (!this.pdfDocument) { -// noData(); -// return; +// function noData() { +// FirefoxCom.request('download', { originalUrl: url }); // } -// this.pdfDocument.getData().then( -// function getDataSuccess(data) { -// var blob = PDFJS.createBlob(data.buffer, 'application/pdf'); -// var blobUrl = window.URL.createObjectURL(blob); -// +// function triggerSaveAs(url, blobUrl) { // FirefoxCom.request('download', { blobUrl: blobUrl, originalUrl: url }, // function response(err) { // if (err) { @@ -977,10 +973,23 @@ var PDFView = { // window.URL.revokeObjectURL(blobUrl); // } // ); -// }, -// noData // Error occurred try downloading with just the url. -// ); +// } //#endif + var URL = window.URL || window.webkitURL; + // If the PDF is not ready yet, or if createObjectURL is not supported, + // just try to download with the url. + if (!this.pdfDocument || !URL) { + noData(); + return; + } + this.pdfDocument.getData().then( + function getDataSuccess(data) { + var blob = PDFJS.createBlob(data.buffer, 'application/pdf'); + var blobUrl = URL.createObjectURL(blob); + triggerSaveAs(url, blobUrl); + }, + noData // Error occurred try downloading with just the url. + ); }, fallback: function pdfViewFallback() {