11 Commits
Author SHA1 Message Date
Jimmy Wärting 1bc9ed39c4 bump minor version 2019-05-14 10:00:17 +02:00
Marcin RybackiandJimmy Wärting 71f266f93e Missing dist build 2019-05-14 09:46:41 +02:00
Marcin RybackiandJimmy Wärting 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öökandJimmy Wärting 3caf053bbd fix autoBom documentation 2019-05-14 09:45:57 +02:00
josephroccaandJimmy Wärting 04ca36440d Updated Chrome data 2019-03-01 09:47:36 +01:00
zachary parrishandJimmy Wärting d87b419616 Update README.md
Just made some minor grammar changes
2019-02-17 17:45:48 +01:00
Jimmy WärtingandGitHub 3e46b73052 Update package.json 2019-02-17 15:24:08 +01:00
TypeError64andJimmy Wärting b1ab588946 Update README.md 2019-02-01 11:29:14 +01:00
Nathan Phillip BrinkandJimmy Wärting 4a73fd7a2d Fix a few spelling errors. 2019-01-07 13:02:54 +01:00
Alexander СветлыйandJimmy Wärting 0e905a3e06 Update README.md
Fix import
2018-12-29 11:02:50 +01:00
segoviaandJimmy Wärting 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
8 changed files with 2717 additions and 120 deletions
+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/), 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). 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 ## [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 ## [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 [#469]: https://github.com/eligrey/FileSaver.js/issues/469
[#470]: https://github.com/eligrey/FileSaver.js/issues/470 [#470]: https://github.com/eligrey/FileSaver.js/issues/470
[#491]: https://github.com/eligrey/FileSaver.js/issues/491 [#491]: https://github.com/eligrey/FileSaver.js/issues/491
[#534]: https://github.com/eligrey/FileSaver.js/issues/534
+19 -18
View File
@@ -8,7 +8,7 @@ FileSaver.js
FileSaver.js is the solution to saving files on the client-side, and is perfect for 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 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 Looking for `canvas.toBlob()` for saving canvases? Check out
[canvas-toBlob.js][2] for a cross-browser implementation. [canvas-toBlob.js][2] for a cross-browser implementation.
@@ -20,8 +20,8 @@ Supported Browsers
| -------------- | ------------- | ------------ | ------------- | ------------ | | -------------- | ------------- | ------------ | ------------- | ------------ |
| Firefox 20+ | Blob | Yes | 800 MiB | None | | Firefox 20+ | Blob | Yes | 800 MiB | None |
| Firefox < 20 | data: URI | No | n/a | [Blob.js](https://github.com/eligrey/Blob.js) | | Firefox < 20 | data: URI | No | n/a | [Blob.js](https://github.com/eligrey/Blob.js) |
| Chrome | Blob | Yes | [500 MiB][3] | None | | Chrome | Blob | Yes | [2GB][3] | None |
| Chrome for Android | Blob | Yes | [500 MiB][3] | None | | Chrome for Android | Blob | Yes | [RAM/5][3] | None |
| Edge | Blob | Yes | ? | None | | Edge | Blob | Yes | ? | None |
| IE 10+ | Blob | Yes | 600 MiB | None | | IE 10+ | Blob | Yes | 600 MiB | None |
| Opera 15+ | Blob | Yes | 500 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 Syntax
------ ------
### Import saveAs() from file-saver ### Import `saveAs()` from file-saver
```js ```js
import saveAs from 'file-saver'; import { saveAs } from 'file-saver';
``` ```
```js ```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 Examples
-------- --------
### Saving text using require ### Saving text using `require()`
```js ```js
var FileSaver = require('file-saver'); var FileSaver = require('file-saver');
var blob = new Blob(["Hello, world!"], {type: "text/plain;charset=utf-8"}); var blob = new Blob(["Hello, world!"], {type: "text/plain;charset=utf-8"});
@@ -87,16 +87,15 @@ FileSaver.saveAs(blob, "hello world.txt");
```js ```js
FileSaver.saveAs("https://httpbin.org/image", "image.jpg"); FileSaver.saveAs("https://httpbin.org/image", "image.jpg");
``` ```
Using URLs within the same origin will just use `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 synchronously head request 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 it using blob URLs If it does, it will download the data and save using blob URLs.
if not it will try to download it using `a[download]` 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. 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. [Blob.js][5] is a cross-browser `Blob` implementation that solves this.
### Saving a canvas ### Saving a canvas
```js ```js
var canvas = document.getElementById("my-canvas"); var canvas = document.getElementById("my-canvas");
canvas.toBlob(function(blob) { canvas.toBlob(function(blob) {
@@ -109,10 +108,10 @@ Note: The standard HTML5 `canvas.toBlob()` method is not available in all browse
### Saving File ### Saving File
You can save a File constructor without specifying a filename. The 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 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) 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 If you still want to change the name, then you can change it in the 2nd argument.
```js ```js
// Note: Ie and Edge don't support the new File constructor, // 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/ [1]: http://eligrey.com/demos/FileSaver.js/
[2]: https://github.com/eligrey/canvas-toBlob.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 [4]: https://developer.mozilla.org/en-US/docs/DOM/Blob
[5]: https://github.com/eligrey/Blob.js [5]: https://github.com/eligrey/Blob.js
[6]: https://github.com/eligrey/canvas-toBlob.js [6]: https://github.com/eligrey/canvas-toBlob.js
@@ -138,6 +137,7 @@ Installation
------------------ ------------------
```bash ```bash
# Basic Node.JS installation
npm install file-saver --save npm install file-saver --save
bower install file-saver bower install file-saver
``` ```
@@ -145,5 +145,6 @@ bower install file-saver
Additionally, TypeScript definitions can be installed via: Additionally, TypeScript definitions can be installed via:
```bash ```bash
# Additional typescript definitions
npm install @types/file-saver --save-dev npm install @types/file-saver --save-dev
``` ```
+9 -5
View File
@@ -30,7 +30,7 @@
if (typeof opts === 'undefined') opts = { if (typeof opts === 'undefined') opts = {
autoBom: false autoBom: false
};else if (typeof opts !== 'object') { };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 = { opts = {
autoBom: !opts autoBom: !opts
}; };
@@ -66,7 +66,11 @@
var xhr = new XMLHttpRequest(); // use sync to avoid popup blocker var xhr = new XMLHttpRequest(); // use sync to avoid popup blocker
xhr.open('HEAD', url, false); xhr.open('HEAD', url, false);
try {
xhr.send(); xhr.send();
} catch (e) {}
return xhr.status >= 200 && xhr.status <= 299; return xhr.status >= 200 && xhr.status <= 299;
} // `a.click()` doesn't work for all browsers (#465) } // `a.click()` doesn't work for all browsers (#465)
@@ -81,7 +85,7 @@
} }
} }
var saveAs = _global.saveAs || // probably in some web worker var saveAs = _global.saveAs || ( // probably in some web worker
typeof window !== 'object' || window !== _global ? function saveAs() {} typeof window !== 'object' || window !== _global ? function saveAs() {}
/* noop */ /* noop */
// Use download attribute first if possible (#193 Lumia mobile) // Use download attribute first if possible (#193 Lumia mobile)
@@ -135,7 +139,7 @@
} // Fallback to using FileReader and a popup } // Fallback to using FileReader and a popup
: function saveAs(blob, name, opts, popup) { : function saveAs(blob, name, opts, popup) {
// Open a popup immediately do go around popup blocker // 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'); popup = popup || open('', '_blank');
if (popup) { if (popup) {
@@ -150,7 +154,7 @@
var isChromeIOS = /CriOS\/[\d]+/.test(navigator.userAgent); var isChromeIOS = /CriOS\/[\d]+/.test(navigator.userAgent);
if ((isChromeIOS || force && isSafari) && typeof FileReader === 'object') { if ((isChromeIOS || force && isSafari) && typeof FileReader === 'object') {
// Safari doesn't allow downloading of blob urls // Safari doesn't allow downloading of blob URLs
var reader = new FileReader(); var reader = new FileReader();
reader.onloadend = function () { reader.onloadend = function () {
@@ -171,7 +175,7 @@
URL.revokeObjectURL(url); URL.revokeObjectURL(url);
}, 4E4); // 40s }, 4E4); // 40s
} }
}; });
_global.saveAs = saveAs.saveAs = saveAs; _global.saveAs = saveAs.saveAs = saveAs;
if (typeof module !== 'undefined') { 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(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;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=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)});
//# sourceMappingURL=FileSaver.min.js.map //# sourceMappingURL=FileSaver.min.js.map
+1 -1
View File
File diff suppressed because one or more lines are too long
+2585
View File
File diff suppressed because it is too large Load Diff
+1 -1
View File
@@ -1,6 +1,6 @@
{ {
"name": "file-saver", "name": "file-saver",
"version": "2.0.0", "version": "2.0.2",
"description": "An HTML5 saveAs() FileSaver implementation", "description": "An HTML5 saveAs() FileSaver implementation",
"main": "dist/FileSaver.min.js", "main": "dist/FileSaver.min.js",
"files": [ "files": [
+7 -5
View File
@@ -8,7 +8,6 @@
* source : http://purl.eligrey.com/github/FileSaver.js * source : http://purl.eligrey.com/github/FileSaver.js
*/ */
// The one and only way of getting global scope in all environments // The one and only way of getting global scope in all environments
// https://stackoverflow.com/q/3277182/1008999 // https://stackoverflow.com/q/3277182/1008999
var _global = typeof window === 'object' && window.window === window var _global = typeof window === 'object' && window.window === window
@@ -20,7 +19,7 @@ var _global = typeof window === 'object' && window.window === window
function bom (blob, opts) { function bom (blob, opts) {
if (typeof opts === 'undefined') opts = { autoBom: false } if (typeof opts === 'undefined') opts = { autoBom: false }
else if (typeof opts !== 'object') { 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 } opts = { autoBom: !opts }
} }
@@ -49,7 +48,9 @@ function corsEnabled (url) {
var xhr = new XMLHttpRequest() var xhr = new XMLHttpRequest()
// use sync to avoid popup blocker // use sync to avoid popup blocker
xhr.open('HEAD', url, false) xhr.open('HEAD', url, false)
try {
xhr.send() xhr.send()
} catch (e) {}
return xhr.status >= 200 && xhr.status <= 299 return xhr.status >= 200 && xhr.status <= 299
} }
@@ -65,7 +66,7 @@ function click(node) {
} }
} }
var saveAs = _global.saveAs || var saveAs = _global.saveAs || (
// probably in some web worker // probably in some web worker
(typeof window !== 'object' || window !== _global) (typeof window !== 'object' || window !== _global)
? function saveAs () { /* noop */ } ? function saveAs () { /* noop */ }
@@ -123,7 +124,7 @@ var saveAs = _global.saveAs ||
// Fallback to using FileReader and a popup // Fallback to using FileReader and a popup
: function saveAs (blob, name, opts, popup) { : function saveAs (blob, name, opts, popup) {
// Open a popup immediately do go around popup blocker // 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') popup = popup || open('', '_blank')
if (popup) { if (popup) {
popup.document.title = popup.document.title =
@@ -137,7 +138,7 @@ var saveAs = _global.saveAs ||
var isChromeIOS = /CriOS\/[\d]+/.test(navigator.userAgent) var isChromeIOS = /CriOS\/[\d]+/.test(navigator.userAgent)
if ((isChromeIOS || (force && isSafari)) && typeof FileReader === 'object') { if ((isChromeIOS || (force && isSafari)) && typeof FileReader === 'object') {
// Safari doesn't allow downloading of blob urls // Safari doesn't allow downloading of blob URLs
var reader = new FileReader() var reader = new FileReader()
reader.onloadend = function () { reader.onloadend = function () {
var url = reader.result var url = reader.result
@@ -156,6 +157,7 @@ var saveAs = _global.saveAs ||
setTimeout(function () { URL.revokeObjectURL(url) }, 4E4) // 40s setTimeout(function () { URL.revokeObjectURL(url) }, 4E4) // 40s
} }
} }
)
_global.saveAs = saveAs.saveAs = saveAs _global.saveAs = saveAs.saveAs = saveAs