| 
									
										
										
										
											2014-01-14 13:58:27 +08:00
										 |  |  | /*! | 
					
						
							|  |  |  |  * FileSaver.js | 
					
						
							| 
									
										
										
										
											2013-12-02 20:15:57 +08:00
										 |  |  |  * A saveAs() FileSaver implementation. | 
					
						
							| 
									
										
										
										
											2014-01-13 06:46:23 +08:00
										 |  |  |  * 2013-12-27 | 
					
						
							| 
									
										
										
										
											2013-12-02 20:15:57 +08:00
										 |  |  |  * | 
					
						
							|  |  |  |  * By Eli Grey, http://eligrey.com
 | 
					
						
							|  |  |  |  * License: X11/MIT | 
					
						
							|  |  |  |  *   See LICENSE.md | 
					
						
							|  |  |  |  */ | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | /*global self */ | 
					
						
							|  |  |  | /*jslint bitwise: true, regexp: true, confusion: true, es5: true, vars: true, white: true, | 
					
						
							|  |  |  |   plusplus: true */ | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2013-08-18 15:28:52 +08:00
										 |  |  | /*! @source http://purl.eligrey.com/github/FileSaver.js/blob/master/FileSaver.js */ | 
					
						
							| 
									
										
										
										
											2013-12-02 20:15:57 +08:00
										 |  |  | 
 | 
					
						
							|  |  |  | var saveAs = saveAs | 
					
						
							| 
									
										
										
										
											2014-01-13 06:46:23 +08:00
										 |  |  |   || (typeof navigator !== "undefined" && navigator.msSaveOrOpenBlob && navigator.msSaveOrOpenBlob.bind(navigator)) | 
					
						
							| 
									
										
										
										
											2013-12-02 20:15:57 +08:00
										 |  |  |   || (function(view) { | 
					
						
							|  |  |  | 	"use strict"; | 
					
						
							|  |  |  | 	var | 
					
						
							|  |  |  | 		  doc = view.document | 
					
						
							|  |  |  | 		  // only get URL when necessary in case BlobBuilder.js hasn't overridden it yet
 | 
					
						
							|  |  |  | 		, get_URL = function() { | 
					
						
							|  |  |  | 			return view.URL || view.webkitURL || view; | 
					
						
							|  |  |  | 		} | 
					
						
							|  |  |  | 		, URL = view.URL || view.webkitURL || view | 
					
						
							|  |  |  | 		, save_link = doc.createElementNS("http://www.w3.org/1999/xhtml", "a") | 
					
						
							|  |  |  | 		, can_use_save_link =  !view.externalHost && "download" in save_link | 
					
						
							|  |  |  | 		, click = function(node) { | 
					
						
							|  |  |  | 			var event = doc.createEvent("MouseEvents"); | 
					
						
							|  |  |  | 			event.initMouseEvent( | 
					
						
							|  |  |  | 				"click", true, false, view, 0, 0, 0, 0, 0 | 
					
						
							|  |  |  | 				, false, false, false, false, 0, null | 
					
						
							|  |  |  | 			); | 
					
						
							|  |  |  | 			node.dispatchEvent(event); | 
					
						
							|  |  |  | 		} | 
					
						
							|  |  |  | 		, webkit_req_fs = view.webkitRequestFileSystem | 
					
						
							|  |  |  | 		, req_fs = view.requestFileSystem || webkit_req_fs || view.mozRequestFileSystem | 
					
						
							|  |  |  | 		, throw_outside = function (ex) { | 
					
						
							|  |  |  | 			(view.setImmediate || view.setTimeout)(function() { | 
					
						
							|  |  |  | 				throw ex; | 
					
						
							|  |  |  | 			}, 0); | 
					
						
							|  |  |  | 		} | 
					
						
							|  |  |  | 		, force_saveable_type = "application/octet-stream" | 
					
						
							|  |  |  | 		, fs_min_size = 0 | 
					
						
							|  |  |  | 		, deletion_queue = [] | 
					
						
							|  |  |  | 		, process_deletion_queue = function() { | 
					
						
							|  |  |  | 			var i = deletion_queue.length; | 
					
						
							|  |  |  | 			while (i--) { | 
					
						
							|  |  |  | 				var file = deletion_queue[i]; | 
					
						
							|  |  |  | 				if (typeof file === "string") { // file is an object URL
 | 
					
						
							|  |  |  | 					URL.revokeObjectURL(file); | 
					
						
							|  |  |  | 				} else { // file is a File
 | 
					
						
							|  |  |  | 					file.remove(); | 
					
						
							|  |  |  | 				} | 
					
						
							|  |  |  | 			} | 
					
						
							|  |  |  | 			deletion_queue.length = 0; // clear queue
 | 
					
						
							|  |  |  | 		} | 
					
						
							|  |  |  | 		, dispatch = function(filesaver, event_types, event) { | 
					
						
							|  |  |  | 			event_types = [].concat(event_types); | 
					
						
							|  |  |  | 			var i = event_types.length; | 
					
						
							|  |  |  | 			while (i--) { | 
					
						
							|  |  |  | 				var listener = filesaver["on" + event_types[i]]; | 
					
						
							|  |  |  | 				if (typeof listener === "function") { | 
					
						
							|  |  |  | 					try { | 
					
						
							|  |  |  | 						listener.call(filesaver, event || filesaver); | 
					
						
							|  |  |  | 					} catch (ex) { | 
					
						
							|  |  |  | 						throw_outside(ex); | 
					
						
							|  |  |  | 					} | 
					
						
							|  |  |  | 				} | 
					
						
							|  |  |  | 			} | 
					
						
							|  |  |  | 		} | 
					
						
							|  |  |  | 		, FileSaver = function(blob, name) { | 
					
						
							|  |  |  | 			// First try a.download, then web filesystem, then object URLs
 | 
					
						
							|  |  |  | 			var | 
					
						
							|  |  |  | 				  filesaver = this | 
					
						
							|  |  |  | 				, type = blob.type | 
					
						
							|  |  |  | 				, blob_changed = false | 
					
						
							|  |  |  | 				, object_url | 
					
						
							|  |  |  | 				, target_view | 
					
						
							|  |  |  | 				, get_object_url = function() { | 
					
						
							|  |  |  | 					var object_url = get_URL().createObjectURL(blob); | 
					
						
							|  |  |  | 					deletion_queue.push(object_url); | 
					
						
							|  |  |  | 					return object_url; | 
					
						
							|  |  |  | 				} | 
					
						
							|  |  |  | 				, dispatch_all = function() { | 
					
						
							|  |  |  | 					dispatch(filesaver, "writestart progress write writeend".split(" ")); | 
					
						
							|  |  |  | 				} | 
					
						
							|  |  |  | 				// on any filesys errors revert to saving with object URLs
 | 
					
						
							|  |  |  | 				, fs_error = function() { | 
					
						
							|  |  |  | 					// don't create more object URLs than needed
 | 
					
						
							|  |  |  | 					if (blob_changed || !object_url) { | 
					
						
							|  |  |  | 						object_url = get_object_url(blob); | 
					
						
							|  |  |  | 					} | 
					
						
							|  |  |  | 					if (target_view) { | 
					
						
							|  |  |  | 						target_view.location.href = object_url; | 
					
						
							|  |  |  | 					} else { | 
					
						
							|  |  |  |                         window.open(object_url, "_blank"); | 
					
						
							|  |  |  |                     } | 
					
						
							|  |  |  | 					filesaver.readyState = filesaver.DONE; | 
					
						
							|  |  |  | 					dispatch_all(); | 
					
						
							|  |  |  | 				} | 
					
						
							|  |  |  | 				, abortable = function(func) { | 
					
						
							|  |  |  | 					return function() { | 
					
						
							|  |  |  | 						if (filesaver.readyState !== filesaver.DONE) { | 
					
						
							|  |  |  | 							return func.apply(this, arguments); | 
					
						
							|  |  |  | 						} | 
					
						
							|  |  |  | 					}; | 
					
						
							|  |  |  | 				} | 
					
						
							|  |  |  | 				, create_if_not_found = {create: true, exclusive: false} | 
					
						
							|  |  |  | 				, slice | 
					
						
							|  |  |  | 			; | 
					
						
							|  |  |  | 			filesaver.readyState = filesaver.INIT; | 
					
						
							|  |  |  | 			if (!name) { | 
					
						
							|  |  |  | 				name = "download"; | 
					
						
							|  |  |  | 			} | 
					
						
							|  |  |  | 			if (can_use_save_link) { | 
					
						
							|  |  |  | 				object_url = get_object_url(blob); | 
					
						
							|  |  |  | 				// FF for Android has a nasty garbage collection mechanism
 | 
					
						
							|  |  |  | 				// that turns all objects that are not pure javascript into 'deadObject'
 | 
					
						
							|  |  |  | 				// this means `doc` and `save_link` are unusable and need to be recreated
 | 
					
						
							|  |  |  | 				// `view` is usable though:
 | 
					
						
							|  |  |  | 				doc = view.document; | 
					
						
							|  |  |  | 				save_link = doc.createElementNS("http://www.w3.org/1999/xhtml", "a"); | 
					
						
							|  |  |  | 				save_link.href = object_url; | 
					
						
							|  |  |  | 				save_link.download = name; | 
					
						
							|  |  |  | 				var event = doc.createEvent("MouseEvents"); | 
					
						
							|  |  |  | 				event.initMouseEvent( | 
					
						
							|  |  |  | 					"click", true, false, view, 0, 0, 0, 0, 0 | 
					
						
							|  |  |  | 					, false, false, false, false, 0, null | 
					
						
							|  |  |  | 				); | 
					
						
							|  |  |  | 				save_link.dispatchEvent(event); | 
					
						
							|  |  |  | 				filesaver.readyState = filesaver.DONE; | 
					
						
							|  |  |  | 				dispatch_all(); | 
					
						
							|  |  |  | 				return; | 
					
						
							|  |  |  | 			} | 
					
						
							|  |  |  | 			// Object and web filesystem URLs have a problem saving in Google Chrome when
 | 
					
						
							|  |  |  | 			// viewed in a tab, so I force save with application/octet-stream
 | 
					
						
							|  |  |  | 			// http://code.google.com/p/chromium/issues/detail?id=91158
 | 
					
						
							|  |  |  | 			if (view.chrome && type && type !== force_saveable_type) { | 
					
						
							|  |  |  | 				slice = blob.slice || blob.webkitSlice; | 
					
						
							|  |  |  | 				blob = slice.call(blob, 0, blob.size, force_saveable_type); | 
					
						
							|  |  |  | 				blob_changed = true; | 
					
						
							|  |  |  | 			} | 
					
						
							|  |  |  | 			// Since I can't be sure that the guessed media type will trigger a download
 | 
					
						
							|  |  |  | 			// in WebKit, I append .download to the filename.
 | 
					
						
							|  |  |  | 			// https://bugs.webkit.org/show_bug.cgi?id=65440
 | 
					
						
							|  |  |  | 			if (webkit_req_fs && name !== "download") { | 
					
						
							|  |  |  | 				name += ".download"; | 
					
						
							|  |  |  | 			} | 
					
						
							|  |  |  | 			if (type === force_saveable_type || webkit_req_fs) { | 
					
						
							|  |  |  | 				target_view = view; | 
					
						
							|  |  |  | 			} | 
					
						
							|  |  |  | 			if (!req_fs) { | 
					
						
							|  |  |  | 				fs_error(); | 
					
						
							|  |  |  | 				return; | 
					
						
							|  |  |  | 			} | 
					
						
							|  |  |  | 			fs_min_size += blob.size; | 
					
						
							|  |  |  | 			req_fs(view.TEMPORARY, fs_min_size, abortable(function(fs) { | 
					
						
							|  |  |  | 				fs.root.getDirectory("saved", create_if_not_found, abortable(function(dir) { | 
					
						
							|  |  |  | 					var save = function() { | 
					
						
							|  |  |  | 						dir.getFile(name, create_if_not_found, abortable(function(file) { | 
					
						
							|  |  |  | 							file.createWriter(abortable(function(writer) { | 
					
						
							|  |  |  | 								writer.onwriteend = function(event) { | 
					
						
							|  |  |  | 									target_view.location.href = file.toURL(); | 
					
						
							|  |  |  | 									deletion_queue.push(file); | 
					
						
							|  |  |  | 									filesaver.readyState = filesaver.DONE; | 
					
						
							|  |  |  | 									dispatch(filesaver, "writeend", event); | 
					
						
							|  |  |  | 								}; | 
					
						
							|  |  |  | 								writer.onerror = function() { | 
					
						
							|  |  |  | 									var error = writer.error; | 
					
						
							|  |  |  | 									if (error.code !== error.ABORT_ERR) { | 
					
						
							|  |  |  | 										fs_error(); | 
					
						
							|  |  |  | 									} | 
					
						
							|  |  |  | 								}; | 
					
						
							|  |  |  | 								"writestart progress write abort".split(" ").forEach(function(event) { | 
					
						
							|  |  |  | 									writer["on" + event] = filesaver["on" + event]; | 
					
						
							|  |  |  | 								}); | 
					
						
							|  |  |  | 								writer.write(blob); | 
					
						
							|  |  |  | 								filesaver.abort = function() { | 
					
						
							|  |  |  | 									writer.abort(); | 
					
						
							|  |  |  | 									filesaver.readyState = filesaver.DONE; | 
					
						
							|  |  |  | 								}; | 
					
						
							|  |  |  | 								filesaver.readyState = filesaver.WRITING; | 
					
						
							|  |  |  | 							}), fs_error); | 
					
						
							|  |  |  | 						}), fs_error); | 
					
						
							|  |  |  | 					}; | 
					
						
							|  |  |  | 					dir.getFile(name, {create: false}, abortable(function(file) { | 
					
						
							|  |  |  | 						// delete file if it already exists
 | 
					
						
							|  |  |  | 						file.remove(); | 
					
						
							|  |  |  | 						save(); | 
					
						
							|  |  |  | 					}), abortable(function(ex) { | 
					
						
							|  |  |  | 						if (ex.code === ex.NOT_FOUND_ERR) { | 
					
						
							|  |  |  | 							save(); | 
					
						
							|  |  |  | 						} else { | 
					
						
							|  |  |  | 							fs_error(); | 
					
						
							|  |  |  | 						} | 
					
						
							|  |  |  | 					})); | 
					
						
							|  |  |  | 				}), fs_error); | 
					
						
							|  |  |  | 			}), fs_error); | 
					
						
							|  |  |  | 		} | 
					
						
							|  |  |  | 		, FS_proto = FileSaver.prototype | 
					
						
							|  |  |  | 		, saveAs = function(blob, name) { | 
					
						
							|  |  |  | 			return new FileSaver(blob, name); | 
					
						
							|  |  |  | 		} | 
					
						
							|  |  |  | 	; | 
					
						
							|  |  |  | 	FS_proto.abort = function() { | 
					
						
							|  |  |  | 		var filesaver = this; | 
					
						
							|  |  |  | 		filesaver.readyState = filesaver.DONE; | 
					
						
							|  |  |  | 		dispatch(filesaver, "abort"); | 
					
						
							|  |  |  | 	}; | 
					
						
							|  |  |  | 	FS_proto.readyState = FS_proto.INIT = 0; | 
					
						
							|  |  |  | 	FS_proto.WRITING = 1; | 
					
						
							|  |  |  | 	FS_proto.DONE = 2; | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | 	FS_proto.error = | 
					
						
							|  |  |  | 	FS_proto.onwritestart = | 
					
						
							|  |  |  | 	FS_proto.onprogress = | 
					
						
							|  |  |  | 	FS_proto.onwrite = | 
					
						
							|  |  |  | 	FS_proto.onabort = | 
					
						
							|  |  |  | 	FS_proto.onerror = | 
					
						
							|  |  |  | 	FS_proto.onwriteend = | 
					
						
							|  |  |  | 		null; | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | 	view.addEventListener("unload", process_deletion_queue, false); | 
					
						
							|  |  |  | 	return saveAs; | 
					
						
							| 
									
										
										
										
											2014-01-13 06:46:23 +08:00
										 |  |  | }( | 
					
						
							|  |  |  | 	   typeof self !== "undefined" && self | 
					
						
							|  |  |  | 	|| typeof window !== "undefined" && window | 
					
						
							|  |  |  | 	|| this.content | 
					
						
							|  |  |  | )); | 
					
						
							| 
									
										
										
										
											2013-12-02 20:15:57 +08:00
										 |  |  | // `self` is undefined in Firefox for Android content script context
 | 
					
						
							|  |  |  | // while `this` is nsIContentFrameMessageManager
 | 
					
						
							|  |  |  | // with an attribute `content` that corresponds to the window
 | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2014-01-13 06:46:23 +08:00
										 |  |  | if (typeof module !== "undefined") module.exports = saveAs; |