partkeepr

fork of partkeepr
git clone https://git.e1e0.net/partkeepr.git
Log | Files | Refs | Submodules | README | LICENSE

FileSaver.js (8586B)


      1 /* FileSaver.js
      2  * A saveAs() FileSaver implementation.
      3  * 1.1.20151003
      4  *
      5  * By Eli Grey, http://eligrey.com
      6  * License: X11/MIT
      7  *   See https://github.com/eligrey/FileSaver.js/blob/master/LICENSE.md
      8  */
      9 
     10 /*global self */
     11 /*jslint bitwise: true, indent: 4, laxbreak: true, laxcomma: true, smarttabs: true, plusplus: true */
     12 
     13 /*! @source http://purl.eligrey.com/github/FileSaver.js/blob/master/FileSaver.js */
     14 
     15 var saveAs = saveAs || (function(view) {
     16 	"use strict";
     17 	// IE <10 is explicitly unsupported
     18 	if (typeof navigator !== "undefined" && /MSIE [1-9]\./.test(navigator.userAgent)) {
     19 		return;
     20 	}
     21 	var
     22 		  doc = view.document
     23 		  // only get URL when necessary in case Blob.js hasn't overridden it yet
     24 		, get_URL = function() {
     25 			return view.URL || view.webkitURL || view;
     26 		}
     27 		, save_link = doc.createElementNS("http://www.w3.org/1999/xhtml", "a")
     28 		, can_use_save_link = "download" in save_link
     29 		, click = function(node) {
     30 			var event = new MouseEvent("click");
     31 			node.dispatchEvent(event);
     32 		}
     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
     36 		, throw_outside = function(ex) {
     37 			(view.setImmediate || view.setTimeout)(function() {
     38 				throw ex;
     39 			}, 0);
     40 		}
     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
     47 		, revoke = function(file) {
     48 			var revoker = function() {
     49 				if (typeof file === "string") { // file is an object URL
     50 					get_URL().revokeObjectURL(file);
     51 				} else { // file is a File
     52 					file.remove();
     53 				}
     54 			};
     55 			if (view.chrome) {
     56 				revoker();
     57 			} else {
     58 				setTimeout(revoker, arbitrary_revoke_timeout);
     59 			}
     60 		}
     61 		, dispatch = function(filesaver, event_types, event) {
     62 			event_types = [].concat(event_types);
     63 			var i = event_types.length;
     64 			while (i--) {
     65 				var listener = filesaver["on" + event_types[i]];
     66 				if (typeof listener === "function") {
     67 					try {
     68 						listener.call(filesaver, event || filesaver);
     69 					} catch (ex) {
     70 						throw_outside(ex);
     71 					}
     72 				}
     73 			}
     74 		}
     75 		, auto_bom = function(blob) {
     76 			// prepend BOM for UTF-8 XML and text/* types (including HTML)
     77 			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});
     79 			}
     80 			return blob;
     81 		}
     82 		, FileSaver = function(blob, name, no_auto_bom) {
     83 			if (!no_auto_bom) {
     84 				blob = auto_bom(blob);
     85 			}
     86 			// First try a.download, then web filesystem, then object URLs
     87 			var
     88 				  filesaver = this
     89 				, type = blob.type
     90 				, blob_changed = false
     91 				, object_url
     92 				, target_view
     93 				, dispatch_all = function() {
     94 					dispatch(filesaver, "writestart progress write writeend".split(" "));
     95 				}
     96 				// on any filesys errors revert to saving with object URLs
     97 				, fs_error = function() {
     98 					if (target_view && is_safari && typeof FileReader !== "undefined") {
     99 						// Safari doesn't allow downloading of blob urls
    100 						var reader = new FileReader();
    101 						reader.onloadend = function() {
    102 							var base64Data = reader.result;
    103 							target_view.location.href = "data:attachment/file" + base64Data.slice(base64Data.search(/[,;]/));
    104 							filesaver.readyState = filesaver.DONE;
    105 							dispatch_all();
    106 						};
    107 						reader.readAsDataURL(blob);
    108 						filesaver.readyState = filesaver.INIT;
    109 						return;
    110 					}
    111 					// don't create more object URLs than needed
    112 					if (blob_changed || !object_url) {
    113 						object_url = get_URL().createObjectURL(blob);
    114 					}
    115 					if (target_view) {
    116 						target_view.location.href = object_url;
    117 					} 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
    122 						}
    123 					}
    124 					filesaver.readyState = filesaver.DONE;
    125 					dispatch_all();
    126 					revoke(object_url);
    127 				}
    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 			;
    138 			filesaver.readyState = filesaver.INIT;
    139 			if (!name) {
    140 				name = "download";
    141 			}
    142 			if (can_use_save_link) {
    143 				object_url = get_URL().createObjectURL(blob);
    144 				save_link.href = object_url;
    145 				save_link.download = name;
    146 				setTimeout(function() {
    147 					click(save_link);
    148 					dispatch_all();
    149 					revoke(object_url);
    150 					filesaver.readyState = filesaver.DONE;
    151 				});
    152 				return;
    153 			}
    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);
    220 		}
    221 		, FS_proto = FileSaver.prototype
    222 		, saveAs = function(blob, name, no_auto_bom) {
    223 			return new FileSaver(blob, name, no_auto_bom);
    224 		}
    225 	;
    226 	// IE 10+ (native saveAs)
    227 	if (typeof navigator !== "undefined" && navigator.msSaveOrOpenBlob) {
    228 		return function(blob, name, no_auto_bom) {
    229 			if (!no_auto_bom) {
    230 				blob = auto_bom(blob);
    231 			}
    232 			return navigator.msSaveOrOpenBlob(blob, name || "download");
    233 		};
    234 	}
    235 
    236 	FS_proto.abort = function() {
    237 		var filesaver = this;
    238 		filesaver.readyState = filesaver.DONE;
    239 		dispatch(filesaver, "abort");
    240 	};
    241 	FS_proto.readyState = FS_proto.INIT = 0;
    242 	FS_proto.WRITING = 1;
    243 	FS_proto.DONE = 2;
    244 
    245 	FS_proto.error =
    246 	FS_proto.onwritestart =
    247 	FS_proto.onprogress =
    248 	FS_proto.onwrite =
    249 	FS_proto.onabort =
    250 	FS_proto.onerror =
    251 	FS_proto.onwriteend =
    252 		null;
    253 
    254 	return saveAs;
    255 }(
    256 	   typeof self !== "undefined" && self
    257 	|| typeof window !== "undefined" && window
    258 	|| this.content
    259 ));
    260 // `self` is undefined in Firefox for Android content script context
    261 // while `this` is nsIContentFrameMessageManager
    262 // with an attribute `content` that corresponds to the window
    263 
    264 if (typeof module !== "undefined" && module.exports) {
    265   module.exports.saveAs = saveAs;
    266 } else if ((typeof define !== "undefined" && define !== null) && (define.amd != null)) {
    267   define([], function() {
    268     return saveAs;
    269   });
    270 }