typo3-typescript-sources 14.3.7 → 14.3.9
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.
- package/.github/workflows/sync-and-publish.yml +240 -191
- package/.last-synced-tag +1 -1
- package/README.md +13 -5
- package/adminpanel/admin-panel.ts +22 -22
- package/adminpanel/modules/cache.ts +3 -3
- package/backend/action-dispatcher.ts +8 -3
- package/backend/bookmark/bookmark-store.ts +5 -5
- package/backend/clipboard-panel.ts +2 -2
- package/backend/code-editor/element/code-mirror-element.ts +1 -1
- package/backend/code-editor/language/typoscript.ts +3 -3
- package/backend/code-editor/stream-parser/typoscript.ts +2 -2
- package/backend/color-picker.ts +2 -2
- package/backend/column-selector-button.ts +11 -8
- package/backend/context-help.ts +3 -3
- package/backend/context-menu.ts +8 -3
- package/backend/drag-tooltip.ts +9 -4
- package/backend/drag-uploader.ts +81 -89
- package/backend/element/draggable-resizable-element.ts +18 -12
- package/backend/element/icon-element.ts +2 -2
- package/backend/element/thumbnail-element.ts +2 -2
- package/backend/element-browser.ts +1 -1
- package/backend/event/consumer-scope.ts +2 -2
- package/backend/event/interaction-request-assignment.ts +1 -1
- package/backend/event/interaction-request-map.ts +3 -3
- package/backend/form-engine/container/flex-form-container-container.ts +2 -2
- package/backend/form-engine/container/flex-form-section-container.ts +1 -1
- package/backend/form-engine/container/inline-control-container.ts +14 -14
- package/backend/form-engine/element/abstract-sortable-select-items.ts +3 -3
- package/backend/form-engine/element/color-element.ts +1 -1
- package/backend/form-engine/element/datetime-element.ts +1 -1
- package/backend/form-engine/element/extra/char-counter.ts +2 -2
- package/backend/form-engine/element/extra/select-box-filter.ts +1 -1
- package/backend/form-engine/element/mfa-info-element.ts +2 -2
- package/backend/form-engine/element/online-media-form-element.ts +8 -4
- package/backend/form-engine/element/select-multiple-side-by-side-element.ts +2 -2
- package/backend/form-engine/element/select-tree.ts +3 -3
- package/backend/form-engine/element/slug-element.ts +7 -7
- package/backend/form-engine/element/suggest/result-container.ts +1 -1
- package/backend/form-engine/element/table-wizard-element.ts +4 -4
- package/backend/form-engine/inline-relation/ajax-dispatcher.ts +3 -3
- package/backend/form-engine-validation.ts +11 -5
- package/backend/form-engine.ts +19 -23
- package/backend/global-event-handler.ts +1 -1
- package/backend/hotkeys/hotkey-struct.ts +1 -1
- package/backend/hotkeys.ts +3 -3
- package/backend/image-manipulation.ts +19 -19
- package/backend/layout-module/column-restriction.ts +61 -0
- package/backend/layout-module/drag-drop.ts +16 -4
- package/backend/layout-module/paste.ts +8 -1
- package/backend/live-search/element/result/item/action/action-container.ts +1 -1
- package/backend/live-search/element/result/item/item-container.ts +4 -4
- package/backend/live-search/element/result/result-container.ts +5 -0
- package/backend/live-search/element/result/result-pagination.ts +1 -1
- package/backend/live-search/live-search.ts +2 -2
- package/backend/localization/label-provider.ts +4 -4
- package/backend/localization/localization-wizard.ts +4 -4
- package/backend/localization/steps/content-record-selection-step.ts +8 -8
- package/backend/localization/steps/handler-selection-step.ts +4 -4
- package/backend/localization/steps/mode-step.ts +4 -4
- package/backend/localization/steps/source-language-step.ts +4 -4
- package/backend/localization/steps/target-language-step.ts +4 -4
- package/backend/login-refresh.ts +1 -9
- package/backend/login.ts +2 -2
- package/backend/modal.ts +38 -5
- package/backend/module/iframe.ts +10 -0
- package/backend/module/router.ts +10 -0
- package/backend/module-menu.ts +3 -3
- package/backend/multi-record-selection-action.ts +1 -1
- package/backend/multi-record-selection-delete-action.ts +1 -1
- package/backend/multi-record-selection.ts +14 -14
- package/backend/multi-step-wizard.ts +9 -2
- package/backend/new-multiple-pages.ts +2 -2
- package/backend/new-record-wizard.ts +15 -15
- package/backend/notification.ts +90 -6
- package/backend/online-media.ts +1 -3
- package/backend/page-wizard/page-wizard.ts +2 -2
- package/backend/page-wizard/steps/doktype-step.ts +5 -5
- package/backend/pagetsconfig/pagetsconfig-includes.ts +1 -1
- package/backend/popover.ts +5 -5
- package/backend/record-download-button.ts +5 -6
- package/backend/recordlist.ts +11 -6
- package/backend/security/element/csp-reports.ts +8 -8
- package/backend/setup-module.ts +2 -2
- package/backend/sortable-table.ts +10 -4
- package/backend/storage/abstract-client-storage.ts +2 -2
- package/backend/storage/module-state-storage.ts +2 -2
- package/backend/tests/backend/utility/dom-helper-test.ts +2 -2
- package/backend/tests/fixtures/modal-autofocus.html +1 -0
- package/backend/tests/form-engine/element/extra/select-box-filter-test.ts +3 -3
- package/backend/tests/form-engine-validation-test.ts +1 -1
- package/backend/tests/modal-test.ts +91 -0
- package/backend/tests/notification-test.ts +176 -0
- package/backend/tests/tree/tree-test.ts +41 -0
- package/backend/tree/file-storage-browser.ts +1 -1
- package/backend/tree/file-storage-tree-container.ts +4 -4
- package/backend/tree/page-browser.ts +1 -1
- package/backend/tree/page-position-select.ts +1 -1
- package/backend/tree/page-tree-element.ts +9 -2
- package/backend/tree/page-tree.ts +7 -1
- package/backend/tree/tree-module-state.ts +5 -5
- package/backend/tree/tree.ts +15 -8
- package/backend/user-pass-login.ts +2 -2
- package/backend/utility/collapse-state-persister.ts +1 -1
- package/backend/utility/collapse-state-search.ts +6 -6
- package/backend/utility/dom-helper.ts +3 -3
- package/backend/utility.ts +6 -6
- package/backend/viewport/content-navigation.ts +5 -0
- package/backend/viewport/navigation-container.ts +1 -1
- package/backend/viewport/toolbar.ts +3 -3
- package/backend/window-manager.ts +2 -2
- package/backend/wizard/events/auto-advance-event.ts +6 -0
- package/backend/wizard/events/before-next-step-event.ts +6 -0
- package/backend/wizard/events/step-summary-event.ts +6 -0
- package/backend/wizard/move-content-element.ts +1 -1
- package/backend/wizard/wizard.ts +8 -10
- package/belog/backend-log.ts +2 -2
- package/beuser/permissions.ts +2 -2
- package/core/ajax/ajax-response.ts +1 -1
- package/core/ajax/input-transformer.ts +1 -1
- package/core/event/debounce-event.ts +4 -4
- package/core/event/event-interface.ts +3 -3
- package/core/event/regular-event.ts +7 -7
- package/core/event/request-animation-frame-event.ts +4 -4
- package/core/event/throttle-event.ts +4 -4
- package/core/java-script-item-processor.ts +6 -0
- package/core/referrer-refresh.ts +2 -2
- package/core/security-utility.ts +1 -1
- package/dashboard/dashboard-wizard.ts +2 -2
- package/dashboard/dashboard.ts +8 -13
- package/dashboard/wizard/steps/preset-step.ts +3 -3
- package/extensionmanager/main.ts +7 -7
- package/filelist/browse-files.ts +1 -1
- package/filelist/browse-folders.ts +2 -2
- package/filelist/file-list-dragdrop.ts +5 -5
- package/filelist/file-list-rename-handler.ts +3 -6
- package/filelist/file-list-replace-handler.ts +3 -6
- package/filelist/file-list-transfer-handler.ts +2 -2
- package/filelist/file-list.ts +8 -9
- package/form/backend/form-editor/component/date-editor.ts +4 -0
- package/form/backend/form-editor/component/form-element-selector.ts +4 -0
- package/form/backend/form-editor/inspector-component.ts +6 -6
- package/form/backend/form-editor/mediator.ts +36 -36
- package/form/backend/form-editor/modals-component.ts +115 -6
- package/form/backend/form-editor/stage-component.ts +4 -4
- package/form/backend/form-editor/view-model.ts +7 -7
- package/form/backend/form-manager/view-model.ts +5 -5
- package/form/backend/form-wizard/form-wizard.ts +2 -2
- package/form/backend/form-wizard/steps/storage-step.ts +1 -1
- package/impexp/import-export.ts +1 -1
- package/info/translation-status.ts +2 -2
- package/install/ajax/ajax-queue.ts +1 -1
- package/install/module/abstract-interactable-module.ts +2 -2
- package/install/module/environment/image-processing.ts +4 -4
- package/install/module/environment/mail-test.ts +2 -2
- package/install/module/maintenance/clear-tables.ts +3 -3
- package/install/module/maintenance/clear-typo3temp-files.ts +8 -8
- package/install/module/maintenance/create-admin.ts +3 -3
- package/install/module/maintenance/database-analyzer.ts +9 -7
- package/install/module/maintenance/language-packs.ts +4 -4
- package/install/module/maintenance/reference-index.ts +1 -1
- package/install/module/settings/change-install-tool-password.ts +1 -1
- package/install/module/settings/extension-configuration.ts +5 -5
- package/install/module/settings/features.ts +1 -1
- package/install/module/settings/local-configuration.ts +5 -5
- package/install/module/settings/presets.ts +2 -2
- package/install/module/settings/system-maintainer.ts +1 -1
- package/install/module/upgrade/extension-scanner.ts +5 -5
- package/install/module/upgrade/tca-migrations-check.ts +1 -1
- package/install/module/upgrade/upgrade-docs.ts +16 -16
- package/install/module/upgrade/upgrade-wizards.ts +7 -8
- package/install/renderable/language-packs.ts +8 -2
- package/lowlevel/query-generator.ts +2 -2
- package/package.json +2 -2
- package/redirects/event-handler.ts +6 -0
- package/rte-ckeditor/ckeditor5.ts +7 -3
- package/rte-ckeditor/legacy/ckeditor5-bundle.ts +0 -1
- package/rte-ckeditor/plugin/typo3-link.ts +7 -9
- package/rte-ckeditor/rte-link-browser.ts +1 -1
- package/rte-ckeditor/tests/ckeditor5-test.ts +68 -0
- package/scheduler/form-engine/element/timing-options-element.ts +1 -1
- package/scheduler/scheduler-add-group.ts +4 -12
- package/scheduler/scheduler.ts +2 -2
- package/styleguide/checkbox-demo.ts +1 -1
- package/tstemplate/template-analyzer.ts +1 -1
- package/viewpage/main.ts +1 -1
- package/workspaces/backend.ts +5 -5
- package/workspaces/preview.ts +41 -2
- package/workspaces/renderable/record-table.ts +95 -78
- package/workspaces/renderable/send-to-stage-form.ts +1 -1
package/backend/drag-uploader.ts
CHANGED
|
@@ -258,7 +258,7 @@ export default class DragUploader {
|
|
|
258
258
|
if (node.matches('.t3js-drag-uploader')) {
|
|
259
259
|
new DragUploader(node);
|
|
260
260
|
} else {
|
|
261
|
-
node.querySelectorAll('.t3js-drag-uploader').forEach((element
|
|
261
|
+
node.querySelectorAll<HTMLElement>('.t3js-drag-uploader').forEach((element): void => {
|
|
262
262
|
new DragUploader(element);
|
|
263
263
|
});
|
|
264
264
|
}
|
|
@@ -269,7 +269,7 @@ export default class DragUploader {
|
|
|
269
269
|
observer.observe(document, { childList: true, subtree: true });
|
|
270
270
|
|
|
271
271
|
DocumentService.ready().then((): void => {
|
|
272
|
-
document.querySelectorAll('.t3js-drag-uploader').forEach((element
|
|
272
|
+
document.querySelectorAll<HTMLElement>('.t3js-drag-uploader').forEach((element): void => {
|
|
273
273
|
new DragUploader(element);
|
|
274
274
|
});
|
|
275
275
|
});
|
|
@@ -371,7 +371,21 @@ export default class DragUploader {
|
|
|
371
371
|
* @param {FileList} files
|
|
372
372
|
*/
|
|
373
373
|
public processFiles(files: FileList): void {
|
|
374
|
-
|
|
374
|
+
const validFiles: File[] = [];
|
|
375
|
+
for (const file of Array.from(files)) {
|
|
376
|
+
const error = this.validateFile(file);
|
|
377
|
+
if (error === null) {
|
|
378
|
+
validFiles.push(file);
|
|
379
|
+
} else {
|
|
380
|
+
Notification.error(coreLabels.get('file_upload.notUploaded.title'), error);
|
|
381
|
+
}
|
|
382
|
+
}
|
|
383
|
+
this.fileInput.value = '';
|
|
384
|
+
if (validFiles.length === 0) {
|
|
385
|
+
return;
|
|
386
|
+
}
|
|
387
|
+
|
|
388
|
+
this.queueLength = validFiles.length;
|
|
375
389
|
|
|
376
390
|
if (this.fileList.parentElement.hasAttribute('hidden')) {
|
|
377
391
|
// Show the filelist (table)
|
|
@@ -385,11 +399,11 @@ export default class DragUploader {
|
|
|
385
399
|
this.overallProgressBar = document.createElement('typo3-backend-progress-bar');
|
|
386
400
|
document.body.appendChild(this.overallProgressBar);
|
|
387
401
|
this.overallProgressBar.start();
|
|
388
|
-
this.percentagePerFile = 1 /
|
|
402
|
+
this.percentagePerFile = 1 / validFiles.length;
|
|
389
403
|
|
|
390
404
|
// Check for each file if is already exist before adding it to the queue
|
|
391
405
|
const ajaxCalls: Promise<void>[] = [];
|
|
392
|
-
|
|
406
|
+
validFiles.forEach((file) => {
|
|
393
407
|
const request = new AjaxRequest(TYPO3.settings.ajaxUrls.file_exists).withQueryArguments({
|
|
394
408
|
fileName: file.name,
|
|
395
409
|
fileTarget: this.target,
|
|
@@ -418,8 +432,6 @@ export default class DragUploader {
|
|
|
418
432
|
this.overallProgressBar.done();
|
|
419
433
|
}
|
|
420
434
|
});
|
|
421
|
-
|
|
422
|
-
this.fileInput.value = '';
|
|
423
435
|
}
|
|
424
436
|
|
|
425
437
|
public fileInDropzone = (): void => {
|
|
@@ -594,7 +606,7 @@ export default class DragUploader {
|
|
|
594
606
|
this.askForOverride[index].action = <Action>select.value;
|
|
595
607
|
}
|
|
596
608
|
} else {
|
|
597
|
-
modal.querySelectorAll('.t3js-actions').forEach((select
|
|
609
|
+
modal.querySelectorAll<HTMLSelectElement>('.t3js-actions').forEach((select) => select.disabled = false);
|
|
598
610
|
}
|
|
599
611
|
}).delegateTo(modal, '.t3js-actions-all');
|
|
600
612
|
|
|
@@ -631,6 +643,37 @@ export default class DragUploader {
|
|
|
631
643
|
document.dispatchEvent(new CustomEvent(uploadFinishedEventName));
|
|
632
644
|
});
|
|
633
645
|
}
|
|
646
|
+
|
|
647
|
+
/**
|
|
648
|
+
* @returns the reason why the file cannot be uploaded, null if it can be uploaded
|
|
649
|
+
*/
|
|
650
|
+
private validateFile(file: File): string | null {
|
|
651
|
+
const extension = file.name.split('.').pop().toLowerCase();
|
|
652
|
+
if (this.maxFileSize > 0 && file.size > this.maxFileSize) {
|
|
653
|
+
return coreLabels.get('file_upload.maxFileSizeExceeded', {
|
|
654
|
+
'0': file.name,
|
|
655
|
+
'1': FormatUtility.fileSizeAsString(this.maxFileSize),
|
|
656
|
+
});
|
|
657
|
+
}
|
|
658
|
+
if (this.fileDenyPattern && file.name.match(this.fileDenyPattern)) {
|
|
659
|
+
return coreLabels.get('file_upload.fileNotAllowed', {
|
|
660
|
+
'0': file.name,
|
|
661
|
+
});
|
|
662
|
+
}
|
|
663
|
+
if (this.filesExtensionsAllowed && !this.filesExtensionsAllowed.split(',').includes(extension)) {
|
|
664
|
+
return coreLabels.get('file_upload.notUploaded.extensionExpected', {
|
|
665
|
+
'0': file.name,
|
|
666
|
+
'1': this.filesExtensionsAllowed.split(',').join(', '),
|
|
667
|
+
});
|
|
668
|
+
}
|
|
669
|
+
if (this.filesExtensionsDisallowed && this.filesExtensionsDisallowed.split(',').includes(extension)) {
|
|
670
|
+
return coreLabels.get('file_upload.notUploaded.extensionDisallowed', {
|
|
671
|
+
'0': file.name,
|
|
672
|
+
'1': extension,
|
|
673
|
+
});
|
|
674
|
+
}
|
|
675
|
+
return null;
|
|
676
|
+
}
|
|
634
677
|
}
|
|
635
678
|
|
|
636
679
|
class FileQueueItem {
|
|
@@ -697,72 +740,41 @@ class FileQueueItem {
|
|
|
697
740
|
// set dummy file icon
|
|
698
741
|
this.iconCol.innerHTML = '<typo3-backend-icon identifier="mimetypes-other-other" />';
|
|
699
742
|
|
|
700
|
-
|
|
701
|
-
|
|
702
|
-
|
|
703
|
-
|
|
704
|
-
|
|
705
|
-
|
|
706
|
-
|
|
707
|
-
|
|
708
|
-
|
|
709
|
-
|
|
710
|
-
|
|
711
|
-
|
|
712
|
-
|
|
713
|
-
|
|
714
|
-
|
|
715
|
-
|
|
716
|
-
|
|
717
|
-
|
|
718
|
-
|
|
719
|
-
'0': this.dragUploader.filesExtensionsAllowed,
|
|
720
|
-
}));
|
|
721
|
-
this.progressBar.value = 100;
|
|
722
|
-
this.progressBar.severity = SeverityEnum.error;
|
|
723
|
-
} else if (this.isProhibitedByDisallowedExtensionsList()) {
|
|
724
|
-
this.updateMessage(coreLabels.get('file_upload.fileExtensionDisallowed', {
|
|
725
|
-
'0': this.dragUploader.filesExtensionsDisallowed,
|
|
726
|
-
}));
|
|
727
|
-
this.progressBar.value = 100;
|
|
728
|
-
this.progressBar.severity = SeverityEnum.error;
|
|
729
|
-
} else {
|
|
730
|
-
this.updateMessage('- ' + FormatUtility.fileSizeAsString(this.file.size));
|
|
731
|
-
|
|
732
|
-
const formData = new FormData();
|
|
733
|
-
formData.append('data[upload][1][target]', this.dragUploader.target);
|
|
734
|
-
formData.append('data[upload][1][data]', '1');
|
|
735
|
-
formData.append('overwriteExistingFiles', this.override);
|
|
736
|
-
formData.append('redirect', '');
|
|
737
|
-
formData.append('upload_1', this.file);
|
|
738
|
-
|
|
739
|
-
// We use XMLHttpRequest as we need the `progress` event which isn't supported by fetch()
|
|
740
|
-
const xhr = new XMLHttpRequest();
|
|
741
|
-
xhr.onreadystatechange = (): void => {
|
|
742
|
-
if (xhr.readyState === XMLHttpRequest.DONE) {
|
|
743
|
-
if (xhr.status === 200) {
|
|
744
|
-
try {
|
|
745
|
-
const response = JSON.parse(xhr.responseText);
|
|
746
|
-
if (!response.hasErrors) {
|
|
747
|
-
this.uploadSuccess(response);
|
|
748
|
-
} else {
|
|
749
|
-
this.uploadError(xhr);
|
|
750
|
-
}
|
|
751
|
-
}
|
|
752
|
-
catch {
|
|
753
|
-
// In case JSON can not be parsed, the upload failed due to server errors,
|
|
754
|
-
// e.g. "POST Content-Length exceeds limit". Just handle as upload error.
|
|
743
|
+
this.updateMessage('- ' + FormatUtility.fileSizeAsString(this.file.size));
|
|
744
|
+
|
|
745
|
+
const formData = new FormData();
|
|
746
|
+
formData.append('data[upload][1][target]', this.dragUploader.target);
|
|
747
|
+
formData.append('data[upload][1][data]', '1');
|
|
748
|
+
formData.append('overwriteExistingFiles', this.override);
|
|
749
|
+
formData.append('redirect', '');
|
|
750
|
+
formData.append('upload_1', this.file);
|
|
751
|
+
|
|
752
|
+
// We use XMLHttpRequest as we need the `progress` event which isn't supported by fetch()
|
|
753
|
+
const xhr = new XMLHttpRequest();
|
|
754
|
+
xhr.onreadystatechange = (): void => {
|
|
755
|
+
if (xhr.readyState === XMLHttpRequest.DONE) {
|
|
756
|
+
if (xhr.status === 200) {
|
|
757
|
+
try {
|
|
758
|
+
const response = JSON.parse(xhr.responseText);
|
|
759
|
+
if (!response.hasErrors) {
|
|
760
|
+
this.uploadSuccess(response);
|
|
761
|
+
} else {
|
|
755
762
|
this.uploadError(xhr);
|
|
756
763
|
}
|
|
757
|
-
}
|
|
764
|
+
}
|
|
765
|
+
catch {
|
|
766
|
+
// In case JSON can not be parsed, the upload failed due to server errors,
|
|
767
|
+
// e.g. "POST Content-Length exceeds limit". Just handle as upload error.
|
|
758
768
|
this.uploadError(xhr);
|
|
759
769
|
}
|
|
770
|
+
} else {
|
|
771
|
+
this.uploadError(xhr);
|
|
760
772
|
}
|
|
761
|
-
}
|
|
762
|
-
|
|
763
|
-
|
|
764
|
-
|
|
765
|
-
|
|
773
|
+
}
|
|
774
|
+
};
|
|
775
|
+
xhr.upload.addEventListener('progress', (e: ProgressEvent) => this.updateProgress(e));
|
|
776
|
+
xhr.open('POST', TYPO3.settings.ajaxUrls.file_process);
|
|
777
|
+
xhr.send(formData);
|
|
766
778
|
}
|
|
767
779
|
|
|
768
780
|
/**
|
|
@@ -925,26 +937,6 @@ class FileQueueItem {
|
|
|
925
937
|
this.row.append(document.createElement('td'));
|
|
926
938
|
}
|
|
927
939
|
}
|
|
928
|
-
|
|
929
|
-
public isProhibitedByAllowedExtensionsList(): boolean {
|
|
930
|
-
if (!this.dragUploader.filesExtensionsAllowed) {
|
|
931
|
-
return false;
|
|
932
|
-
}
|
|
933
|
-
const extension = this.file.name.split('.').pop();
|
|
934
|
-
const allowed = this.dragUploader.filesExtensionsAllowed.split(',');
|
|
935
|
-
|
|
936
|
-
return !allowed.includes(extension.toLowerCase());
|
|
937
|
-
}
|
|
938
|
-
|
|
939
|
-
public isProhibitedByDisallowedExtensionsList(): boolean {
|
|
940
|
-
if (!this.dragUploader.filesExtensionsDisallowed) {
|
|
941
|
-
return false;
|
|
942
|
-
}
|
|
943
|
-
const extension = this.file.name.split('.').pop();
|
|
944
|
-
const disallowed = this.dragUploader.filesExtensionsDisallowed.split(',');
|
|
945
|
-
|
|
946
|
-
return disallowed.includes(extension.toLowerCase());
|
|
947
|
-
}
|
|
948
940
|
}
|
|
949
941
|
|
|
950
942
|
DragUploader.init();
|
|
@@ -94,22 +94,22 @@ export class DraggableResizableElement extends LitElement {
|
|
|
94
94
|
|
|
95
95
|
public override connectedCallback(): void {
|
|
96
96
|
super.connectedCallback();
|
|
97
|
-
this.pointerEventNames.pointerDown.forEach((name
|
|
98
|
-
document.addEventListener(name, this.handleStart, true));
|
|
99
|
-
this.pointerEventNames.pointerMove.forEach((name
|
|
100
|
-
document.addEventListener(name, this.handleUpdate, true));
|
|
101
|
-
this.pointerEventNames.pointerUp.forEach((name
|
|
102
|
-
document.addEventListener(name, this.handleFinish, true));
|
|
97
|
+
this.pointerEventNames.pointerDown.forEach((name): void =>
|
|
98
|
+
document.addEventListener(name, this.handleStart as EventListener, true));
|
|
99
|
+
this.pointerEventNames.pointerMove.forEach((name): void =>
|
|
100
|
+
document.addEventListener(name, this.handleUpdate as EventListener, true));
|
|
101
|
+
this.pointerEventNames.pointerUp.forEach((name): void =>
|
|
102
|
+
document.addEventListener(name, this.handleFinish as EventListener, true));
|
|
103
103
|
}
|
|
104
104
|
|
|
105
105
|
public override disconnectedCallback(): void {
|
|
106
106
|
super.disconnectedCallback();
|
|
107
|
-
this.pointerEventNames.pointerDown.forEach((name
|
|
108
|
-
document.removeEventListener(name, this.handleStart, true));
|
|
109
|
-
this.pointerEventNames.pointerMove.forEach((name
|
|
110
|
-
document.removeEventListener(name, this.handleUpdate, true));
|
|
111
|
-
this.pointerEventNames.pointerUp.forEach((name
|
|
112
|
-
document.removeEventListener(name, this.handleFinish, true));
|
|
107
|
+
this.pointerEventNames.pointerDown.forEach((name): void =>
|
|
108
|
+
document.removeEventListener(name, this.handleStart as EventListener, true));
|
|
109
|
+
this.pointerEventNames.pointerMove.forEach((name): void =>
|
|
110
|
+
document.removeEventListener(name, this.handleUpdate as EventListener, true));
|
|
111
|
+
this.pointerEventNames.pointerUp.forEach((name): void =>
|
|
112
|
+
document.removeEventListener(name, this.handleFinish as EventListener, true));
|
|
113
113
|
}
|
|
114
114
|
|
|
115
115
|
protected override render(): TemplateResult {
|
|
@@ -246,4 +246,10 @@ declare global {
|
|
|
246
246
|
interface HTMLElementTagNameMap {
|
|
247
247
|
'typo3-backend-draggable-resizable': DraggableResizableElement;
|
|
248
248
|
}
|
|
249
|
+
|
|
250
|
+
interface HTMLElementEventMap {
|
|
251
|
+
'draggable-resizable-started': DraggableResizableEvent;
|
|
252
|
+
'draggable-resizable-updated': DraggableResizableEvent;
|
|
253
|
+
'draggable-resizable-finished': DraggableResizableEvent;
|
|
254
|
+
}
|
|
249
255
|
}
|
|
@@ -48,10 +48,10 @@ export class IconElement extends LitElement {
|
|
|
48
48
|
@property({ type: String }) raw?: string = null;
|
|
49
49
|
|
|
50
50
|
private readonly iconTask = new Task(this, {
|
|
51
|
-
task: async ([identifier, size, overlay, state, markup]
|
|
51
|
+
task: async ([identifier, size, overlay, state, markup], { signal }): Promise<string> => {
|
|
52
52
|
return await Icons.getIcon(identifier, size, overlay, state, markup, signal);
|
|
53
53
|
},
|
|
54
|
-
args: () => [this.identifier, this.size, this.overlay, this.state, this.markup]
|
|
54
|
+
args: () => [this.identifier, this.size, this.overlay, this.state, this.markup] as const
|
|
55
55
|
});
|
|
56
56
|
|
|
57
57
|
protected override render(): TemplateResult | symbol {
|
|
@@ -34,7 +34,7 @@ export class ThumbnailElement extends LitElement {
|
|
|
34
34
|
@property({ type: Number, reflect: true }) height: number;
|
|
35
35
|
|
|
36
36
|
private readonly thumbnailTask = new Task(this, {
|
|
37
|
-
task: async ([url, size, keepAspectRatio, width, height]
|
|
37
|
+
task: async ([url, size, keepAspectRatio, width, height]): Promise<TemplateResult> => {
|
|
38
38
|
const thumbnailUrl = new URL(url, window.origin);
|
|
39
39
|
thumbnailUrl.searchParams.set('size', size);
|
|
40
40
|
thumbnailUrl.searchParams.set('keepAspectRatio', keepAspectRatio ? '1' : '0');
|
|
@@ -60,7 +60,7 @@ export class ThumbnailElement extends LitElement {
|
|
|
60
60
|
}));
|
|
61
61
|
return html`${img}`;
|
|
62
62
|
},
|
|
63
|
-
args: () => [this.url, this.size, this.keepAspectRatio, this.width, this.height]
|
|
63
|
+
args: () => [this.url, this.size, this.keepAspectRatio, this.width, this.height] as const
|
|
64
64
|
});
|
|
65
65
|
|
|
66
66
|
protected override createRenderRoot(): HTMLElement | ShadowRoot {
|
|
@@ -79,7 +79,7 @@ class ElementBrowser {
|
|
|
79
79
|
const isInModalFrame = typeof window.frames !== 'undefined'
|
|
80
80
|
&& typeof window.frames.frameElement !== 'undefined'
|
|
81
81
|
&& window.frames.frameElement.classList.contains('t3js-modal-iframe');
|
|
82
|
-
const otherModalFrames = Array.from(top.frames || []).filter((item
|
|
82
|
+
const otherModalFrames = Array.from(top.frames || []).filter((item) => {
|
|
83
83
|
try {
|
|
84
84
|
return typeof item.frameElement !== 'undefined'
|
|
85
85
|
&& item.frameElement.classList.contains('t3js-modal-iframe')
|
|
@@ -33,14 +33,14 @@ class ConsumerScope {
|
|
|
33
33
|
|
|
34
34
|
public detach(consumer: Consumable): void {
|
|
35
35
|
this.consumers = this.consumers.filter(
|
|
36
|
-
(currentConsumer
|
|
36
|
+
(currentConsumer) => currentConsumer !== consumer,
|
|
37
37
|
);
|
|
38
38
|
}
|
|
39
39
|
|
|
40
40
|
public async invoke(request: InteractionRequest): Promise<void> {
|
|
41
41
|
const promises: Promise<void>[] = [];
|
|
42
42
|
this.consumers.forEach(
|
|
43
|
-
(consumer
|
|
43
|
+
(consumer) => {
|
|
44
44
|
const promise: Promise<void> = consumer.consume.call(consumer, request);
|
|
45
45
|
if (promise) {
|
|
46
46
|
promises.push(promise);
|
|
@@ -17,7 +17,7 @@ import type { InteractionRequestAssignment, PromiseControls } from './interactio
|
|
|
17
17
|
class InteractionRequestMap {
|
|
18
18
|
private assignments: InteractionRequestAssignment[] = [];
|
|
19
19
|
|
|
20
|
-
public attachFor(request: InteractionRequest, deferred: PromiseControls<
|
|
20
|
+
public attachFor(request: InteractionRequest, deferred: PromiseControls<never>): void {
|
|
21
21
|
let targetAssignment: InteractionRequestAssignment = this.getFor(request);
|
|
22
22
|
if (targetAssignment === null) {
|
|
23
23
|
targetAssignment = { request, deferreds: [] };
|
|
@@ -29,14 +29,14 @@ class InteractionRequestMap {
|
|
|
29
29
|
public detachFor(request: InteractionRequest): void {
|
|
30
30
|
const targetAssignment = this.getFor(request);
|
|
31
31
|
this.assignments = this.assignments.filter(
|
|
32
|
-
(assignment
|
|
32
|
+
(assignment) => assignment === targetAssignment,
|
|
33
33
|
);
|
|
34
34
|
}
|
|
35
35
|
|
|
36
36
|
public getFor(triggerEvent: InteractionRequest): InteractionRequestAssignment | null {
|
|
37
37
|
let targetAssignment: InteractionRequestAssignment = null;
|
|
38
38
|
this.assignments.some(
|
|
39
|
-
(assignment
|
|
39
|
+
(assignment) => {
|
|
40
40
|
if (assignment.request === triggerEvent) {
|
|
41
41
|
targetAssignment = assignment;
|
|
42
42
|
return true;
|
|
@@ -135,7 +135,7 @@ class FlexFormContainerContainer {
|
|
|
135
135
|
}
|
|
136
136
|
|
|
137
137
|
private registerPanelToggle(): void {
|
|
138
|
-
['hide.bs.collapse', 'show.bs.collapse'].forEach((eventName
|
|
138
|
+
['hide.bs.collapse', 'show.bs.collapse'].forEach((eventName): void => {
|
|
139
139
|
new RegularEvent(eventName, (e: Event): void => {
|
|
140
140
|
if (e.target !== this.containerContent) {
|
|
141
141
|
return;
|
|
@@ -147,7 +147,7 @@ class FlexFormContainerContainer {
|
|
|
147
147
|
}
|
|
148
148
|
|
|
149
149
|
private registerPreviewUpdate(): void {
|
|
150
|
-
['input', 'change'].forEach((eventName
|
|
150
|
+
['input', 'change'].forEach((eventName): void => {
|
|
151
151
|
new RegularEvent(eventName, (): void => {
|
|
152
152
|
this.generatePreview();
|
|
153
153
|
}).delegateTo(this.containerContent, 'input[type="text"], textarea');
|
|
@@ -98,7 +98,7 @@ class FlexFormSectionContainer {
|
|
|
98
98
|
|
|
99
99
|
private readonly updateSorting = (e: Sortable.SortableEvent): void => {
|
|
100
100
|
const actionFields: NodeListOf<HTMLInputElement> = this.container.querySelectorAll(Selectors.actionFieldSelector);
|
|
101
|
-
actionFields.forEach((element
|
|
101
|
+
actionFields.forEach((element, key): void => {
|
|
102
102
|
element.value = key.toString();
|
|
103
103
|
});
|
|
104
104
|
|
|
@@ -161,7 +161,7 @@ class InlineControlContainer extends HTMLElement {
|
|
|
161
161
|
}
|
|
162
162
|
|
|
163
163
|
private static getValuesFromHashMap(hashmap: UniqueDefinitionCollection): Array<any> {
|
|
164
|
-
return Object.keys(hashmap).map((key
|
|
164
|
+
return Object.keys(hashmap).map((key) => hashmap[key]);
|
|
165
165
|
}
|
|
166
166
|
|
|
167
167
|
private static selectOptionValueExists(selectElement: HTMLSelectElement, value: string): boolean {
|
|
@@ -449,10 +449,10 @@ class InlineControlContainer extends HTMLElement {
|
|
|
449
449
|
* @param {string} afterUid
|
|
450
450
|
*/
|
|
451
451
|
private async importRecord(params: Array<any>, afterUid?: string): Promise<void> {
|
|
452
|
-
return this.ajaxDispatcher.send(
|
|
452
|
+
return this.ajaxDispatcher.send<InlineResponseInterface>(
|
|
453
453
|
this.ajaxDispatcher.newRequest(this.ajaxDispatcher.getEndpoint(this.endpoints.create)),
|
|
454
454
|
params,
|
|
455
|
-
).then(async (response
|
|
455
|
+
).then(async (response): Promise<void> => {
|
|
456
456
|
if (this.isBelowMax()) {
|
|
457
457
|
this.createRecord(
|
|
458
458
|
response.compilerInput.uid,
|
|
@@ -553,10 +553,10 @@ class InlineControlContainer extends HTMLElement {
|
|
|
553
553
|
return;
|
|
554
554
|
}
|
|
555
555
|
|
|
556
|
-
this.ajaxDispatcher.send(
|
|
556
|
+
this.ajaxDispatcher.send<InlineResponseInterface>(
|
|
557
557
|
this.ajaxDispatcher.newRequest(this.ajaxDispatcher.getEndpoint(this.endpoints.synchronizelocalize)),
|
|
558
558
|
[this.objectGroup, targetElement.dataset.type],
|
|
559
|
-
).then(async (response
|
|
559
|
+
).then(async (response): Promise<void> => {
|
|
560
560
|
this.recordsContainer.insertAdjacentHTML('beforeend', response.data);
|
|
561
561
|
|
|
562
562
|
const objectIdPrefix = this.objectGroup + Separators.structureSeparator;
|
|
@@ -617,9 +617,9 @@ class InlineControlContainer extends HTMLElement {
|
|
|
617
617
|
|
|
618
618
|
if (!isLoading) {
|
|
619
619
|
const ajaxRequest = this.ajaxDispatcher.newRequest(this.ajaxDispatcher.getEndpoint(this.endpoints.details));
|
|
620
|
-
const request = this.ajaxDispatcher.send(ajaxRequest, [objectId]);
|
|
620
|
+
const request = this.ajaxDispatcher.send<InlineResponseInterface>(ajaxRequest, [objectId]);
|
|
621
621
|
|
|
622
|
-
request.then(async (response
|
|
622
|
+
request.then(async (response): Promise<void> => {
|
|
623
623
|
delete this.requestQueue[objectId];
|
|
624
624
|
delete this.progressQueue[objectId];
|
|
625
625
|
|
|
@@ -762,7 +762,7 @@ class InlineControlContainer extends HTMLElement {
|
|
|
762
762
|
const currentRecordContainer = this.getRecordContainer(objectId);
|
|
763
763
|
const recordUid = currentRecordContainer.dataset.objectUid;
|
|
764
764
|
const recordListContainer = this.recordsContainer;
|
|
765
|
-
const records = Array.from(recordListContainer.children).map((child
|
|
765
|
+
const records = Array.from(recordListContainer.children as HTMLCollectionOf<HTMLElement>).map((child) => child.dataset.objectUid);
|
|
766
766
|
const position = records.indexOf(recordUid);
|
|
767
767
|
let isChanged = false;
|
|
768
768
|
|
|
@@ -795,8 +795,8 @@ class InlineControlContainer extends HTMLElement {
|
|
|
795
795
|
}
|
|
796
796
|
|
|
797
797
|
const recordListContainer = this.recordsContainer;
|
|
798
|
-
const records = Array.from(recordListContainer.querySelectorAll(selector`[data-object-parent-group="${this.objectGroup}"][data-placeholder-record="0"]`))
|
|
799
|
-
.map((child
|
|
798
|
+
const records = Array.from(recordListContainer.querySelectorAll<HTMLElement>(selector`[data-object-parent-group="${this.objectGroup}"][data-placeholder-record="0"]`))
|
|
799
|
+
.map((child) => child.dataset.objectUid);
|
|
800
800
|
|
|
801
801
|
(<HTMLInputElement>formField).value = records.join(',');
|
|
802
802
|
FormEngine.markFieldAsChanged(formField);
|
|
@@ -841,12 +841,12 @@ class InlineControlContainer extends HTMLElement {
|
|
|
841
841
|
* @param {boolean} visible
|
|
842
842
|
*/
|
|
843
843
|
private toggleContainerControls(visible: boolean): void {
|
|
844
|
-
const controlContainer = this.querySelectorAll(
|
|
844
|
+
const controlContainer = this.querySelectorAll<HTMLElement>(
|
|
845
845
|
':scope > ' + Selectors.controlContainer
|
|
846
846
|
);
|
|
847
|
-
controlContainer.forEach((container
|
|
847
|
+
controlContainer.forEach((container): void => {
|
|
848
848
|
const controlContainerButtons = container.querySelectorAll<HTMLButtonElement | HTMLAnchorElement>('button, a');
|
|
849
|
-
controlContainerButtons.forEach((button
|
|
849
|
+
controlContainerButtons.forEach((button): void => {
|
|
850
850
|
button.hidden = !visible;
|
|
851
851
|
});
|
|
852
852
|
});
|
|
@@ -912,7 +912,7 @@ class InlineControlContainer extends HTMLElement {
|
|
|
912
912
|
return;
|
|
913
913
|
}
|
|
914
914
|
|
|
915
|
-
records.forEach((recordUid
|
|
915
|
+
records.forEach((recordUid, index): void => {
|
|
916
916
|
const recordContainer = this.getRecordContainer(objectId + Separators.structureSeparator + recordUid);
|
|
917
917
|
if (recordContainer === null) {
|
|
918
918
|
return;
|
|
@@ -25,7 +25,7 @@ export abstract class AbstractSortableSelectItems {
|
|
|
25
25
|
* @param {HTMLSelectElement} fieldElement
|
|
26
26
|
*/
|
|
27
27
|
private static moveOptionToTop(fieldElement: HTMLSelectElement): void {
|
|
28
|
-
Array.from(fieldElement.querySelectorAll(':checked')).reverse().forEach((optionEl
|
|
28
|
+
Array.from(fieldElement.querySelectorAll<HTMLOptionElement>(':checked')).reverse().forEach((optionEl): void => {
|
|
29
29
|
fieldElement.insertBefore(optionEl, fieldElement.firstElementChild);
|
|
30
30
|
});
|
|
31
31
|
}
|
|
@@ -36,7 +36,7 @@ export abstract class AbstractSortableSelectItems {
|
|
|
36
36
|
* @param {HTMLSelectElement} fieldElement
|
|
37
37
|
*/
|
|
38
38
|
private static moveOptionToBottom(fieldElement: HTMLSelectElement): void {
|
|
39
|
-
fieldElement.querySelectorAll(':checked').forEach((optionEl
|
|
39
|
+
fieldElement.querySelectorAll<HTMLOptionElement>(':checked').forEach((optionEl): void => {
|
|
40
40
|
fieldElement.insertBefore(optionEl, null);
|
|
41
41
|
});
|
|
42
42
|
}
|
|
@@ -85,7 +85,7 @@ export abstract class AbstractSortableSelectItems {
|
|
|
85
85
|
*/
|
|
86
86
|
private static removeOption(fieldElement: HTMLSelectElement, availableFieldElement: HTMLSelectElement): void {
|
|
87
87
|
const previousSelectIndex = fieldElement.selectedIndex;
|
|
88
|
-
fieldElement.querySelectorAll(':checked').forEach((option
|
|
88
|
+
fieldElement.querySelectorAll<HTMLOptionElement>(':checked').forEach((option): void => {
|
|
89
89
|
const originalOption = <HTMLOptionElement>availableFieldElement.querySelector(selector`option[value="${option.value}"]`);
|
|
90
90
|
if (originalOption !== null) {
|
|
91
91
|
originalOption.classList.remove('hidden');
|
|
@@ -72,7 +72,7 @@ class ColorElement extends HTMLElement {
|
|
|
72
72
|
FormEngineValidation.validateField(e.target as HTMLInputElement);
|
|
73
73
|
FormEngine.markFieldAsChanged(e.target as HTMLInputElement);
|
|
74
74
|
|
|
75
|
-
document.querySelectorAll('.module-docheader-bar .btn').forEach((btn
|
|
75
|
+
document.querySelectorAll<HTMLButtonElement>('.module-docheader-bar .btn').forEach((btn): void => {
|
|
76
76
|
btn.classList.remove('disabled');
|
|
77
77
|
btn.disabled = false;
|
|
78
78
|
});
|
|
@@ -56,7 +56,7 @@ class DatetimeElement extends HTMLElement {
|
|
|
56
56
|
FormEngineValidation.validateField(e.target as HTMLInputElement);
|
|
57
57
|
FormEngine.markFieldAsChanged(e.target as HTMLInputElement);
|
|
58
58
|
|
|
59
|
-
document.querySelectorAll('.module-docheader-bar .btn').forEach((btn
|
|
59
|
+
document.querySelectorAll<HTMLButtonElement>('.module-docheader-bar .btn').forEach((btn): void => {
|
|
60
60
|
btn.classList.remove('disabled');
|
|
61
61
|
btn.disabled = false;
|
|
62
62
|
});
|
|
@@ -73,11 +73,11 @@ export class CharCounter extends LitElement {
|
|
|
73
73
|
this.targetElement.removeEventListener('blur', this.onBlur);
|
|
74
74
|
}
|
|
75
75
|
|
|
76
|
-
private readonly onInput = (e:
|
|
76
|
+
private readonly onInput = (e: Event): void => {
|
|
77
77
|
this.determineRemainingCharacters(e.target as HTMLInputElement|HTMLTextAreaElement);
|
|
78
78
|
};
|
|
79
79
|
|
|
80
|
-
private readonly onFocus = (e:
|
|
80
|
+
private readonly onFocus = (e: Event): void => {
|
|
81
81
|
this.determineRemainingCharacters(e.target as HTMLInputElement|HTMLTextAreaElement);
|
|
82
82
|
this.hidden = false;
|
|
83
83
|
};
|
|
@@ -82,7 +82,7 @@ class SelectBoxFilter {
|
|
|
82
82
|
// A plain substring match, no RegExp involved, therefore nothing to escape either
|
|
83
83
|
const foldedFilterText = TextNormalizer.foldCaseAndDiacritics(TextNormalizer.normalizeInvisibleCharacters(filterText));
|
|
84
84
|
|
|
85
|
-
this.availableOptions.forEach((option
|
|
85
|
+
this.availableOptions.forEach((option, index): void => {
|
|
86
86
|
option.hidden = filterText.length > 0 && !this.foldedLabels[index].includes(foldedFilterText);
|
|
87
87
|
SelectBoxFilter.toggleOptGroup(option);
|
|
88
88
|
});
|
|
@@ -71,7 +71,7 @@ class MfaInfoElement {
|
|
|
71
71
|
this.prepareDeactivateRequest(this.deactivteMfaButton);
|
|
72
72
|
}).bindTo(this.deactivteMfaButton);
|
|
73
73
|
|
|
74
|
-
this.deactivteProviderButtons.forEach((buttonElement
|
|
74
|
+
this.deactivteProviderButtons.forEach((buttonElement): void => {
|
|
75
75
|
new RegularEvent('click', (e: Event): void => {
|
|
76
76
|
e.preventDefault();
|
|
77
77
|
this.prepareDeactivateRequest(buttonElement);
|
|
@@ -120,7 +120,7 @@ class MfaInfoElement {
|
|
|
120
120
|
}).then(async (response: AjaxResponse): Promise<void> => {
|
|
121
121
|
const data: Response = await response.resolve();
|
|
122
122
|
if (data.status.length > 0) {
|
|
123
|
-
data.status.forEach((status
|
|
123
|
+
data.status.forEach((status): void => {
|
|
124
124
|
if (data.success) {
|
|
125
125
|
Notification.success(status.title, status.message);
|
|
126
126
|
} else {
|
|
@@ -30,14 +30,14 @@ export class OnlineMediaFormElement extends LitElement {
|
|
|
30
30
|
|
|
31
31
|
protected override render(): TemplateResult {
|
|
32
32
|
return html`
|
|
33
|
-
<form @submit="${ this.dispatchSubmitEvent }">
|
|
33
|
+
<form id="online-media-form" @submit="${ this.dispatchSubmitEvent }">
|
|
34
34
|
<div class="form-control-wrap">
|
|
35
|
-
<input type="text" class="form-control" name="online-media-url" placeholder="${this.placeholder}" required>
|
|
35
|
+
<input type="text" class="form-control" name="online-media-url" placeholder="${this.placeholder}" required autofocus>
|
|
36
36
|
<div class="form-text">
|
|
37
37
|
${this.allowedExtensionsHelpText}<br>
|
|
38
38
|
<ul class="badge-list">
|
|
39
|
-
${this.allowedExtensions.split(',').map((ext
|
|
40
|
-
<li><span class="badge badge-secondary">${ext.trim().
|
|
39
|
+
${this.allowedExtensions.split(',').map((ext) => html`
|
|
40
|
+
<li><span class="badge badge-secondary">${ext.trim().toLowerCase()}</span></li>
|
|
41
41
|
`)}
|
|
42
42
|
</ul>
|
|
43
43
|
</div>
|
|
@@ -62,4 +62,8 @@ declare global {
|
|
|
62
62
|
interface HTMLElementTagNameMap {
|
|
63
63
|
'typo3-backend-formengine-online-media-form': OnlineMediaFormElement;
|
|
64
64
|
}
|
|
65
|
+
|
|
66
|
+
interface HTMLElementEventMap {
|
|
67
|
+
'typo3:formengine:online-media-added': CustomEvent<{ file: number }>;
|
|
68
|
+
}
|
|
65
69
|
}
|
|
@@ -52,9 +52,9 @@ class SelectMultipleSideBySideElement extends AbstractSortableSelectItems {
|
|
|
52
52
|
const fieldName = element.dataset.relatedfieldname;
|
|
53
53
|
if (fieldName) {
|
|
54
54
|
const exclusiveValues = Utility.trimExplode(',', element.dataset?.exclusivevalues ?? '');
|
|
55
|
-
const selectedOptions = element.querySelectorAll('option:checked'); // Yep, :checked finds selected options
|
|
55
|
+
const selectedOptions = element.querySelectorAll<HTMLOptionElement>('option:checked'); // Yep, :checked finds selected options
|
|
56
56
|
if (selectedOptions.length > 0) {
|
|
57
|
-
selectedOptions.forEach((optionElement
|
|
57
|
+
selectedOptions.forEach((optionElement): void => {
|
|
58
58
|
FormEngine.setSelectOptionFromExternalSource(
|
|
59
59
|
fieldName,
|
|
60
60
|
optionElement.value,
|