1 var saveAs = saveAs || (function(view) {
3 // IE <10 is explicitly unsupported
4 if (typeof view === "undefined" || typeof navigator !== "undefined" && /MSIE [1-9]\./.test(navigator.userAgent)) {
9 // only get URL when necessary in case Blob.js hasn't overridden it yet
10 , get_URL = function() {
11 return view.URL || view.webkitURL || view;
13 , save_link = doc.createElementNS("http://www.w3.org/1999/xhtml", "a")
14 , can_use_save_link = "download" in save_link
15 , click = function(node) {
16 var event = new MouseEvent("click");
17 node.dispatchEvent(event);
19 , is_safari = /constructor/i.test(view.HTMLElement)
20 , throw_outside = function(ex) {
21 (view.setImmediate || view.setTimeout)(function() {
25 , force_saveable_type = "application/octet-stream"
26 // the Blob API is fundamentally broken as there is no "downloadfinished" event to subscribe to
27 , arbitrary_revoke_timeout = 1000 * 40 // in ms
28 , revoke = function(file) {
29 var revoker = function() {
30 if (typeof file === "string") { // file is an object URL
31 get_URL().revokeObjectURL(file);
32 } else { // file is a File
36 setTimeout(revoker, arbitrary_revoke_timeout);
38 , dispatch = function(filesaver, event_types, event) {
39 event_types = [].concat(event_types);
40 var i = event_types.length;
42 var listener = filesaver["on" + event_types[i]];
43 if (typeof listener === "function") {
45 listener.call(filesaver, event || filesaver);
52 , auto_bom = function(blob) {
53 // prepend BOM for UTF-8 XML and text/* types (including HTML)
54 // note: your browser will automatically convert UTF-16 U+FEFF to EF BB BF
55 if (/^\s*(?:text\/\S*|application\/xml|\S*\/\S*\+xml)\s*;.*charset\s*=\s*utf-8/i.test(blob.type)) {
56 return new Blob([String.fromCharCode(0xFEFF), blob], {type: blob.type});
60 , FileSaver = function(blob, name, no_auto_bom) {
62 blob = auto_bom(blob);
64 // First try a.download, then web filesystem, then object URLs
68 , force = type === force_saveable_type
70 , dispatch_all = function() {
71 dispatch(filesaver, "writestart progress write writeend".split(" "));
73 // on any filesys errors revert to saving with object URLs
74 , fs_error = function() {
75 if (force && is_safari && view.FileReader) {
76 // Safari doesn't allow downloading of blob urls
77 var reader = new FileReader();
78 reader.onloadend = function() {
79 var base64Data = reader.result;
80 view.location.href = "data:attachment/file" + base64Data.slice(base64Data.search(/[,;]/));
81 filesaver.readyState = filesaver.DONE;
84 reader.readAsDataURL(blob);
85 filesaver.readyState = filesaver.INIT;
88 // don't create more object URLs than needed
90 object_url = get_URL().createObjectURL(blob);
93 view.location.href = object_url;
95 var opened = view.open(object_url, "_blank");
97 // Apple does not allow window.open, see https://developer.apple.com/library/safari/documentation/Tools/Conceptual/SafariExtensionGuide/WorkingwithWindowsandTabs/WorkingwithWindowsandTabs.html
98 view.location.href = object_url;
101 filesaver.readyState = filesaver.DONE;
106 filesaver.readyState = filesaver.INIT;
108 if (can_use_save_link) {
109 object_url = get_URL().createObjectURL(blob);
110 setTimeout(function() {
111 save_link.href = object_url;
112 save_link.download = name;
116 filesaver.readyState = filesaver.DONE;
123 , FS_proto = FileSaver.prototype
124 , saveAs = function(blob, name, no_auto_bom) {
125 return new FileSaver(blob, name || blob.name || "download", no_auto_bom);
128 // IE 10+ (native saveAs)
129 if (typeof navigator !== "undefined" && navigator.msSaveOrOpenBlob) {
130 return function(blob, name, no_auto_bom) {
131 name = name || blob.name || "download";
134 blob = auto_bom(blob);
136 return navigator.msSaveOrOpenBlob(blob, name);
140 FS_proto.abort = function(){};
141 FS_proto.readyState = FS_proto.INIT = 0;
142 FS_proto.WRITING = 1;
146 FS_proto.onwritestart =
147 FS_proto.onprogress =
151 FS_proto.onwriteend =
156 typeof self !== "undefined" && self
157 || typeof window !== "undefined" && window
160 // `self` is undefined in Firefox for Android content script context
161 // while `this` is nsIContentFrameMessageManager
162 // with an attribute `content` that corresponds to the window
164 if (typeof module !== "undefined" && module.exports) {
165 module.exports.saveAs = saveAs;
166 } else if ((typeof define !== "undefined" && define !== null) && (define.amd !== null)) {
167 define([], function() {