asciiblaster- draw irc art in your web browser |
git clone git://git.acid.vegas/asciiblaster.git |
Log | Files | Refs | Archive | README |
FileSaver.js (7398B)
1 /* FileSaver.js 2 * A saveAs() FileSaver implementation. 3 * 2013-10-21 4 * 5 * By Eli Grey, http://eligrey.com 6 * License: X11/MIT 7 * See LICENSE.md 8 */ 9 10 /*global self */ 11 /*jslint bitwise: true, regexp: true, confusion: true, es5: true, vars: true, white: true, 12 plusplus: true */ 13 14 /*! @source http://purl.eligrey.com/github/FileSaver.js/blob/master/FileSaver.js */ 15 16 var saveAs = saveAs 17 || (typeof navigator !== 'undefined' && navigator.msSaveOrOpenBlob && navigator.msSaveOrOpenBlob.bind(navigator)) 18 || (function(view) { 19 "use strict"; 20 var 21 doc = view.document 22 // only get URL when necessary in case BlobBuilder.js hasn't overridden it yet 23 , get_URL = function() { 24 return view.URL || view.webkitURL || view; 25 } 26 , URL = view.URL || view.webkitURL || view 27 , save_link = doc.createElementNS("http://www.w3.org/1999/xhtml", "a") 28 , can_use_save_link = !view.externalHost && "download" in save_link 29 , click = function(node) { 30 var event = doc.createEvent("MouseEvents"); 31 event.initMouseEvent( 32 "click", true, false, view, 0, 0, 0, 0, 0 33 , false, false, false, false, 0, null 34 ); 35 node.dispatchEvent(event); 36 } 37 , webkit_req_fs = view.webkitRequestFileSystem 38 , req_fs = view.requestFileSystem || webkit_req_fs || view.mozRequestFileSystem 39 , throw_outside = function (ex) { 40 (view.setImmediate || view.setTimeout)(function() { 41 throw ex; 42 }, 0); 43 } 44 , force_saveable_type = "application/octet-stream" 45 , fs_min_size = 0 46 , deletion_queue = [] 47 , process_deletion_queue = function() { 48 var i = deletion_queue.length; 49 while (i--) { 50 var file = deletion_queue[i]; 51 if (typeof file === "string") { // file is an object URL 52 URL.revokeObjectURL(file); 53 } else { // file is a File 54 file.remove(); 55 } 56 } 57 deletion_queue.length = 0; // clear queue 58 } 59 , dispatch = function(filesaver, event_types, event) { 60 event_types = [].concat(event_types); 61 var i = event_types.length; 62 while (i--) { 63 var listener = filesaver["on" + event_types[i]]; 64 if (typeof listener === "function") { 65 try { 66 listener.call(filesaver, event || filesaver); 67 } catch (ex) { 68 throw_outside(ex); 69 } 70 } 71 } 72 } 73 , FileSaver = function(blob, name) { 74 // First try a.download, then web filesystem, then object URLs 75 var 76 filesaver = this 77 , type = blob.type 78 , blob_changed = false 79 , object_url 80 , target_view 81 , get_object_url = function() { 82 var object_url = get_URL().createObjectURL(blob); 83 deletion_queue.push(object_url); 84 return object_url; 85 } 86 , dispatch_all = function() { 87 dispatch(filesaver, "writestart progress write writeend".split(" ")); 88 } 89 // on any filesys errors revert to saving with object URLs 90 , fs_error = function() { 91 // don't create more object URLs than needed 92 if (blob_changed || !object_url) { 93 object_url = get_object_url(blob); 94 } 95 if (target_view) { 96 target_view.location.href = object_url; 97 } else { 98 window.open(object_url, "_blank"); 99 } 100 filesaver.readyState = filesaver.DONE; 101 dispatch_all(); 102 } 103 , abortable = function(func) { 104 return function() { 105 if (filesaver.readyState !== filesaver.DONE) { 106 return func.apply(this, arguments); 107 } 108 }; 109 } 110 , create_if_not_found = {create: true, exclusive: false} 111 , slice 112 ; 113 filesaver.readyState = filesaver.INIT; 114 if (!name) { 115 name = "download"; 116 } 117 if (can_use_save_link) { 118 object_url = get_object_url(blob); 119 // FF for Android has a nasty garbage collection mechanism 120 // that turns all objects that are not pure javascript into 'deadObject' 121 // this means `doc` and `save_link` are unusable and need to be recreated 122 // `view` is usable though: 123 doc = view.document; 124 save_link = doc.createElementNS("http://www.w3.org/1999/xhtml", "a"); 125 save_link.href = object_url; 126 save_link.download = name; 127 var event = doc.createEvent("MouseEvents"); 128 event.initMouseEvent( 129 "click", true, false, view, 0, 0, 0, 0, 0 130 , false, false, false, false, 0, null 131 ); 132 save_link.dispatchEvent(event); 133 filesaver.readyState = filesaver.DONE; 134 dispatch_all(); 135 return; 136 } 137 // Object and web filesystem URLs have a problem saving in Google Chrome when 138 // viewed in a tab, so I force save with application/octet-stream 139 // http://code.google.com/p/chromium/issues/detail?id=91158 140 if (view.chrome && type && type !== force_saveable_type) { 141 slice = blob.slice || blob.webkitSlice; 142 blob = slice.call(blob, 0, blob.size, force_saveable_type); 143 blob_changed = true; 144 } 145 // Since I can't be sure that the guessed media type will trigger a download 146 // in WebKit, I append .download to the filename. 147 // https://bugs.webkit.org/show_bug.cgi?id=65440 148 if (webkit_req_fs && name !== "download") { 149 name += ".download"; 150 } 151 if (type === force_saveable_type || webkit_req_fs) { 152 target_view = view; 153 } 154 if (!req_fs) { 155 fs_error(); 156 return; 157 } 158 fs_min_size += blob.size; 159 req_fs(view.TEMPORARY, fs_min_size, abortable(function(fs) { 160 fs.root.getDirectory("saved", create_if_not_found, abortable(function(dir) { 161 var save = function() { 162 dir.getFile(name, create_if_not_found, abortable(function(file) { 163 file.createWriter(abortable(function(writer) { 164 writer.onwriteend = function(event) { 165 target_view.location.href = file.toURL(); 166 deletion_queue.push(file); 167 filesaver.readyState = filesaver.DONE; 168 dispatch(filesaver, "writeend", event); 169 }; 170 writer.onerror = function() { 171 var error = writer.error; 172 if (error.code !== error.ABORT_ERR) { 173 fs_error(); 174 } 175 }; 176 "writestart progress write abort".split(" ").forEach(function(event) { 177 writer["on" + event] = filesaver["on" + event]; 178 }); 179 writer.write(blob); 180 filesaver.abort = function() { 181 writer.abort(); 182 filesaver.readyState = filesaver.DONE; 183 }; 184 filesaver.readyState = filesaver.WRITING; 185 }), fs_error); 186 }), fs_error); 187 }; 188 dir.getFile(name, {create: false}, abortable(function(file) { 189 // delete file if it already exists 190 file.remove(); 191 save(); 192 }), abortable(function(ex) { 193 if (ex.code === ex.NOT_FOUND_ERR) { 194 save(); 195 } else { 196 fs_error(); 197 } 198 })); 199 }), fs_error); 200 }), fs_error); 201 } 202 , FS_proto = FileSaver.prototype 203 , saveAs = function(blob, name) { 204 return new FileSaver(blob, name); 205 } 206 ; 207 FS_proto.abort = function() { 208 var filesaver = this; 209 filesaver.readyState = filesaver.DONE; 210 dispatch(filesaver, "abort"); 211 }; 212 FS_proto.readyState = FS_proto.INIT = 0; 213 FS_proto.WRITING = 1; 214 FS_proto.DONE = 2; 215 216 FS_proto.error = 217 FS_proto.onwritestart = 218 FS_proto.onprogress = 219 FS_proto.onwrite = 220 FS_proto.onabort = 221 FS_proto.onerror = 222 FS_proto.onwriteend = 223 null; 224 225 view.addEventListener("unload", process_deletion_queue, false); 226 return saveAs; 227 }(this.self || this.window || this.content)); 228 // `self` is undefined in Firefox for Android content script context 229 // while `this` is nsIContentFrameMessageManager 230 // with an attribute `content` that corresponds to the window 231 232 if (typeof module !== 'undefined') module.exports = saveAs;