typo3-typescript-sources 13.4.20
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 +265 -0
- package/.last-synced-tag +1 -0
- package/LICENSE.txt +339 -0
- package/README-TYPO3.md +166 -0
- package/README.md +28 -0
- package/adminpanel/admin-panel.ts +375 -0
- package/adminpanel/modules/cache.ts +27 -0
- package/adminpanel/modules/preview.ts +75 -0
- package/backend/action-button/abstract-action.ts +22 -0
- package/backend/action-button/deferred-action.ts +41 -0
- package/backend/action-button/immediate-action.ts +31 -0
- package/backend/action-dispatcher.ts +104 -0
- package/backend/ajax-data-handler/message-interface.ts +18 -0
- package/backend/ajax-data-handler/response-interface.ts +20 -0
- package/backend/ajax-data-handler.ts +214 -0
- package/backend/backend-exception.ts +22 -0
- package/backend/broadcast-message.ts +50 -0
- package/backend/broadcast-service.ts +52 -0
- package/backend/browse-database.ts +38 -0
- package/backend/clear-cache.ts +88 -0
- package/backend/clipboard-panel.ts +240 -0
- package/backend/close-current-window.ts +2 -0
- package/backend/code-editor/autocomplete/completion-result.ts +105 -0
- package/backend/code-editor/autocomplete/ts-code-completion.ts +142 -0
- package/backend/code-editor/autocomplete/ts-parser.ts +485 -0
- package/backend/code-editor/autocomplete/ts-ref.ts +164 -0
- package/backend/code-editor/element/code-mirror-element.ts +282 -0
- package/backend/code-editor/language/typoscript.ts +181 -0
- package/backend/code-editor/stream-parser/typoscript.ts +1600 -0
- package/backend/color-picker.ts +158 -0
- package/backend/color-scheme-switch.ts +179 -0
- package/backend/column-selector-button.ts +302 -0
- package/backend/context-help.ts +68 -0
- package/backend/context-menu-actions.ts +322 -0
- package/backend/context-menu.ts +751 -0
- package/backend/copy-to-clipboard.ts +79 -0
- package/backend/date-time-picker.ts +270 -0
- package/backend/document-save-actions.ts +159 -0
- package/backend/drag-tooltip.ts +285 -0
- package/backend/drag-uploader.ts +914 -0
- package/backend/element/alert-element.ts +116 -0
- package/backend/element/dispatch-modal-button.ts +50 -0
- package/backend/element/draggable-resizable-element.ts +249 -0
- package/backend/element/editable-page-title.ts +306 -0
- package/backend/element/icon-element.ts +84 -0
- package/backend/element/immediate-action-element.ts +89 -0
- package/backend/element/pagination.ts +59 -0
- package/backend/element/progress-bar-element.ts +172 -0
- package/backend/element/progress-tracker-element.ts +119 -0
- package/backend/element/pseudo-button.ts +58 -0
- package/backend/element/spinner-element.ts +51 -0
- package/backend/element/thumbnail-element.ts +80 -0
- package/backend/element-browser.ts +182 -0
- package/backend/enum/data-transfer-types.ts +21 -0
- package/backend/enum/icon-types.ts +31 -0
- package/backend/enum/key-types.ts +27 -0
- package/backend/enum/severity.ts +20 -0
- package/backend/enum/viewport/scaffold-identifier.ts +24 -0
- package/backend/event/client-request.ts +25 -0
- package/backend/event/consumable.ts +18 -0
- package/backend/event/consumer-scope.ts +54 -0
- package/backend/event/event-dispatcher.ts +26 -0
- package/backend/event/interaction-request-assignment.ts +24 -0
- package/backend/event/interaction-request-map.ts +75 -0
- package/backend/event/interaction-request.ts +48 -0
- package/backend/event/trigger-request.ts +56 -0
- package/backend/form/submit-interceptor.ts +66 -0
- package/backend/form-engine/container/files-control-container.ts +716 -0
- package/backend/form-engine/container/flex-form-container-container.ts +166 -0
- package/backend/form-engine/container/flex-form-section-container.ts +210 -0
- package/backend/form-engine/container/inline-control-container.ts +1230 -0
- package/backend/form-engine/container/site-language-container.ts +616 -0
- package/backend/form-engine/element/abstract-sortable-select-items.ts +186 -0
- package/backend/form-engine/element/category-element.ts +160 -0
- package/backend/form-engine/element/color-element.ts +81 -0
- package/backend/form-engine/element/datetime-element.ts +66 -0
- package/backend/form-engine/element/extra/char-counter.ts +112 -0
- package/backend/form-engine/element/extra/select-box-filter.ts +85 -0
- package/backend/form-engine/element/folder-element.ts +66 -0
- package/backend/form-engine/element/group-element.ts +47 -0
- package/backend/form-engine/element/json-element.ts +52 -0
- package/backend/form-engine/element/link-element.ts +121 -0
- package/backend/form-engine/element/mfa-info-element.ts +169 -0
- package/backend/form-engine/element/modifier/resizable.ts +27 -0
- package/backend/form-engine/element/modifier/tabbable.ts +29 -0
- package/backend/form-engine/element/online-media-form-element.ts +65 -0
- package/backend/form-engine/element/password-element.ts +71 -0
- package/backend/form-engine/element/select-multiple-side-by-side-element.ts +83 -0
- package/backend/form-engine/element/select-single-element.ts +82 -0
- package/backend/form-engine/element/select-tree-element.ts +148 -0
- package/backend/form-engine/element/select-tree-toolbar.ts +118 -0
- package/backend/form-engine/element/select-tree.ts +210 -0
- package/backend/form-engine/element/slug-element.ts +243 -0
- package/backend/form-engine/element/suggest/result-container.ts +118 -0
- package/backend/form-engine/element/suggest/result-item.ts +90 -0
- package/backend/form-engine/element/table-permission-element.ts +101 -0
- package/backend/form-engine/element/table-wizard-element.ts +427 -0
- package/backend/form-engine/element/text-element.ts +52 -0
- package/backend/form-engine/element/text-table-element.ts +31 -0
- package/backend/form-engine/field-control/add-record.ts +40 -0
- package/backend/form-engine/field-control/edit-popup.ts +64 -0
- package/backend/form-engine/field-control/insert-clipboard.ts +50 -0
- package/backend/form-engine/field-control/link-popup.ts +53 -0
- package/backend/form-engine/field-control/list-module.ts +40 -0
- package/backend/form-engine/field-control/password-generator.ts +102 -0
- package/backend/form-engine/field-control/reset-selection.ts +48 -0
- package/backend/form-engine/field-wizard/localization-state-selector.ts +67 -0
- package/backend/form-engine/field-wizard/value-picker.ts +123 -0
- package/backend/form-engine/field-wizard/value-slider.ts +86 -0
- package/backend/form-engine/inline-relation/ajax-dispatcher.ts +124 -0
- package/backend/form-engine/inline-relation/inline-response-interface.ts +41 -0
- package/backend/form-engine-link-browser-adapter.ts +129 -0
- package/backend/form-engine-review.ts +155 -0
- package/backend/form-engine-suggest.ts +133 -0
- package/backend/form-engine-validation.ts +686 -0
- package/backend/form-engine.ts +1391 -0
- package/backend/global-event-handler.ts +252 -0
- package/backend/grid-editor.ts +1077 -0
- package/backend/hashing/md5.ts +252 -0
- package/backend/helper.ts +24 -0
- package/backend/hotkeys/hotkey-storage.ts +63 -0
- package/backend/hotkeys.ts +216 -0
- package/backend/icons.ts +236 -0
- package/backend/image-manipulation.ts +885 -0
- package/backend/info-window.ts +46 -0
- package/backend/input/clearable.ts +128 -0
- package/backend/input/index.d.ts +8 -0
- package/backend/java-script-module-import-event-handler.ts +19 -0
- package/backend/key-bindings.ts +42 -0
- package/backend/layout-module/drag-drop.ts +359 -0
- package/backend/layout-module/paste.ts +165 -0
- package/backend/link-browser.ts +89 -0
- package/backend/live-search/element/backend-search.ts +34 -0
- package/backend/live-search/element/hint.ts +33 -0
- package/backend/live-search/element/provider/default-result-item.ts +52 -0
- package/backend/live-search/element/provider/page-provider-result-item.ts +52 -0
- package/backend/live-search/element/result/item/action/action-container.ts +135 -0
- package/backend/live-search/element/result/item/action/action.ts +56 -0
- package/backend/live-search/element/result/item/item-container.ts +224 -0
- package/backend/live-search/element/result/item/item.ts +74 -0
- package/backend/live-search/element/result/result-container.ts +110 -0
- package/backend/live-search/element/result/result-detail-container.ts +50 -0
- package/backend/live-search/element/result/result-pagination.ts +122 -0
- package/backend/live-search/element/search-option-item.ts +70 -0
- package/backend/live-search/live-search-configurator.ts +54 -0
- package/backend/live-search/live-search-shortcut.ts +29 -0
- package/backend/live-search/result-types/backend-module-result-type.ts +8 -0
- package/backend/live-search/result-types/default-result-type.ts +21 -0
- package/backend/live-search/result-types/page-result-type.ts +23 -0
- package/backend/localization.ts +390 -0
- package/backend/login-refresh.ts +525 -0
- package/backend/login.ts +179 -0
- package/backend/mail-link-handler.ts +45 -0
- package/backend/modal-interface.ts +19 -0
- package/backend/modal.ts +685 -0
- package/backend/module/iframe.ts +125 -0
- package/backend/module/router.ts +275 -0
- package/backend/module-menu.ts +550 -0
- package/backend/module.ts +133 -0
- package/backend/multi-record-selection-action.ts +44 -0
- package/backend/multi-record-selection-delete-action.ts +108 -0
- package/backend/multi-record-selection-edit-action.ts +56 -0
- package/backend/multi-record-selection.ts +468 -0
- package/backend/multi-step-wizard.ts +568 -0
- package/backend/new-content-element-wizard-button.ts +51 -0
- package/backend/new-multiple-pages.ts +108 -0
- package/backend/new-record-wizard.ts +680 -0
- package/backend/notification.ts +366 -0
- package/backend/offset.ts +40 -0
- package/backend/online-media.ts +110 -0
- package/backend/page-actions.ts +91 -0
- package/backend/page-link-handler.ts +51 -0
- package/backend/pagetsconfig/pagetsconfig-includes.ts +77 -0
- package/backend/popover.ts +165 -0
- package/backend/record-download-button.ts +104 -0
- package/backend/record-link-handler.ts +31 -0
- package/backend/record-search.ts +44 -0
- package/backend/recordlist.ts +230 -0
- package/backend/resource/resource.ts +35 -0
- package/backend/security/element/csp-reports.ts +406 -0
- package/backend/security/element/sudo-mode.ts +249 -0
- package/backend/security/sudo-mode-interceptor.ts +19 -0
- package/backend/settings/editor/editable-setting.ts +231 -0
- package/backend/settings/editor.ts +451 -0
- package/backend/settings/enum/settings-mode.enum.ts +24 -0
- package/backend/settings/type/base.ts +200 -0
- package/backend/settings/type/bool.ts +56 -0
- package/backend/settings/type/color.ts +64 -0
- package/backend/settings/type/int.ts +85 -0
- package/backend/settings/type/number.ts +61 -0
- package/backend/settings/type/page.ts +100 -0
- package/backend/settings/type/string.ts +77 -0
- package/backend/settings/type/stringlist.ts +87 -0
- package/backend/severity.ts +88 -0
- package/backend/site-inline-actions.ts +32 -0
- package/backend/sortable-table.ts +208 -0
- package/backend/storage/abstract-client-storage.ts +76 -0
- package/backend/storage/browser-session.ts +28 -0
- package/backend/storage/client.ts +28 -0
- package/backend/storage/module-state-storage.ts +118 -0
- package/backend/storage/persistent.ts +204 -0
- package/backend/switch-user.ts +82 -0
- package/backend/tabs.ts +72 -0
- package/backend/telephone-link-handler.ts +40 -0
- package/backend/tests/backend/storage/browser-storage-test.ts +87 -0
- package/backend/tests/backend/storage/client-test.ts +87 -0
- package/backend/tests/backend/utility/dom-helper-test.ts +51 -0
- package/backend/tests/backend-exception-test.ts +28 -0
- package/backend/tests/element/immediate-action-element-test.ts +81 -0
- package/backend/tests/form-engine-validation-test.ts +304 -0
- package/backend/tests/grid-editor-test.ts +29 -0
- package/backend/tests/hashing/md5Test.ts +28 -0
- package/backend/tests/icons-test.ts +23 -0
- package/backend/tests/notification-test.ts +161 -0
- package/backend/tests/popover-test.ts +83 -0
- package/backend/toolbar/clear-cache-menu.ts +88 -0
- package/backend/toolbar/live-search.ts +284 -0
- package/backend/toolbar/shortcut-menu.ts +254 -0
- package/backend/toolbar/system-information-menu.ts +161 -0
- package/backend/toolbar.ts +41 -0
- package/backend/tree/file-storage-browser.ts +194 -0
- package/backend/tree/file-storage-tree-container.ts +465 -0
- package/backend/tree/file-storage-tree.ts +42 -0
- package/backend/tree/page-browser.ts +272 -0
- package/backend/tree/page-tree-element.ts +602 -0
- package/backend/tree/page-tree.ts +152 -0
- package/backend/tree/tree-module-state.ts +159 -0
- package/backend/tree/tree-node-toggle.ts +31 -0
- package/backend/tree/tree-node.ts +97 -0
- package/backend/tree/tree-toolbar.ts +117 -0
- package/backend/tree/tree.ts +1595 -0
- package/backend/url-link-handler.ts +36 -0
- package/backend/user-pass-login.ts +255 -0
- package/backend/user-settings-manager.ts +189 -0
- package/backend/utility/collapse-state-persister.ts +205 -0
- package/backend/utility/collapse-state-search.ts +183 -0
- package/backend/utility/dom-helper.ts +91 -0
- package/backend/utility/drag-drop-utility.ts +47 -0
- package/backend/utility/message-utility.ts +45 -0
- package/backend/utility/top-level-module-import.ts +32 -0
- package/backend/utility.ts +194 -0
- package/backend/viewport/abstract-container.ts +22 -0
- package/backend/viewport/content-container.ts +98 -0
- package/backend/viewport/loader.ts +28 -0
- package/backend/viewport/navigation-container.ts +119 -0
- package/backend/viewport/resizable-navigation.ts +176 -0
- package/backend/viewport/toolbar.ts +27 -0
- package/backend/viewport/topbar.ts +39 -0
- package/backend/viewport.ts +46 -0
- package/backend/window-manager.ts +84 -0
- package/backend/wizard/move-content-element.ts +107 -0
- package/backend/wizard/move-page.ts +74 -0
- package/backend/wizard.ts +331 -0
- package/belog/backend-log.ts +88 -0
- package/beuser/backend-user-listing.ts +40 -0
- package/beuser/permissions.ts +291 -0
- package/core/ajax/ajax-request-types.ts +15 -0
- package/core/ajax/ajax-request.ts +202 -0
- package/core/ajax/ajax-response.ts +57 -0
- package/core/ajax/input-transformer.ts +92 -0
- package/core/ajax/simple-response-interface.ts +5 -0
- package/core/authentication/mfa-provider/totp.ts +54 -0
- package/core/cache/dedupe-async-task.ts +95 -0
- package/core/directive/markdown.ts +82 -0
- package/core/directive/nl2br.ts +16 -0
- package/core/document-service.ts +35 -0
- package/core/event/debounce-event.ts +40 -0
- package/core/event/event-interface.ts +24 -0
- package/core/event/regular-event.ts +58 -0
- package/core/event/request-animation-frame-event.ts +42 -0
- package/core/event/throttle-event.ts +54 -0
- package/core/java-script-item-handler.ts +29 -0
- package/core/java-script-item-processor.ts +171 -0
- package/core/lit-helper.ts +126 -0
- package/core/literals.ts +17 -0
- package/core/referrer-refresh.ts +2 -0
- package/core/security-utility.ts +89 -0
- package/core/tests/ajax/ajax-request-test.ts +290 -0
- package/core/tests/ajax/input-transformer-test.ts +64 -0
- package/core/tests/cache/dedupe-async-task-test.ts +152 -0
- package/core/tests/event/throttle-event-test.ts +47 -0
- package/core/tests/literals-test.ts +24 -0
- package/core/tests/security-utility-test.ts +50 -0
- package/core/utility/types.ts +9 -0
- package/dashboard/chart-initializer.ts +136 -0
- package/dashboard/dashboard.ts +1487 -0
- package/extensionmanager/distribution-image.ts +55 -0
- package/extensionmanager/main.ts +291 -0
- package/extensionmanager/repository.ts +195 -0
- package/extensionmanager/update.ts +118 -0
- package/extensionmanager/upload-form.ts +42 -0
- package/filelist/browse-files.ts +148 -0
- package/filelist/browse-folders.ts +94 -0
- package/filelist/context-menu-actions.ts +335 -0
- package/filelist/create-folder.ts +69 -0
- package/filelist/file-delete.ts +69 -0
- package/filelist/file-list-actions.ts +132 -0
- package/filelist/file-list-dragdrop.ts +139 -0
- package/filelist/file-list-rename-handler.ts +128 -0
- package/filelist/file-list-transfer-handler.ts +138 -0
- package/filelist/file-list.ts +396 -0
- package/filelist/file-replace.ts +37 -0
- package/filelist/linkbrowser-file-handler.ts +94 -0
- package/filelist/linkbrowser-folder-handler.ts +74 -0
- package/filelist/rename-file.ts +109 -0
- package/form/backend/form-editor/component/property-grid-editor.ts +340 -0
- package/form/backend/form-editor/core.ts +2104 -0
- package/form/backend/form-editor/helper.ts +226 -0
- package/form/backend/form-editor/inspector-component.ts +2323 -0
- package/form/backend/form-editor/mediator.ts +941 -0
- package/form/backend/form-editor/modals-component.ts +433 -0
- package/form/backend/form-editor/stage-component.ts +908 -0
- package/form/backend/form-editor/tree-component.ts +548 -0
- package/form/backend/form-editor/view-model.ts +1343 -0
- package/form/backend/form-editor.ts +846 -0
- package/form/backend/form-manager/main.ts +39 -0
- package/form/backend/form-manager/view-model.ts +789 -0
- package/form/backend/form-manager.ts +180 -0
- package/form/backend/helper.ts +60 -0
- package/form/frontend/date-picker.ts +38 -0
- package/frontend/default_frontend.ts +82 -0
- package/impexp/context-menu-actions.ts +50 -0
- package/impexp/import-export.ts +62 -0
- package/indexed-search/pagination.ts +26 -0
- package/indexed-search/statistics.ts +50 -0
- package/info/translation-status.ts +48 -0
- package/install/ajax/ajax-queue.ts +83 -0
- package/install/init-install.ts +2 -0
- package/install/init-installer.ts +2 -0
- package/install/install.ts +25 -0
- package/install/installer.ts +458 -0
- package/install/message-interface.ts +18 -0
- package/install/module/abstract-inline-module.ts +27 -0
- package/install/module/abstract-interactable-module.ts +107 -0
- package/install/module/environment/environment-check.ts +92 -0
- package/install/module/environment/folder-structure.ts +145 -0
- package/install/module/environment/image-processing.ts +141 -0
- package/install/module/environment/mail-test.ts +127 -0
- package/install/module/environment/php-info.ts +50 -0
- package/install/module/environment/system-information.ts +50 -0
- package/install/module/maintenance/cache.ts +59 -0
- package/install/module/maintenance/clear-tables.ts +134 -0
- package/install/module/maintenance/clear-typo3temp-files.ts +137 -0
- package/install/module/maintenance/create-admin.ts +126 -0
- package/install/module/maintenance/database-analyzer.ts +266 -0
- package/install/module/maintenance/dump-autoload.ts +58 -0
- package/install/module/maintenance/language-packs.ts +338 -0
- package/install/module/maintenance/reset-backend-user-uc.ts +58 -0
- package/install/module/password-strength.ts +56 -0
- package/install/module/settings/change-install-tool-password.ts +101 -0
- package/install/module/settings/extension-configuration.ts +224 -0
- package/install/module/settings/features.ts +102 -0
- package/install/module/settings/local-configuration.ts +316 -0
- package/install/module/settings/presets.ts +147 -0
- package/install/module/settings/system-maintainer.ts +111 -0
- package/install/module/upgrade/core-update.ts +255 -0
- package/install/module/upgrade/extension-compat-tester.ts +195 -0
- package/install/module/upgrade/extension-scanner.ts +381 -0
- package/install/module/upgrade/tca-ext-tables-check.ts +93 -0
- package/install/module/upgrade/tca-migrations-check.ts +101 -0
- package/install/module/upgrade/upgrade-docs.ts +310 -0
- package/install/module/upgrade/upgrade-wizards.ts +612 -0
- package/install/renderable/clearable.ts +113 -0
- package/install/renderable/flash-message.ts +64 -0
- package/install/renderable/info-box.ts +66 -0
- package/install/renderable/language-packs.ts +304 -0
- package/install/renderable/offset-group.ts +38 -0
- package/install/renderable/severity.ts +49 -0
- package/install/renderable/wrap-group.ts +36 -0
- package/install/router.ts +468 -0
- package/linkvalidator/linkvalidator-modal.ts +45 -0
- package/linkvalidator/linkvalidator.ts +101 -0
- package/lowlevel/query-generator.ts +132 -0
- package/lowlevel/reference-index.ts +44 -0
- package/opendocs/toolbar/opendocs-menu.ts +117 -0
- package/package.json +34 -0
- package/recycler/recycler.ts +539 -0
- package/redirects/event-handler.ts +108 -0
- package/redirects/form-engine-evaluation.ts +34 -0
- package/redirects/redirects-module.ts +58 -0
- package/rte-ckeditor/ckeditor5.ts +402 -0
- package/rte-ckeditor/css-prefixer.ts +94 -0
- package/rte-ckeditor/legacy/ckeditor5-bundle.ts +17 -0
- package/rte-ckeditor/legacy/ckeditor5-inspector.ts +2 -0
- package/rte-ckeditor/plugin/typo3-link.ts +810 -0
- package/rte-ckeditor/plugin/whitespace.ts +114 -0
- package/rte-ckeditor/rte-link-browser.ts +112 -0
- package/rte-ckeditor/tests/css-prefixer-test.ts +314 -0
- package/scheduler/scheduler-add-group.ts +119 -0
- package/scheduler/scheduler-editable-group-name.ts +307 -0
- package/scheduler/scheduler-sortable-groups.ts +59 -0
- package/scheduler/scheduler.ts +466 -0
- package/setup/setup-module.ts +122 -0
- package/styleguide/checkbox-demo.ts +5 -0
- package/styleguide/element/theme-switcher-element.ts +101 -0
- package/styleguide/filter.ts +22 -0
- package/styleguide/find-icons.ts +78 -0
- package/styleguide/processing-indicator.ts +78 -0
- package/styleguide/render-notifications.ts +64 -0
- package/sys-note/element/delete-button.ts +78 -0
- package/tstemplate/constant-editor.ts +64 -0
- package/tstemplate/information-module.ts +31 -0
- package/tstemplate/template-analyzer.ts +77 -0
- package/viewpage/main.ts +253 -0
- package/workspaces/backend.ts +979 -0
- package/workspaces/preview.ts +232 -0
- package/workspaces/renderable/comment-view.ts +79 -0
- package/workspaces/renderable/diff-view.ts +58 -0
- package/workspaces/renderable/history-view.ts +97 -0
- package/workspaces/renderable/record-information.ts +118 -0
- package/workspaces/renderable/record-table.ts +355 -0
- package/workspaces/renderable/send-to-stage-form.ts +108 -0
- package/workspaces/toolbar/workspaces-menu.ts +190 -0
- package/workspaces/utility/icon-helper.ts +57 -0
- package/workspaces/workspaces.ts +136 -0
|
@@ -0,0 +1,224 @@
|
|
|
1
|
+
/*
|
|
2
|
+
* This file is part of the TYPO3 CMS project.
|
|
3
|
+
*
|
|
4
|
+
* It is free software; you can redistribute it and/or modify it under
|
|
5
|
+
* the terms of the GNU General Public License, either version 2
|
|
6
|
+
* of the License, or any later version.
|
|
7
|
+
*
|
|
8
|
+
* For the full copyright and license information, please read the
|
|
9
|
+
* LICENSE.txt file that was distributed with this source code.
|
|
10
|
+
*
|
|
11
|
+
* The TYPO3 project - inspiring people to share!
|
|
12
|
+
*/
|
|
13
|
+
|
|
14
|
+
import 'bootstrap';
|
|
15
|
+
import '../../renderable/clearable';
|
|
16
|
+
import '../../renderable/wrap-group';
|
|
17
|
+
import '../../renderable/offset-group';
|
|
18
|
+
import { AbstractInteractableModule, type ModuleLoadedResponse } from '../abstract-interactable-module';
|
|
19
|
+
import ModuleMenu from '@typo3/backend/module-menu';
|
|
20
|
+
import Notification from '@typo3/backend/notification';
|
|
21
|
+
import AjaxRequest from '@typo3/core/ajax/ajax-request';
|
|
22
|
+
import Router from '../../router';
|
|
23
|
+
import { topLevelModuleImport } from '@typo3/backend/utility/top-level-module-import';
|
|
24
|
+
import type MessageInterface from '@typo3/install/message-interface';
|
|
25
|
+
import RegularEvent from '@typo3/core/event/regular-event';
|
|
26
|
+
import { Collapse } from 'bootstrap';
|
|
27
|
+
import DebounceEvent from '@typo3/core/event/debounce-event';
|
|
28
|
+
import { KeyTypesEnum } from '@typo3/backend/enum/key-types';
|
|
29
|
+
import type { AjaxResponse } from '@typo3/core/ajax/ajax-response';
|
|
30
|
+
import type { ModalElement } from '@typo3/backend/modal';
|
|
31
|
+
|
|
32
|
+
enum Identifiers {
|
|
33
|
+
formListener = '.t3js-extensionConfiguration-form',
|
|
34
|
+
searchInput = '.t3js-extensionConfiguration-search'
|
|
35
|
+
}
|
|
36
|
+
|
|
37
|
+
type ExtensionConfigurationWrittenResponse = {
|
|
38
|
+
status: MessageInterface[],
|
|
39
|
+
success: boolean,
|
|
40
|
+
};
|
|
41
|
+
|
|
42
|
+
/**
|
|
43
|
+
* Module: @typo3/install/module/extension-configuration
|
|
44
|
+
*/
|
|
45
|
+
class ExtensionConfiguration extends AbstractInteractableModule {
|
|
46
|
+
public override initialize(currentModal: ModalElement): void {
|
|
47
|
+
super.initialize(currentModal);
|
|
48
|
+
this.getContent();
|
|
49
|
+
|
|
50
|
+
// Focus search field on certain user interactions
|
|
51
|
+
new RegularEvent('keydown', (event: KeyboardEvent) => {
|
|
52
|
+
const searchInput = currentModal.querySelector<HTMLInputElement>(Identifiers.searchInput);
|
|
53
|
+
if (event.ctrlKey || event.metaKey) {
|
|
54
|
+
// Focus search field on ctrl-f
|
|
55
|
+
if (event.key === 'f' || event.key === 'F') {
|
|
56
|
+
event.preventDefault();
|
|
57
|
+
searchInput.focus();
|
|
58
|
+
}
|
|
59
|
+
} else if (event.key === KeyTypesEnum.ESCAPE) {
|
|
60
|
+
if (searchInput.value.trim() !== '') {
|
|
61
|
+
// Clear search on ESC key otherwise close the modal
|
|
62
|
+
event.preventDefault();
|
|
63
|
+
searchInput.value = '';
|
|
64
|
+
searchInput.focus();
|
|
65
|
+
}
|
|
66
|
+
}
|
|
67
|
+
}).bindTo(currentModal);
|
|
68
|
+
|
|
69
|
+
// Perform expand collapse on search matches
|
|
70
|
+
new DebounceEvent('input', (event: Event, target: HTMLInputElement): void => {
|
|
71
|
+
const typedQuery = target.value;
|
|
72
|
+
this.search(typedQuery);
|
|
73
|
+
}, 100).delegateTo(currentModal, Identifiers.searchInput);
|
|
74
|
+
|
|
75
|
+
new RegularEvent('change', (event: Event, target: HTMLInputElement): void => {
|
|
76
|
+
const typedQuery = target.value;
|
|
77
|
+
this.search(typedQuery);
|
|
78
|
+
}).delegateTo(currentModal, Identifiers.searchInput);
|
|
79
|
+
|
|
80
|
+
new RegularEvent('submit', (event: Event, target: HTMLFormElement): void => {
|
|
81
|
+
event.preventDefault();
|
|
82
|
+
this.write(target);
|
|
83
|
+
}).delegateTo(currentModal, Identifiers.formListener);
|
|
84
|
+
}
|
|
85
|
+
|
|
86
|
+
private search(typedQuery: string): void {
|
|
87
|
+
this.currentModal.querySelectorAll('.search-item').forEach((element: Element): void => {
|
|
88
|
+
if (typedQuery === '' || element.textContent.toLowerCase().trim().includes(typedQuery.toLowerCase())) {
|
|
89
|
+
element.classList.add('searchhit');
|
|
90
|
+
element.classList.remove('hidden');
|
|
91
|
+
} else {
|
|
92
|
+
element.classList.remove('searchhit');
|
|
93
|
+
element.classList.add('hidden');
|
|
94
|
+
}
|
|
95
|
+
});
|
|
96
|
+
this.currentModal.querySelectorAll('.searchhit').forEach((resultElement: HTMLElement) => {
|
|
97
|
+
Collapse.getOrCreateInstance(resultElement).show();
|
|
98
|
+
});
|
|
99
|
+
}
|
|
100
|
+
|
|
101
|
+
private getContent(): void {
|
|
102
|
+
const modalContent = this.getModalBody();
|
|
103
|
+
(new AjaxRequest(Router.getUrl('extensionConfigurationGetContent')))
|
|
104
|
+
.get({ cache: 'no-cache' })
|
|
105
|
+
.then(
|
|
106
|
+
async (response: AjaxResponse): Promise<void> => {
|
|
107
|
+
const data: ModuleLoadedResponse = await response.resolve();
|
|
108
|
+
if (data.success === true) {
|
|
109
|
+
modalContent.innerHTML = data.html;
|
|
110
|
+
(modalContent.querySelector(Identifiers.searchInput) as HTMLInputElement).clearable();
|
|
111
|
+
this.initializeWrap();
|
|
112
|
+
this.initializeColorPicker();
|
|
113
|
+
}
|
|
114
|
+
},
|
|
115
|
+
(error: AjaxResponse): void => {
|
|
116
|
+
Router.handleAjaxError(error, modalContent);
|
|
117
|
+
}
|
|
118
|
+
);
|
|
119
|
+
}
|
|
120
|
+
|
|
121
|
+
private initializeColorPicker(): void {
|
|
122
|
+
const isInIframe = window.location !== window.parent.location;
|
|
123
|
+
if (isInIframe) {
|
|
124
|
+
topLevelModuleImport('@typo3/backend/color-picker.js');
|
|
125
|
+
} else {
|
|
126
|
+
import('@typo3/backend/color-picker');
|
|
127
|
+
}
|
|
128
|
+
}
|
|
129
|
+
|
|
130
|
+
/**
|
|
131
|
+
* Submit the form and show the result message
|
|
132
|
+
*/
|
|
133
|
+
private write(form: HTMLFormElement): void {
|
|
134
|
+
const modalContent = this.getModalBody();
|
|
135
|
+
const executeToken = this.getModuleContent().dataset.extensionConfigurationWriteToken;
|
|
136
|
+
const extensionConfiguration: Record<string, string> = {};
|
|
137
|
+
for (const [name, value] of new FormData(form)) {
|
|
138
|
+
extensionConfiguration[name] = value.toString();
|
|
139
|
+
}
|
|
140
|
+
|
|
141
|
+
(new AjaxRequest(Router.getUrl()))
|
|
142
|
+
.post({
|
|
143
|
+
install: {
|
|
144
|
+
token: executeToken,
|
|
145
|
+
action: 'extensionConfigurationWrite',
|
|
146
|
+
extensionKey: form.dataset.extensionKey,
|
|
147
|
+
extensionConfiguration: extensionConfiguration,
|
|
148
|
+
},
|
|
149
|
+
})
|
|
150
|
+
.then(
|
|
151
|
+
async (response: AjaxResponse): Promise<void> => {
|
|
152
|
+
const data: ExtensionConfigurationWrittenResponse = await response.resolve();
|
|
153
|
+
if (data.success === true && Array.isArray(data.status)) {
|
|
154
|
+
data.status.forEach((element: MessageInterface): void => {
|
|
155
|
+
Notification.showMessage(element.title, element.message, element.severity);
|
|
156
|
+
});
|
|
157
|
+
if (document.body.dataset.context === 'backend') {
|
|
158
|
+
ModuleMenu.App.refreshMenu();
|
|
159
|
+
}
|
|
160
|
+
} else {
|
|
161
|
+
Notification.error('Something went wrong', 'The request was not processed successfully. Please check the browser\'s console and TYPO3\'s log.');
|
|
162
|
+
}
|
|
163
|
+
},
|
|
164
|
+
(error: AjaxResponse): void => {
|
|
165
|
+
Router.handleAjaxError(error, modalContent);
|
|
166
|
+
}
|
|
167
|
+
);
|
|
168
|
+
}
|
|
169
|
+
|
|
170
|
+
/**
|
|
171
|
+
* configuration properties
|
|
172
|
+
*/
|
|
173
|
+
private initializeWrap(): void {
|
|
174
|
+
const isInIframe = window.location !== window.parent.location;
|
|
175
|
+
if (isInIframe) {
|
|
176
|
+
topLevelModuleImport('@typo3/install/renderable/wrap-group.js');
|
|
177
|
+
topLevelModuleImport('@typo3/install/renderable/offset-group.js');
|
|
178
|
+
}
|
|
179
|
+
|
|
180
|
+
this.currentModal.querySelectorAll('.t3js-emconf-offset').forEach((element: HTMLInputElement): void => {
|
|
181
|
+
const parent = element.parentElement;
|
|
182
|
+
|
|
183
|
+
element.setAttribute('data-offsetfield-x', '#' + element.id + '_offset_x');
|
|
184
|
+
element.setAttribute('data-offsetfield-y', '#' + element.id + '_offset_y');
|
|
185
|
+
element.classList.add('hidden');
|
|
186
|
+
|
|
187
|
+
const offsetGroup = parent.ownerDocument.createElement('typo3-install-offset-group');
|
|
188
|
+
offsetGroup.offsetId = element.id;
|
|
189
|
+
offsetGroup.values = element.value.split(',');
|
|
190
|
+
|
|
191
|
+
parent.appendChild(offsetGroup);
|
|
192
|
+
|
|
193
|
+
parent.querySelectorAll('.t3js-emconf-offsetfield').forEach((offsetField: HTMLInputElement) => {
|
|
194
|
+
new RegularEvent('keyup', (event: KeyboardEvent) => {
|
|
195
|
+
const target = parent.querySelector<HTMLInputElement>((event.currentTarget as HTMLElement).dataset.target);
|
|
196
|
+
target.value = parent.querySelector<HTMLInputElement>(target.dataset.offsetfieldX).value + ',' + parent.querySelector<HTMLInputElement>(target.dataset.offsetfieldY).value;
|
|
197
|
+
}).bindTo(offsetField);
|
|
198
|
+
});
|
|
199
|
+
});
|
|
200
|
+
|
|
201
|
+
this.currentModal.querySelectorAll('.t3js-emconf-wrap').forEach((element: HTMLInputElement): void => {
|
|
202
|
+
const parent = element.parentElement;
|
|
203
|
+
|
|
204
|
+
element.setAttribute('data-wrapfield-start', '#' + element.id + '_wrap_start');
|
|
205
|
+
element.setAttribute('data-wrapfield-end', '#' + element.id + '_wrap_end');
|
|
206
|
+
element.classList.add('hidden');
|
|
207
|
+
|
|
208
|
+
const offsetGroup = parent.ownerDocument.createElement('typo3-install-wrap-group');
|
|
209
|
+
offsetGroup.wrapId = element.id;
|
|
210
|
+
offsetGroup.values = element.value.split('|');
|
|
211
|
+
|
|
212
|
+
parent.appendChild(offsetGroup);
|
|
213
|
+
|
|
214
|
+
parent.querySelectorAll('.t3js-emconf-wrapfield').forEach((wrapField: HTMLInputElement) => {
|
|
215
|
+
new RegularEvent('keyup', (event: KeyboardEvent) => {
|
|
216
|
+
const target = parent.querySelector<HTMLInputElement>((event.currentTarget as HTMLElement).dataset.target);
|
|
217
|
+
target.value = parent.querySelector<HTMLInputElement>(target.dataset.wrapfieldStart).value + '|' + parent.querySelector<HTMLInputElement>(target.dataset.wrapfieldEnd).value;
|
|
218
|
+
}).bindTo(wrapField);
|
|
219
|
+
});
|
|
220
|
+
});
|
|
221
|
+
}
|
|
222
|
+
}
|
|
223
|
+
|
|
224
|
+
export default new ExtensionConfiguration();
|
|
@@ -0,0 +1,102 @@
|
|
|
1
|
+
/*
|
|
2
|
+
* This file is part of the TYPO3 CMS project.
|
|
3
|
+
*
|
|
4
|
+
* It is free software; you can redistribute it and/or modify it under
|
|
5
|
+
* the terms of the GNU General Public License, either version 2
|
|
6
|
+
* of the License, or any later version.
|
|
7
|
+
*
|
|
8
|
+
* For the full copyright and license information, please read the
|
|
9
|
+
* LICENSE.txt file that was distributed with this source code.
|
|
10
|
+
*
|
|
11
|
+
* The TYPO3 project - inspiring people to share!
|
|
12
|
+
*/
|
|
13
|
+
|
|
14
|
+
import { AbstractInteractableModule, type ModuleLoadedResponseWithButtons } from '../abstract-interactable-module';
|
|
15
|
+
import Modal from '@typo3/backend/modal';
|
|
16
|
+
import Notification from '@typo3/backend/notification';
|
|
17
|
+
import AjaxRequest from '@typo3/core/ajax/ajax-request';
|
|
18
|
+
import Router from '../../router';
|
|
19
|
+
import RegularEvent from '@typo3/core/event/regular-event';
|
|
20
|
+
import type { AjaxResponse } from '@typo3/core/ajax/ajax-response';
|
|
21
|
+
import type { ModalElement } from '@typo3/backend/modal';
|
|
22
|
+
import type MessageInterface from '@typo3/install/message-interface';
|
|
23
|
+
|
|
24
|
+
enum Identifiers {
|
|
25
|
+
saveTrigger = '.t3js-features-save'
|
|
26
|
+
}
|
|
27
|
+
|
|
28
|
+
type FeaturesWrittenResponse = {
|
|
29
|
+
status: MessageInterface[],
|
|
30
|
+
success: boolean,
|
|
31
|
+
};
|
|
32
|
+
|
|
33
|
+
/**
|
|
34
|
+
* Module: @typo3/install/module/features
|
|
35
|
+
*/
|
|
36
|
+
class Features extends AbstractInteractableModule {
|
|
37
|
+
public override initialize(currentModal: ModalElement): void {
|
|
38
|
+
super.initialize(currentModal);
|
|
39
|
+
this.getContent();
|
|
40
|
+
|
|
41
|
+
new RegularEvent('click', (event: Event): void => {
|
|
42
|
+
event.preventDefault();
|
|
43
|
+
this.save();
|
|
44
|
+
}).delegateTo(currentModal, Identifiers.saveTrigger);
|
|
45
|
+
}
|
|
46
|
+
|
|
47
|
+
private getContent(): void {
|
|
48
|
+
const modalContent = this.getModalBody();
|
|
49
|
+
(new AjaxRequest(Router.getUrl('featuresGetContent')))
|
|
50
|
+
.get({ cache: 'no-cache' })
|
|
51
|
+
.then(
|
|
52
|
+
async (response: AjaxResponse): Promise<void> => {
|
|
53
|
+
const data: ModuleLoadedResponseWithButtons = await response.resolve();
|
|
54
|
+
if (data.success === true && data.html !== 'undefined' && data.html.length > 0) {
|
|
55
|
+
modalContent.innerHTML = data.html;
|
|
56
|
+
Modal.setButtons(data.buttons);
|
|
57
|
+
} else {
|
|
58
|
+
Notification.error('Something went wrong', 'The request was not processed successfully. Please check the browser\'s console and TYPO3\'s log.');
|
|
59
|
+
}
|
|
60
|
+
},
|
|
61
|
+
(error: AjaxResponse): void => {
|
|
62
|
+
Router.handleAjaxError(error, modalContent);
|
|
63
|
+
}
|
|
64
|
+
);
|
|
65
|
+
}
|
|
66
|
+
|
|
67
|
+
private save(): void {
|
|
68
|
+
this.setModalButtonsState(false);
|
|
69
|
+
|
|
70
|
+
const modalContent = this.getModalBody();
|
|
71
|
+
const executeToken = this.getModuleContent().dataset.featuresSaveToken;
|
|
72
|
+
const postData: Record<string, string> = {};
|
|
73
|
+
const formData = new FormData(this.findInModal('form'));
|
|
74
|
+
for (const [name, value] of formData) {
|
|
75
|
+
postData[name] = value.toString();
|
|
76
|
+
}
|
|
77
|
+
postData['install[action]'] = 'featuresSave';
|
|
78
|
+
postData['install[token]'] = executeToken;
|
|
79
|
+
(new AjaxRequest(Router.getUrl()))
|
|
80
|
+
.post(postData)
|
|
81
|
+
.then(
|
|
82
|
+
async (response: AjaxResponse): Promise<void> => {
|
|
83
|
+
const data: FeaturesWrittenResponse = await response.resolve();
|
|
84
|
+
if (data.success === true && Array.isArray(data.status)) {
|
|
85
|
+
data.status.forEach((element: MessageInterface): void => {
|
|
86
|
+
Notification.showMessage(element.title, element.message, element.severity);
|
|
87
|
+
});
|
|
88
|
+
this.getContent();
|
|
89
|
+
} else {
|
|
90
|
+
Notification.error('Something went wrong', 'The request was not processed successfully. Please check the browser\'s console and TYPO3\'s log.');
|
|
91
|
+
}
|
|
92
|
+
},
|
|
93
|
+
(error: AjaxResponse): void => {
|
|
94
|
+
Router.handleAjaxError(error, modalContent);
|
|
95
|
+
}
|
|
96
|
+
).finally((): void => {
|
|
97
|
+
this.setModalButtonsState(true);
|
|
98
|
+
});
|
|
99
|
+
}
|
|
100
|
+
}
|
|
101
|
+
|
|
102
|
+
export default new Features();
|
|
@@ -0,0 +1,316 @@
|
|
|
1
|
+
/*
|
|
2
|
+
* This file is part of the TYPO3 CMS project.
|
|
3
|
+
*
|
|
4
|
+
* It is free software; you can redistribute it and/or modify it under
|
|
5
|
+
* the terms of the GNU General Public License, either version 2
|
|
6
|
+
* of the License, or any later version.
|
|
7
|
+
*
|
|
8
|
+
* For the full copyright and license information, please read the
|
|
9
|
+
* LICENSE.txt file that was distributed with this source code.
|
|
10
|
+
*
|
|
11
|
+
* The TYPO3 project - inspiring people to share!
|
|
12
|
+
*/
|
|
13
|
+
|
|
14
|
+
import 'bootstrap';
|
|
15
|
+
import { Collapse } from 'bootstrap';
|
|
16
|
+
import '../../renderable/clearable';
|
|
17
|
+
import { AbstractInteractableModule, type ModuleLoadedResponseWithButtons } from '../abstract-interactable-module';
|
|
18
|
+
import Modal from '@typo3/backend/modal';
|
|
19
|
+
import Notification from '@typo3/backend/notification';
|
|
20
|
+
import AjaxRequest from '@typo3/core/ajax/ajax-request';
|
|
21
|
+
import Router from '../../router';
|
|
22
|
+
import RegularEvent from '@typo3/core/event/regular-event';
|
|
23
|
+
import { KeyTypesEnum } from '@typo3/backend/enum/key-types';
|
|
24
|
+
import type { AjaxResponse } from '@typo3/core/ajax/ajax-response';
|
|
25
|
+
import type { ModalElement } from '@typo3/backend/modal';
|
|
26
|
+
import type MessageInterface from '@typo3/install/message-interface';
|
|
27
|
+
|
|
28
|
+
enum Identifiers {
|
|
29
|
+
item = '.t3js-localConfiguration-item',
|
|
30
|
+
toggleAllTrigger = '.t3js-localConfiguration-toggleAll',
|
|
31
|
+
writeTrigger = '.t3js-localConfiguration-write',
|
|
32
|
+
searchTrigger = '.t3js-localConfiguration-search',
|
|
33
|
+
createRowTrigger = '.t3js-localConfiguration-createRow',
|
|
34
|
+
removeRowTrigger = '.t3js-localConfiguration-removeRow',
|
|
35
|
+
configurationItem = '.t3js-localConfiguration-configuration-item',
|
|
36
|
+
}
|
|
37
|
+
|
|
38
|
+
type LocalConfigurationWrittenResponse = {
|
|
39
|
+
status: MessageInterface[],
|
|
40
|
+
success: boolean,
|
|
41
|
+
};
|
|
42
|
+
|
|
43
|
+
/**
|
|
44
|
+
* Module: @typo3/install/module/local-configuration
|
|
45
|
+
*/
|
|
46
|
+
class LocalConfiguration extends AbstractInteractableModule {
|
|
47
|
+
private searchInput: HTMLInputElement;
|
|
48
|
+
private toggleAll: boolean = false;
|
|
49
|
+
|
|
50
|
+
public override initialize(currentModal: ModalElement): void {
|
|
51
|
+
super.initialize(currentModal);
|
|
52
|
+
this.getContent();
|
|
53
|
+
|
|
54
|
+
// Write out new settings
|
|
55
|
+
new RegularEvent('click', (event: Event): void => {
|
|
56
|
+
event.preventDefault();
|
|
57
|
+
this.write();
|
|
58
|
+
}).delegateTo(currentModal, Identifiers.writeTrigger);
|
|
59
|
+
|
|
60
|
+
// Expand / collapse "Toggle all" button
|
|
61
|
+
new RegularEvent('click', (): void => {
|
|
62
|
+
const modalContent = this.getModalBody();
|
|
63
|
+
const panels = modalContent.querySelectorAll<HTMLElement>('.panel-collapse');
|
|
64
|
+
this.toggleAll = !this.toggleAll;
|
|
65
|
+
const action = this.toggleAll ? 'show' : 'hide';
|
|
66
|
+
panels.forEach((panel: HTMLElement) => {
|
|
67
|
+
const toggleButton: HTMLElement = modalContent.querySelector(`[data-bs-target="#${panel.id}"]`);
|
|
68
|
+
if (toggleButton) {
|
|
69
|
+
toggleButton.classList.toggle('collapsed', !this.toggleAll);
|
|
70
|
+
}
|
|
71
|
+
Collapse.getOrCreateInstance(panel)[action]();
|
|
72
|
+
});
|
|
73
|
+
}).delegateTo(currentModal, Identifiers.toggleAllTrigger);
|
|
74
|
+
|
|
75
|
+
// Focus search field on certain user interactions
|
|
76
|
+
new RegularEvent('keydown', (event: KeyboardEvent) => {
|
|
77
|
+
const searchInput = currentModal.querySelector<HTMLInputElement>(Identifiers.searchTrigger);
|
|
78
|
+
if (event.ctrlKey || event.metaKey) {
|
|
79
|
+
// Focus search field on ctrl-f
|
|
80
|
+
if (event.key === 'f' || event.key === 'F') {
|
|
81
|
+
event.preventDefault();
|
|
82
|
+
searchInput.focus();
|
|
83
|
+
}
|
|
84
|
+
} else if (event.key === KeyTypesEnum.ESCAPE) {
|
|
85
|
+
if (searchInput.value.trim() !== '') {
|
|
86
|
+
// Clear search on ESC key otherwise close the modal
|
|
87
|
+
event.preventDefault();
|
|
88
|
+
searchInput.value = '';
|
|
89
|
+
searchInput.focus();
|
|
90
|
+
}
|
|
91
|
+
}
|
|
92
|
+
}).bindTo(currentModal);
|
|
93
|
+
|
|
94
|
+
// Perform expand collapse on search matches
|
|
95
|
+
new RegularEvent('input', (event: Event, target: HTMLInputElement): void => {
|
|
96
|
+
const typedQuery = target.value;
|
|
97
|
+
this.search(typedQuery);
|
|
98
|
+
}).delegateTo(currentModal, Identifiers.searchTrigger);
|
|
99
|
+
|
|
100
|
+
new RegularEvent('change', (event: Event, target: HTMLInputElement): void => {
|
|
101
|
+
const typedQuery = target.value;
|
|
102
|
+
this.search(typedQuery);
|
|
103
|
+
}).delegateTo(currentModal, Identifiers.searchTrigger);
|
|
104
|
+
|
|
105
|
+
// Remove a cloned row
|
|
106
|
+
new RegularEvent('click', (event: Event, target: HTMLInputElement): void => {
|
|
107
|
+
event.preventDefault();
|
|
108
|
+
const row = target.closest(Identifiers.configurationItem);
|
|
109
|
+
row?.remove();
|
|
110
|
+
}).delegateTo(currentModal, Identifiers.removeRowTrigger);
|
|
111
|
+
|
|
112
|
+
// Add a fresh clone row
|
|
113
|
+
new RegularEvent('click', (event: Event, target: HTMLInputElement): void => {
|
|
114
|
+
event.preventDefault();
|
|
115
|
+
|
|
116
|
+
const container = target.closest('.t3js-configuration-list') as HTMLElement|null;
|
|
117
|
+
if (container === null) {
|
|
118
|
+
return;
|
|
119
|
+
}
|
|
120
|
+
|
|
121
|
+
const querySelectorLast = (selector: string): HTMLElement|null => {
|
|
122
|
+
const elements = container.querySelectorAll(selector);
|
|
123
|
+
return elements.item(elements.length - 1) as HTMLElement|null;
|
|
124
|
+
};
|
|
125
|
+
|
|
126
|
+
// Iterate all rows to find empty inputs per row
|
|
127
|
+
const rows = container.querySelectorAll(Identifiers.configurationItem);
|
|
128
|
+
for (const row of rows) {
|
|
129
|
+
const inputs = row.querySelectorAll('input[type="text"]') as NodeListOf<HTMLInputElement>;
|
|
130
|
+
let arrayKey;
|
|
131
|
+
let arrayValue;
|
|
132
|
+
if (container.dataset.type === 'map') {
|
|
133
|
+
arrayKey = inputs.item(0).value.trim();
|
|
134
|
+
arrayValue = inputs.item(1).value.trim();
|
|
135
|
+
} else if (container.dataset.type === 'element-list') {
|
|
136
|
+
arrayKey = undefined;
|
|
137
|
+
arrayValue = inputs[0].value.trim();
|
|
138
|
+
} else {
|
|
139
|
+
return;
|
|
140
|
+
}
|
|
141
|
+
|
|
142
|
+
// Skip if map is lacking key/value, or element-list is lacking value
|
|
143
|
+
// @todo: this doesn't allow empty values when using `map` – on purpose?
|
|
144
|
+
if (arrayKey === '' || arrayValue === '') {
|
|
145
|
+
for (const input of inputs) {
|
|
146
|
+
if (input.value === '') {
|
|
147
|
+
// Found an empty input, focus it
|
|
148
|
+
input.focus();
|
|
149
|
+
return;
|
|
150
|
+
}
|
|
151
|
+
}
|
|
152
|
+
}
|
|
153
|
+
}
|
|
154
|
+
|
|
155
|
+
const rowTemplate = (container.querySelector('#' + container.dataset.namespace) as HTMLTemplateElement).content.cloneNode(true) as DocumentFragment;
|
|
156
|
+
container.querySelector('.configuration-map-item-collection').append(rowTemplate);
|
|
157
|
+
|
|
158
|
+
const lastRow = querySelectorLast(Identifiers.configurationItem);
|
|
159
|
+
// Focus first input field in inserted item
|
|
160
|
+
(lastRow.querySelector('input[type="text"]') as HTMLInputElement|null)?.focus();
|
|
161
|
+
}).delegateTo(currentModal, Identifiers.createRowTrigger);
|
|
162
|
+
}
|
|
163
|
+
|
|
164
|
+
private search(typedQuery: string): void {
|
|
165
|
+
this.currentModal.querySelectorAll(Identifiers.item).forEach((element: HTMLElement): void => {
|
|
166
|
+
if (element.textContent.toLowerCase().trim().includes(typedQuery.toLowerCase())) {
|
|
167
|
+
element.classList.remove('hidden');
|
|
168
|
+
element.classList.add('searchhit');
|
|
169
|
+
} else {
|
|
170
|
+
element.classList.remove('searchhit');
|
|
171
|
+
element.classList.add('hidden');
|
|
172
|
+
}
|
|
173
|
+
});
|
|
174
|
+
|
|
175
|
+
this.currentModal.querySelectorAll('.searchhit').forEach((resultElement: HTMLElement) => {
|
|
176
|
+
const collapseElement = resultElement.closest('.panel-collapse');
|
|
177
|
+
Collapse.getOrCreateInstance(collapseElement).show();
|
|
178
|
+
});
|
|
179
|
+
}
|
|
180
|
+
|
|
181
|
+
private getContent(): void {
|
|
182
|
+
const modalContent = this.getModalBody();
|
|
183
|
+
(new AjaxRequest(Router.getUrl('localConfigurationGetContent')))
|
|
184
|
+
.get({ cache: 'no-cache' })
|
|
185
|
+
.then(
|
|
186
|
+
async (response: AjaxResponse): Promise<void> => {
|
|
187
|
+
const data: ModuleLoadedResponseWithButtons = await response.resolve();
|
|
188
|
+
if (data.success === true) {
|
|
189
|
+
modalContent.innerHTML = data.html;
|
|
190
|
+
Modal.setButtons(data.buttons);
|
|
191
|
+
this.searchInput = modalContent.querySelector<HTMLInputElement>((Identifiers.searchTrigger));
|
|
192
|
+
this.searchInput.clearable();
|
|
193
|
+
}
|
|
194
|
+
},
|
|
195
|
+
(error: AjaxResponse): void => {
|
|
196
|
+
Router.handleAjaxError(error, modalContent);
|
|
197
|
+
}
|
|
198
|
+
);
|
|
199
|
+
}
|
|
200
|
+
|
|
201
|
+
private write(): void {
|
|
202
|
+
this.setModalButtonsState(false);
|
|
203
|
+
|
|
204
|
+
const modalContent = this.getModalBody();
|
|
205
|
+
const executeToken = this.getModuleContent().dataset.localConfigurationWriteToken;
|
|
206
|
+
const configurationValues: Record<string, string | Record<string, string>> = {};
|
|
207
|
+
const collectedArrayKeys: Record<string, string[]> = {};
|
|
208
|
+
const collectedArrayValues: Record<string, string[]> = {};
|
|
209
|
+
this.currentModal.querySelectorAll('.t3js-localConfiguration-pathValue').forEach((element: HTMLInputElement): void => {
|
|
210
|
+
if (element.type === 'checkbox') {
|
|
211
|
+
if (element.checked) {
|
|
212
|
+
configurationValues[element.dataset.path] = '1';
|
|
213
|
+
} else {
|
|
214
|
+
configurationValues[element.dataset.path] = '0';
|
|
215
|
+
}
|
|
216
|
+
} else {
|
|
217
|
+
if (element.dataset.valuetype === 'map' || element.dataset.valuetype === 'element-list') {
|
|
218
|
+
// Special type "data-valuetype='map|element-list'" found.
|
|
219
|
+
// "map": has 'speaking' key and a value
|
|
220
|
+
// "element-list": only the value counts, the key is just a running numerical index
|
|
221
|
+
// Note that "array" is a regular input string value that is later exploded and NOT part
|
|
222
|
+
// of this code fork. The type "list" is a string-only listing NOT getting exploded.
|
|
223
|
+
// We want to convert these pairs:
|
|
224
|
+
// <input type="text" name="/GFX/someKey/key[]" value="myKey">
|
|
225
|
+
// <input type="text" name="/GFX/someKey/value[]" value="myValue">
|
|
226
|
+
// <input type="text" name="/GFX/someKey/key[]" value="anotherKey">
|
|
227
|
+
// <input type="text" name="/GFX/someKey/value[]" value="anotherValue">
|
|
228
|
+
// into:
|
|
229
|
+
// configurationValues[GFX/someKey][myKey] = myValue
|
|
230
|
+
// configurationValues[GFX/someKey][anotherKey] = anotherValue
|
|
231
|
+
// This is done with a temporary helper structure of collectedArrayKeys+collectedArrayValues,
|
|
232
|
+
// indexed by their main key ("GFX/someKey") so they can later be easily piped into it as JavaScript array.
|
|
233
|
+
|
|
234
|
+
// The "value[]" portion is always required (for map+list), but "key[]" can be optional (only needed for map)
|
|
235
|
+
if (element.dataset.path!.includes('/key[]') && element.value !== '') {
|
|
236
|
+
const itemArrayPath = element.dataset.path!.replace('/key[]', '');
|
|
237
|
+
if (collectedArrayKeys[itemArrayPath] === undefined) {
|
|
238
|
+
collectedArrayKeys[itemArrayPath] = [];
|
|
239
|
+
}
|
|
240
|
+
collectedArrayKeys[itemArrayPath].push(element.value);
|
|
241
|
+
} else if (element.dataset.path!.includes('/value[]') && element.value !== '') {
|
|
242
|
+
const itemArrayPath = element.dataset.path!.replace('/value[]', '');
|
|
243
|
+
if (collectedArrayValues[itemArrayPath] === undefined) {
|
|
244
|
+
collectedArrayValues[itemArrayPath] = [];
|
|
245
|
+
}
|
|
246
|
+
collectedArrayValues[itemArrayPath].push(element.value);
|
|
247
|
+
}
|
|
248
|
+
} else {
|
|
249
|
+
// Regular input string values.
|
|
250
|
+
configurationValues[element.dataset.path] = element.value;
|
|
251
|
+
}
|
|
252
|
+
}
|
|
253
|
+
});
|
|
254
|
+
|
|
255
|
+
// Now iterate the collectedArrayValues and collectedArrayKeys (map needs key+value, list only values).
|
|
256
|
+
for (const itemArrayPath in collectedArrayValues) {
|
|
257
|
+
if (Object.prototype.hasOwnProperty.call(collectedArrayValues, itemArrayPath)) {
|
|
258
|
+
// Create a properly typed object for the collection
|
|
259
|
+
if (configurationValues[itemArrayPath] === undefined) {
|
|
260
|
+
configurationValues[itemArrayPath] = {};
|
|
261
|
+
}
|
|
262
|
+
|
|
263
|
+
// Ensure configurationValues[itemArrayPath] is treated as a Record.
|
|
264
|
+
// Record keys are sorted, and configuration values are also persisted with sorting.
|
|
265
|
+
const configObject = configurationValues[itemArrayPath] as Record<string, string>;
|
|
266
|
+
|
|
267
|
+
// Iterate by index, not by keys array values
|
|
268
|
+
collectedArrayValues[itemArrayPath].forEach((arrayValue, index) => {
|
|
269
|
+
// Ensure we really have that paired collectedArrayValues[] value corresponding to the same key for maps.
|
|
270
|
+
// Empty key+value pairs are skipped (removed from config).
|
|
271
|
+
// Also, element-list is evaluated for the cases collectedArrayKeys is not set.
|
|
272
|
+
if (arrayValue === '') {
|
|
273
|
+
return;
|
|
274
|
+
}
|
|
275
|
+
|
|
276
|
+
if (collectedArrayKeys[itemArrayPath]
|
|
277
|
+
&& collectedArrayKeys[itemArrayPath][index] !== undefined
|
|
278
|
+
&& collectedArrayKeys[itemArrayPath][index] !== ''
|
|
279
|
+
) {
|
|
280
|
+
// Case "map"
|
|
281
|
+
// Now populate configurationValues[itemArrayPath][myKey] = myValue
|
|
282
|
+
const arrayKey = collectedArrayKeys[itemArrayPath][index];
|
|
283
|
+
configObject[arrayKey] = arrayValue;
|
|
284
|
+
} else {
|
|
285
|
+
// Case "list"
|
|
286
|
+
// Now populate configurationValues[itemArrayPath][numericalKey] = myValue
|
|
287
|
+
configObject[index] = arrayValue;
|
|
288
|
+
}
|
|
289
|
+
});
|
|
290
|
+
}
|
|
291
|
+
}
|
|
292
|
+
|
|
293
|
+
(new AjaxRequest(Router.getUrl())).post({
|
|
294
|
+
install: {
|
|
295
|
+
action: 'localConfigurationWrite',
|
|
296
|
+
token: executeToken,
|
|
297
|
+
configurationValues: configurationValues,
|
|
298
|
+
},
|
|
299
|
+
}).then(async (response: AjaxResponse): Promise<void> => {
|
|
300
|
+
const data: LocalConfigurationWrittenResponse = await response.resolve();
|
|
301
|
+
if (data.success === true && Array.isArray(data.status)) {
|
|
302
|
+
data.status.forEach((element: MessageInterface): void => {
|
|
303
|
+
Notification.showMessage(element.title, element.message, element.severity);
|
|
304
|
+
});
|
|
305
|
+
} else {
|
|
306
|
+
Notification.error('Something went wrong', 'The request was not processed successfully. Please check the browser\'s console and TYPO3\'s log.');
|
|
307
|
+
}
|
|
308
|
+
}, (error: AjaxResponse): void => {
|
|
309
|
+
Router.handleAjaxError(error, modalContent);
|
|
310
|
+
}).finally((): void => {
|
|
311
|
+
this.setModalButtonsState(true);
|
|
312
|
+
});
|
|
313
|
+
}
|
|
314
|
+
}
|
|
315
|
+
|
|
316
|
+
export default new LocalConfiguration();
|