diff --git a/extensions/firefox/components/PdfStreamConverter.js b/extensions/firefox/components/PdfStreamConverter.js index 84430a658..c89731b59 100644 --- a/extensions/firefox/components/PdfStreamConverter.js +++ b/extensions/firefox/components/PdfStreamConverter.js @@ -206,6 +206,10 @@ ChromeActions.prototype = { // The data may not be downloaded so we need just retry getting the pdf with // the original url. var originalUri = NetUtil.newURI(data.originalUrl); + var filename = data.filename; + if (typeof filename !== 'string' || !/\.pdf$/i.test(filename)) { + filename = 'document.pdf'; + } var blobUri = data.blobUrl ? NetUtil.newURI(data.blobUrl) : originalUri; var extHelperAppSvc = Cc['@mozilla.org/uriloader/external-helper-app-service;1']. @@ -234,7 +238,9 @@ ChromeActions.prototype = { // contentDisposition/contentDispositionFilename is readonly before FF18 channel.contentDisposition = Ci.nsIChannel.DISPOSITION_ATTACHMENT; if (self.contentDispositionFilename) { - channel.contentDispositionFilename = self.contentDispositionFilename; + channel.contentDispositionFilename = self.contentDispositionFilename; + } else { + channel.contentDispositionFilename = filename; } } catch (e) {} channel.setURI(originalUri); diff --git a/web/compatibility.js b/web/compatibility.js index e9b69ed07..0d12c64a9 100644 --- a/web/compatibility.js +++ b/web/compatibility.js @@ -92,6 +92,13 @@ if (typeof PDFJS === 'undefined') { window.Float64Array = TypedArray; })(); +// URL = URL || webkitURL +(function normalizeURLObject() { + if (!window.URL && window.webkitURL) { + window.URL = window.webkitURL; + } +})(); + // Object.create() ? (function checkObjectCreateCompatibility() { if (typeof Object.create !== 'undefined') diff --git a/web/viewer.js b/web/viewer.js index 9ac2f5a95..a21cde03a 100644 --- a/web/viewer.js +++ b/web/viewer.js @@ -14,6 +14,7 @@ * See the License for the specific language governing permissions and * limitations under the License. */ +/* globals URL*/ /* globals PDFJS, PDFBug, FirefoxCom, Stats, Cache, PDFFindBar */ /* globals PDFFindController, ProgressBar, getFileName, CustomStyle */ /* globals getOutputScale, TextLayerBuilder */ @@ -914,60 +915,86 @@ var PDFView = { }, download: function pdfViewDownload() { - function noData() { - FirefoxCom.request('download', { originalUrl: url }); - } var url = this.url.split('#')[0]; + function getPDFFileNameFromURL(url) { + 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); + var suggestedFilename = reFilename.exec(splitURI[1]) || + reFilename.exec(splitURI[2]) || + reFilename.exec(splitURI[3]); + if (suggestedFilename) { + suggestedFilename = suggestedFilename[0]; + if (suggestedFilename.indexOf('%') != -1) { + // URL-encoded %2Fpath%2Fto%2Ffile.pdf should be file.pdf + try { + suggestedFilename = + reFilename.exec(decodeURIComponent(suggestedFilename))[0]; + } catch(e) { // Possible (extremely rare) errors: + // URIError "Malformed URI", e.g. for "%AA.pdf" + // TypeError "null has no properties", e.g. for "%2F.pdf" + } + } + } + return suggestedFilename || 'document.pdf'; + } //#if !(FIREFOX || MOZCENTRAL) + 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; - 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 ? '?' : '&'; - } - - 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) { + a.download = getPDFFileNameFromURL(url); + } + // 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, +// filename: getPDFFileNameFromURL(url) +// }); // } -// this.pdfDocument.getData().then( -// function getDataSuccess(data) { -// var blob = PDFJS.createBlob(data.buffer, 'application/pdf'); -// var blobUrl = window.URL.createObjectURL(blob); -// -// FirefoxCom.request('download', { blobUrl: blobUrl, originalUrl: url }, +// function triggerSaveAs(url, blobUrl) { +// FirefoxCom.request('download', { +// blobUrl: blobUrl, +// originalUrl: url, +// filename: getPDFFileNameFromURL(url) +// }, // function response(err) { // if (err) { // // This error won't really be helpful because it's likely the @@ -977,10 +1004,31 @@ var PDFView = { // window.URL.revokeObjectURL(blobUrl); // } // ); -// }, -// noData // Error occurred try downloading with just the url. -// ); +// } //#endif + // If the PDF is not ready yet, or if URL.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'); +//#if GENERIC + if (navigator.msSaveBlob) { + // IE10 / IE11 + if (!navigator.msSaveBlob(blob, getPDFFileNameFromURL(url))) { + noData(); + } + return; + } +//#endif + var blobUrl = URL.createObjectURL(blob); + triggerSaveAs(url, blobUrl); + }, + noData // Error occurred try downloading with just the url. + ).then(null, noData); }, fallback: function pdfViewFallback() {