@formio/js 5.0.0-rc.34 → 5.0.0-rc.36
Sign up to get free protection for your applications and to get access to all the features.
- package/dist/fonts/bootstrap-icons.woff +0 -0
- package/dist/fonts/bootstrap-icons.woff2 +0 -0
- package/dist/formio.builder.css +19 -15
- package/dist/formio.builder.min.css +1 -1
- package/dist/formio.embed.js +1 -1
- package/dist/formio.embed.min.js +1 -1
- package/dist/formio.form.css +19 -15
- package/dist/formio.form.js +19 -19
- package/dist/formio.form.min.css +1 -1
- package/dist/formio.form.min.js +1 -1
- package/dist/formio.form.min.js.LICENSE.txt +1 -1
- package/dist/formio.full.css +363 -19
- package/dist/formio.full.js +20 -20
- package/dist/formio.full.min.css +3 -3
- package/dist/formio.full.min.js +1 -1
- package/dist/formio.full.min.js.LICENSE.txt +1 -1
- package/dist/formio.js +8 -8
- package/dist/formio.min.js +1 -1
- package/embed.d.ts +1 -0
- package/lib/cjs/CDN.js +12 -6
- package/lib/cjs/Webform.js +4 -1
- package/lib/cjs/Wizard.js +6 -9
- package/lib/cjs/components/_classes/component/Component.js +6 -1
- package/lib/cjs/components/_classes/nested/NestedComponent.js +1 -1
- package/lib/cjs/components/container/fixtures/comp4.js +45 -0
- package/lib/cjs/components/container/fixtures/index.js +3 -1
- package/lib/cjs/components/datetime/DateTime.js +6 -0
- package/lib/cjs/components/file/File.js +465 -215
- package/lib/cjs/components/file/editForm/File.edit.display.js +17 -0
- package/lib/cjs/components/textarea/TextArea.js +2 -2
- package/lib/cjs/components/textfield/TextField.js +3 -1
- package/lib/cjs/components/time/Time.js +3 -0
- package/lib/cjs/providers/storage/azure.js +6 -1
- package/lib/cjs/providers/storage/base64.js +1 -1
- package/lib/cjs/providers/storage/googleDrive.js +5 -1
- package/lib/cjs/providers/storage/indexeddb.js +1 -1
- package/lib/cjs/providers/storage/s3.js +5 -1
- package/lib/cjs/providers/storage/xhr.js +10 -0
- package/lib/mjs/CDN.js +12 -6
- package/lib/mjs/Webform.js +4 -1
- package/lib/mjs/Wizard.js +6 -9
- package/lib/mjs/components/_classes/component/Component.js +6 -1
- package/lib/mjs/components/_classes/nested/NestedComponent.js +1 -1
- package/lib/mjs/components/container/fixtures/comp4.js +43 -0
- package/lib/mjs/components/container/fixtures/index.js +2 -1
- package/lib/mjs/components/datetime/DateTime.js +6 -0
- package/lib/mjs/components/file/File.js +463 -224
- package/lib/mjs/components/file/editForm/File.edit.display.js +17 -0
- package/lib/mjs/components/textarea/TextArea.js +2 -2
- package/lib/mjs/components/textfield/TextField.js +6 -0
- package/lib/mjs/components/time/Time.js +3 -0
- package/lib/mjs/providers/storage/azure.js +6 -1
- package/lib/mjs/providers/storage/base64.js +1 -1
- package/lib/mjs/providers/storage/googleDrive.js +5 -1
- package/lib/mjs/providers/storage/indexeddb.js +1 -1
- package/lib/mjs/providers/storage/s3.js +5 -1
- package/lib/mjs/providers/storage/xhr.js +10 -0
- package/package.json +6 -3
- package/sdk.d.ts +1 -0
- package/types/components/_classes/component/component.d.ts +1 -1
- package/types/components/schema.d.ts +1 -1
- package/types/formio.d.ts +1 -0
- package/types/index.d.ts +1 -1
- package/types/sdk.d.ts +1 -0
- package/utils.d.ts +1 -0
@@ -42,6 +42,7 @@ if (htmlCanvasElement && !htmlCanvasElement.prototype.toBlob) {
|
|
42
42
|
}
|
43
43
|
});
|
44
44
|
}
|
45
|
+
const createRandomString = () => Math.random().toString(36).substring(2, 15);
|
45
46
|
class FileComponent extends Field_1.default {
|
46
47
|
static schema(...extend) {
|
47
48
|
return Field_1.default.schema({
|
@@ -90,8 +91,13 @@ class FileComponent extends Field_1.default {
|
|
90
91
|
progress: progressSupported,
|
91
92
|
};
|
92
93
|
this.cameraMode = false;
|
93
|
-
this.statuses = [];
|
94
94
|
this.fileDropHidden = false;
|
95
|
+
this.filesToSync = {
|
96
|
+
filesToUpload: [],
|
97
|
+
filesToDelete: [],
|
98
|
+
};
|
99
|
+
this.isSyncing = false;
|
100
|
+
this.abortUploads = [];
|
95
101
|
}
|
96
102
|
get dataReady() {
|
97
103
|
return this.filesReady || Promise.resolve();
|
@@ -136,14 +142,37 @@ class FileComponent extends Field_1.default {
|
|
136
142
|
}
|
137
143
|
this._fileBrowseHidden = value;
|
138
144
|
}
|
145
|
+
get shouldSyncFiles() {
|
146
|
+
return Boolean(this.filesToSync.filesToDelete.length || this.filesToSync.filesToUpload.length);
|
147
|
+
}
|
148
|
+
get autoSync() {
|
149
|
+
return lodash_1.default.get(this, 'component.autoSync', false);
|
150
|
+
}
|
151
|
+
get columnsSize() {
|
152
|
+
const actionsColumn = this.disabled ? 0 : this.autoSync ? 2 : 1;
|
153
|
+
const typeColumn = this.hasTypes ? 2 : 0;
|
154
|
+
const sizeColumn = 2;
|
155
|
+
const nameColumn = 12 - actionsColumn - typeColumn - sizeColumn;
|
156
|
+
return {
|
157
|
+
name: nameColumn,
|
158
|
+
size: sizeColumn,
|
159
|
+
type: typeColumn,
|
160
|
+
actions: actionsColumn,
|
161
|
+
};
|
162
|
+
}
|
139
163
|
render() {
|
164
|
+
const { filesToDelete, filesToUpload } = this.filesToSync;
|
140
165
|
return super.render(this.renderTemplate('file', {
|
141
166
|
fileSize: this.fileSize,
|
142
167
|
files: this.dataValue || [],
|
143
|
-
|
168
|
+
filesToDelete,
|
169
|
+
filesToUpload,
|
144
170
|
disabled: this.disabled,
|
145
171
|
support: this.support,
|
146
|
-
fileDropHidden: this.fileDropHidden
|
172
|
+
fileDropHidden: this.fileDropHidden,
|
173
|
+
showSyncButton: this.autoSync && (filesToDelete.length || filesToUpload.length),
|
174
|
+
isSyncing: this.isSyncing,
|
175
|
+
columns: this.columnsSize,
|
147
176
|
}));
|
148
177
|
}
|
149
178
|
getVideoStream(constraints) {
|
@@ -204,7 +233,7 @@ class FileComponent extends Field_1.default {
|
|
204
233
|
this.getFrame(videoPlayer)
|
205
234
|
.then((frame) => {
|
206
235
|
frame.name = `photo-${Date.now()}.png`;
|
207
|
-
this.
|
236
|
+
this.handleFilesToUpload([frame]);
|
208
237
|
this.cameraMode = false;
|
209
238
|
this.redraw();
|
210
239
|
});
|
@@ -281,20 +310,10 @@ class FileComponent extends Field_1.default {
|
|
281
310
|
}
|
282
311
|
return options;
|
283
312
|
}
|
284
|
-
|
285
|
-
|
286
|
-
|
287
|
-
|
288
|
-
if (fileService && typeof fileService.deleteFile === 'function') {
|
289
|
-
fileService.deleteFile(fileInfo, options);
|
290
|
-
}
|
291
|
-
else {
|
292
|
-
const formio = this.options.formio || (this.root && this.root.formio);
|
293
|
-
if (formio) {
|
294
|
-
formio.makeRequest('', fileInfo.url, 'delete');
|
295
|
-
}
|
296
|
-
}
|
297
|
-
}
|
313
|
+
get actions() {
|
314
|
+
return {
|
315
|
+
abort: this.abortRequest.bind(this),
|
316
|
+
};
|
298
317
|
}
|
299
318
|
attach(element) {
|
300
319
|
this.loadRefs(element, {
|
@@ -307,19 +326,22 @@ class FileComponent extends Field_1.default {
|
|
307
326
|
videoPlayer: 'single',
|
308
327
|
fileLink: 'multiple',
|
309
328
|
removeLink: 'multiple',
|
310
|
-
|
329
|
+
fileToSyncRemove: 'multiple',
|
311
330
|
fileImage: 'multiple',
|
312
331
|
fileType: 'multiple',
|
313
332
|
fileProcessingLoader: 'single',
|
333
|
+
syncNow: 'single',
|
334
|
+
restoreFile: 'multiple',
|
335
|
+
progress: 'multiple',
|
314
336
|
});
|
315
337
|
// Ensure we have an empty input refs. We need this for the setValue method to redraw the control when it is set.
|
316
338
|
this.refs.input = [];
|
317
339
|
const superAttach = super.attach(element);
|
318
340
|
if (this.refs.fileDrop) {
|
319
|
-
if (!this.statuses.length) {
|
320
|
-
|
321
|
-
}
|
322
|
-
const
|
341
|
+
// if (!this.statuses.length) {
|
342
|
+
// this.refs.fileDrop.removeAttribute('hidden');
|
343
|
+
// }
|
344
|
+
const _this = this;
|
323
345
|
this.addEventListener(this.refs.fileDrop, 'dragover', function (event) {
|
324
346
|
this.className = 'fileSelector fileDragOver';
|
325
347
|
event.preventDefault();
|
@@ -331,15 +353,18 @@ class FileComponent extends Field_1.default {
|
|
331
353
|
this.addEventListener(this.refs.fileDrop, 'drop', function (event) {
|
332
354
|
this.className = 'fileSelector';
|
333
355
|
event.preventDefault();
|
334
|
-
|
356
|
+
_this.handleFilesToUpload(event.dataTransfer.files);
|
335
357
|
});
|
336
358
|
}
|
359
|
+
this.addEventListener(element, 'click', (event) => {
|
360
|
+
this.handleAction(event);
|
361
|
+
});
|
337
362
|
if (this.refs.fileBrowse) {
|
338
363
|
this.addEventListener(this.refs.fileBrowse, 'click', (event) => {
|
339
364
|
event.preventDefault();
|
340
365
|
this.browseFiles(this.browseOptions)
|
341
366
|
.then((files) => {
|
342
|
-
this.
|
367
|
+
this.handleFilesToUpload(files);
|
343
368
|
});
|
344
369
|
});
|
345
370
|
}
|
@@ -351,22 +376,27 @@ class FileComponent extends Field_1.default {
|
|
351
376
|
});
|
352
377
|
this.refs.removeLink.forEach((removeLink, index) => {
|
353
378
|
this.addEventListener(removeLink, 'click', (event) => {
|
379
|
+
event.preventDefault();
|
354
380
|
const fileInfo = this.dataValue[index];
|
355
|
-
this.
|
381
|
+
this.handleFileToRemove(fileInfo);
|
382
|
+
});
|
383
|
+
});
|
384
|
+
this.refs.fileToSyncRemove.forEach((fileToSyncRemove, index) => {
|
385
|
+
this.addEventListener(fileToSyncRemove, 'click', (event) => {
|
356
386
|
event.preventDefault();
|
357
|
-
this.splice(index);
|
387
|
+
this.filesToSync.filesToUpload.splice(index, 1);
|
358
388
|
this.redraw();
|
359
389
|
});
|
360
390
|
});
|
361
|
-
this.refs.
|
362
|
-
this.addEventListener(
|
391
|
+
this.refs.restoreFile.forEach((fileToRestore, index) => {
|
392
|
+
this.addEventListener(fileToRestore, 'click', (event) => {
|
363
393
|
event.preventDefault();
|
364
|
-
const
|
365
|
-
|
366
|
-
|
367
|
-
|
368
|
-
|
369
|
-
this.
|
394
|
+
const fileInfo = this.filesToSync.filesToDelete[index];
|
395
|
+
delete fileInfo.status;
|
396
|
+
delete fileInfo.message;
|
397
|
+
this.filesToSync.filesToDelete.splice(index, 1);
|
398
|
+
this.dataValue.push(fileInfo);
|
399
|
+
this.triggerChange();
|
370
400
|
this.redraw();
|
371
401
|
});
|
372
402
|
});
|
@@ -380,7 +410,7 @@ class FileComponent extends Field_1.default {
|
|
380
410
|
reader.onloadend = (evt) => {
|
381
411
|
const blob = new Blob([new Uint8Array(evt.target.result)], { type: file.type });
|
382
412
|
blob.name = file.name;
|
383
|
-
this.
|
413
|
+
this.handleFilesToUpload([blob]);
|
384
414
|
};
|
385
415
|
reader.readAsArrayBuffer(file);
|
386
416
|
});
|
@@ -402,7 +432,7 @@ class FileComponent extends Field_1.default {
|
|
402
432
|
reader.onloadend = (evt) => {
|
403
433
|
const blob = new Blob([new Uint8Array(evt.target.result)], { type: file.type });
|
404
434
|
blob.name = file.name;
|
405
|
-
this.
|
435
|
+
this.handleFilesToUpload([blob]);
|
406
436
|
};
|
407
437
|
reader.readAsArrayBuffer(file);
|
408
438
|
});
|
@@ -432,6 +462,9 @@ class FileComponent extends Field_1.default {
|
|
432
462
|
});
|
433
463
|
}
|
434
464
|
this.refs.fileType.forEach((fileType, index) => {
|
465
|
+
if (!this.dataValue[index]) {
|
466
|
+
return;
|
467
|
+
}
|
435
468
|
this.dataValue[index].fileType = this.dataValue[index].fileType || this.component.fileTypes[0].label;
|
436
469
|
this.addEventListener(fileType, 'change', (event) => {
|
437
470
|
event.preventDefault();
|
@@ -439,6 +472,10 @@ class FileComponent extends Field_1.default {
|
|
439
472
|
this.dataValue[index].fileType = fileType.label;
|
440
473
|
});
|
441
474
|
});
|
475
|
+
this.addEventListener(this.refs.syncNow, 'click', (event) => {
|
476
|
+
event.preventDefault();
|
477
|
+
this.syncFiles();
|
478
|
+
});
|
442
479
|
const fileService = this.fileService;
|
443
480
|
if (fileService) {
|
444
481
|
const loadingImages = [];
|
@@ -554,199 +591,396 @@ class FileComponent extends Field_1.default {
|
|
554
591
|
validateMaxSize(file, val) {
|
555
592
|
return file.size - 0.1 <= this.translateScalars(val);
|
556
593
|
}
|
557
|
-
|
558
|
-
|
559
|
-
if (
|
560
|
-
|
561
|
-
|
594
|
+
abortRequest(id) {
|
595
|
+
const abortUpload = this.abortUploads.find(abortUpload => abortUpload.id === id);
|
596
|
+
if (abortUpload) {
|
597
|
+
abortUpload.abort();
|
598
|
+
}
|
599
|
+
}
|
600
|
+
handleAction(event) {
|
601
|
+
const target = event.target;
|
602
|
+
if (!target.id) {
|
603
|
+
return;
|
604
|
+
}
|
605
|
+
const [action, id] = target.id.split('-');
|
606
|
+
if (!action || !id || !this.actions[action]) {
|
607
|
+
return;
|
608
|
+
}
|
609
|
+
this.actions[action](id);
|
610
|
+
}
|
611
|
+
getFileName(file) {
|
612
|
+
return (0, utils_1.uniqueName)(file.name, this.component.fileNameTemplate, this.evalContext());
|
613
|
+
}
|
614
|
+
getInitFileToSync(file) {
|
615
|
+
const escapedFileName = file.name ? file.name.replaceAll('<', '<').replaceAll('>', '>') : file.name;
|
616
|
+
return {
|
617
|
+
id: createRandomString(),
|
618
|
+
// Get a unique name for this file to keep file collisions from occurring.
|
619
|
+
dir: this.interpolate(this.component.dir || ''),
|
620
|
+
name: this.getFileName(file),
|
621
|
+
originalName: escapedFileName,
|
622
|
+
fileKey: this.component.fileKey || 'file',
|
623
|
+
storage: this.component.storage,
|
624
|
+
options: this.component.options,
|
625
|
+
file,
|
626
|
+
size: file.size,
|
627
|
+
status: 'info',
|
628
|
+
message: this.t('Processing file. Please wait...'),
|
629
|
+
hash: '',
|
630
|
+
};
|
631
|
+
}
|
632
|
+
handleSubmissionRevisions(file) {
|
633
|
+
return __awaiter(this, void 0, void 0, function* () {
|
634
|
+
if (this.root.form.submissionRevisions !== 'true') {
|
635
|
+
return '';
|
562
636
|
}
|
563
|
-
|
637
|
+
const bmf = new browser_md5_file_1.default();
|
638
|
+
const hash = yield new Promise((resolve, reject) => {
|
639
|
+
this.emit('fileUploadingStart');
|
640
|
+
bmf.md5(file, (err, md5) => {
|
641
|
+
if (err) {
|
642
|
+
return reject(err);
|
643
|
+
}
|
644
|
+
return resolve(md5);
|
645
|
+
});
|
646
|
+
});
|
647
|
+
this.emit('fileUploadingEnd');
|
648
|
+
return hash;
|
649
|
+
});
|
650
|
+
}
|
651
|
+
validateFileName(file) {
|
652
|
+
// Check if file with the same name is being uploaded
|
653
|
+
const fileWithSameNameUploading = this.filesToSync.filesToUpload
|
654
|
+
.some(fileToSync => { var _a; return ((_a = fileToSync.file) === null || _a === void 0 ? void 0 : _a.name) === file.name; });
|
655
|
+
const fileWithSameNameUploaded = this.dataValue
|
656
|
+
.some(fileStatus => fileStatus.originalName === file.name);
|
657
|
+
return fileWithSameNameUploaded || fileWithSameNameUploading
|
658
|
+
? {
|
659
|
+
status: 'error',
|
660
|
+
message: this.t(`File with the same name is already ${fileWithSameNameUploading ? 'being ' : ''}uploaded`),
|
661
|
+
}
|
662
|
+
: {};
|
663
|
+
}
|
664
|
+
validateFileSettings(file) {
|
665
|
+
// Check file pattern
|
666
|
+
if (this.component.filePattern && !this.validatePattern(file, this.component.filePattern)) {
|
667
|
+
return {
|
668
|
+
status: 'error',
|
669
|
+
message: this.t('File is the wrong type; it must be {{ pattern }}', {
|
670
|
+
pattern: this.component.filePattern,
|
671
|
+
}),
|
672
|
+
};
|
564
673
|
}
|
565
|
-
|
566
|
-
|
567
|
-
|
568
|
-
|
569
|
-
|
570
|
-
|
571
|
-
|
572
|
-
|
573
|
-
|
574
|
-
|
575
|
-
|
576
|
-
|
577
|
-
|
578
|
-
|
579
|
-
|
580
|
-
}
|
581
|
-
|
582
|
-
|
583
|
-
|
584
|
-
|
585
|
-
|
586
|
-
|
587
|
-
|
588
|
-
|
589
|
-
|
590
|
-
|
591
|
-
|
592
|
-
|
593
|
-
|
594
|
-
|
595
|
-
|
674
|
+
// Check file minimum size
|
675
|
+
if (this.component.fileMinSize && !this.validateMinSize(file, this.component.fileMinSize)) {
|
676
|
+
return {
|
677
|
+
status: 'error',
|
678
|
+
message: this.t('File is too small; it must be at least {{ size }}', {
|
679
|
+
size: this.component.fileMinSize,
|
680
|
+
}),
|
681
|
+
};
|
682
|
+
}
|
683
|
+
// Check file maximum size
|
684
|
+
if (this.component.fileMaxSize && !this.validateMaxSize(file, this.component.fileMaxSize)) {
|
685
|
+
return {
|
686
|
+
status: 'error',
|
687
|
+
message: this.t('File is too big; it must be at most {{ size }}', {
|
688
|
+
size: this.component.fileMaxSize,
|
689
|
+
}),
|
690
|
+
};
|
691
|
+
}
|
692
|
+
return {};
|
693
|
+
}
|
694
|
+
validateFileService() {
|
695
|
+
const { fileService } = this;
|
696
|
+
return !fileService
|
697
|
+
? {
|
698
|
+
status: 'error',
|
699
|
+
message: this.t('File Service not provided.'),
|
700
|
+
}
|
701
|
+
: {};
|
702
|
+
}
|
703
|
+
validateFile(file) {
|
704
|
+
const fileServiceValidation = this.validateFileService();
|
705
|
+
if (fileServiceValidation.status === 'error') {
|
706
|
+
return fileServiceValidation;
|
707
|
+
}
|
708
|
+
const fileNameValidation = this.validateFileName(file);
|
709
|
+
if (fileNameValidation.status === 'error') {
|
710
|
+
return fileNameValidation;
|
711
|
+
}
|
712
|
+
return this.validateFileSettings(file);
|
713
|
+
}
|
714
|
+
getGroupPermissions() {
|
715
|
+
let groupKey = null;
|
716
|
+
let groupPermissions = null;
|
717
|
+
//Iterate through form components to find group resource if one exists
|
718
|
+
this.root.everyComponent((element) => {
|
719
|
+
var _a, _b;
|
720
|
+
if (((_a = element.component) === null || _a === void 0 ? void 0 : _a.submissionAccess) || ((_b = element.component) === null || _b === void 0 ? void 0 : _b.defaultPermission)) {
|
721
|
+
groupPermissions = !element.component.submissionAccess ? [
|
722
|
+
{
|
723
|
+
type: element.component.defaultPermission,
|
724
|
+
roles: [],
|
725
|
+
},
|
726
|
+
] : element.component.submissionAccess;
|
727
|
+
groupPermissions.forEach((permission) => {
|
728
|
+
groupKey = ['admin', 'write', 'create'].includes(permission.type) ? element.component.key : null;
|
729
|
+
});
|
730
|
+
}
|
731
|
+
});
|
732
|
+
return { groupKey, groupPermissions };
|
733
|
+
}
|
734
|
+
triggerFileProcessor(file) {
|
735
|
+
return __awaiter(this, void 0, void 0, function* () {
|
736
|
+
let processedFile = null;
|
737
|
+
if (this.root.options.fileProcessor) {
|
738
|
+
try {
|
739
|
+
if (this.refs.fileProcessingLoader) {
|
740
|
+
this.refs.fileProcessingLoader.style.display = 'block';
|
741
|
+
}
|
742
|
+
const fileProcessorHandler = (0, fileProcessor_1.default)(this.fileService, this.root.options.fileProcessor);
|
743
|
+
processedFile = yield fileProcessorHandler(file, this.component.properties);
|
596
744
|
}
|
597
|
-
|
598
|
-
|
599
|
-
|
745
|
+
catch (err) {
|
746
|
+
this.fileDropHidden = false;
|
747
|
+
return {
|
748
|
+
status: 'error',
|
749
|
+
message: this.t('File processing has been failed.'),
|
750
|
+
};
|
600
751
|
}
|
601
|
-
|
602
|
-
|
603
|
-
|
604
|
-
|
605
|
-
&& fileStatus.status === 'error');
|
606
|
-
if (fileWithSameNameUploaded || fileWithSameNameUploading) {
|
607
|
-
fileUpload.status = 'error';
|
608
|
-
fileUpload.message = this.t(`File with the same name is already ${fileWithSameNameUploading ? 'being ' : ''}uploaded`);
|
752
|
+
finally {
|
753
|
+
if (this.refs.fileProcessingLoader) {
|
754
|
+
this.refs.fileProcessingLoader.style.display = 'none';
|
755
|
+
}
|
609
756
|
}
|
610
|
-
|
611
|
-
|
757
|
+
}
|
758
|
+
return {
|
759
|
+
file: processedFile,
|
760
|
+
};
|
761
|
+
});
|
762
|
+
}
|
763
|
+
prepareFileToUpload(file) {
|
764
|
+
return __awaiter(this, void 0, void 0, function* () {
|
765
|
+
const fileToSync = this.getInitFileToSync(file);
|
766
|
+
fileToSync.hash = yield this.handleSubmissionRevisions(file);
|
767
|
+
const { status, message } = this.validateFile(file);
|
768
|
+
if (status === 'error') {
|
769
|
+
fileToSync.isValidationError = true;
|
770
|
+
fileToSync.status = status;
|
771
|
+
fileToSync.message = message;
|
772
|
+
return this.filesToSync.filesToUpload.push(fileToSync);
|
773
|
+
}
|
774
|
+
if (this.component.privateDownload) {
|
775
|
+
file.private = true;
|
776
|
+
}
|
777
|
+
const { groupKey, groupPermissions } = this.getGroupPermissions();
|
778
|
+
const processedFile = yield this.triggerFileProcessor(file);
|
779
|
+
if (processedFile.status === 'error') {
|
780
|
+
fileToSync.status === 'error';
|
781
|
+
fileToSync.message = processedFile.message;
|
782
|
+
return this.filesToSync.filesToUpload.push(fileToSync);
|
783
|
+
}
|
784
|
+
if (this.autoSync) {
|
785
|
+
fileToSync.message = this.t('Ready to be uploaded into storage');
|
786
|
+
}
|
787
|
+
this.filesToSync.filesToUpload.push(Object.assign(Object.assign({}, fileToSync), { message: fileToSync.message, file: processedFile.file || file, url: this.interpolate(this.component.url, { file: fileToSync }), groupPermissions, groupResourceId: groupKey ? this.currentForm.submission.data[groupKey]._id : null }));
|
788
|
+
});
|
789
|
+
}
|
790
|
+
prepareFilesToUpload(files) {
|
791
|
+
return __awaiter(this, void 0, void 0, function* () {
|
792
|
+
// Only allow one upload if not multiple.
|
793
|
+
if (!this.component.multiple) {
|
794
|
+
files = Array.prototype.slice.call(files, 0, 1);
|
795
|
+
}
|
796
|
+
if (this.component.storage && files && files.length) {
|
797
|
+
this.fileDropHidden = true;
|
798
|
+
return Promise.all([...files].map((file) => __awaiter(this, void 0, void 0, function* () {
|
799
|
+
yield this.prepareFileToUpload(file);
|
612
800
|
this.redraw();
|
801
|
+
})));
|
802
|
+
}
|
803
|
+
else {
|
804
|
+
return Promise.resolve();
|
805
|
+
}
|
806
|
+
});
|
807
|
+
}
|
808
|
+
handleFilesToUpload(files) {
|
809
|
+
return __awaiter(this, void 0, void 0, function* () {
|
810
|
+
yield this.prepareFilesToUpload(files);
|
811
|
+
if (!this.autoSync) {
|
812
|
+
yield this.syncFiles();
|
813
|
+
}
|
814
|
+
});
|
815
|
+
}
|
816
|
+
prepareFileToDelete(fileInfo) {
|
817
|
+
this.filesToSync.filesToDelete.push(Object.assign(Object.assign({}, fileInfo), { status: 'info', message: this.autoSync
|
818
|
+
? this.t('Ready to be removed from storage')
|
819
|
+
: this.t('Preparing file to remove') }));
|
820
|
+
const index = this.dataValue.findIndex(file => file.name === fileInfo.name);
|
821
|
+
this.splice(index);
|
822
|
+
this.redraw();
|
823
|
+
}
|
824
|
+
handleFileToRemove(fileInfo) {
|
825
|
+
this.prepareFileToDelete(fileInfo);
|
826
|
+
if (!this.autoSync) {
|
827
|
+
this.syncFiles();
|
828
|
+
}
|
829
|
+
}
|
830
|
+
deleteFile(fileInfo) {
|
831
|
+
return __awaiter(this, void 0, void 0, function* () {
|
832
|
+
const { options = {} } = this.component;
|
833
|
+
if (fileInfo && (['url', 'indexeddb', 's3', 'azure', 'googledrive'].includes(this.component.storage))) {
|
834
|
+
const { fileService } = this;
|
835
|
+
if (fileService && typeof fileService.deleteFile === 'function') {
|
836
|
+
return yield fileService.deleteFile(fileInfo, options);
|
613
837
|
}
|
614
|
-
|
615
|
-
|
616
|
-
|
617
|
-
|
618
|
-
|
619
|
-
});
|
620
|
-
}
|
621
|
-
// Check file minimum size
|
622
|
-
if (this.component.fileMinSize && !this.validateMinSize(file, this.component.fileMinSize)) {
|
623
|
-
fileUpload.status = 'error';
|
624
|
-
fileUpload.message = this.t('File is too small; it must be at least {{ size }}', {
|
625
|
-
size: this.component.fileMinSize,
|
626
|
-
});
|
838
|
+
else {
|
839
|
+
const formio = this.options.formio || (this.root && this.root.formio);
|
840
|
+
if (formio) {
|
841
|
+
return yield formio.makeRequest('', fileInfo.url, 'delete');
|
842
|
+
}
|
627
843
|
}
|
628
|
-
|
629
|
-
|
630
|
-
|
631
|
-
|
632
|
-
|
633
|
-
|
844
|
+
}
|
845
|
+
});
|
846
|
+
}
|
847
|
+
delete() {
|
848
|
+
return __awaiter(this, void 0, void 0, function* () {
|
849
|
+
if (!this.filesToSync.filesToDelete.length) {
|
850
|
+
return Promise.resolve();
|
851
|
+
}
|
852
|
+
return yield Promise.all(this.filesToSync.filesToDelete.map((fileToSync) => __awaiter(this, void 0, void 0, function* () {
|
853
|
+
try {
|
854
|
+
if (fileToSync.isValidationError) {
|
855
|
+
return { fileToSync };
|
856
|
+
}
|
857
|
+
yield this.deleteFile(fileToSync);
|
858
|
+
fileToSync.status = 'success';
|
859
|
+
fileToSync.message = this.t('Succefully removed');
|
634
860
|
}
|
635
|
-
|
636
|
-
|
637
|
-
|
638
|
-
if (!fileService) {
|
639
|
-
fileUpload.status = 'error';
|
640
|
-
fileUpload.message = this.t('File Service not provided.');
|
861
|
+
catch (response) {
|
862
|
+
fileToSync.status = 'error';
|
863
|
+
fileToSync.message = typeof response === 'string' ? response : response.toString();
|
641
864
|
}
|
642
|
-
|
643
|
-
this.statuses.push(fileUpload);
|
865
|
+
finally {
|
644
866
|
this.redraw();
|
645
867
|
}
|
646
|
-
|
647
|
-
|
648
|
-
|
649
|
-
|
650
|
-
|
651
|
-
|
652
|
-
|
653
|
-
|
654
|
-
|
655
|
-
|
656
|
-
|
657
|
-
|
658
|
-
|
659
|
-
|
660
|
-
|
661
|
-
|
662
|
-
|
663
|
-
|
664
|
-
|
665
|
-
|
666
|
-
|
667
|
-
|
668
|
-
|
669
|
-
|
670
|
-
|
671
|
-
|
672
|
-
|
673
|
-
|
674
|
-
|
675
|
-
|
676
|
-
|
677
|
-
|
678
|
-
|
679
|
-
|
680
|
-
|
681
|
-
|
682
|
-
|
683
|
-
|
684
|
-
|
685
|
-
|
686
|
-
|
687
|
-
|
688
|
-
|
689
|
-
|
690
|
-
|
691
|
-
|
868
|
+
return { fileToSync };
|
869
|
+
})));
|
870
|
+
});
|
871
|
+
}
|
872
|
+
updateProgress(fileInfo, progressEvent) {
|
873
|
+
fileInfo.progress = parseInt(100.0 * progressEvent.loaded / progressEvent.total);
|
874
|
+
if (fileInfo.status !== 'progress') {
|
875
|
+
fileInfo.status = 'progress';
|
876
|
+
delete fileInfo.message;
|
877
|
+
this.redraw();
|
878
|
+
}
|
879
|
+
else {
|
880
|
+
const progress = Array.prototype.find.call(this.refs.progress, progressElement => progressElement.id === fileInfo.id);
|
881
|
+
progress.innerHTML = `<span class="visually-hidden">${fileInfo.progress}% ${this.t('Complete')}</span>`;
|
882
|
+
progress.style.width = `${fileInfo.progress}%`;
|
883
|
+
progress.ariaValueNow = fileInfo.progress.toString();
|
884
|
+
}
|
885
|
+
}
|
886
|
+
getMultipartOptions(fileToSync) {
|
887
|
+
let count = 0;
|
888
|
+
return this.component.useMultipartUpload && this.component.multipart ? Object.assign(Object.assign({}, this.component.multipart), { progressCallback: (total) => {
|
889
|
+
count++;
|
890
|
+
fileToSync.status = 'progress';
|
891
|
+
fileToSync.progress = parseInt(100 * count / total);
|
892
|
+
delete fileToSync.message;
|
893
|
+
this.redraw();
|
894
|
+
}, changeMessage: (message) => {
|
895
|
+
fileToSync.message = message;
|
896
|
+
this.redraw();
|
897
|
+
} }) : false;
|
898
|
+
}
|
899
|
+
uploadFile(fileToSync) {
|
900
|
+
return __awaiter(this, void 0, void 0, function* () {
|
901
|
+
return yield this.fileService.uploadFile(fileToSync.storage, fileToSync.file, fileToSync.name, fileToSync.dir,
|
902
|
+
// Progress callback
|
903
|
+
this.updateProgress.bind(this, fileToSync), fileToSync.url, fileToSync.options, fileToSync.fileKey, fileToSync.groupPermissions, fileToSync.groupResourceId, () => { },
|
904
|
+
// Abort upload callback
|
905
|
+
(abort) => this.abortUploads.push({
|
906
|
+
id: fileToSync.id,
|
907
|
+
abort,
|
908
|
+
}), this.getMultipartOptions(fileToSync));
|
909
|
+
});
|
910
|
+
}
|
911
|
+
upload() {
|
912
|
+
return __awaiter(this, void 0, void 0, function* () {
|
913
|
+
if (!this.filesToSync.filesToUpload.length) {
|
914
|
+
return Promise.resolve();
|
915
|
+
}
|
916
|
+
return yield Promise.all(this.filesToSync.filesToUpload.map((fileToSync) => __awaiter(this, void 0, void 0, function* () {
|
917
|
+
let fileInfo = null;
|
918
|
+
try {
|
919
|
+
if (fileToSync.isValidationError) {
|
920
|
+
return {
|
921
|
+
fileToSync,
|
922
|
+
fileInfo,
|
923
|
+
};
|
692
924
|
}
|
693
|
-
|
694
|
-
|
695
|
-
|
696
|
-
|
697
|
-
|
698
|
-
|
699
|
-
|
700
|
-
|
701
|
-
|
702
|
-
|
703
|
-
|
704
|
-
|
705
|
-
|
925
|
+
fileInfo = yield this.uploadFile(fileToSync);
|
926
|
+
fileToSync.status = 'success';
|
927
|
+
fileToSync.message = this.t('Succefully uploaded');
|
928
|
+
fileInfo.originalName = fileToSync.originalName;
|
929
|
+
fileInfo.hash = fileToSync.hash;
|
930
|
+
}
|
931
|
+
catch (response) {
|
932
|
+
fileToSync.status = 'error';
|
933
|
+
delete fileToSync.progress;
|
934
|
+
fileToSync.message = typeof response === 'string'
|
935
|
+
? response
|
936
|
+
: response.type === 'abort'
|
937
|
+
? this.t('Request was aborted')
|
938
|
+
: response.toString();
|
939
|
+
}
|
940
|
+
finally {
|
941
|
+
delete fileToSync.progress;
|
706
942
|
this.redraw();
|
707
|
-
const filePromise = fileService.uploadFile(storage, processedFile || file, fileName, dir,
|
708
|
-
// Progress callback
|
709
|
-
(evt) => {
|
710
|
-
fileUpload.status = 'progress';
|
711
|
-
fileUpload.progress = parseInt(100.0 * evt.loaded / evt.total);
|
712
|
-
delete fileUpload.message;
|
713
|
-
this.redraw();
|
714
|
-
}, url, options, fileKey, groupPermissions, groupResourceId,
|
715
|
-
// Upload start callback
|
716
|
-
() => {
|
717
|
-
this.emit('fileUploadingStart', filePromise);
|
718
|
-
}, (abort) => fileUpload.abort = abort, multipartOptions).then((fileInfo) => {
|
719
|
-
const index = this.statuses.indexOf(fileUpload);
|
720
|
-
if (index !== -1) {
|
721
|
-
this.statuses.splice(index, 1);
|
722
|
-
}
|
723
|
-
fileInfo.originalName = escapedFileName;
|
724
|
-
fileInfo.hash = fileUpload.hash;
|
725
|
-
if (!this.hasValue()) {
|
726
|
-
this.dataValue = [];
|
727
|
-
}
|
728
|
-
this.dataValue.push(fileInfo);
|
729
|
-
lodash_1.default.pull(this.filesUploading, fileInfo.originalName);
|
730
|
-
this.fileDropHidden = false;
|
731
|
-
this.redraw();
|
732
|
-
this.triggerChange();
|
733
|
-
this.emit('fileUploadingEnd', filePromise);
|
734
|
-
})
|
735
|
-
.catch((response) => {
|
736
|
-
fileUpload.status = 'error';
|
737
|
-
fileUpload.message = typeof response === 'string' ? response : response.toString();
|
738
|
-
delete fileUpload.progress;
|
739
|
-
this.fileDropHidden = false;
|
740
|
-
lodash_1.default.pull(this.filesUploading, file.name);
|
741
|
-
this.redraw();
|
742
|
-
this.emit('fileUploadingEnd', filePromise);
|
743
|
-
});
|
744
943
|
}
|
745
|
-
|
746
|
-
|
944
|
+
return {
|
945
|
+
fileToSync,
|
946
|
+
fileInfo,
|
947
|
+
};
|
948
|
+
})));
|
949
|
+
});
|
950
|
+
}
|
951
|
+
syncFiles() {
|
952
|
+
return __awaiter(this, void 0, void 0, function* () {
|
953
|
+
this.isSyncing = true;
|
954
|
+
this.fileDropHidden = true;
|
955
|
+
this.redraw();
|
956
|
+
try {
|
957
|
+
const [filesToDelete = [], filesToUpload = []] = yield Promise.all([this.delete(), this.upload()]);
|
958
|
+
this.filesToSync.filesToDelete = filesToDelete
|
959
|
+
.filter(file => { var _a; return ((_a = file.fileToSync) === null || _a === void 0 ? void 0 : _a.status) === 'error'; })
|
960
|
+
.map(file => file.fileToSync);
|
961
|
+
this.filesToSync.filesToUpload = filesToUpload
|
962
|
+
.filter(file => { var _a; return ((_a = file.fileToSync) === null || _a === void 0 ? void 0 : _a.status) === 'error'; })
|
963
|
+
.map(file => file.fileToSync);
|
964
|
+
if (!this.hasValue()) {
|
965
|
+
this.dataValue = [];
|
747
966
|
}
|
748
|
-
|
749
|
-
|
967
|
+
const data = filesToUpload
|
968
|
+
.filter(file => { var _a; return ((_a = file.fileToSync) === null || _a === void 0 ? void 0 : _a.status) === 'success'; })
|
969
|
+
.map(file => file.fileInfo);
|
970
|
+
this.dataValue.push(...data);
|
971
|
+
this.triggerChange();
|
972
|
+
return Promise.resolve();
|
973
|
+
}
|
974
|
+
catch (err) {
|
975
|
+
return Promise.reject();
|
976
|
+
}
|
977
|
+
finally {
|
978
|
+
this.isSyncing = false;
|
979
|
+
this.fileDropHidden = false;
|
980
|
+
this.abortUploads = [];
|
981
|
+
this.redraw();
|
982
|
+
}
|
983
|
+
});
|
750
984
|
}
|
751
985
|
getFile(fileInfo) {
|
752
986
|
const { options = {} } = this.component;
|
@@ -781,7 +1015,23 @@ class FileComponent extends Field_1.default {
|
|
781
1015
|
this.refs.fileBrowse.focus();
|
782
1016
|
}
|
783
1017
|
}
|
784
|
-
|
1018
|
+
beforeSubmit() {
|
1019
|
+
return __awaiter(this, void 0, void 0, function* () {
|
1020
|
+
try {
|
1021
|
+
if (!this.autoSync) {
|
1022
|
+
return Promise.resolve();
|
1023
|
+
}
|
1024
|
+
yield this.syncFiles();
|
1025
|
+
return this.shouldSyncFiles
|
1026
|
+
? Promise.reject('Synchronization is failed')
|
1027
|
+
: Promise.resolve();
|
1028
|
+
}
|
1029
|
+
catch (error) {
|
1030
|
+
return Promise.reject(error.message);
|
1031
|
+
}
|
1032
|
+
});
|
1033
|
+
}
|
1034
|
+
destroy(all) {
|
785
1035
|
this.stopVideo();
|
786
1036
|
super.destroy(all);
|
787
1037
|
}
|