ぼざクリ タグ広場 https://hub.nizika.monster
You can not select more than 25 topics Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.
 
 
 
 
 
 

885 lines
30 KiB

  1. (function(factory) {
  2. typeof define === "function" && define.amd ? define(factory) : factory();
  3. })((function() {
  4. "use strict";
  5. var sparkMd5 = {
  6. exports: {}
  7. };
  8. (function(module, exports) {
  9. (function(factory) {
  10. {
  11. module.exports = factory();
  12. }
  13. })((function(undefined$1) {
  14. var hex_chr = [ "0", "1", "2", "3", "4", "5", "6", "7", "8", "9", "a", "b", "c", "d", "e", "f" ];
  15. function md5cycle(x, k) {
  16. var a = x[0], b = x[1], c = x[2], d = x[3];
  17. a += (b & c | ~b & d) + k[0] - 680876936 | 0;
  18. a = (a << 7 | a >>> 25) + b | 0;
  19. d += (a & b | ~a & c) + k[1] - 389564586 | 0;
  20. d = (d << 12 | d >>> 20) + a | 0;
  21. c += (d & a | ~d & b) + k[2] + 606105819 | 0;
  22. c = (c << 17 | c >>> 15) + d | 0;
  23. b += (c & d | ~c & a) + k[3] - 1044525330 | 0;
  24. b = (b << 22 | b >>> 10) + c | 0;
  25. a += (b & c | ~b & d) + k[4] - 176418897 | 0;
  26. a = (a << 7 | a >>> 25) + b | 0;
  27. d += (a & b | ~a & c) + k[5] + 1200080426 | 0;
  28. d = (d << 12 | d >>> 20) + a | 0;
  29. c += (d & a | ~d & b) + k[6] - 1473231341 | 0;
  30. c = (c << 17 | c >>> 15) + d | 0;
  31. b += (c & d | ~c & a) + k[7] - 45705983 | 0;
  32. b = (b << 22 | b >>> 10) + c | 0;
  33. a += (b & c | ~b & d) + k[8] + 1770035416 | 0;
  34. a = (a << 7 | a >>> 25) + b | 0;
  35. d += (a & b | ~a & c) + k[9] - 1958414417 | 0;
  36. d = (d << 12 | d >>> 20) + a | 0;
  37. c += (d & a | ~d & b) + k[10] - 42063 | 0;
  38. c = (c << 17 | c >>> 15) + d | 0;
  39. b += (c & d | ~c & a) + k[11] - 1990404162 | 0;
  40. b = (b << 22 | b >>> 10) + c | 0;
  41. a += (b & c | ~b & d) + k[12] + 1804603682 | 0;
  42. a = (a << 7 | a >>> 25) + b | 0;
  43. d += (a & b | ~a & c) + k[13] - 40341101 | 0;
  44. d = (d << 12 | d >>> 20) + a | 0;
  45. c += (d & a | ~d & b) + k[14] - 1502002290 | 0;
  46. c = (c << 17 | c >>> 15) + d | 0;
  47. b += (c & d | ~c & a) + k[15] + 1236535329 | 0;
  48. b = (b << 22 | b >>> 10) + c | 0;
  49. a += (b & d | c & ~d) + k[1] - 165796510 | 0;
  50. a = (a << 5 | a >>> 27) + b | 0;
  51. d += (a & c | b & ~c) + k[6] - 1069501632 | 0;
  52. d = (d << 9 | d >>> 23) + a | 0;
  53. c += (d & b | a & ~b) + k[11] + 643717713 | 0;
  54. c = (c << 14 | c >>> 18) + d | 0;
  55. b += (c & a | d & ~a) + k[0] - 373897302 | 0;
  56. b = (b << 20 | b >>> 12) + c | 0;
  57. a += (b & d | c & ~d) + k[5] - 701558691 | 0;
  58. a = (a << 5 | a >>> 27) + b | 0;
  59. d += (a & c | b & ~c) + k[10] + 38016083 | 0;
  60. d = (d << 9 | d >>> 23) + a | 0;
  61. c += (d & b | a & ~b) + k[15] - 660478335 | 0;
  62. c = (c << 14 | c >>> 18) + d | 0;
  63. b += (c & a | d & ~a) + k[4] - 405537848 | 0;
  64. b = (b << 20 | b >>> 12) + c | 0;
  65. a += (b & d | c & ~d) + k[9] + 568446438 | 0;
  66. a = (a << 5 | a >>> 27) + b | 0;
  67. d += (a & c | b & ~c) + k[14] - 1019803690 | 0;
  68. d = (d << 9 | d >>> 23) + a | 0;
  69. c += (d & b | a & ~b) + k[3] - 187363961 | 0;
  70. c = (c << 14 | c >>> 18) + d | 0;
  71. b += (c & a | d & ~a) + k[8] + 1163531501 | 0;
  72. b = (b << 20 | b >>> 12) + c | 0;
  73. a += (b & d | c & ~d) + k[13] - 1444681467 | 0;
  74. a = (a << 5 | a >>> 27) + b | 0;
  75. d += (a & c | b & ~c) + k[2] - 51403784 | 0;
  76. d = (d << 9 | d >>> 23) + a | 0;
  77. c += (d & b | a & ~b) + k[7] + 1735328473 | 0;
  78. c = (c << 14 | c >>> 18) + d | 0;
  79. b += (c & a | d & ~a) + k[12] - 1926607734 | 0;
  80. b = (b << 20 | b >>> 12) + c | 0;
  81. a += (b ^ c ^ d) + k[5] - 378558 | 0;
  82. a = (a << 4 | a >>> 28) + b | 0;
  83. d += (a ^ b ^ c) + k[8] - 2022574463 | 0;
  84. d = (d << 11 | d >>> 21) + a | 0;
  85. c += (d ^ a ^ b) + k[11] + 1839030562 | 0;
  86. c = (c << 16 | c >>> 16) + d | 0;
  87. b += (c ^ d ^ a) + k[14] - 35309556 | 0;
  88. b = (b << 23 | b >>> 9) + c | 0;
  89. a += (b ^ c ^ d) + k[1] - 1530992060 | 0;
  90. a = (a << 4 | a >>> 28) + b | 0;
  91. d += (a ^ b ^ c) + k[4] + 1272893353 | 0;
  92. d = (d << 11 | d >>> 21) + a | 0;
  93. c += (d ^ a ^ b) + k[7] - 155497632 | 0;
  94. c = (c << 16 | c >>> 16) + d | 0;
  95. b += (c ^ d ^ a) + k[10] - 1094730640 | 0;
  96. b = (b << 23 | b >>> 9) + c | 0;
  97. a += (b ^ c ^ d) + k[13] + 681279174 | 0;
  98. a = (a << 4 | a >>> 28) + b | 0;
  99. d += (a ^ b ^ c) + k[0] - 358537222 | 0;
  100. d = (d << 11 | d >>> 21) + a | 0;
  101. c += (d ^ a ^ b) + k[3] - 722521979 | 0;
  102. c = (c << 16 | c >>> 16) + d | 0;
  103. b += (c ^ d ^ a) + k[6] + 76029189 | 0;
  104. b = (b << 23 | b >>> 9) + c | 0;
  105. a += (b ^ c ^ d) + k[9] - 640364487 | 0;
  106. a = (a << 4 | a >>> 28) + b | 0;
  107. d += (a ^ b ^ c) + k[12] - 421815835 | 0;
  108. d = (d << 11 | d >>> 21) + a | 0;
  109. c += (d ^ a ^ b) + k[15] + 530742520 | 0;
  110. c = (c << 16 | c >>> 16) + d | 0;
  111. b += (c ^ d ^ a) + k[2] - 995338651 | 0;
  112. b = (b << 23 | b >>> 9) + c | 0;
  113. a += (c ^ (b | ~d)) + k[0] - 198630844 | 0;
  114. a = (a << 6 | a >>> 26) + b | 0;
  115. d += (b ^ (a | ~c)) + k[7] + 1126891415 | 0;
  116. d = (d << 10 | d >>> 22) + a | 0;
  117. c += (a ^ (d | ~b)) + k[14] - 1416354905 | 0;
  118. c = (c << 15 | c >>> 17) + d | 0;
  119. b += (d ^ (c | ~a)) + k[5] - 57434055 | 0;
  120. b = (b << 21 | b >>> 11) + c | 0;
  121. a += (c ^ (b | ~d)) + k[12] + 1700485571 | 0;
  122. a = (a << 6 | a >>> 26) + b | 0;
  123. d += (b ^ (a | ~c)) + k[3] - 1894986606 | 0;
  124. d = (d << 10 | d >>> 22) + a | 0;
  125. c += (a ^ (d | ~b)) + k[10] - 1051523 | 0;
  126. c = (c << 15 | c >>> 17) + d | 0;
  127. b += (d ^ (c | ~a)) + k[1] - 2054922799 | 0;
  128. b = (b << 21 | b >>> 11) + c | 0;
  129. a += (c ^ (b | ~d)) + k[8] + 1873313359 | 0;
  130. a = (a << 6 | a >>> 26) + b | 0;
  131. d += (b ^ (a | ~c)) + k[15] - 30611744 | 0;
  132. d = (d << 10 | d >>> 22) + a | 0;
  133. c += (a ^ (d | ~b)) + k[6] - 1560198380 | 0;
  134. c = (c << 15 | c >>> 17) + d | 0;
  135. b += (d ^ (c | ~a)) + k[13] + 1309151649 | 0;
  136. b = (b << 21 | b >>> 11) + c | 0;
  137. a += (c ^ (b | ~d)) + k[4] - 145523070 | 0;
  138. a = (a << 6 | a >>> 26) + b | 0;
  139. d += (b ^ (a | ~c)) + k[11] - 1120210379 | 0;
  140. d = (d << 10 | d >>> 22) + a | 0;
  141. c += (a ^ (d | ~b)) + k[2] + 718787259 | 0;
  142. c = (c << 15 | c >>> 17) + d | 0;
  143. b += (d ^ (c | ~a)) + k[9] - 343485551 | 0;
  144. b = (b << 21 | b >>> 11) + c | 0;
  145. x[0] = a + x[0] | 0;
  146. x[1] = b + x[1] | 0;
  147. x[2] = c + x[2] | 0;
  148. x[3] = d + x[3] | 0;
  149. }
  150. function md5blk(s) {
  151. var md5blks = [], i;
  152. for (i = 0; i < 64; i += 4) {
  153. md5blks[i >> 2] = s.charCodeAt(i) + (s.charCodeAt(i + 1) << 8) + (s.charCodeAt(i + 2) << 16) + (s.charCodeAt(i + 3) << 24);
  154. }
  155. return md5blks;
  156. }
  157. function md5blk_array(a) {
  158. var md5blks = [], i;
  159. for (i = 0; i < 64; i += 4) {
  160. md5blks[i >> 2] = a[i] + (a[i + 1] << 8) + (a[i + 2] << 16) + (a[i + 3] << 24);
  161. }
  162. return md5blks;
  163. }
  164. function md51(s) {
  165. var n = s.length, state = [ 1732584193, -271733879, -1732584194, 271733878 ], i, length, tail, tmp, lo, hi;
  166. for (i = 64; i <= n; i += 64) {
  167. md5cycle(state, md5blk(s.substring(i - 64, i)));
  168. }
  169. s = s.substring(i - 64);
  170. length = s.length;
  171. tail = [ 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0 ];
  172. for (i = 0; i < length; i += 1) {
  173. tail[i >> 2] |= s.charCodeAt(i) << (i % 4 << 3);
  174. }
  175. tail[i >> 2] |= 128 << (i % 4 << 3);
  176. if (i > 55) {
  177. md5cycle(state, tail);
  178. for (i = 0; i < 16; i += 1) {
  179. tail[i] = 0;
  180. }
  181. }
  182. tmp = n * 8;
  183. tmp = tmp.toString(16).match(/(.*?)(.{0,8})$/);
  184. lo = parseInt(tmp[2], 16);
  185. hi = parseInt(tmp[1], 16) || 0;
  186. tail[14] = lo;
  187. tail[15] = hi;
  188. md5cycle(state, tail);
  189. return state;
  190. }
  191. function md51_array(a) {
  192. var n = a.length, state = [ 1732584193, -271733879, -1732584194, 271733878 ], i, length, tail, tmp, lo, hi;
  193. for (i = 64; i <= n; i += 64) {
  194. md5cycle(state, md5blk_array(a.subarray(i - 64, i)));
  195. }
  196. a = i - 64 < n ? a.subarray(i - 64) : new Uint8Array(0);
  197. length = a.length;
  198. tail = [ 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0 ];
  199. for (i = 0; i < length; i += 1) {
  200. tail[i >> 2] |= a[i] << (i % 4 << 3);
  201. }
  202. tail[i >> 2] |= 128 << (i % 4 << 3);
  203. if (i > 55) {
  204. md5cycle(state, tail);
  205. for (i = 0; i < 16; i += 1) {
  206. tail[i] = 0;
  207. }
  208. }
  209. tmp = n * 8;
  210. tmp = tmp.toString(16).match(/(.*?)(.{0,8})$/);
  211. lo = parseInt(tmp[2], 16);
  212. hi = parseInt(tmp[1], 16) || 0;
  213. tail[14] = lo;
  214. tail[15] = hi;
  215. md5cycle(state, tail);
  216. return state;
  217. }
  218. function rhex(n) {
  219. var s = "", j;
  220. for (j = 0; j < 4; j += 1) {
  221. s += hex_chr[n >> j * 8 + 4 & 15] + hex_chr[n >> j * 8 & 15];
  222. }
  223. return s;
  224. }
  225. function hex(x) {
  226. var i;
  227. for (i = 0; i < x.length; i += 1) {
  228. x[i] = rhex(x[i]);
  229. }
  230. return x.join("");
  231. }
  232. if (hex(md51("hello")) !== "5d41402abc4b2a76b9719d911017c592") ;
  233. if (typeof ArrayBuffer !== "undefined" && !ArrayBuffer.prototype.slice) {
  234. (function() {
  235. function clamp(val, length) {
  236. val = val | 0 || 0;
  237. if (val < 0) {
  238. return Math.max(val + length, 0);
  239. }
  240. return Math.min(val, length);
  241. }
  242. ArrayBuffer.prototype.slice = function(from, to) {
  243. var length = this.byteLength, begin = clamp(from, length), end = length, num, target, targetArray, sourceArray;
  244. if (to !== undefined$1) {
  245. end = clamp(to, length);
  246. }
  247. if (begin > end) {
  248. return new ArrayBuffer(0);
  249. }
  250. num = end - begin;
  251. target = new ArrayBuffer(num);
  252. targetArray = new Uint8Array(target);
  253. sourceArray = new Uint8Array(this, begin, num);
  254. targetArray.set(sourceArray);
  255. return target;
  256. };
  257. })();
  258. }
  259. function toUtf8(str) {
  260. if (/[\u0080-\uFFFF]/.test(str)) {
  261. str = unescape(encodeURIComponent(str));
  262. }
  263. return str;
  264. }
  265. function utf8Str2ArrayBuffer(str, returnUInt8Array) {
  266. var length = str.length, buff = new ArrayBuffer(length), arr = new Uint8Array(buff), i;
  267. for (i = 0; i < length; i += 1) {
  268. arr[i] = str.charCodeAt(i);
  269. }
  270. return returnUInt8Array ? arr : buff;
  271. }
  272. function arrayBuffer2Utf8Str(buff) {
  273. return String.fromCharCode.apply(null, new Uint8Array(buff));
  274. }
  275. function concatenateArrayBuffers(first, second, returnUInt8Array) {
  276. var result = new Uint8Array(first.byteLength + second.byteLength);
  277. result.set(new Uint8Array(first));
  278. result.set(new Uint8Array(second), first.byteLength);
  279. return returnUInt8Array ? result : result.buffer;
  280. }
  281. function hexToBinaryString(hex) {
  282. var bytes = [], length = hex.length, x;
  283. for (x = 0; x < length - 1; x += 2) {
  284. bytes.push(parseInt(hex.substr(x, 2), 16));
  285. }
  286. return String.fromCharCode.apply(String, bytes);
  287. }
  288. function SparkMD5() {
  289. this.reset();
  290. }
  291. SparkMD5.prototype.append = function(str) {
  292. this.appendBinary(toUtf8(str));
  293. return this;
  294. };
  295. SparkMD5.prototype.appendBinary = function(contents) {
  296. this._buff += contents;
  297. this._length += contents.length;
  298. var length = this._buff.length, i;
  299. for (i = 64; i <= length; i += 64) {
  300. md5cycle(this._hash, md5blk(this._buff.substring(i - 64, i)));
  301. }
  302. this._buff = this._buff.substring(i - 64);
  303. return this;
  304. };
  305. SparkMD5.prototype.end = function(raw) {
  306. var buff = this._buff, length = buff.length, i, tail = [ 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0 ], ret;
  307. for (i = 0; i < length; i += 1) {
  308. tail[i >> 2] |= buff.charCodeAt(i) << (i % 4 << 3);
  309. }
  310. this._finish(tail, length);
  311. ret = hex(this._hash);
  312. if (raw) {
  313. ret = hexToBinaryString(ret);
  314. }
  315. this.reset();
  316. return ret;
  317. };
  318. SparkMD5.prototype.reset = function() {
  319. this._buff = "";
  320. this._length = 0;
  321. this._hash = [ 1732584193, -271733879, -1732584194, 271733878 ];
  322. return this;
  323. };
  324. SparkMD5.prototype.getState = function() {
  325. return {
  326. buff: this._buff,
  327. length: this._length,
  328. hash: this._hash.slice()
  329. };
  330. };
  331. SparkMD5.prototype.setState = function(state) {
  332. this._buff = state.buff;
  333. this._length = state.length;
  334. this._hash = state.hash;
  335. return this;
  336. };
  337. SparkMD5.prototype.destroy = function() {
  338. delete this._hash;
  339. delete this._buff;
  340. delete this._length;
  341. };
  342. SparkMD5.prototype._finish = function(tail, length) {
  343. var i = length, tmp, lo, hi;
  344. tail[i >> 2] |= 128 << (i % 4 << 3);
  345. if (i > 55) {
  346. md5cycle(this._hash, tail);
  347. for (i = 0; i < 16; i += 1) {
  348. tail[i] = 0;
  349. }
  350. }
  351. tmp = this._length * 8;
  352. tmp = tmp.toString(16).match(/(.*?)(.{0,8})$/);
  353. lo = parseInt(tmp[2], 16);
  354. hi = parseInt(tmp[1], 16) || 0;
  355. tail[14] = lo;
  356. tail[15] = hi;
  357. md5cycle(this._hash, tail);
  358. };
  359. SparkMD5.hash = function(str, raw) {
  360. return SparkMD5.hashBinary(toUtf8(str), raw);
  361. };
  362. SparkMD5.hashBinary = function(content, raw) {
  363. var hash = md51(content), ret = hex(hash);
  364. return raw ? hexToBinaryString(ret) : ret;
  365. };
  366. SparkMD5.ArrayBuffer = function() {
  367. this.reset();
  368. };
  369. SparkMD5.ArrayBuffer.prototype.append = function(arr) {
  370. var buff = concatenateArrayBuffers(this._buff.buffer, arr, true), length = buff.length, i;
  371. this._length += arr.byteLength;
  372. for (i = 64; i <= length; i += 64) {
  373. md5cycle(this._hash, md5blk_array(buff.subarray(i - 64, i)));
  374. }
  375. this._buff = i - 64 < length ? new Uint8Array(buff.buffer.slice(i - 64)) : new Uint8Array(0);
  376. return this;
  377. };
  378. SparkMD5.ArrayBuffer.prototype.end = function(raw) {
  379. var buff = this._buff, length = buff.length, tail = [ 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0 ], i, ret;
  380. for (i = 0; i < length; i += 1) {
  381. tail[i >> 2] |= buff[i] << (i % 4 << 3);
  382. }
  383. this._finish(tail, length);
  384. ret = hex(this._hash);
  385. if (raw) {
  386. ret = hexToBinaryString(ret);
  387. }
  388. this.reset();
  389. return ret;
  390. };
  391. SparkMD5.ArrayBuffer.prototype.reset = function() {
  392. this._buff = new Uint8Array(0);
  393. this._length = 0;
  394. this._hash = [ 1732584193, -271733879, -1732584194, 271733878 ];
  395. return this;
  396. };
  397. SparkMD5.ArrayBuffer.prototype.getState = function() {
  398. var state = SparkMD5.prototype.getState.call(this);
  399. state.buff = arrayBuffer2Utf8Str(state.buff);
  400. return state;
  401. };
  402. SparkMD5.ArrayBuffer.prototype.setState = function(state) {
  403. state.buff = utf8Str2ArrayBuffer(state.buff, true);
  404. return SparkMD5.prototype.setState.call(this, state);
  405. };
  406. SparkMD5.ArrayBuffer.prototype.destroy = SparkMD5.prototype.destroy;
  407. SparkMD5.ArrayBuffer.prototype._finish = SparkMD5.prototype._finish;
  408. SparkMD5.ArrayBuffer.hash = function(arr, raw) {
  409. var hash = md51_array(new Uint8Array(arr)), ret = hex(hash);
  410. return raw ? hexToBinaryString(ret) : ret;
  411. };
  412. return SparkMD5;
  413. }));
  414. })(sparkMd5);
  415. var SparkMD5 = sparkMd5.exports;
  416. const fileSlice = File.prototype.slice || File.prototype.mozSlice || File.prototype.webkitSlice;
  417. class FileChecksum {
  418. static create(file, callback) {
  419. const instance = new FileChecksum(file);
  420. instance.create(callback);
  421. }
  422. constructor(file) {
  423. this.file = file;
  424. this.chunkSize = 2097152;
  425. this.chunkCount = Math.ceil(this.file.size / this.chunkSize);
  426. this.chunkIndex = 0;
  427. }
  428. create(callback) {
  429. this.callback = callback;
  430. this.md5Buffer = new SparkMD5.ArrayBuffer;
  431. this.fileReader = new FileReader;
  432. this.fileReader.addEventListener("load", (event => this.fileReaderDidLoad(event)));
  433. this.fileReader.addEventListener("error", (event => this.fileReaderDidError(event)));
  434. this.readNextChunk();
  435. }
  436. fileReaderDidLoad(event) {
  437. this.md5Buffer.append(event.target.result);
  438. if (!this.readNextChunk()) {
  439. const binaryDigest = this.md5Buffer.end(true);
  440. const base64digest = btoa(binaryDigest);
  441. this.callback(null, base64digest);
  442. }
  443. }
  444. fileReaderDidError(event) {
  445. this.callback(`Error reading ${this.file.name}`);
  446. }
  447. readNextChunk() {
  448. if (this.chunkIndex < this.chunkCount || this.chunkIndex == 0 && this.chunkCount == 0) {
  449. const start = this.chunkIndex * this.chunkSize;
  450. const end = Math.min(start + this.chunkSize, this.file.size);
  451. const bytes = fileSlice.call(this.file, start, end);
  452. this.fileReader.readAsArrayBuffer(bytes);
  453. this.chunkIndex++;
  454. return true;
  455. } else {
  456. return false;
  457. }
  458. }
  459. }
  460. function getMetaValue(name) {
  461. const element = findElement(document.head, `meta[name="${name}"]`);
  462. if (element) {
  463. return element.getAttribute("content");
  464. }
  465. }
  466. function findElements(root, selector) {
  467. if (typeof root == "string") {
  468. selector = root;
  469. root = document;
  470. }
  471. const elements = root.querySelectorAll(selector);
  472. return toArray(elements);
  473. }
  474. function findElement(root, selector) {
  475. if (typeof root == "string") {
  476. selector = root;
  477. root = document;
  478. }
  479. return root.querySelector(selector);
  480. }
  481. function dispatchEvent(element, type, eventInit = {}) {
  482. const {disabled: disabled} = element;
  483. const {bubbles: bubbles, cancelable: cancelable, detail: detail} = eventInit;
  484. const event = document.createEvent("Event");
  485. event.initEvent(type, bubbles || true, cancelable || true);
  486. event.detail = detail || {};
  487. try {
  488. element.disabled = false;
  489. element.dispatchEvent(event);
  490. } finally {
  491. element.disabled = disabled;
  492. }
  493. return event;
  494. }
  495. function toArray(value) {
  496. if (Array.isArray(value)) {
  497. return value;
  498. } else if (Array.from) {
  499. return Array.from(value);
  500. } else {
  501. return [].slice.call(value);
  502. }
  503. }
  504. class BlobRecord {
  505. constructor(file, checksum, url, customHeaders = {}) {
  506. this.file = file;
  507. this.attributes = {
  508. filename: file.name,
  509. content_type: file.type || "application/octet-stream",
  510. byte_size: file.size,
  511. checksum: checksum
  512. };
  513. this.xhr = new XMLHttpRequest;
  514. this.xhr.open("POST", url, true);
  515. this.xhr.responseType = "json";
  516. this.xhr.setRequestHeader("Content-Type", "application/json");
  517. this.xhr.setRequestHeader("Accept", "application/json");
  518. this.xhr.setRequestHeader("X-Requested-With", "XMLHttpRequest");
  519. Object.keys(customHeaders).forEach((headerKey => {
  520. this.xhr.setRequestHeader(headerKey, customHeaders[headerKey]);
  521. }));
  522. const csrfToken = getMetaValue("csrf-token");
  523. if (csrfToken != undefined) {
  524. this.xhr.setRequestHeader("X-CSRF-Token", csrfToken);
  525. }
  526. this.xhr.addEventListener("load", (event => this.requestDidLoad(event)));
  527. this.xhr.addEventListener("error", (event => this.requestDidError(event)));
  528. }
  529. get status() {
  530. return this.xhr.status;
  531. }
  532. get response() {
  533. const {responseType: responseType, response: response} = this.xhr;
  534. if (responseType == "json") {
  535. return response;
  536. } else {
  537. return JSON.parse(response);
  538. }
  539. }
  540. create(callback) {
  541. this.callback = callback;
  542. this.xhr.send(JSON.stringify({
  543. blob: this.attributes
  544. }));
  545. }
  546. requestDidLoad(event) {
  547. if (this.status >= 200 && this.status < 300) {
  548. const {response: response} = this;
  549. const {direct_upload: direct_upload} = response;
  550. delete response.direct_upload;
  551. this.attributes = response;
  552. this.directUploadData = direct_upload;
  553. this.callback(null, this.toJSON());
  554. } else {
  555. this.requestDidError(event);
  556. }
  557. }
  558. requestDidError(event) {
  559. this.callback(`Error creating Blob for "${this.file.name}". Status: ${this.status}`);
  560. }
  561. toJSON() {
  562. const result = {};
  563. for (const key in this.attributes) {
  564. result[key] = this.attributes[key];
  565. }
  566. return result;
  567. }
  568. }
  569. class BlobUpload {
  570. constructor(blob) {
  571. this.blob = blob;
  572. this.file = blob.file;
  573. const {url: url, headers: headers} = blob.directUploadData;
  574. this.xhr = new XMLHttpRequest;
  575. this.xhr.open("PUT", url, true);
  576. this.xhr.responseType = "text";
  577. for (const key in headers) {
  578. this.xhr.setRequestHeader(key, headers[key]);
  579. }
  580. this.xhr.addEventListener("load", (event => this.requestDidLoad(event)));
  581. this.xhr.addEventListener("error", (event => this.requestDidError(event)));
  582. }
  583. create(callback) {
  584. this.callback = callback;
  585. this.xhr.send(this.file.slice());
  586. }
  587. requestDidLoad(event) {
  588. const {status: status, response: response} = this.xhr;
  589. if (status >= 200 && status < 300) {
  590. this.callback(null, response);
  591. } else {
  592. this.requestDidError(event);
  593. }
  594. }
  595. requestDidError(event) {
  596. this.callback(`Error storing "${this.file.name}". Status: ${this.xhr.status}`);
  597. }
  598. }
  599. let id = 0;
  600. class DirectUpload {
  601. constructor(file, url, delegate, customHeaders = {}) {
  602. this.id = ++id;
  603. this.file = file;
  604. this.url = url;
  605. this.delegate = delegate;
  606. this.customHeaders = customHeaders;
  607. }
  608. create(callback) {
  609. FileChecksum.create(this.file, ((error, checksum) => {
  610. if (error) {
  611. callback(error);
  612. return;
  613. }
  614. const blob = new BlobRecord(this.file, checksum, this.url, this.customHeaders);
  615. notify(this.delegate, "directUploadWillCreateBlobWithXHR", blob.xhr);
  616. blob.create((error => {
  617. if (error) {
  618. callback(error);
  619. } else {
  620. const upload = new BlobUpload(blob);
  621. notify(this.delegate, "directUploadWillStoreFileWithXHR", upload.xhr);
  622. upload.create((error => {
  623. if (error) {
  624. callback(error);
  625. } else {
  626. callback(null, blob.toJSON());
  627. }
  628. }));
  629. }
  630. }));
  631. }));
  632. }
  633. }
  634. function notify(object, methodName, ...messages) {
  635. if (object && typeof object[methodName] == "function") {
  636. return object[methodName](...messages);
  637. }
  638. }
  639. class DirectUploadController {
  640. constructor(input, file) {
  641. this.input = input;
  642. this.file = file;
  643. this.directUpload = new DirectUpload(this.file, this.url, this);
  644. this.dispatch("initialize");
  645. }
  646. start(callback) {
  647. const hiddenInput = document.createElement("input");
  648. hiddenInput.type = "hidden";
  649. hiddenInput.name = this.input.name;
  650. this.input.insertAdjacentElement("beforebegin", hiddenInput);
  651. this.dispatch("start");
  652. this.directUpload.create(((error, attributes) => {
  653. if (error) {
  654. hiddenInput.parentNode.removeChild(hiddenInput);
  655. this.dispatchError(error);
  656. } else {
  657. hiddenInput.value = attributes.signed_id;
  658. }
  659. this.dispatch("end");
  660. callback(error);
  661. }));
  662. }
  663. uploadRequestDidProgress(event) {
  664. const progress = event.loaded / event.total * 100;
  665. if (progress) {
  666. this.dispatch("progress", {
  667. progress: progress
  668. });
  669. }
  670. }
  671. get url() {
  672. return this.input.getAttribute("data-direct-upload-url");
  673. }
  674. dispatch(name, detail = {}) {
  675. detail.file = this.file;
  676. detail.id = this.directUpload.id;
  677. return dispatchEvent(this.input, `direct-upload:${name}`, {
  678. detail: detail
  679. });
  680. }
  681. dispatchError(error) {
  682. const event = this.dispatch("error", {
  683. error: error
  684. });
  685. if (!event.defaultPrevented) {
  686. alert(error);
  687. }
  688. }
  689. directUploadWillCreateBlobWithXHR(xhr) {
  690. this.dispatch("before-blob-request", {
  691. xhr: xhr
  692. });
  693. }
  694. directUploadWillStoreFileWithXHR(xhr) {
  695. this.dispatch("before-storage-request", {
  696. xhr: xhr
  697. });
  698. xhr.upload.addEventListener("progress", (event => this.uploadRequestDidProgress(event)));
  699. }
  700. }
  701. const inputSelector = "input[type=file][data-direct-upload-url]:not([disabled])";
  702. class DirectUploadsController {
  703. constructor(form) {
  704. this.form = form;
  705. this.inputs = findElements(form, inputSelector).filter((input => input.files.length));
  706. }
  707. start(callback) {
  708. const controllers = this.createDirectUploadControllers();
  709. const startNextController = () => {
  710. const controller = controllers.shift();
  711. if (controller) {
  712. controller.start((error => {
  713. if (error) {
  714. callback(error);
  715. this.dispatch("end");
  716. } else {
  717. startNextController();
  718. }
  719. }));
  720. } else {
  721. callback();
  722. this.dispatch("end");
  723. }
  724. };
  725. this.dispatch("start");
  726. startNextController();
  727. }
  728. createDirectUploadControllers() {
  729. const controllers = [];
  730. this.inputs.forEach((input => {
  731. toArray(input.files).forEach((file => {
  732. const controller = new DirectUploadController(input, file);
  733. controllers.push(controller);
  734. }));
  735. }));
  736. return controllers;
  737. }
  738. dispatch(name, detail = {}) {
  739. return dispatchEvent(this.form, `direct-uploads:${name}`, {
  740. detail: detail
  741. });
  742. }
  743. }
  744. const processingAttribute = "data-direct-uploads-processing";
  745. const submitButtonsByForm = new WeakMap;
  746. let started = false;
  747. function start() {
  748. if (!started) {
  749. started = true;
  750. document.addEventListener("click", didClick, true);
  751. document.addEventListener("submit", didSubmitForm, true);
  752. document.addEventListener("ajax:before", didSubmitRemoteElement);
  753. }
  754. }
  755. function didClick(event) {
  756. const button = event.target.closest("button, input");
  757. if (button && button.type === "submit" && button.form) {
  758. submitButtonsByForm.set(button.form, button);
  759. }
  760. }
  761. function didSubmitForm(event) {
  762. handleFormSubmissionEvent(event);
  763. }
  764. function didSubmitRemoteElement(event) {
  765. if (event.target.tagName == "FORM") {
  766. handleFormSubmissionEvent(event);
  767. }
  768. }
  769. function handleFormSubmissionEvent(event) {
  770. const form = event.target;
  771. if (form.hasAttribute(processingAttribute)) {
  772. event.preventDefault();
  773. return;
  774. }
  775. const controller = new DirectUploadsController(form);
  776. const {inputs: inputs} = controller;
  777. if (inputs.length) {
  778. event.preventDefault();
  779. form.setAttribute(processingAttribute, "");
  780. inputs.forEach(disable);
  781. controller.start((error => {
  782. form.removeAttribute(processingAttribute);
  783. if (error) {
  784. inputs.forEach(enable);
  785. } else {
  786. submitForm(form);
  787. }
  788. }));
  789. }
  790. }
  791. function submitForm(form) {
  792. let button = submitButtonsByForm.get(form) || findElement(form, "input[type=submit], button[type=submit]");
  793. if (button) {
  794. const {disabled: disabled} = button;
  795. button.disabled = false;
  796. button.focus();
  797. button.click();
  798. button.disabled = disabled;
  799. } else {
  800. button = document.createElement("input");
  801. button.type = "submit";
  802. button.style.display = "none";
  803. form.appendChild(button);
  804. button.click();
  805. form.removeChild(button);
  806. }
  807. submitButtonsByForm.delete(form);
  808. }
  809. function disable(input) {
  810. input.disabled = true;
  811. }
  812. function enable(input) {
  813. input.disabled = false;
  814. }
  815. function autostart() {
  816. if (window.ActiveStorage) {
  817. start();
  818. }
  819. }
  820. setTimeout(autostart, 1);
  821. class AttachmentUpload {
  822. constructor(attachment, element) {
  823. this.attachment = attachment;
  824. this.element = element;
  825. this.directUpload = new DirectUpload(attachment.file, this.directUploadUrl, this);
  826. }
  827. start() {
  828. this.directUpload.create(this.directUploadDidComplete.bind(this));
  829. this.dispatch("start");
  830. }
  831. directUploadWillStoreFileWithXHR(xhr) {
  832. xhr.upload.addEventListener("progress", (event => {
  833. const progress = event.loaded / event.total * 100;
  834. this.attachment.setUploadProgress(progress);
  835. if (progress) {
  836. this.dispatch("progress", {
  837. progress: progress
  838. });
  839. }
  840. }));
  841. }
  842. directUploadDidComplete(error, attributes) {
  843. if (error) {
  844. this.dispatchError(error);
  845. } else {
  846. this.attachment.setAttributes({
  847. sgid: attributes.attachable_sgid,
  848. url: this.createBlobUrl(attributes.signed_id, attributes.filename)
  849. });
  850. this.dispatch("end");
  851. }
  852. }
  853. createBlobUrl(signedId, filename) {
  854. return this.blobUrlTemplate.replace(":signed_id", signedId).replace(":filename", encodeURIComponent(filename));
  855. }
  856. dispatch(name, detail = {}) {
  857. detail.attachment = this.attachment;
  858. return dispatchEvent(this.element, `direct-upload:${name}`, {
  859. detail: detail
  860. });
  861. }
  862. dispatchError(error) {
  863. const event = this.dispatch("error", {
  864. error: error
  865. });
  866. if (!event.defaultPrevented) {
  867. alert(error);
  868. }
  869. }
  870. get directUploadUrl() {
  871. return this.element.dataset.directUploadUrl;
  872. }
  873. get blobUrlTemplate() {
  874. return this.element.dataset.blobUrlTemplate;
  875. }
  876. }
  877. addEventListener("trix-attachment-add", (event => {
  878. const {attachment: attachment, target: target} = event;
  879. if (attachment.file) {
  880. const upload = new AttachmentUpload(attachment, target);
  881. upload.start();
  882. }
  883. }));
  884. }));