Skip to content

Commit 850cdea

Browse files
committed
fix #1147
1 parent 28561d5 commit 850cdea

File tree

1 file changed

+36
-118
lines changed

1 file changed

+36
-118
lines changed

src/filesaver.js

+36-118
Original file line numberDiff line numberDiff line change
@@ -1,6 +1,7 @@
11
/* FileSaver.js
22
* A saveAs() FileSaver implementation.
3-
* 1.1.20151003
3+
* 1.3.2
4+
* 2016-06-16 18:25:19
45
*
56
* By Eli Grey, http://eligrey.com
67
* License: MIT
@@ -15,7 +16,7 @@
1516
var saveAs = saveAs || (function(view) {
1617
"use strict";
1718
// IE <10 is explicitly unsupported
18-
if (typeof navigator !== "undefined" && /MSIE [1-9]\./.test(navigator.userAgent)) {
19+
if (typeof view === "undefined" || typeof navigator !== "undefined" && /MSIE [1-9]\./.test(navigator.userAgent)) {
1920
return;
2021
}
2122
var
@@ -30,20 +31,16 @@ var saveAs = saveAs || (function(view) {
3031
var event = new MouseEvent("click");
3132
node.dispatchEvent(event);
3233
}
33-
, is_safari = /Version\/[\d\.]+.*Safari/.test(navigator.userAgent)
34-
, webkit_req_fs = view.webkitRequestFileSystem
35-
, req_fs = view.requestFileSystem || webkit_req_fs || view.mozRequestFileSystem
34+
, is_safari = /constructor/i.test(view.HTMLElement) || view.safari
35+
, is_chrome_ios =/CriOS\/[\d]+/.test(navigator.userAgent)
3636
, throw_outside = function(ex) {
3737
(view.setImmediate || view.setTimeout)(function() {
3838
throw ex;
3939
}, 0);
4040
}
4141
, force_saveable_type = "application/octet-stream"
42-
, fs_min_size = 0
43-
// See https://code.google.com/p/chromium/issues/detail?id=375297#c7 and
44-
// https://github.com/eligrey/FileSaver.js/commit/485930a#commitcomment-8768047
45-
// for the reasoning behind the timeout and revocation flow
46-
, arbitrary_revoke_timeout = 500 // in ms
42+
// the Blob API is fundamentally broken as there is no "downloadfinished" event to subscribe to
43+
, arbitrary_revoke_timeout = 1000 * 40 // in ms
4744
, revoke = function(file) {
4845
var revoker = function() {
4946
if (typeof file === "string") { // file is an object URL
@@ -52,11 +49,7 @@ var saveAs = saveAs || (function(view) {
5249
file.remove();
5350
}
5451
};
55-
if (view.chrome) {
56-
revoker();
57-
} else {
58-
setTimeout(revoker, arbitrary_revoke_timeout);
59-
}
52+
setTimeout(revoker, arbitrary_revoke_timeout);
6053
}
6154
, dispatch = function(filesaver, event_types, event) {
6255
event_types = [].concat(event_types);
@@ -74,8 +67,9 @@ var saveAs = saveAs || (function(view) {
7467
}
7568
, auto_bom = function(blob) {
7669
// prepend BOM for UTF-8 XML and text/* types (including HTML)
70+
// note: your browser will automatically convert UTF-16 U+FEFF to EF BB BF
7771
if (/^\s*(?:text\/\S*|application\/xml|\S*\/\S*\+xml)\s*;.*charset\s*=\s*utf-8/i.test(blob.type)) {
78-
return new Blob(["\ufeff", blob], {type: blob.type});
72+
return new Blob([String.fromCharCode(0xFEFF), blob], {type: blob.type});
7973
}
8074
return blob;
8175
}
@@ -87,20 +81,21 @@ var saveAs = saveAs || (function(view) {
8781
var
8882
filesaver = this
8983
, type = blob.type
90-
, blob_changed = false
84+
, force = type === force_saveable_type
9185
, object_url
92-
, target_view
9386
, dispatch_all = function() {
9487
dispatch(filesaver, "writestart progress write writeend".split(" "));
9588
}
9689
// on any filesys errors revert to saving with object URLs
9790
, fs_error = function() {
98-
if (target_view && is_safari && typeof FileReader !== "undefined") {
91+
if ((is_chrome_ios || (force && is_safari)) && view.FileReader) {
9992
// Safari doesn't allow downloading of blob urls
10093
var reader = new FileReader();
10194
reader.onloadend = function() {
102-
var base64Data = reader.result;
103-
target_view.location.href = "data:attachment/file" + base64Data.slice(base64Data.search(/[,;]/));
95+
var url = is_chrome_ios ? reader.result : reader.result.replace(/^data:[^;]*;/, 'data:attachment/file;');
96+
var popup = view.open(url, '_blank');
97+
if(!popup) view.location.href = url;
98+
url=undefined; // release reference before dispatching
10499
filesaver.readyState = filesaver.DONE;
105100
dispatch_all();
106101
};
@@ -109,135 +104,58 @@ var saveAs = saveAs || (function(view) {
109104
return;
110105
}
111106
// don't create more object URLs than needed
112-
if (blob_changed || !object_url) {
107+
if (!object_url) {
113108
object_url = get_URL().createObjectURL(blob);
114109
}
115-
if (target_view) {
116-
target_view.location.href = object_url;
110+
if (force) {
111+
view.location.href = object_url;
117112
} else {
118-
var new_tab = view.open(object_url, "_blank");
119-
if (new_tab == undefined && is_safari) {
120-
//Apple do not allow window.open, see http://bit.ly/1kZffRI
121-
view.location.href = object_url
113+
var opened = view.open(object_url, "_blank");
114+
if (!opened) {
115+
// Apple does not allow window.open, see https://developer.apple.com/library/safari/documentation/Tools/Conceptual/SafariExtensionGuide/WorkingwithWindowsandTabs/WorkingwithWindowsandTabs.html
116+
view.location.href = object_url;
122117
}
123118
}
124119
filesaver.readyState = filesaver.DONE;
125120
dispatch_all();
126121
revoke(object_url);
127122
}
128-
, abortable = function(func) {
129-
return function() {
130-
if (filesaver.readyState !== filesaver.DONE) {
131-
return func.apply(this, arguments);
132-
}
133-
};
134-
}
135-
, create_if_not_found = {create: true, exclusive: false}
136-
, slice
137123
;
138124
filesaver.readyState = filesaver.INIT;
139-
if (!name) {
140-
name = "download";
141-
}
125+
142126
if (can_use_save_link) {
143127
object_url = get_URL().createObjectURL(blob);
144-
save_link.href = object_url;
145-
save_link.download = name;
146128
setTimeout(function() {
129+
save_link.href = object_url;
130+
save_link.download = name;
147131
click(save_link);
148132
dispatch_all();
149133
revoke(object_url);
150134
filesaver.readyState = filesaver.DONE;
151135
});
152136
return;
153137
}
154-
// Object and web filesystem URLs have a problem saving in Google Chrome when
155-
// viewed in a tab, so I force save with application/octet-stream
156-
// http://code.google.com/p/chromium/issues/detail?id=91158
157-
// Update: Google errantly closed 91158, I submitted it again:
158-
// https://code.google.com/p/chromium/issues/detail?id=389642
159-
if (view.chrome && type && type !== force_saveable_type) {
160-
slice = blob.slice || blob.webkitSlice;
161-
blob = slice.call(blob, 0, blob.size, force_saveable_type);
162-
blob_changed = true;
163-
}
164-
// Since I can't be sure that the guessed media type will trigger a download
165-
// in WebKit, I append .download to the filename.
166-
// https://bugs.webkit.org/show_bug.cgi?id=65440
167-
if (webkit_req_fs && name !== "download") {
168-
name += ".download";
169-
}
170-
if (type === force_saveable_type || webkit_req_fs) {
171-
target_view = view;
172-
}
173-
if (!req_fs) {
174-
fs_error();
175-
return;
176-
}
177-
fs_min_size += blob.size;
178-
req_fs(view.TEMPORARY, fs_min_size, abortable(function(fs) {
179-
fs.root.getDirectory("saved", create_if_not_found, abortable(function(dir) {
180-
var save = function() {
181-
dir.getFile(name, create_if_not_found, abortable(function(file) {
182-
file.createWriter(abortable(function(writer) {
183-
writer.onwriteend = function(event) {
184-
target_view.location.href = file.toURL();
185-
filesaver.readyState = filesaver.DONE;
186-
dispatch(filesaver, "writeend", event);
187-
revoke(file);
188-
};
189-
writer.onerror = function() {
190-
var error = writer.error;
191-
if (error.code !== error.ABORT_ERR) {
192-
fs_error();
193-
}
194-
};
195-
"writestart progress write abort".split(" ").forEach(function(event) {
196-
writer["on" + event] = filesaver["on" + event];
197-
});
198-
writer.write(blob);
199-
filesaver.abort = function() {
200-
writer.abort();
201-
filesaver.readyState = filesaver.DONE;
202-
};
203-
filesaver.readyState = filesaver.WRITING;
204-
}), fs_error);
205-
}), fs_error);
206-
};
207-
dir.getFile(name, {create: false}, abortable(function(file) {
208-
// delete file if it already exists
209-
file.remove();
210-
save();
211-
}), abortable(function(ex) {
212-
if (ex.code === ex.NOT_FOUND_ERR) {
213-
save();
214-
} else {
215-
fs_error();
216-
}
217-
}));
218-
}), fs_error);
219-
}), fs_error);
138+
139+
fs_error();
220140
}
221141
, FS_proto = FileSaver.prototype
222142
, saveAs = function(blob, name, no_auto_bom) {
223-
return new FileSaver(blob, name, no_auto_bom);
143+
return new FileSaver(blob, name || blob.name || "download", no_auto_bom);
224144
}
225145
;
226146
// IE 10+ (native saveAs)
227147
if (typeof navigator !== "undefined" && navigator.msSaveOrOpenBlob) {
228148
return function(blob, name, no_auto_bom) {
149+
name = name || blob.name || "download";
150+
229151
if (!no_auto_bom) {
230152
blob = auto_bom(blob);
231153
}
232-
return navigator.msSaveOrOpenBlob(blob, name || "download");
154+
return navigator.msSaveOrOpenBlob(blob, name);
233155
};
234156
}
235157

236-
FS_proto.abort = function() {
237-
var filesaver = this;
238-
filesaver.readyState = filesaver.DONE;
239-
dispatch(filesaver, "abort");
240-
};
158+
FS_proto.abort = function(){};
241159
FS_proto.readyState = FS_proto.INIT = 0;
242160
FS_proto.WRITING = 1;
243161
FS_proto.DONE = 2;
@@ -263,8 +181,8 @@ var saveAs = saveAs || (function(view) {
263181

264182
if (typeof module !== "undefined" && module.exports) {
265183
module.exports.saveAs = saveAs;
266-
} else if ((typeof define !== "undefined" && define !== null) && (define.amd != null)) {
267-
define([], function() {
184+
} else if ((typeof define !== "undefined" && define !== null) && (define.amd !== null)) {
185+
define("FileSaver.js", function() {
268186
return saveAs;
269187
});
270-
}
188+
}

0 commit comments

Comments
 (0)