1
1
/* FileSaver.js
2
2
* A saveAs() FileSaver implementation.
3
- * 1.1.20151003
3
+ * 1.3.2
4
+ * 2016-06-16 18:25:19
4
5
*
5
6
* By Eli Grey, http://eligrey.com
6
7
* License: MIT
15
16
var saveAs = saveAs || ( function ( view ) {
16
17
"use strict" ;
17
18
// IE <10 is explicitly unsupported
18
- if ( typeof navigator !== "undefined" && / M S I E [ 1 - 9 ] \. / . test ( navigator . userAgent ) ) {
19
+ if ( typeof view === "undefined" || typeof navigator !== "undefined" && / M S I E [ 1 - 9 ] \. / . test ( navigator . userAgent ) ) {
19
20
return ;
20
21
}
21
22
var
@@ -30,20 +31,16 @@ var saveAs = saveAs || (function(view) {
30
31
var event = new MouseEvent ( "click" ) ;
31
32
node . dispatchEvent ( event ) ;
32
33
}
33
- , is_safari = / V e r s i o n \/ [ \d \. ] + .* S a f a r i / . test ( navigator . userAgent )
34
- , webkit_req_fs = view . webkitRequestFileSystem
35
- , req_fs = view . requestFileSystem || webkit_req_fs || view . mozRequestFileSystem
34
+ , is_safari = / c o n s t r u c t o r / i. test ( view . HTMLElement ) || view . safari
35
+ , is_chrome_ios = / C r i O S \/ [ \d ] + / . test ( navigator . userAgent )
36
36
, throw_outside = function ( ex ) {
37
37
( view . setImmediate || view . setTimeout ) ( function ( ) {
38
38
throw ex ;
39
39
} , 0 ) ;
40
40
}
41
41
, 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
47
44
, revoke = function ( file ) {
48
45
var revoker = function ( ) {
49
46
if ( typeof file === "string" ) { // file is an object URL
@@ -52,11 +49,7 @@ var saveAs = saveAs || (function(view) {
52
49
file . remove ( ) ;
53
50
}
54
51
} ;
55
- if ( view . chrome ) {
56
- revoker ( ) ;
57
- } else {
58
- setTimeout ( revoker , arbitrary_revoke_timeout ) ;
59
- }
52
+ setTimeout ( revoker , arbitrary_revoke_timeout ) ;
60
53
}
61
54
, dispatch = function ( filesaver , event_types , event ) {
62
55
event_types = [ ] . concat ( event_types ) ;
@@ -74,8 +67,9 @@ var saveAs = saveAs || (function(view) {
74
67
}
75
68
, auto_bom = function ( blob ) {
76
69
// 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
77
71
if ( / ^ \s * (?: t e x t \/ \S * | a p p l i c a t i o n \/ x m l | \S * \/ \S * \+ x m l ) \s * ; .* c h a r s e t \s * = \s * u t f - 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 } ) ;
79
73
}
80
74
return blob ;
81
75
}
@@ -87,20 +81,21 @@ var saveAs = saveAs || (function(view) {
87
81
var
88
82
filesaver = this
89
83
, type = blob . type
90
- , blob_changed = false
84
+ , force = type === force_saveable_type
91
85
, object_url
92
- , target_view
93
86
, dispatch_all = function ( ) {
94
87
dispatch ( filesaver , "writestart progress write writeend" . split ( " " ) ) ;
95
88
}
96
89
// on any filesys errors revert to saving with object URLs
97
90
, fs_error = function ( ) {
98
- if ( target_view && is_safari && typeof FileReader !== "undefined" ) {
91
+ if ( ( is_chrome_ios || ( force && is_safari ) ) && view . FileReader ) {
99
92
// Safari doesn't allow downloading of blob urls
100
93
var reader = new FileReader ( ) ;
101
94
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 ( / ^ d a t a : [ ^ ; ] * ; / , 'data:attachment/file;' ) ;
96
+ var popup = view . open ( url , '_blank' ) ;
97
+ if ( ! popup ) view . location . href = url ;
98
+ url = undefined ; // release reference before dispatching
104
99
filesaver . readyState = filesaver . DONE ;
105
100
dispatch_all ( ) ;
106
101
} ;
@@ -109,135 +104,58 @@ var saveAs = saveAs || (function(view) {
109
104
return ;
110
105
}
111
106
// don't create more object URLs than needed
112
- if ( blob_changed || ! object_url ) {
107
+ if ( ! object_url ) {
113
108
object_url = get_URL ( ) . createObjectURL ( blob ) ;
114
109
}
115
- if ( target_view ) {
116
- target_view . location . href = object_url ;
110
+ if ( force ) {
111
+ view . location . href = object_url ;
117
112
} 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 ;
122
117
}
123
118
}
124
119
filesaver . readyState = filesaver . DONE ;
125
120
dispatch_all ( ) ;
126
121
revoke ( object_url ) ;
127
122
}
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
137
123
;
138
124
filesaver . readyState = filesaver . INIT ;
139
- if ( ! name ) {
140
- name = "download" ;
141
- }
125
+
142
126
if ( can_use_save_link ) {
143
127
object_url = get_URL ( ) . createObjectURL ( blob ) ;
144
- save_link . href = object_url ;
145
- save_link . download = name ;
146
128
setTimeout ( function ( ) {
129
+ save_link . href = object_url ;
130
+ save_link . download = name ;
147
131
click ( save_link ) ;
148
132
dispatch_all ( ) ;
149
133
revoke ( object_url ) ;
150
134
filesaver . readyState = filesaver . DONE ;
151
135
} ) ;
152
136
return ;
153
137
}
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 ( ) ;
220
140
}
221
141
, FS_proto = FileSaver . prototype
222
142
, 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 ) ;
224
144
}
225
145
;
226
146
// IE 10+ (native saveAs)
227
147
if ( typeof navigator !== "undefined" && navigator . msSaveOrOpenBlob ) {
228
148
return function ( blob , name , no_auto_bom ) {
149
+ name = name || blob . name || "download" ;
150
+
229
151
if ( ! no_auto_bom ) {
230
152
blob = auto_bom ( blob ) ;
231
153
}
232
- return navigator . msSaveOrOpenBlob ( blob , name || "download" ) ;
154
+ return navigator . msSaveOrOpenBlob ( blob , name ) ;
233
155
} ;
234
156
}
235
157
236
- FS_proto . abort = function ( ) {
237
- var filesaver = this ;
238
- filesaver . readyState = filesaver . DONE ;
239
- dispatch ( filesaver , "abort" ) ;
240
- } ;
158
+ FS_proto . abort = function ( ) { } ;
241
159
FS_proto . readyState = FS_proto . INIT = 0 ;
242
160
FS_proto . WRITING = 1 ;
243
161
FS_proto . DONE = 2 ;
@@ -263,8 +181,8 @@ var saveAs = saveAs || (function(view) {
263
181
264
182
if ( typeof module !== "undefined" && module . exports ) {
265
183
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 ( ) {
268
186
return saveAs ;
269
187
} ) ;
270
- }
188
+ }
0 commit comments