FileSaver.js

An HTML5 saveAs() FileSaver implementation

Dieses Skript sollte nicht direkt installiert werden. Es handelt sich hier um eine Bibliothek für andere Skripte, welche über folgenden Befehl in den Metadaten eines Skriptes eingebunden wird // @require https://update.greatest.deepsurf.us/scripts/4274/13748/FileSaverjs.js

  1. /* FileSaver.js
  2. * A saveAs() FileSaver implementation.
  3. * 2014-07-25
  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
  16. // IE 10+ (native saveAs)
  17. || (typeof navigator !== "undefined" &&
  18. navigator.msSaveOrOpenBlob && navigator.msSaveOrOpenBlob.bind(navigator))
  19. // Everyone else
  20. || (function(view) {
  21. "use strict";
  22. // IE <10 is explicitly unsupported
  23. if (typeof navigator !== "undefined" &&
  24. /MSIE [1-9]\./.test(navigator.userAgent)) {
  25. return;
  26. }
  27. var
  28. doc = view.document
  29. // only get URL when necessary in case Blob.js hasn't overridden it yet
  30. , get_URL = function() {
  31. return view.URL || view.webkitURL || view;
  32. }
  33. , save_link = doc.createElementNS("http://www.w3.org/1999/xhtml", "a")
  34. , can_use_save_link = !view.externalHost && "download" in save_link
  35. , click = function(node) {
  36. var event = doc.createEvent("MouseEvents");
  37. event.initMouseEvent(
  38. "click", true, false, view, 0, 0, 0, 0, 0
  39. , false, false, false, false, 0, null
  40. );
  41. node.dispatchEvent(event);
  42. }
  43. , webkit_req_fs = view.webkitRequestFileSystem
  44. , req_fs = view.requestFileSystem || webkit_req_fs || view.mozRequestFileSystem
  45. , throw_outside = function(ex) {
  46. (view.setImmediate || view.setTimeout)(function() {
  47. throw ex;
  48. }, 0);
  49. }
  50. , force_saveable_type = "application/octet-stream"
  51. , fs_min_size = 0
  52. // See https://code.google.com/p/chromium/issues/detail?id=375297#c7 for
  53. // the reasoning behind the timeout and revocation flow
  54. , arbitrary_revoke_timeout = 10
  55. , revoke = function(file) {
  56. var revoker = function() {
  57. if (typeof file === "string") { // file is an object URL
  58. get_URL().revokeObjectURL(file);
  59. } else { // file is a File
  60. file.remove();
  61. }
  62. };
  63. if (view.chrome) {
  64. revoker();
  65. } else {
  66. setTimeout(revoker, arbitrary_revoke_timeout);
  67. }
  68. }
  69. , dispatch = function(filesaver, event_types, event) {
  70. event_types = [].concat(event_types);
  71. var i = event_types.length;
  72. while (i--) {
  73. var listener = filesaver["on" + event_types[i]];
  74. if (typeof listener === "function") {
  75. try {
  76. listener.call(filesaver, event || filesaver);
  77. } catch (ex) {
  78. throw_outside(ex);
  79. }
  80. }
  81. }
  82. }
  83. , FileSaver = function(blob, name) {
  84. // First try a.download, then web filesystem, then object URLs
  85. var
  86. filesaver = this
  87. , type = blob.type
  88. , blob_changed = false
  89. , object_url
  90. , target_view
  91. , dispatch_all = function() {
  92. dispatch(filesaver, "writestart progress write writeend".split(" "));
  93. }
  94. // on any filesys errors revert to saving with object URLs
  95. , fs_error = function() {
  96. // don't create more object URLs than needed
  97. if (blob_changed || !object_url) {
  98. object_url = get_URL().createObjectURL(blob);
  99. }
  100. if (target_view) {
  101. target_view.location.href = object_url;
  102. } else {
  103. var new_tab = view.open(object_url, "_blank");
  104. if (new_tab == undefined && typeof safari !== "undefined") {
  105. //Apple do not allow window.open, see http://bit.ly/1kZffRI
  106. view.location.href = object_url
  107. }
  108. }
  109. filesaver.readyState = filesaver.DONE;
  110. dispatch_all();
  111. revoke(object_url);
  112. }
  113. , abortable = function(func) {
  114. return function() {
  115. if (filesaver.readyState !== filesaver.DONE) {
  116. return func.apply(this, arguments);
  117. }
  118. };
  119. }
  120. , create_if_not_found = {create: true, exclusive: false}
  121. , slice
  122. ;
  123. filesaver.readyState = filesaver.INIT;
  124. if (!name) {
  125. name = "download";
  126. }
  127. if (can_use_save_link) {
  128. object_url = get_URL().createObjectURL(blob);
  129. save_link.href = object_url;
  130. save_link.download = name;
  131. click(save_link);
  132. filesaver.readyState = filesaver.DONE;
  133. dispatch_all();
  134. revoke(object_url);
  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. // Update: Google errantly closed 91158, I submitted it again:
  141. // https://code.google.com/p/chromium/issues/detail?id=389642
  142. if (view.chrome && type && type !== force_saveable_type) {
  143. slice = blob.slice || blob.webkitSlice;
  144. blob = slice.call(blob, 0, blob.size, force_saveable_type);
  145. blob_changed = true;
  146. }
  147. // Since I can't be sure that the guessed media type will trigger a download
  148. // in WebKit, I append .download to the filename.
  149. // https://bugs.webkit.org/show_bug.cgi?id=65440
  150. if (webkit_req_fs && name !== "download") {
  151. name += ".download";
  152. }
  153. if (type === force_saveable_type || webkit_req_fs) {
  154. target_view = view;
  155. }
  156. if (!req_fs) {
  157. fs_error();
  158. return;
  159. }
  160. fs_min_size += blob.size;
  161. req_fs(view.TEMPORARY, fs_min_size, abortable(function(fs) {
  162. fs.root.getDirectory("saved", create_if_not_found, abortable(function(dir) {
  163. var save = function() {
  164. dir.getFile(name, create_if_not_found, abortable(function(file) {
  165. file.createWriter(abortable(function(writer) {
  166. writer.onwriteend = function(event) {
  167. target_view.location.href = file.toURL();
  168. filesaver.readyState = filesaver.DONE;
  169. dispatch(filesaver, "writeend", event);
  170. revoke(file);
  171. };
  172. writer.onerror = function() {
  173. var error = writer.error;
  174. if (error.code !== error.ABORT_ERR) {
  175. fs_error();
  176. }
  177. };
  178. "writestart progress write abort".split(" ").forEach(function(event) {
  179. writer["on" + event] = filesaver["on" + event];
  180. });
  181. writer.write(blob);
  182. filesaver.abort = function() {
  183. writer.abort();
  184. filesaver.readyState = filesaver.DONE;
  185. };
  186. filesaver.readyState = filesaver.WRITING;
  187. }), fs_error);
  188. }), fs_error);
  189. };
  190. dir.getFile(name, {create: false}, abortable(function(file) {
  191. // delete file if it already exists
  192. file.remove();
  193. save();
  194. }), abortable(function(ex) {
  195. if (ex.code === ex.NOT_FOUND_ERR) {
  196. save();
  197. } else {
  198. fs_error();
  199. }
  200. }));
  201. }), fs_error);
  202. }), fs_error);
  203. }
  204. , FS_proto = FileSaver.prototype
  205. , saveAs = function(blob, name) {
  206. return new FileSaver(blob, name);
  207. }
  208. ;
  209. FS_proto.abort = function() {
  210. var filesaver = this;
  211. filesaver.readyState = filesaver.DONE;
  212. dispatch(filesaver, "abort");
  213. };
  214. FS_proto.readyState = FS_proto.INIT = 0;
  215. FS_proto.WRITING = 1;
  216. FS_proto.DONE = 2;
  217.  
  218. FS_proto.error =
  219. FS_proto.onwritestart =
  220. FS_proto.onprogress =
  221. FS_proto.onwrite =
  222. FS_proto.onabort =
  223. FS_proto.onerror =
  224. FS_proto.onwriteend =
  225. null;
  226.  
  227. return saveAs;
  228. }(
  229. typeof self !== "undefined" && self
  230. || typeof window !== "undefined" && window
  231. || this.content
  232. ));
  233. // `self` is undefined in Firefox for Android content script context
  234. // while `this` is nsIContentFrameMessageManager
  235. // with an attribute `content` that corresponds to the window
  236.  
  237. if (typeof module !== "undefined" && module !== null) {
  238. module.exports = saveAs;
  239. } else if ((typeof define !== "undefined" && define !== null) && (define.amd != null)) {
  240. define([], function() {
  241. return saveAs;
  242. });
  243. }