tessa 2.0 → 6.0.0.rc2
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- checksums.yaml +4 -4
- data/README.md +11 -18
- data/app/assets/javascripts/tessa.esm.js +212 -173
- data/app/assets/javascripts/tessa.js +206 -167
- data/app/javascript/activestorage/file_checksum.ts +76 -0
- data/app/javascript/tessa/index.ts +264 -0
- data/app/javascript/tessa/types.ts +34 -0
- data/config/routes.rb +0 -1
- data/lib/tessa/simple_form/asset_input.rb +24 -25
- data/lib/tessa/version.rb +1 -1
- data/lib/tessa.rb +0 -80
- data/package.json +7 -2
- data/rollup.config.js +5 -5
- data/spec/dummy/app/models/single_asset_model.rb +1 -1
- data/spec/dummy/app/models/single_asset_model_form.rb +3 -5
- data/spec/dummy/bin/rails +2 -2
- data/spec/dummy/bin/rake +2 -2
- data/spec/dummy/bin/setup +14 -6
- data/spec/dummy/bin/yarn +9 -3
- data/spec/dummy/config/application.rb +11 -9
- data/spec/dummy/config/boot.rb +1 -1
- data/spec/dummy/config/environment.rb +1 -1
- data/spec/dummy/config/environments/development.rb +34 -5
- data/spec/dummy/config/environments/production.rb +49 -10
- data/spec/dummy/config/environments/test.rb +28 -12
- data/spec/dummy/config/initializers/backtrace_silencers.rb +4 -3
- data/spec/dummy/config/initializers/content_security_policy.rb +5 -0
- data/spec/dummy/config/initializers/filter_parameter_logging.rb +3 -1
- data/spec/dummy/config/initializers/new_framework_defaults_6_1.rb +67 -0
- data/spec/dummy/config/initializers/permissions_policy.rb +11 -0
- data/spec/dummy/config/initializers/wrap_parameters.rb +5 -0
- data/spec/dummy/config/locales/en.yml +1 -1
- data/spec/dummy/config/routes.rb +1 -1
- data/spec/dummy/config/storage.yml +31 -0
- data/spec/dummy/config.ru +2 -1
- data/spec/dummy/db/migrate/20230406194400_add_service_name_to_active_storage_blobs.active_storage.rb +22 -0
- data/spec/dummy/db/migrate/20230406194401_create_active_storage_variant_records.active_storage.rb +27 -0
- data/spec/dummy/db/schema.rb +15 -7
- data/tessa.gemspec +4 -5
- data/tsconfig.json +10 -0
- data/yarn.lock +74 -7
- metadata +36 -74
- data/app/javascript/activestorage/file_checksum.js +0 -53
- data/app/javascript/tessa/index.js.coffee +0 -183
- data/lib/tasks/tessa.rake +0 -18
- data/lib/tessa/active_storage/asset_wrapper.rb +0 -32
- data/lib/tessa/asset/failure.rb +0 -37
- data/lib/tessa/asset.rb +0 -47
- data/lib/tessa/asset_change.rb +0 -49
- data/lib/tessa/asset_change_set.rb +0 -49
- data/lib/tessa/config.rb +0 -16
- data/lib/tessa/controller_helpers.rb +0 -16
- data/lib/tessa/fake_connection.rb +0 -29
- data/lib/tessa/jobs/migrate_assets_job.rb +0 -222
- data/lib/tessa/model/dynamic_extensions.rb +0 -145
- data/lib/tessa/model/field.rb +0 -77
- data/lib/tessa/model.rb +0 -94
- data/lib/tessa/rack_upload_proxy.rb +0 -41
- data/lib/tessa/response_factory.rb +0 -15
- data/lib/tessa/upload/uploads_file.rb +0 -18
- data/lib/tessa/upload.rb +0 -31
- data/lib/tessa/view_helpers.rb +0 -23
- data/spec/dummy/app/models/multiple_asset_model.rb +0 -8
- data/spec/support/remote_call_macro.rb +0 -40
- data/spec/tessa/asset/failure_spec.rb +0 -48
- data/spec/tessa/asset_change_set_spec.rb +0 -198
- data/spec/tessa/asset_change_spec.rb +0 -86
- data/spec/tessa/asset_spec.rb +0 -196
- data/spec/tessa/config_spec.rb +0 -70
- data/spec/tessa/controller_helpers_spec.rb +0 -55
- data/spec/tessa/jobs/migrate_assets_job_spec.rb +0 -247
- data/spec/tessa/model_field_spec.rb +0 -72
- data/spec/tessa/model_spec.rb +0 -325
- data/spec/tessa/rack_upload_proxy_spec.rb +0 -83
- data/spec/tessa/upload/uploads_file_spec.rb +0 -72
- data/spec/tessa/upload_spec.rb +0 -125
- data/spec/tessa_spec.rb +0 -23
@@ -2,6 +2,34 @@
|
|
2
2
|
typeof define === "function" && define.amd ? define(factory) : factory();
|
3
3
|
})((function() {
|
4
4
|
"use strict";
|
5
|
+
var extendStatics = function(d, b) {
|
6
|
+
extendStatics = Object.setPrototypeOf || {
|
7
|
+
__proto__: []
|
8
|
+
} instanceof Array && function(d, b) {
|
9
|
+
d.__proto__ = b;
|
10
|
+
} || function(d, b) {
|
11
|
+
for (var p in b) if (Object.prototype.hasOwnProperty.call(b, p)) d[p] = b[p];
|
12
|
+
};
|
13
|
+
return extendStatics(d, b);
|
14
|
+
};
|
15
|
+
function __extends(d, b) {
|
16
|
+
if (typeof b !== "function" && b !== null) throw new TypeError("Class extends value " + String(b) + " is not a constructor or null");
|
17
|
+
extendStatics(d, b);
|
18
|
+
function __() {
|
19
|
+
this.constructor = d;
|
20
|
+
}
|
21
|
+
d.prototype = b === null ? Object.create(b) : (__.prototype = b.prototype, new __);
|
22
|
+
}
|
23
|
+
var __assign = function() {
|
24
|
+
__assign = Object.assign || function __assign(t) {
|
25
|
+
for (var s, i = 1, n = arguments.length; i < n; i++) {
|
26
|
+
s = arguments[i];
|
27
|
+
for (var p in s) if (Object.prototype.hasOwnProperty.call(s, p)) t[p] = s[p];
|
28
|
+
}
|
29
|
+
return t;
|
30
|
+
};
|
31
|
+
return __assign.apply(this, arguments);
|
32
|
+
};
|
5
33
|
var sparkMd5 = {
|
6
34
|
exports: {}
|
7
35
|
};
|
@@ -412,249 +440,260 @@
|
|
412
440
|
return SparkMD5;
|
413
441
|
}));
|
414
442
|
})(sparkMd5);
|
415
|
-
var
|
416
|
-
|
417
|
-
|
418
|
-
static create(file, callback) {
|
419
|
-
const instance = new FileChecksum(file);
|
420
|
-
instance.create(callback);
|
421
|
-
}
|
422
|
-
constructor(file) {
|
443
|
+
var fileSlice = File.prototype.slice || File.prototype.mozSlice || File.prototype.webkitSlice;
|
444
|
+
var FileChecksum = function() {
|
445
|
+
function FileChecksum(file) {
|
423
446
|
this.file = file;
|
424
447
|
this.chunkSize = 2097152;
|
425
448
|
this.chunkCount = Math.ceil(this.file.size / this.chunkSize);
|
426
449
|
this.chunkIndex = 0;
|
427
450
|
}
|
428
|
-
create(callback) {
|
451
|
+
FileChecksum.create = function(file, callback) {
|
452
|
+
var instance = new FileChecksum(file);
|
453
|
+
instance.create(callback);
|
454
|
+
};
|
455
|
+
FileChecksum.prototype.create = function(callback) {
|
456
|
+
var _this = this;
|
429
457
|
this.callback = callback;
|
430
|
-
this.md5Buffer = new
|
458
|
+
this.md5Buffer = new sparkMd5.exports.ArrayBuffer;
|
431
459
|
this.fileReader = new FileReader;
|
432
|
-
this.fileReader.addEventListener("load", (
|
433
|
-
|
460
|
+
this.fileReader.addEventListener("load", (function(event) {
|
461
|
+
return _this.fileReaderDidLoad(event);
|
462
|
+
}));
|
463
|
+
this.fileReader.addEventListener("error", (function(event) {
|
464
|
+
return _this.fileReaderDidError(event);
|
465
|
+
}));
|
434
466
|
this.readNextChunk();
|
435
|
-
}
|
436
|
-
fileReaderDidLoad(event) {
|
467
|
+
};
|
468
|
+
FileChecksum.prototype.fileReaderDidLoad = function(event) {
|
469
|
+
var _a;
|
470
|
+
if (!this.md5Buffer || !this.fileReader) {
|
471
|
+
throw new Error("FileChecksum: fileReaderDidLoad called before create");
|
472
|
+
}
|
473
|
+
if (!((_a = event.target) === null || _a === void 0 ? void 0 : _a.result)) {
|
474
|
+
return;
|
475
|
+
}
|
437
476
|
this.md5Buffer.append(event.target.result);
|
438
477
|
if (!this.readNextChunk()) {
|
439
|
-
|
440
|
-
|
441
|
-
this.callback
|
478
|
+
var binaryDigest = this.md5Buffer.end(true);
|
479
|
+
var base64digest = btoa(binaryDigest);
|
480
|
+
if (this.callback) {
|
481
|
+
this.callback(null, base64digest);
|
482
|
+
}
|
483
|
+
}
|
484
|
+
};
|
485
|
+
FileChecksum.prototype.fileReaderDidError = function(event) {
|
486
|
+
if (this.callback) {
|
487
|
+
this.callback("Error reading ".concat(this.file.name));
|
488
|
+
}
|
489
|
+
};
|
490
|
+
FileChecksum.prototype.readNextChunk = function() {
|
491
|
+
if (!this.fileReader) {
|
492
|
+
throw new Error("FileChecksum: readNextChunk called before create");
|
442
493
|
}
|
443
|
-
}
|
444
|
-
fileReaderDidError(event) {
|
445
|
-
this.callback(`Error reading ${this.file.name}`);
|
446
|
-
}
|
447
|
-
readNextChunk() {
|
448
494
|
if (this.chunkIndex < this.chunkCount || this.chunkIndex == 0 && this.chunkCount == 0) {
|
449
|
-
|
450
|
-
|
451
|
-
|
495
|
+
var start = this.chunkIndex * this.chunkSize;
|
496
|
+
var end = Math.min(start + this.chunkSize, this.file.size);
|
497
|
+
var bytes = fileSlice.call(this.file, start, end);
|
452
498
|
this.fileReader.readAsArrayBuffer(bytes);
|
453
499
|
this.chunkIndex++;
|
454
500
|
return true;
|
455
501
|
} else {
|
456
502
|
return false;
|
457
503
|
}
|
458
|
-
}
|
459
|
-
|
460
|
-
|
504
|
+
};
|
505
|
+
return FileChecksum;
|
506
|
+
}();
|
461
507
|
window.WCC || (window.WCC = {});
|
462
|
-
$ = window.jQuery;
|
463
|
-
Dropzone.autoDiscover = false;
|
464
|
-
|
465
|
-
|
466
|
-
|
467
|
-
|
508
|
+
var $ = window.jQuery;
|
509
|
+
window.Dropzone.autoDiscover = false;
|
510
|
+
var BaseDropzone = window.Dropzone;
|
511
|
+
var WCCDropzone = function(_super) {
|
512
|
+
__extends(WCCDropzone, _super);
|
513
|
+
function WCCDropzone() {
|
514
|
+
return _super !== null && _super.apply(this, arguments) || this;
|
515
|
+
}
|
516
|
+
WCCDropzone.prototype.uploadFile = function(file) {
|
517
|
+
var _this = this;
|
518
|
+
var _a;
|
519
|
+
var xhr = new XMLHttpRequest;
|
468
520
|
file.xhr = xhr;
|
469
521
|
xhr.open(file.uploadMethod, file.uploadURL, true);
|
470
|
-
response = null;
|
471
|
-
handleError = ()
|
472
|
-
|
473
|
-
|
474
|
-
|
522
|
+
var response = null;
|
523
|
+
var handleError = function() {
|
524
|
+
var _a;
|
525
|
+
_this._errorProcessing([ file ], response || ((_a = _this.options.dictResponseError) === null || _a === void 0 ? void 0 : _a.replace("{{statusCode}}", xhr.status.toString())), xhr);
|
526
|
+
};
|
527
|
+
var updateProgress = function(e) {
|
528
|
+
var _a;
|
529
|
+
var progress;
|
530
|
+
if (e) {
|
475
531
|
progress = 100 * e.loaded / e.total;
|
476
|
-
file.upload = {
|
532
|
+
file.upload = __assign(__assign({}, file.upload), {
|
477
533
|
progress: progress,
|
478
534
|
total: e.total,
|
479
535
|
bytesSent: e.loaded
|
480
|
-
};
|
536
|
+
});
|
481
537
|
} else {
|
482
|
-
allFilesFinished = true;
|
483
538
|
progress = 100;
|
484
|
-
|
485
|
-
|
539
|
+
var allFilesFinished = false;
|
540
|
+
if (file.upload.progress == 100 && file.upload.bytesSent == file.upload.total) {
|
541
|
+
allFilesFinished = true;
|
486
542
|
}
|
487
543
|
file.upload.progress = progress;
|
488
|
-
file.upload.bytesSent = file.upload.total;
|
544
|
+
file.upload.bytesSent = (_a = file.upload) === null || _a === void 0 ? void 0 : _a.total;
|
489
545
|
if (allFilesFinished) {
|
490
546
|
return;
|
491
547
|
}
|
492
548
|
}
|
493
|
-
|
549
|
+
_this.emit("uploadprogress", file, progress, file.upload.bytesSent);
|
494
550
|
};
|
495
|
-
xhr.onload = e
|
496
|
-
|
497
|
-
if (file.status === WCC.Dropzone.CANCELED) {
|
551
|
+
xhr.onload = function(e) {
|
552
|
+
if (file.status == WCCDropzone.CANCELED) {
|
498
553
|
return;
|
499
554
|
}
|
500
|
-
if (xhr.readyState
|
555
|
+
if (xhr.readyState != 4) {
|
501
556
|
return;
|
502
557
|
}
|
503
558
|
response = xhr.responseText;
|
504
|
-
if (xhr.getResponseHeader("content-type") &&
|
559
|
+
if (xhr.getResponseHeader("content-type") && xhr.getResponseHeader("content-type").indexOf("application/json") >= 0) {
|
505
560
|
try {
|
506
561
|
response = JSON.parse(response);
|
507
|
-
} catch (
|
508
|
-
e = error1;
|
562
|
+
} catch (e) {
|
509
563
|
response = "Invalid JSON response from server.";
|
510
564
|
}
|
511
565
|
}
|
512
566
|
updateProgress();
|
513
|
-
if (
|
514
|
-
|
515
|
-
} else {
|
516
|
-
return this._finished([ file ], response, e);
|
567
|
+
if (xhr.status < 200 || xhr.status >= 300) handleError(); else {
|
568
|
+
_this._finished([ file ], response, e);
|
517
569
|
}
|
518
570
|
};
|
519
|
-
xhr.onerror = ()
|
520
|
-
if (file.status
|
571
|
+
xhr.onerror = function() {
|
572
|
+
if (file.status == WCCDropzone.CANCELED) {
|
521
573
|
return;
|
522
574
|
}
|
523
|
-
|
575
|
+
handleError();
|
524
576
|
};
|
525
|
-
progressObj = (
|
577
|
+
var progressObj = (_a = xhr.upload) !== null && _a !== void 0 ? _a : xhr;
|
526
578
|
progressObj.onprogress = updateProgress;
|
527
|
-
headers = {
|
579
|
+
var headers = {
|
528
580
|
Accept: "application/json",
|
529
581
|
"Cache-Control": "no-cache",
|
530
582
|
"X-Requested-With": "XMLHttpRequest"
|
531
583
|
};
|
532
584
|
if (this.options.headers) {
|
533
|
-
|
585
|
+
Object.assign(headers, this.options.headers);
|
534
586
|
}
|
535
587
|
if (file.uploadHeaders) {
|
536
|
-
|
588
|
+
Object.assign(headers, file.uploadHeaders);
|
537
589
|
}
|
538
|
-
for (
|
539
|
-
|
590
|
+
for (var _i = 0, _b = Object.entries(headers); _i < _b.length; _i++) {
|
591
|
+
var _c = _b[_i], headerName = _c[0], headerValue = _c[1];
|
540
592
|
xhr.setRequestHeader(headerName, headerValue);
|
541
593
|
}
|
542
594
|
this.emit("sending", file, xhr);
|
543
|
-
|
544
|
-
}
|
545
|
-
uploadFiles(files) {
|
546
|
-
var
|
547
|
-
|
548
|
-
|
549
|
-
file = files[l];
|
550
|
-
results.push(this.uploadFile(file));
|
595
|
+
xhr.send(file);
|
596
|
+
};
|
597
|
+
WCCDropzone.prototype.uploadFiles = function(files) {
|
598
|
+
for (var _i = 0, files_1 = files; _i < files_1.length; _i++) {
|
599
|
+
var file = files_1[_i];
|
600
|
+
this.uploadFile(file);
|
551
601
|
}
|
552
|
-
return results;
|
553
|
-
}
|
554
|
-
};
|
555
|
-
WCC.Dropzone.uploadPendingWarning = "File uploads have not yet completed. If you submit the form now they will not be saved. Are you sure you want to continue?";
|
556
|
-
WCC.Dropzone.prototype.defaultOptions.url = "UNUSED";
|
557
|
-
WCC.Dropzone.prototype.defaultOptions.dictDefaultMessage = "Drop files or click to upload.";
|
558
|
-
WCC.Dropzone.prototype.defaultOptions.accept = function(file, done) {
|
559
|
-
var dz, postData, tessaParams;
|
560
|
-
dz = $(file._removeLink).closest(".tessa-upload").first();
|
561
|
-
tessaParams = dz.data("tessa-params") || {};
|
562
|
-
postData = {
|
563
|
-
name: file.name,
|
564
|
-
size: file.size,
|
565
|
-
mime_type: file.type
|
566
602
|
};
|
567
|
-
|
568
|
-
|
569
|
-
|
570
|
-
|
603
|
+
return WCCDropzone;
|
604
|
+
}(BaseDropzone);
|
605
|
+
var uploadPendingWarning = "File uploads have not yet completed. If you submit the form now they will not be saved. Are you sure you want to continue?";
|
606
|
+
function tessaInit() {
|
607
|
+
$(".tessa-upload").each((function(i, item) {
|
608
|
+
var $item = $(item);
|
609
|
+
var directUploadURL = $item.data("direct-upload-url") || "/rails/active_storage/direct_uploads";
|
610
|
+
var options = __assign({
|
611
|
+
maxFiles: 1,
|
612
|
+
addRemoveLinks: true,
|
613
|
+
url: "UNUSED",
|
614
|
+
dictDefaultMessage: "Drop files or click to upload.",
|
615
|
+
accept: createAcceptFn({
|
616
|
+
directUploadURL: directUploadURL
|
617
|
+
})
|
618
|
+
}, $item.data("dropzone-options"));
|
619
|
+
if ($item.hasClass("multiple")) {
|
620
|
+
options.maxFiles = undefined;
|
571
621
|
}
|
572
|
-
|
573
|
-
|
574
|
-
|
575
|
-
|
576
|
-
|
577
|
-
|
578
|
-
|
579
|
-
|
580
|
-
|
581
|
-
|
582
|
-
|
583
|
-
|
584
|
-
|
585
|
-
|
586
|
-
|
622
|
+
var dropzone = new WCCDropzone(item, options);
|
623
|
+
$item.find('input[type="hidden"]').each((function(i, input) {
|
624
|
+
var _a, _b;
|
625
|
+
var $input = $(input);
|
626
|
+
var mockFile = $input.data("meta");
|
627
|
+
if (!mockFile) {
|
628
|
+
return;
|
629
|
+
}
|
630
|
+
mockFile.accepted = true;
|
631
|
+
(_a = dropzone.options.addedfile) === null || _a === void 0 ? void 0 : _a.call(dropzone, mockFile);
|
632
|
+
(_b = dropzone.options.thumbnail) === null || _b === void 0 ? void 0 : _b.call(dropzone, mockFile, mockFile.url);
|
633
|
+
dropzone.emit("complete", mockFile);
|
634
|
+
dropzone.files.push(mockFile);
|
635
|
+
}));
|
636
|
+
var inputName = $item.data("input-name") || $item.find('input[type="hidden"]').attr("name");
|
637
|
+
dropzone.on("success", (function(file) {
|
638
|
+
$('input[name="'.concat(inputName, '"]')).val(file.signedID);
|
639
|
+
}));
|
640
|
+
dropzone.on("removedfile", (function(file) {
|
641
|
+
$item.find('input[name="'.concat(inputName, '"]')).val("");
|
642
|
+
}));
|
587
643
|
}));
|
588
|
-
|
589
|
-
|
590
|
-
|
591
|
-
|
592
|
-
var $form;
|
593
|
-
$form = $(form);
|
594
|
-
return $form.bind("submit", (function(event) {
|
595
|
-
var safeToSubmit;
|
596
|
-
safeToSubmit = true;
|
644
|
+
$("form:has(.tessa-upload)").each((function(i, form) {
|
645
|
+
var $form = $(form);
|
646
|
+
$form.on("submit", (function(event) {
|
647
|
+
var safeToSubmit = true;
|
597
648
|
$form.find(".tessa-upload").each((function(j, dropzoneElement) {
|
598
|
-
|
599
|
-
if (file.status
|
600
|
-
|
649
|
+
dropzoneElement.dropzone.files.forEach((function(file) {
|
650
|
+
if (file.status && file.status != WCCDropzone.SUCCESS) {
|
651
|
+
safeToSubmit = false;
|
601
652
|
}
|
602
653
|
}));
|
603
654
|
}));
|
604
|
-
if (!safeToSubmit && !confirm(
|
655
|
+
if (!safeToSubmit && !confirm(uploadPendingWarning)) {
|
605
656
|
return false;
|
606
657
|
}
|
607
658
|
}));
|
608
659
|
}));
|
609
|
-
|
610
|
-
|
611
|
-
|
612
|
-
|
613
|
-
|
614
|
-
|
660
|
+
}
|
661
|
+
function createAcceptFn(_a) {
|
662
|
+
var directUploadURL = _a.directUploadURL;
|
663
|
+
return function(file, done) {
|
664
|
+
var postData = {
|
665
|
+
blob: {
|
666
|
+
filename: file.name,
|
667
|
+
byte_size: file.size,
|
668
|
+
content_type: file.type,
|
669
|
+
checksum: ""
|
670
|
+
}
|
615
671
|
};
|
616
|
-
|
617
|
-
|
618
|
-
|
619
|
-
}
|
620
|
-
inputPrefix = $item.data("asset-field-prefix");
|
621
|
-
dropzone = new WCC.Dropzone(item, args);
|
622
|
-
$item.find('input[type="hidden"]').each((function(j, input) {
|
623
|
-
var $input, mockFile;
|
624
|
-
$input = $(input);
|
625
|
-
mockFile = $input.data("meta");
|
626
|
-
mockFile.accepted = true;
|
627
|
-
dropzone.options.addedfile.call(dropzone, mockFile);
|
628
|
-
dropzone.options.thumbnail.call(dropzone, mockFile, mockFile.url);
|
629
|
-
dropzone.emit("complete", mockFile);
|
630
|
-
return dropzone.files.push(mockFile);
|
631
|
-
}));
|
632
|
-
updateAction = function(file) {
|
633
|
-
var actionInput, inputID;
|
634
|
-
if (file.assetID == null) {
|
635
|
-
return;
|
672
|
+
FileChecksum.create(file, (function(error, checksum) {
|
673
|
+
if (error) {
|
674
|
+
return done(error);
|
636
675
|
}
|
637
|
-
|
638
|
-
|
639
|
-
if (!actionInput.length) {
|
640
|
-
actionInput = $('<input type="hidden">').attr({
|
641
|
-
id: inputID,
|
642
|
-
name: `${inputPrefix}[${file.assetID}][action]`
|
643
|
-
}).appendTo(item);
|
676
|
+
if (!checksum) {
|
677
|
+
return done("Failed to generate checksum for file '".concat(file.name, "'"));
|
644
678
|
}
|
645
|
-
|
646
|
-
|
647
|
-
|
648
|
-
|
649
|
-
|
650
|
-
|
651
|
-
|
652
|
-
|
653
|
-
|
679
|
+
postData.blob["checksum"] = checksum;
|
680
|
+
$.ajax(directUploadURL, {
|
681
|
+
type: "POST",
|
682
|
+
data: postData,
|
683
|
+
success: function(response) {
|
684
|
+
file.uploadURL = response.direct_upload.url;
|
685
|
+
file.uploadMethod = "PUT";
|
686
|
+
file.uploadHeaders = response.direct_upload.headers;
|
687
|
+
file.signedID = response.signed_id;
|
688
|
+
done();
|
689
|
+
},
|
690
|
+
error: function(response) {
|
691
|
+
console.error(response);
|
692
|
+
done("Failed to initiate the upload process!");
|
693
|
+
}
|
694
|
+
});
|
654
695
|
}));
|
655
|
-
}
|
656
|
-
}
|
657
|
-
$(
|
658
|
-
return window.WCC.tessaInit();
|
659
|
-
}));
|
696
|
+
};
|
697
|
+
}
|
698
|
+
$(tessaInit);
|
660
699
|
}));
|
@@ -0,0 +1,76 @@
|
|
1
|
+
import * as SparkMD5 from "spark-md5"
|
2
|
+
|
3
|
+
const fileSlice = File.prototype.slice || (File.prototype as any).mozSlice || (File.prototype as any).webkitSlice
|
4
|
+
|
5
|
+
type FileChecksumCallback = (error: string | null, checksum?: string) => void
|
6
|
+
|
7
|
+
export class FileChecksum {
|
8
|
+
static create(file: File, callback: FileChecksumCallback) {
|
9
|
+
const instance = new FileChecksum(file)
|
10
|
+
instance.create(callback)
|
11
|
+
}
|
12
|
+
|
13
|
+
private file: File
|
14
|
+
private chunkSize: number
|
15
|
+
private chunkCount: number
|
16
|
+
private chunkIndex: number
|
17
|
+
private md5Buffer?: SparkMD5.ArrayBuffer
|
18
|
+
private fileReader?: FileReader
|
19
|
+
private callback?: FileChecksumCallback
|
20
|
+
|
21
|
+
constructor(file: File) {
|
22
|
+
this.file = file
|
23
|
+
this.chunkSize = 2097152 // 2MB
|
24
|
+
this.chunkCount = Math.ceil(this.file.size / this.chunkSize)
|
25
|
+
this.chunkIndex = 0
|
26
|
+
}
|
27
|
+
|
28
|
+
create(callback: FileChecksumCallback) {
|
29
|
+
this.callback = callback
|
30
|
+
this.md5Buffer = new SparkMD5.ArrayBuffer
|
31
|
+
this.fileReader = new FileReader
|
32
|
+
this.fileReader.addEventListener("load", event => this.fileReaderDidLoad(event))
|
33
|
+
this.fileReader.addEventListener("error", event => this.fileReaderDidError(event))
|
34
|
+
this.readNextChunk()
|
35
|
+
}
|
36
|
+
|
37
|
+
private fileReaderDidLoad(event: ProgressEvent<FileReader>) {
|
38
|
+
if (!this.md5Buffer || !this.fileReader) {
|
39
|
+
throw new Error("FileChecksum: fileReaderDidLoad called before create")
|
40
|
+
}
|
41
|
+
if (!event.target?.result) { return }
|
42
|
+
|
43
|
+
this.md5Buffer.append(event.target.result as ArrayBuffer)
|
44
|
+
|
45
|
+
if (!this.readNextChunk()) {
|
46
|
+
const binaryDigest = this.md5Buffer.end(true)
|
47
|
+
const base64digest = btoa(binaryDigest)
|
48
|
+
if (this.callback) {
|
49
|
+
this.callback(null, base64digest)
|
50
|
+
}
|
51
|
+
}
|
52
|
+
}
|
53
|
+
|
54
|
+
private fileReaderDidError(event: ProgressEvent<FileReader>) {
|
55
|
+
if (this.callback) {
|
56
|
+
this.callback(`Error reading ${this.file.name}`)
|
57
|
+
}
|
58
|
+
}
|
59
|
+
|
60
|
+
private readNextChunk() {
|
61
|
+
if (!this.fileReader) {
|
62
|
+
throw new Error("FileChecksum: readNextChunk called before create")
|
63
|
+
}
|
64
|
+
|
65
|
+
if (this.chunkIndex < this.chunkCount || (this.chunkIndex == 0 && this.chunkCount == 0)) {
|
66
|
+
const start = this.chunkIndex * this.chunkSize
|
67
|
+
const end = Math.min(start + this.chunkSize, this.file.size)
|
68
|
+
const bytes = fileSlice.call(this.file, start, end)
|
69
|
+
this.fileReader.readAsArrayBuffer(bytes)
|
70
|
+
this.chunkIndex++
|
71
|
+
return true
|
72
|
+
} else {
|
73
|
+
return false
|
74
|
+
}
|
75
|
+
}
|
76
|
+
}
|