27 Commits

Author SHA1 Message Date
Eli Grey 648ff96f8b Use FileReader in macOS native apps using WebKit (#613)
Use FileReader in macOS native apps using WebKit
2020-01-30 16:44:01 -08:00
Rajiv Shah 7a8ff3cc6a Switch isWebKit and isSafari conditions to maintain behavior
Using isWebKit before isSafari could cause Safari to use FileReader even if force === false, since the user agent for Safari also includes AppleWebKit
2020-01-30 19:40:57 -05:00
Rajiv Shah 0a2e868b48 Rebuild dist 2020-01-30 19:20:04 -05:00
Rajiv Shah 16a8bb9e8f Bump version to 2.0.3 2020-01-30 19:18:02 -05:00
Rajiv Shah 572f254834 Ensure Chrome iOS still works 2020-01-30 19:00:37 -05:00
Rajiv Shah d3d2bd20d6 Merge branch 'master' into feature/webkit-macos 2020-01-30 18:50:01 -05:00
Susanne Gerber 480d547986 fix small spelling error 2020-01-25 23:06:39 +01:00
Rajiv Shah db7880179f Use FileReader in macOS native apps using WebKit 2019-12-21 17:41:53 -05:00
Eli Grey 9a0a1e4ae2 Add GitHub Sponsors funding method 2019-10-22 10:42:27 -07:00
Eli Grey 1ea2325a75 Bump mixin-deep from 1.3.1 to 1.3.2 (#601)
Bump mixin-deep from 1.3.1 to 1.3.2
2019-10-14 13:13:09 -07:00
dependabot[bot] 35e9d8127d Bump mixin-deep from 1.3.1 to 1.3.2
Bumps [mixin-deep](https://github.com/jonschlinkert/mixin-deep) from 1.3.1 to 1.3.2.
- [Release notes](https://github.com/jonschlinkert/mixin-deep/releases)
- [Commits](https://github.com/jonschlinkert/mixin-deep/compare/1.3.1...1.3.2)

Signed-off-by: dependabot[bot] <support@github.com>
2019-10-14 18:22:49 +00:00
Eli Grey 538c4b5751 Bump lodash from 4.17.11 to 4.17.14 (#575)
Bump lodash from 4.17.11 to 4.17.14
2019-10-14 11:21:37 -07:00
Eli Grey 556db1f6df Merge pull request #577 from chrisdoble/master
Fix downloads in Chrome iOS
2019-07-15 23:34:35 -07:00
Chris Doble b95a82a3ec Check that FileReader exists, not that it's an object
Fixes #576
2019-07-16 16:14:44 +10:00
dependabot[bot] 35f0e568d9 Bump lodash from 4.17.11 to 4.17.14
Bumps [lodash](https://github.com/lodash/lodash) from 4.17.11 to 4.17.14.
- [Release notes](https://github.com/lodash/lodash/releases)
- [Commits](https://github.com/lodash/lodash/compare/4.17.11...4.17.14)

Signed-off-by: dependabot[bot] <support@github.com>
2019-07-11 03:41:59 +00:00
Eli Grey a7e1ccfc44 Create FUNDING.yml 2019-06-11 22:39:07 -07:00
Jimmy Wärting 1bc9ed39c4 bump minor version 2019-05-14 10:00:17 +02:00
Marcin Rybacki 71f266f93e Missing dist build 2019-05-14 09:46:41 +02:00
Marcin Rybacki 9bd5261f60 Catching an exception on Send. This happens when request for HEAD returns 405 Method Not Allowed. Instead of error http status, this may throw an exception. Return false and fallback to link download. 2019-05-14 09:46:41 +02:00
Oskar Köök 3caf053bbd fix autoBom documentation 2019-05-14 09:45:57 +02:00
josephrocca 04ca36440d Updated Chrome data 2019-03-01 09:47:36 +01:00
zachary parrish d87b419616 Update README.md
Just made some minor grammar changes
2019-02-17 17:45:48 +01:00
Jimmy Wärting 3e46b73052 Update package.json 2019-02-17 15:24:08 +01:00
TypeError64 b1ab588946 Update README.md 2019-02-01 11:29:14 +01:00
Nathan Phillip Brink 4a73fd7a2d Fix a few spelling errors. 2019-01-07 13:02:54 +01:00
Alexander Светлый 0e905a3e06 Update README.md
Fix import
2018-12-29 11:02:50 +01:00
segovia 283f438c31 Fix accidental rewrite of global saveAs function
The change is just to put parentheses around the code after `var saveAs = _global.saveAs ||`
and then indent it properly.

closes #498
2018-12-29 11:01:25 +01:00
9 changed files with 2858 additions and 124 deletions
+3
View File
@@ -0,0 +1,3 @@
# These are supported funding model platforms
github: eligrey
+6 -1
View File
@@ -4,9 +4,13 @@ All notable changes to this project will be documented in this file.
The format is based on [Keep a Changelog](https://keepachangelog.com/en/1.0.0/),
and this project adheres to [Semantic Versioning](https://semver.org/spec/v2.0.0.html).
## [2.0.2] - 2019-05-14
- Catching an exception on Send (HEAD) ([#534])
## [2.0.0] - 2018-10-17
- Removed eval to resolve CSP [#465]
- Removed eval to resolve CSP ([#465])
## [2.0.0-rc.4] - 2018-10-17
@@ -53,3 +57,4 @@ and this project adheres to [Semantic Versioning](https://semver.org/spec/v2.0.0
[#469]: https://github.com/eligrey/FileSaver.js/issues/469
[#470]: https://github.com/eligrey/FileSaver.js/issues/470
[#491]: https://github.com/eligrey/FileSaver.js/issues/491
[#534]: https://github.com/eligrey/FileSaver.js/issues/534
+20 -19
View File
@@ -1,4 +1,4 @@
If you need to save really large files bigger then the blob's size limitation or don't have
If you need to save really large files bigger than the blob's size limitation or don't have
enough RAM, then have a look at the more advanced [StreamSaver.js][7]
that can save data directly to the hard drive asynchronously with the power of the new streams API. That will have
support for progress, cancelation and knowing when it's done writing
@@ -8,7 +8,7 @@ FileSaver.js
FileSaver.js is the solution to saving files on the client-side, and is perfect for
web apps that generates files on the client, However if the file is coming from the
server we recommend you to first try to use [Content-Disposition][8] attachment response header as it has more cross-browser compatible
server we recommend you to first try to use [Content-Disposition][8] attachment response header as it has more cross-browser compatiblity.
Looking for `canvas.toBlob()` for saving canvases? Check out
[canvas-toBlob.js][2] for a cross-browser implementation.
@@ -20,8 +20,8 @@ Supported Browsers
| -------------- | ------------- | ------------ | ------------- | ------------ |
| Firefox 20+ | Blob | Yes | 800 MiB | None |
| Firefox < 20 | data: URI | No | n/a | [Blob.js](https://github.com/eligrey/Blob.js) |
| Chrome | Blob | Yes | [500 MiB][3] | None |
| Chrome for Android | Blob | Yes | [500 MiB][3] | None |
| Chrome | Blob | Yes | [2GB][3] | None |
| Chrome for Android | Blob | Yes | [RAM/5][3] | None |
| Edge | Blob | Yes | ? | None |
| IE 10+ | Blob | Yes | 600 MiB | None |
| Opera 15+ | Blob | Yes | 500 MiB | None |
@@ -54,21 +54,21 @@ saveAs must be run within a user interaction event such as onTouchDown or onClic
Syntax
------
### Import saveAs() from file-saver
### Import `saveAs()` from file-saver
```js
import saveAs from 'file-saver';
import { saveAs } from 'file-saver';
```
```js
FileSaver saveAs(Blob/File/Url, optional DOMString filename, optional Object { autoBOM })
FileSaver saveAs(Blob/File/Url, optional DOMString filename, optional Object { autoBom })
```
Pass `{ autoBOM: true }` if you want FileSaver.js to automatically provide Unicode text encoding hints (see: [byte order mark](https://en.wikipedia.org/wiki/Byte_order_mark)).
Pass `{ autoBom: true }` if you want FileSaver.js to automatically provide Unicode text encoding hints (see: [byte order mark](https://en.wikipedia.org/wiki/Byte_order_mark)). Note that this is only done if your blob type has `charset=utf-8` set.
Examples
--------
### Saving text using require
### Saving text using `require()`
```js
var FileSaver = require('file-saver');
var blob = new Blob(["Hello, world!"], {type: "text/plain;charset=utf-8"});
@@ -87,16 +87,15 @@ FileSaver.saveAs(blob, "hello world.txt");
```js
FileSaver.saveAs("https://httpbin.org/image", "image.jpg");
```
Using URLs within the same origin will just use `a[download]`
Otherwise, it will first check if it supports cors header with a synchronously head request
if it does it will download the data and save it using blob URLs
if not it will try to download it using `a[download]`
Using URLs within the same origin will just use `a[download]`.
Otherwise, it will first check if it supports cors header with a synchronous head request.
If it does, it will download the data and save using blob URLs.
If not, it will try to download it using `a[download]`.
The standard W3C File API [`Blob`][4] interface is not available in all browsers.
[Blob.js][5] is a cross-browser `Blob` implementation that solves this.
### Saving a canvas
```js
var canvas = document.getElementById("my-canvas");
canvas.toBlob(function(blob) {
@@ -109,10 +108,10 @@ Note: The standard HTML5 `canvas.toBlob()` method is not available in all browse
### Saving File
You can save a File constructor without specifying a filename. The
File itself already contains a name, There is a hand full of ways to get a file
instance (from storage, file input, new constructor, clipboard event)
But if you still want to change the name, then you can change it in the 2nd argument
You can save a File constructor without specifying a filename. If the
file itself already contains a name, there is a hand full of ways to get a file
instance (from storage, file input, new constructor, clipboard event).
If you still want to change the name, then you can change it in the 2nd argument.
```js
// Note: Ie and Edge don't support the new File constructor,
@@ -127,7 +126,7 @@ FileSaver.saveAs(file);
[1]: http://eligrey.com/demos/FileSaver.js/
[2]: https://github.com/eligrey/canvas-toBlob.js
[3]: https://code.google.com/p/chromium/issues/detail?id=375297
[3]: https://bugs.chromium.org/p/chromium/issues/detail?id=375297#c107
[4]: https://developer.mozilla.org/en-US/docs/DOM/Blob
[5]: https://github.com/eligrey/Blob.js
[6]: https://github.com/eligrey/canvas-toBlob.js
@@ -138,6 +137,7 @@ Installation
------------------
```bash
# Basic Node.JS installation
npm install file-saver --save
bower install file-saver
```
@@ -145,5 +145,6 @@ bower install file-saver
Additionally, TypeScript definitions can be installed via:
```bash
# Additional typescript definitions
npm install @types/file-saver --save-dev
```
+16 -10
View File
@@ -30,7 +30,7 @@
if (typeof opts === 'undefined') opts = {
autoBom: false
};else if (typeof opts !== 'object') {
console.warn('Depricated: Expected third argument to be a object');
console.warn('Deprecated: Expected third argument to be a object');
opts = {
autoBom: !opts
};
@@ -66,7 +66,11 @@
var xhr = new XMLHttpRequest(); // use sync to avoid popup blocker
xhr.open('HEAD', url, false);
xhr.send();
try {
xhr.send();
} catch (e) {}
return xhr.status >= 200 && xhr.status <= 299;
} // `a.click()` doesn't work for all browsers (#465)
@@ -79,13 +83,15 @@
evt.initMouseEvent('click', true, true, window, 0, 0, 0, 80, 20, false, false, false, false, 0, null);
node.dispatchEvent(evt);
}
}
} // Detect WebKit inside a native macOS app
var saveAs = _global.saveAs || // probably in some web worker
var isWebKit = /AppleWebKit/.test(navigator.userAgent);
var saveAs = _global.saveAs || ( // probably in some web worker
typeof window !== 'object' || window !== _global ? function saveAs() {}
/* noop */
// Use download attribute first if possible (#193 Lumia mobile)
: 'download' in HTMLAnchorElement.prototype ? function saveAs(blob, name, opts) {
// Use download attribute first if possible (#193 Lumia mobile) unless this is a native macOS app
: 'download' in HTMLAnchorElement.prototype && !isWebKit ? function saveAs(blob, name, opts) {
var URL = _global.URL || _global.webkitURL;
var a = document.createElement('a');
name = name || blob.name || 'download';
@@ -135,7 +141,7 @@
} // Fallback to using FileReader and a popup
: function saveAs(blob, name, opts, popup) {
// Open a popup immediately do go around popup blocker
// Mostly only avalible on user interaction and the fileReader is async so...
// Mostly only available on user interaction and the fileReader is async so...
popup = popup || open('', '_blank');
if (popup) {
@@ -149,8 +155,8 @@
var isChromeIOS = /CriOS\/[\d]+/.test(navigator.userAgent);
if ((isChromeIOS || force && isSafari) && typeof FileReader === 'object') {
// Safari doesn't allow downloading of blob urls
if ((isChromeIOS || force && isSafari || isWebKit) && typeof FileReader !== 'undefined') {
// Safari doesn't allow downloading of blob URLs
var reader = new FileReader();
reader.onloadend = function () {
@@ -171,7 +177,7 @@
URL.revokeObjectURL(url);
}, 4E4); // 40s
}
};
});
_global.saveAs = saveAs.saveAs = saveAs;
if (typeof module !== 'undefined') {
+1 -1
View File
@@ -1,3 +1,3 @@
(function(a,b){if("function"==typeof define&&define.amd)define([],b);else if("undefined"!=typeof exports)b();else{b(),a.FileSaver={exports:{}}.exports}})(this,function(){"use strict";function b(a,b){return"undefined"==typeof b?b={autoBom:!1}:"object"!=typeof b&&(console.warn("Depricated: Expected third argument to be a object"),b={autoBom:!b}),b.autoBom&&/^\s*(?:text\/\S*|application\/xml|\S*\/\S*\+xml)\s*;.*charset\s*=\s*utf-8/i.test(a.type)?new Blob(["\uFEFF",a],{type:a.type}):a}function c(b,c,d){var e=new XMLHttpRequest;e.open("GET",b),e.responseType="blob",e.onload=function(){a(e.response,c,d)},e.onerror=function(){console.error("could not download file")},e.send()}function d(a){var b=new XMLHttpRequest;return b.open("HEAD",a,!1),b.send(),200<=b.status&&299>=b.status}function e(a){try{a.dispatchEvent(new MouseEvent("click"))}catch(c){var b=document.createEvent("MouseEvents");b.initMouseEvent("click",!0,!0,window,0,0,0,80,20,!1,!1,!1,!1,0,null),a.dispatchEvent(b)}}var f="object"==typeof window&&window.window===window?window:"object"==typeof self&&self.self===self?self:"object"==typeof global&&global.global===global?global:void 0,a=f.saveAs||"object"!=typeof window||window!==f?function(){}:"download"in HTMLAnchorElement.prototype?function(b,g,h){var i=f.URL||f.webkitURL,j=document.createElement("a");g=g||b.name||"download",j.download=g,j.rel="noopener","string"==typeof b?(j.href=b,j.origin===location.origin?e(j):d(j.href)?c(b,g,h):e(j,j.target="_blank")):(j.href=i.createObjectURL(b),setTimeout(function(){i.revokeObjectURL(j.href)},4E4),setTimeout(function(){e(j)},0))}:"msSaveOrOpenBlob"in navigator?function(f,g,h){if(g=g||f.name||"download","string"!=typeof f)navigator.msSaveOrOpenBlob(b(f,h),g);else if(d(f))c(f,g,h);else{var i=document.createElement("a");i.href=f,i.target="_blank",setTimeout(function(){e(i)})}}:function(a,b,d,e){if(e=e||open("","_blank"),e&&(e.document.title=e.document.body.innerText="downloading..."),"string"==typeof a)return c(a,b,d);var g="application/octet-stream"===a.type,h=/constructor/i.test(f.HTMLElement)||f.safari,i=/CriOS\/[\d]+/.test(navigator.userAgent);if((i||g&&h)&&"object"==typeof FileReader){var j=new FileReader;j.onloadend=function(){var a=j.result;a=i?a:a.replace(/^data:[^;]*;/,"data:attachment/file;"),e?e.location.href=a:location=a,e=null},j.readAsDataURL(a)}else{var k=f.URL||f.webkitURL,l=k.createObjectURL(a);e?e.location=l:location.href=l,e=null,setTimeout(function(){k.revokeObjectURL(l)},4E4)}};f.saveAs=a.saveAs=a,"undefined"!=typeof module&&(module.exports=a)});
(function(a,b){if("function"==typeof define&&define.amd)define([],b);else if("undefined"!=typeof exports)b();else{b(),a.FileSaver={exports:{}}.exports}})(this,function(){"use strict";function b(a,b){return"undefined"==typeof b?b={autoBom:!1}:"object"!=typeof b&&(console.warn("Deprecated: Expected third argument to be a object"),b={autoBom:!b}),b.autoBom&&/^\s*(?:text\/\S*|application\/xml|\S*\/\S*\+xml)\s*;.*charset\s*=\s*utf-8/i.test(a.type)?new Blob(["\uFEFF",a],{type:a.type}):a}function c(a,b,c){var d=new XMLHttpRequest;d.open("GET",a),d.responseType="blob",d.onload=function(){g(d.response,b,c)},d.onerror=function(){console.error("could not download file")},d.send()}function d(a){var b=new XMLHttpRequest;b.open("HEAD",a,!1);try{b.send()}catch(a){}return 200<=b.status&&299>=b.status}function e(a){try{a.dispatchEvent(new MouseEvent("click"))}catch(c){var b=document.createEvent("MouseEvents");b.initMouseEvent("click",!0,!0,window,0,0,0,80,20,!1,!1,!1,!1,0,null),a.dispatchEvent(b)}}var f="object"==typeof window&&window.window===window?window:"object"==typeof self&&self.self===self?self:"object"==typeof global&&global.global===global?global:void 0,a=/AppleWebKit/.test(navigator.userAgent),g=f.saveAs||("object"!=typeof window||window!==f?function(){}:"download"in HTMLAnchorElement.prototype&&!a?function(b,g,h){var i=f.URL||f.webkitURL,j=document.createElement("a");g=g||b.name||"download",j.download=g,j.rel="noopener","string"==typeof b?(j.href=b,j.origin===location.origin?e(j):d(j.href)?c(b,g,h):e(j,j.target="_blank")):(j.href=i.createObjectURL(b),setTimeout(function(){i.revokeObjectURL(j.href)},4E4),setTimeout(function(){e(j)},0))}:"msSaveOrOpenBlob"in navigator?function(f,g,h){if(g=g||f.name||"download","string"!=typeof f)navigator.msSaveOrOpenBlob(b(f,h),g);else if(d(f))c(f,g,h);else{var i=document.createElement("a");i.href=f,i.target="_blank",setTimeout(function(){e(i)})}}:function(b,d,e,g){if(g=g||open("","_blank"),g&&(g.document.title=g.document.body.innerText="downloading..."),"string"==typeof b)return c(b,d,e);var h="application/octet-stream"===b.type,i=/constructor/i.test(f.HTMLElement)||f.safari,j=/CriOS\/[\d]+/.test(navigator.userAgent);if((j||h&&i||a)&&"undefined"!=typeof FileReader){var k=new FileReader;k.onloadend=function(){var a=k.result;a=j?a:a.replace(/^data:[^;]*;/,"data:attachment/file;"),g?g.location.href=a:location=a,g=null},k.readAsDataURL(b)}else{var l=f.URL||f.webkitURL,m=l.createObjectURL(b);g?g.location=m:location.href=m,g=null,setTimeout(function(){l.revokeObjectURL(m)},4E4)}});f.saveAs=g.saveAs=g,"undefined"!=typeof module&&(module.exports=g)});
//# sourceMappingURL=FileSaver.min.js.map
+1 -1
View File
File diff suppressed because one or more lines are too long
+2714
View File
File diff suppressed because it is too large Load Diff
+1 -1
View File
@@ -1,6 +1,6 @@
{
"name": "file-saver",
"version": "2.0.0",
"version": "2.0.3",
"description": "An HTML5 saveAs() FileSaver implementation",
"main": "dist/FileSaver.min.js",
"files": [
+96 -91
View File
@@ -8,7 +8,6 @@
* source : http://purl.eligrey.com/github/FileSaver.js
*/
// The one and only way of getting global scope in all environments
// https://stackoverflow.com/q/3277182/1008999
var _global = typeof window === 'object' && window.window === window
@@ -20,7 +19,7 @@ var _global = typeof window === 'object' && window.window === window
function bom (blob, opts) {
if (typeof opts === 'undefined') opts = { autoBom: false }
else if (typeof opts !== 'object') {
console.warn('Depricated: Expected third argument to be a object')
console.warn('Deprecated: Expected third argument to be a object')
opts = { autoBom: !opts }
}
@@ -49,12 +48,14 @@ function corsEnabled (url) {
var xhr = new XMLHttpRequest()
// use sync to avoid popup blocker
xhr.open('HEAD', url, false)
xhr.send()
try {
xhr.send()
} catch (e) {}
return xhr.status >= 200 && xhr.status <= 299
}
// `a.click()` doesn't work for all browsers (#465)
function click(node) {
function click (node) {
try {
node.dispatchEvent(new MouseEvent('click'))
} catch (e) {
@@ -65,97 +66,101 @@ function click(node) {
}
}
var saveAs = _global.saveAs ||
// probably in some web worker
(typeof window !== 'object' || window !== _global)
? function saveAs () { /* noop */ }
// Detect WebKit inside a native macOS app
var isWebKit = /AppleWebKit/.test(navigator.userAgent)
// Use download attribute first if possible (#193 Lumia mobile)
: 'download' in HTMLAnchorElement.prototype
? function saveAs (blob, name, opts) {
var URL = _global.URL || _global.webkitURL
var a = document.createElement('a')
name = name || blob.name || 'download'
var saveAs = _global.saveAs || (
// probably in some web worker
(typeof window !== 'object' || window !== _global)
? function saveAs () { /* noop */ }
a.download = name
a.rel = 'noopener' // tabnabbing
// TODO: detect chrome extensions & packaged apps
// a.target = '_blank'
if (typeof blob === 'string') {
// Support regular links
a.href = blob
if (a.origin !== location.origin) {
corsEnabled(a.href)
? download(blob, name, opts)
: click(a, a.target = '_blank')
} else {
click(a)
}
} else {
// Support blobs
a.href = URL.createObjectURL(blob)
setTimeout(function () { URL.revokeObjectURL(a.href) }, 4E4) // 40s
setTimeout(function () { click(a) }, 0)
}
}
// Use msSaveOrOpenBlob as a second approach
: 'msSaveOrOpenBlob' in navigator
? function saveAs (blob, name, opts) {
name = name || blob.name || 'download'
if (typeof blob === 'string') {
if (corsEnabled(blob)) {
download(blob, name, opts)
} else {
var a = document.createElement('a')
a.href = blob
a.target = '_blank'
setTimeout(function () { click(a) })
}
} else {
navigator.msSaveOrOpenBlob(bom(blob, opts), name)
}
}
// Fallback to using FileReader and a popup
: function saveAs (blob, name, opts, popup) {
// Open a popup immediately do go around popup blocker
// Mostly only avalible on user interaction and the fileReader is async so...
popup = popup || open('', '_blank')
if (popup) {
popup.document.title =
popup.document.body.innerText = 'downloading...'
}
if (typeof blob === 'string') return download(blob, name, opts)
var force = blob.type === 'application/octet-stream'
var isSafari = /constructor/i.test(_global.HTMLElement) || _global.safari
var isChromeIOS = /CriOS\/[\d]+/.test(navigator.userAgent)
if ((isChromeIOS || (force && isSafari)) && typeof FileReader === 'object') {
// Safari doesn't allow downloading of blob urls
var reader = new FileReader()
reader.onloadend = function () {
var url = reader.result
url = isChromeIOS ? url : url.replace(/^data:[^;]*;/, 'data:attachment/file;')
if (popup) popup.location.href = url
else location = url
popup = null // reverse-tabnabbing #460
}
reader.readAsDataURL(blob)
} else {
// Use download attribute first if possible (#193 Lumia mobile) unless this is a native macOS app
: ('download' in HTMLAnchorElement.prototype && !isWebKit)
? function saveAs (blob, name, opts) {
var URL = _global.URL || _global.webkitURL
var url = URL.createObjectURL(blob)
if (popup) popup.location = url
else location.href = url
popup = null // reverse-tabnabbing #460
setTimeout(function () { URL.revokeObjectURL(url) }, 4E4) // 40s
var a = document.createElement('a')
name = name || blob.name || 'download'
a.download = name
a.rel = 'noopener' // tabnabbing
// TODO: detect chrome extensions & packaged apps
// a.target = '_blank'
if (typeof blob === 'string') {
// Support regular links
a.href = blob
if (a.origin !== location.origin) {
corsEnabled(a.href)
? download(blob, name, opts)
: click(a, a.target = '_blank')
} else {
click(a)
}
} else {
// Support blobs
a.href = URL.createObjectURL(blob)
setTimeout(function () { URL.revokeObjectURL(a.href) }, 4E4) // 40s
setTimeout(function () { click(a) }, 0)
}
}
}
// Use msSaveOrOpenBlob as a second approach
: 'msSaveOrOpenBlob' in navigator
? function saveAs (blob, name, opts) {
name = name || blob.name || 'download'
if (typeof blob === 'string') {
if (corsEnabled(blob)) {
download(blob, name, opts)
} else {
var a = document.createElement('a')
a.href = blob
a.target = '_blank'
setTimeout(function () { click(a) })
}
} else {
navigator.msSaveOrOpenBlob(bom(blob, opts), name)
}
}
// Fallback to using FileReader and a popup
: function saveAs (blob, name, opts, popup) {
// Open a popup immediately do go around popup blocker
// Mostly only available on user interaction and the fileReader is async so...
popup = popup || open('', '_blank')
if (popup) {
popup.document.title =
popup.document.body.innerText = 'downloading...'
}
if (typeof blob === 'string') return download(blob, name, opts)
var force = blob.type === 'application/octet-stream'
var isSafari = /constructor/i.test(_global.HTMLElement) || _global.safari
var isChromeIOS = /CriOS\/[\d]+/.test(navigator.userAgent)
if ((isChromeIOS || (force && isSafari) || isWebKit) && typeof FileReader !== 'undefined') {
// Safari doesn't allow downloading of blob URLs
var reader = new FileReader()
reader.onloadend = function () {
var url = reader.result
url = isChromeIOS ? url : url.replace(/^data:[^;]*;/, 'data:attachment/file;')
if (popup) popup.location.href = url
else location = url
popup = null // reverse-tabnabbing #460
}
reader.readAsDataURL(blob)
} else {
var URL = _global.URL || _global.webkitURL
var url = URL.createObjectURL(blob)
if (popup) popup.location = url
else location.href = url
popup = null // reverse-tabnabbing #460
setTimeout(function () { URL.revokeObjectURL(url) }, 4E4) // 40s
}
}
)
_global.saveAs = saveAs.saveAs = saveAs