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
package/backend/modal.ts
ADDED
|
@@ -0,0 +1,685 @@
|
|
|
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 { Modal as BootstrapModal } from 'bootstrap';
|
|
15
|
+
import { html, nothing, LitElement, type TemplateResult, type PropertyValues } from 'lit';
|
|
16
|
+
import { customElement, property, state } from 'lit/decorators';
|
|
17
|
+
import { unsafeHTML } from 'lit/directives/unsafe-html';
|
|
18
|
+
import { classMap, type ClassInfo } from 'lit/directives/class-map';
|
|
19
|
+
import { styleMap, type StyleInfo } from 'lit/directives/style-map';
|
|
20
|
+
import { ifDefined } from 'lit/directives/if-defined';
|
|
21
|
+
import { classesArrayToClassInfo } from '@typo3/core/lit-helper';
|
|
22
|
+
import RegularEvent from '@typo3/core/event/regular-event';
|
|
23
|
+
import type { AjaxResponse } from '@typo3/core/ajax/ajax-response';
|
|
24
|
+
import type { AbstractAction } from './action-button/abstract-action';
|
|
25
|
+
import type { ModalResponseEvent } from '@typo3/backend/modal-interface';
|
|
26
|
+
import { SeverityEnum } from './enum/severity';
|
|
27
|
+
import AjaxRequest from '@typo3/core/ajax/ajax-request';
|
|
28
|
+
import Severity from './severity';
|
|
29
|
+
import '@typo3/backend/element/icon-element';
|
|
30
|
+
import '@typo3/backend/element/spinner-element';
|
|
31
|
+
|
|
32
|
+
enum Identifiers {
|
|
33
|
+
modal = '.t3js-modal',
|
|
34
|
+
content = '.t3js-modal-content',
|
|
35
|
+
close = '.t3js-modal-close',
|
|
36
|
+
body = '.t3js-modal-body',
|
|
37
|
+
footer = '.t3js-modal-footer',
|
|
38
|
+
}
|
|
39
|
+
|
|
40
|
+
export enum Sizes {
|
|
41
|
+
small = 'small',
|
|
42
|
+
default = 'default',
|
|
43
|
+
medium = 'medium',
|
|
44
|
+
large = 'large',
|
|
45
|
+
full = 'full',
|
|
46
|
+
}
|
|
47
|
+
|
|
48
|
+
export enum Styles {
|
|
49
|
+
default = 'default',
|
|
50
|
+
light = 'light',
|
|
51
|
+
dark = 'dark',
|
|
52
|
+
}
|
|
53
|
+
|
|
54
|
+
export enum Types {
|
|
55
|
+
default = 'default',
|
|
56
|
+
template = 'template',
|
|
57
|
+
ajax = 'ajax',
|
|
58
|
+
iframe = 'iframe',
|
|
59
|
+
}
|
|
60
|
+
|
|
61
|
+
type ModalCallbackFunction = (modal: ModalElement) => void;
|
|
62
|
+
|
|
63
|
+
export interface Button {
|
|
64
|
+
text: string;
|
|
65
|
+
active?: boolean;
|
|
66
|
+
btnClass: string;
|
|
67
|
+
name?: string;
|
|
68
|
+
form?: string;
|
|
69
|
+
trigger?: (e: Event, modal: ModalElement) => void;
|
|
70
|
+
icon?: string;
|
|
71
|
+
action?: AbstractAction;
|
|
72
|
+
}
|
|
73
|
+
|
|
74
|
+
export interface Configuration {
|
|
75
|
+
type: Types;
|
|
76
|
+
title: string;
|
|
77
|
+
// @todo remove support for JQuery based content
|
|
78
|
+
content: TemplateResult | string | JQuery | Element | DocumentFragment;
|
|
79
|
+
severity: SeverityEnum;
|
|
80
|
+
buttons: Array<Button>;
|
|
81
|
+
style: Styles;
|
|
82
|
+
size: Sizes;
|
|
83
|
+
additionalCssClasses: Array<string>;
|
|
84
|
+
callback: ModalCallbackFunction | null;
|
|
85
|
+
ajaxCallback: ModalCallbackFunction | null;
|
|
86
|
+
staticBackdrop: boolean;
|
|
87
|
+
hideCloseButton: boolean;
|
|
88
|
+
}
|
|
89
|
+
|
|
90
|
+
type PartialConfiguration = Partial<Omit<Configuration, 'buttons'> & { buttons: Array<Partial<Button>> }>;
|
|
91
|
+
|
|
92
|
+
@customElement('typo3-backend-modal')
|
|
93
|
+
export class ModalElement extends LitElement {
|
|
94
|
+
@property({ type: String, reflect: true }) modalTitle: string = '';
|
|
95
|
+
@property({ type: String, reflect: true }) content: string = '';
|
|
96
|
+
@property({ type: String, reflect: true }) type: Types = Types.default;
|
|
97
|
+
@property({ type: String, reflect: true }) severity: SeverityEnum = SeverityEnum.notice;
|
|
98
|
+
@property({ type: String, reflect: true }) variant: Styles = Styles.default;
|
|
99
|
+
@property({ type: String, reflect: true }) size: Sizes = Sizes.default;
|
|
100
|
+
@property({ type: Number, reflect: true }) zindex: number = 5000;
|
|
101
|
+
@property({ type: Boolean }) staticBackdrop: boolean = false;
|
|
102
|
+
@property({ type: Boolean }) hideCloseButton: boolean = false;
|
|
103
|
+
@property({ type: Array }) additionalCssClasses: Array<string> = [];
|
|
104
|
+
@property({ type: Array, attribute: false }) buttons: Array<Button> = [];
|
|
105
|
+
|
|
106
|
+
@state() templateResultContent: TemplateResult | JQuery | Element | DocumentFragment = null;
|
|
107
|
+
@state() activeButton: Button = null;
|
|
108
|
+
|
|
109
|
+
public bootstrapModal: BootstrapModal = null;
|
|
110
|
+
public callback: ModalCallbackFunction = null;
|
|
111
|
+
public ajaxCallback: ModalCallbackFunction = null;
|
|
112
|
+
|
|
113
|
+
public userData: { [key: string]: any } = {};
|
|
114
|
+
|
|
115
|
+
private keydownEventHandler: RegularEvent = null;
|
|
116
|
+
|
|
117
|
+
public setContent(content: TemplateResult | JQuery | Element | DocumentFragment): void {
|
|
118
|
+
this.templateResultContent = content;
|
|
119
|
+
}
|
|
120
|
+
|
|
121
|
+
public hideModal(): void {
|
|
122
|
+
if (this.bootstrapModal) {
|
|
123
|
+
this.bootstrapModal.hide();
|
|
124
|
+
this.keydownEventHandler?.release();
|
|
125
|
+
}
|
|
126
|
+
}
|
|
127
|
+
|
|
128
|
+
protected override createRenderRoot(): HTMLElement | ShadowRoot {
|
|
129
|
+
// Avoid shadow DOM for Bootstrap CSS to be applied
|
|
130
|
+
return this;
|
|
131
|
+
}
|
|
132
|
+
|
|
133
|
+
protected override firstUpdated(): void {
|
|
134
|
+
this.bootstrapModal = new BootstrapModal(this.renderRoot.querySelector(Identifiers.modal), {});
|
|
135
|
+
this.bootstrapModal.show();
|
|
136
|
+
if (this.callback) {
|
|
137
|
+
this.callback(this);
|
|
138
|
+
}
|
|
139
|
+
}
|
|
140
|
+
|
|
141
|
+
protected override updated(changedProperties: PropertyValues): void {
|
|
142
|
+
if (changedProperties.has('templateResultContent')) {
|
|
143
|
+
this.dispatchEvent(new CustomEvent('modal-updated', { bubbles: true }));
|
|
144
|
+
}
|
|
145
|
+
}
|
|
146
|
+
|
|
147
|
+
protected override render(): TemplateResult {
|
|
148
|
+
const styles: StyleInfo = {
|
|
149
|
+
zIndex: this.zindex.toString()
|
|
150
|
+
};
|
|
151
|
+
const classes: ClassInfo = classesArrayToClassInfo([
|
|
152
|
+
`modal-type-${this.type}`,
|
|
153
|
+
`modal-severity-${Severity.getCssClass(this.severity)}`,
|
|
154
|
+
`modal-style-${this.variant}`,
|
|
155
|
+
`modal-size-${this.size}`,
|
|
156
|
+
...this.additionalCssClasses,
|
|
157
|
+
]);
|
|
158
|
+
return html`
|
|
159
|
+
<div
|
|
160
|
+
tabindex="-1"
|
|
161
|
+
class="modal fade t3js-modal ${classMap(classes)}"
|
|
162
|
+
style=${styleMap(styles)}
|
|
163
|
+
data-bs-backdrop="${ifDefined(this.staticBackdrop) ? 'static' : true}"
|
|
164
|
+
@show.bs.modal=${() => this.trigger('typo3-modal-show')}
|
|
165
|
+
@shown.bs.modal=${() => this.trigger('typo3-modal-shown')}
|
|
166
|
+
@hide.bs.modal=${() => this.trigger('typo3-modal-hide')}
|
|
167
|
+
@hidden.bs.modal=${() => this.trigger('typo3-modal-hidden')}
|
|
168
|
+
>
|
|
169
|
+
<div class="modal-dialog">
|
|
170
|
+
<div class="t3js-modal-content modal-content">
|
|
171
|
+
<div class="modal-header">
|
|
172
|
+
<h1 class="h4 t3js-modal-title modal-title">${this.modalTitle}</h1>
|
|
173
|
+
${this.hideCloseButton ? nothing : html`
|
|
174
|
+
<button class="t3js-modal-close close" @click=${() => this.bootstrapModal.hide()}>
|
|
175
|
+
<typo3-backend-icon identifier="actions-close" size="small"></typo3-backend-icon>
|
|
176
|
+
<span class="visually-hidden">${TYPO3?.lang?.['button.close'] || 'Close'} ${this.modalTitle}</span>
|
|
177
|
+
</button>
|
|
178
|
+
`}
|
|
179
|
+
</div>
|
|
180
|
+
<div class="t3js-modal-body modal-body">${this.renderModalBody()}</div>
|
|
181
|
+
${this.buttons.length === 0 ? nothing : html`
|
|
182
|
+
<div class="t3js-modal-footer modal-footer">
|
|
183
|
+
${this.buttons.map(button => this.renderModalButton(button))}
|
|
184
|
+
</div>
|
|
185
|
+
`}
|
|
186
|
+
</div>
|
|
187
|
+
</div>
|
|
188
|
+
</div>
|
|
189
|
+
`;
|
|
190
|
+
}
|
|
191
|
+
|
|
192
|
+
private _buttonClick(event: Event, button: Button): void {
|
|
193
|
+
const buttonElement = event.currentTarget as HTMLButtonElement;
|
|
194
|
+
if (button.action) {
|
|
195
|
+
this.activeButton = button;
|
|
196
|
+
button.action.execute(buttonElement).then((): void => this.bootstrapModal.hide());
|
|
197
|
+
} else if (button.trigger) {
|
|
198
|
+
button.trigger(event, this);
|
|
199
|
+
}
|
|
200
|
+
buttonElement.dispatchEvent(new CustomEvent('button.clicked', { bubbles: true }));
|
|
201
|
+
}
|
|
202
|
+
|
|
203
|
+
private renderAjaxBody(): TemplateResult {
|
|
204
|
+
if (this.templateResultContent === null) {
|
|
205
|
+
new AjaxRequest(this.content as string).get()
|
|
206
|
+
.then(async (response: AjaxResponse): Promise<void> => {
|
|
207
|
+
const htmlResponse = await response.raw().text();
|
|
208
|
+
this.templateResultContent = html`${unsafeHTML(htmlResponse)}`;
|
|
209
|
+
this.updateComplete.then(() => {
|
|
210
|
+
if (this.ajaxCallback) {
|
|
211
|
+
this.ajaxCallback(this);
|
|
212
|
+
}
|
|
213
|
+
this.dispatchEvent(new CustomEvent('modal-loaded'));
|
|
214
|
+
});
|
|
215
|
+
})
|
|
216
|
+
.catch(async (response: AjaxResponse): Promise<void> => {
|
|
217
|
+
const htmlResponse = await response.raw().text();
|
|
218
|
+
if (htmlResponse) {
|
|
219
|
+
this.templateResultContent = html`${unsafeHTML(htmlResponse)}`;
|
|
220
|
+
} else {
|
|
221
|
+
this.templateResultContent = html`<p><strong>Oops, received a ${response.response.status} response from </strong> <span class="text-break">${this.content}</span>.</p>`;
|
|
222
|
+
}
|
|
223
|
+
});
|
|
224
|
+
return html`<div class="modal-loading"><typo3-backend-spinner size="large"></typo3-backend-spinner></div>`;
|
|
225
|
+
}
|
|
226
|
+
|
|
227
|
+
return this.templateResultContent as TemplateResult;
|
|
228
|
+
}
|
|
229
|
+
|
|
230
|
+
private renderModalBody(): TemplateResult | JQuery | Element | DocumentFragment {
|
|
231
|
+
this.keydownEventHandler = new RegularEvent('keydown', this.handleKeydown);
|
|
232
|
+
this.keydownEventHandler.bindTo(document);
|
|
233
|
+
|
|
234
|
+
if (this.type === Types.iframe) {
|
|
235
|
+
const loadCallback = (e: Event) => {
|
|
236
|
+
const iframe = e.currentTarget as HTMLIFrameElement;
|
|
237
|
+
if (iframe.contentDocument.title) {
|
|
238
|
+
this.modalTitle = iframe.contentDocument.title;
|
|
239
|
+
}
|
|
240
|
+
new RegularEvent('keydown', this.handleKeydown).bindTo(iframe.contentDocument);
|
|
241
|
+
};
|
|
242
|
+
return html`
|
|
243
|
+
<iframe src="${this.content}" name="modal_frame" class="modal-iframe t3js-modal-iframe" @load=${loadCallback}></iframe>
|
|
244
|
+
`;
|
|
245
|
+
}
|
|
246
|
+
|
|
247
|
+
if (this.type === Types.ajax) {
|
|
248
|
+
return this.renderAjaxBody();
|
|
249
|
+
}
|
|
250
|
+
|
|
251
|
+
if (this.type === Types.template) {
|
|
252
|
+
return this.templateResultContent;
|
|
253
|
+
}
|
|
254
|
+
|
|
255
|
+
return html`<p>${this.content}</p>`;
|
|
256
|
+
}
|
|
257
|
+
|
|
258
|
+
private renderModalButton(button: Button): TemplateResult {
|
|
259
|
+
const btnClass = button.btnClass || 'btn-default';
|
|
260
|
+
const classes: ClassInfo = {
|
|
261
|
+
['btn']: true,
|
|
262
|
+
[btnClass]: true,
|
|
263
|
+
['t3js-active']: button.active,
|
|
264
|
+
['disabled']: this.activeButton && this.activeButton !== button,
|
|
265
|
+
};
|
|
266
|
+
return html`
|
|
267
|
+
<button class=${classMap(classes)}
|
|
268
|
+
name=${ifDefined(button.name || undefined)}
|
|
269
|
+
form=${ifDefined(button.form || undefined)}
|
|
270
|
+
@click=${(e: Event) => this._buttonClick(e, button)}>
|
|
271
|
+
${button.icon ? html`<typo3-backend-icon identifier="${button.icon}" size="small"></typo3-backend-icon>` : nothing}
|
|
272
|
+
${button.text}
|
|
273
|
+
</button>
|
|
274
|
+
`;
|
|
275
|
+
}
|
|
276
|
+
|
|
277
|
+
private trigger(event: string): void {
|
|
278
|
+
this.dispatchEvent(new CustomEvent(event, { bubbles: true, composed: true }));
|
|
279
|
+
}
|
|
280
|
+
|
|
281
|
+
private handleKeydown(e: KeyboardEvent): void {
|
|
282
|
+
if (e.key === 'Escape' && parent?.top?.TYPO3?.Modal) {
|
|
283
|
+
parent.top.TYPO3.Modal.dismiss();
|
|
284
|
+
}
|
|
285
|
+
}
|
|
286
|
+
}
|
|
287
|
+
|
|
288
|
+
declare global {
|
|
289
|
+
interface HTMLElementTagNameMap {
|
|
290
|
+
'typo3-backend-modal': ModalElement;
|
|
291
|
+
}
|
|
292
|
+
}
|
|
293
|
+
|
|
294
|
+
/**
|
|
295
|
+
* Module: @typo3/backend/modal
|
|
296
|
+
* API for modal windows powered by Twitter Bootstrap.
|
|
297
|
+
*/
|
|
298
|
+
class Modal {
|
|
299
|
+
// @todo: drop? available as named exports
|
|
300
|
+
public readonly sizes: typeof Sizes = Sizes;
|
|
301
|
+
public readonly styles: typeof Styles = Styles;
|
|
302
|
+
public readonly types: typeof Types = Types;
|
|
303
|
+
|
|
304
|
+
// @todo: currentModal could be a getter method for the last element in this.instances
|
|
305
|
+
public currentModal: ModalElement = null;
|
|
306
|
+
private readonly instances: Array<ModalElement> = [];
|
|
307
|
+
|
|
308
|
+
private readonly defaultConfiguration: Configuration = {
|
|
309
|
+
type: Types.default,
|
|
310
|
+
title: 'Information',
|
|
311
|
+
content: 'No content provided, please check your <code>Modal</code> configuration.',
|
|
312
|
+
severity: SeverityEnum.notice,
|
|
313
|
+
buttons: [],
|
|
314
|
+
style: Styles.default,
|
|
315
|
+
size: Sizes.default,
|
|
316
|
+
additionalCssClasses: [],
|
|
317
|
+
callback: null,
|
|
318
|
+
ajaxCallback: null,
|
|
319
|
+
staticBackdrop: false,
|
|
320
|
+
hideCloseButton: false
|
|
321
|
+
};
|
|
322
|
+
|
|
323
|
+
constructor() {
|
|
324
|
+
this.initializeMarkupTrigger(document);
|
|
325
|
+
}
|
|
326
|
+
|
|
327
|
+
private static createModalResponseEventFromElement(element: HTMLElement, result: boolean): ModalResponseEvent | null {
|
|
328
|
+
if (!element.dataset.eventName) {
|
|
329
|
+
return null;
|
|
330
|
+
}
|
|
331
|
+
return new CustomEvent(
|
|
332
|
+
element.dataset.eventName, {
|
|
333
|
+
bubbles: true,
|
|
334
|
+
detail: { result, payload: element.dataset.eventPayload || null }
|
|
335
|
+
});
|
|
336
|
+
}
|
|
337
|
+
|
|
338
|
+
/**
|
|
339
|
+
* Close the current open modal
|
|
340
|
+
*/
|
|
341
|
+
public dismiss(): void {
|
|
342
|
+
if (this.currentModal) {
|
|
343
|
+
this.currentModal.hideModal();
|
|
344
|
+
}
|
|
345
|
+
}
|
|
346
|
+
|
|
347
|
+
/**
|
|
348
|
+
* Shows a confirmation dialog
|
|
349
|
+
* Events:
|
|
350
|
+
* - button.clicked
|
|
351
|
+
* - confirm.button.cancel
|
|
352
|
+
* - confirm.button.ok
|
|
353
|
+
*
|
|
354
|
+
* @param {string} title The title for the confirm modal
|
|
355
|
+
* @param {TemplateResult | string | JQuery | Element | DocumentFragment} content The content for the conform modal, e.g. the main question
|
|
356
|
+
* @param {SeverityEnum} severity Default SeverityEnum.warning
|
|
357
|
+
* @param {Array<Button>} buttons An array with buttons, default no buttons
|
|
358
|
+
* @param {Array<string>} additionalCssClasses Additional css classes to add to the modal
|
|
359
|
+
* @returns {ModalElement}
|
|
360
|
+
*/
|
|
361
|
+
public confirm(
|
|
362
|
+
title: string,
|
|
363
|
+
content: TemplateResult | string | JQuery | Element | DocumentFragment,
|
|
364
|
+
severity: SeverityEnum = SeverityEnum.warning,
|
|
365
|
+
buttons: Array<Button> = [],
|
|
366
|
+
additionalCssClasses?: Array<string>,
|
|
367
|
+
): ModalElement {
|
|
368
|
+
if (buttons.length === 0) {
|
|
369
|
+
buttons.push(
|
|
370
|
+
{
|
|
371
|
+
text: TYPO3?.lang?.['button.cancel'] || 'Cancel',
|
|
372
|
+
active: true,
|
|
373
|
+
btnClass: 'btn-default',
|
|
374
|
+
name: 'cancel',
|
|
375
|
+
},
|
|
376
|
+
{
|
|
377
|
+
text: TYPO3?.lang?.['button.ok'] || 'OK',
|
|
378
|
+
btnClass: 'btn-' + Severity.getCssClass(severity),
|
|
379
|
+
name: 'ok',
|
|
380
|
+
},
|
|
381
|
+
);
|
|
382
|
+
}
|
|
383
|
+
|
|
384
|
+
const modal = this.advanced({
|
|
385
|
+
title,
|
|
386
|
+
content,
|
|
387
|
+
severity,
|
|
388
|
+
buttons,
|
|
389
|
+
additionalCssClasses
|
|
390
|
+
});
|
|
391
|
+
|
|
392
|
+
modal.addEventListener('button.clicked', (e: Event): void => {
|
|
393
|
+
const button = e.target as HTMLButtonElement;
|
|
394
|
+
if (button.getAttribute('name') === 'cancel') {
|
|
395
|
+
button.dispatchEvent(new CustomEvent('confirm.button.cancel', { bubbles: true }));
|
|
396
|
+
} else if (button.getAttribute('name') === 'ok') {
|
|
397
|
+
button.dispatchEvent(new CustomEvent('confirm.button.ok', { bubbles: true }));
|
|
398
|
+
}
|
|
399
|
+
});
|
|
400
|
+
|
|
401
|
+
return modal;
|
|
402
|
+
}
|
|
403
|
+
|
|
404
|
+
/**
|
|
405
|
+
* Load URL with AJAX, append the content to the modal-body
|
|
406
|
+
* and trigger the callback
|
|
407
|
+
*
|
|
408
|
+
* @param {string} title
|
|
409
|
+
* @param {SeverityEnum} severity
|
|
410
|
+
* @param {Array<Button>} buttons
|
|
411
|
+
* @param {string} url
|
|
412
|
+
* @param {ModalCallbackFunction} callback
|
|
413
|
+
* @param {string} target
|
|
414
|
+
* @returns {ModalElement}
|
|
415
|
+
*/
|
|
416
|
+
public loadUrl(
|
|
417
|
+
title: string,
|
|
418
|
+
severity: SeverityEnum = SeverityEnum.info,
|
|
419
|
+
buttons: Array<Button>,
|
|
420
|
+
url: string,
|
|
421
|
+
callback?: ModalCallbackFunction
|
|
422
|
+
): ModalElement {
|
|
423
|
+
return this.advanced({
|
|
424
|
+
type: Types.ajax,
|
|
425
|
+
title,
|
|
426
|
+
severity,
|
|
427
|
+
buttons,
|
|
428
|
+
ajaxCallback: callback,
|
|
429
|
+
content: url,
|
|
430
|
+
});
|
|
431
|
+
}
|
|
432
|
+
|
|
433
|
+
/**
|
|
434
|
+
* Shows a dialog
|
|
435
|
+
*
|
|
436
|
+
* @param {string} title
|
|
437
|
+
* @param {string | JQuery | Element | DocumentFragment} content
|
|
438
|
+
* @param {number} severity
|
|
439
|
+
* @param {Array<Button>} buttons
|
|
440
|
+
* @param {Array<string>} additionalCssClasses
|
|
441
|
+
* @returns {ModalElement}
|
|
442
|
+
*/
|
|
443
|
+
public show(
|
|
444
|
+
title: string,
|
|
445
|
+
content: string | JQuery | Element | DocumentFragment,
|
|
446
|
+
severity: SeverityEnum = SeverityEnum.info,
|
|
447
|
+
buttons?: Array<Button>,
|
|
448
|
+
additionalCssClasses?: Array<string>,
|
|
449
|
+
): ModalElement {
|
|
450
|
+
return this.advanced({
|
|
451
|
+
type: Types.default,
|
|
452
|
+
title,
|
|
453
|
+
content,
|
|
454
|
+
severity,
|
|
455
|
+
buttons,
|
|
456
|
+
additionalCssClasses,
|
|
457
|
+
});
|
|
458
|
+
}
|
|
459
|
+
|
|
460
|
+
/**
|
|
461
|
+
* Loads modal by configuration
|
|
462
|
+
*/
|
|
463
|
+
public advanced(configuration: PartialConfiguration): ModalElement {
|
|
464
|
+
// Validation of configuration
|
|
465
|
+
configuration.type = typeof configuration.type === 'string' && configuration.type in Types
|
|
466
|
+
? configuration.type
|
|
467
|
+
: this.defaultConfiguration.type;
|
|
468
|
+
configuration.title = typeof configuration.title === 'string'
|
|
469
|
+
? configuration.title
|
|
470
|
+
: this.defaultConfiguration.title;
|
|
471
|
+
configuration.content = typeof configuration.content === 'string' || typeof configuration.content === 'object'
|
|
472
|
+
? configuration.content
|
|
473
|
+
: this.defaultConfiguration.content;
|
|
474
|
+
configuration.severity = typeof configuration.severity !== 'undefined'
|
|
475
|
+
? configuration.severity
|
|
476
|
+
: this.defaultConfiguration.severity;
|
|
477
|
+
configuration.buttons = <Array<Button>>configuration.buttons || this.defaultConfiguration.buttons;
|
|
478
|
+
configuration.size = typeof configuration.size === 'string' && configuration.size in Sizes
|
|
479
|
+
? configuration.size
|
|
480
|
+
: this.defaultConfiguration.size;
|
|
481
|
+
configuration.style = typeof configuration.style === 'string' && configuration.style in Styles
|
|
482
|
+
? configuration.style
|
|
483
|
+
: this.defaultConfiguration.style;
|
|
484
|
+
configuration.additionalCssClasses = configuration.additionalCssClasses || this.defaultConfiguration.additionalCssClasses;
|
|
485
|
+
configuration.callback = typeof configuration.callback === 'function' ? configuration.callback : this.defaultConfiguration.callback;
|
|
486
|
+
configuration.ajaxCallback = typeof configuration.ajaxCallback === 'function'
|
|
487
|
+
? configuration.ajaxCallback
|
|
488
|
+
: this.defaultConfiguration.ajaxCallback;
|
|
489
|
+
configuration.staticBackdrop = configuration.staticBackdrop || this.defaultConfiguration.staticBackdrop;
|
|
490
|
+
configuration.hideCloseButton = configuration.hideCloseButton || this.defaultConfiguration.hideCloseButton;
|
|
491
|
+
|
|
492
|
+
return this.generate(configuration);
|
|
493
|
+
}
|
|
494
|
+
|
|
495
|
+
public setButtons(buttons: Array<Button>): ModalElement {
|
|
496
|
+
this.currentModal.buttons = buttons;
|
|
497
|
+
return this.currentModal;
|
|
498
|
+
}
|
|
499
|
+
|
|
500
|
+
/**
|
|
501
|
+
* Initialize markup with data attributes
|
|
502
|
+
*
|
|
503
|
+
* @param {HTMLDocument} theDocument
|
|
504
|
+
* @internal
|
|
505
|
+
*/
|
|
506
|
+
public initializeMarkupTrigger(theDocument: Document): void {
|
|
507
|
+
const modalTrigger = (evt: Event, triggerElement: HTMLElement): void => {
|
|
508
|
+
evt.preventDefault();
|
|
509
|
+
const content = triggerElement.dataset.bsContent || triggerElement.dataset.content || TYPO3?.lang?.['message.confirmation'] || 'Are you sure?';
|
|
510
|
+
let severity = SeverityEnum.notice;
|
|
511
|
+
if (triggerElement.dataset.severity in SeverityEnum) {
|
|
512
|
+
const severityKey = triggerElement.dataset.severity as keyof typeof SeverityEnum;
|
|
513
|
+
severity = SeverityEnum[severityKey];
|
|
514
|
+
}
|
|
515
|
+
let size = Sizes.default;
|
|
516
|
+
if (triggerElement.dataset.size in Sizes) {
|
|
517
|
+
const sizeKey = triggerElement.dataset.size as keyof typeof Sizes;
|
|
518
|
+
size = Sizes[sizeKey];
|
|
519
|
+
}
|
|
520
|
+
let url = triggerElement.dataset.url || null;
|
|
521
|
+
if (url !== null) {
|
|
522
|
+
const separator = url.includes('?') ? '&' : '?';
|
|
523
|
+
const params = new URLSearchParams(triggerElement.dataset).toString();
|
|
524
|
+
url = url + separator + params;
|
|
525
|
+
}
|
|
526
|
+
this.advanced({
|
|
527
|
+
type: url !== null ? Types.ajax : Types.default,
|
|
528
|
+
title: triggerElement.dataset.title || 'Alert',
|
|
529
|
+
content: url !== null ? url : content,
|
|
530
|
+
size,
|
|
531
|
+
severity,
|
|
532
|
+
staticBackdrop: triggerElement.dataset.staticBackdrop !== undefined,
|
|
533
|
+
buttons: [
|
|
534
|
+
{
|
|
535
|
+
text: triggerElement.dataset.buttonCloseText || TYPO3?.lang?.['button.close'] || 'Close',
|
|
536
|
+
active: true,
|
|
537
|
+
btnClass: 'btn-default',
|
|
538
|
+
trigger: (e: Event, modal: ModalElement): void => {
|
|
539
|
+
modal.hideModal();
|
|
540
|
+
const event = Modal.createModalResponseEventFromElement(triggerElement, false);
|
|
541
|
+
if (event !== null) {
|
|
542
|
+
triggerElement.dispatchEvent(event);
|
|
543
|
+
}
|
|
544
|
+
},
|
|
545
|
+
},
|
|
546
|
+
{
|
|
547
|
+
text: triggerElement.dataset.buttonOkText || TYPO3?.lang?.['button.ok'] || 'OK',
|
|
548
|
+
btnClass: 'btn-' + Severity.getCssClass(severity),
|
|
549
|
+
trigger: (e: Event, modal: ModalElement): void => {
|
|
550
|
+
modal.hideModal();
|
|
551
|
+
const event = Modal.createModalResponseEventFromElement(triggerElement, true);
|
|
552
|
+
if (event !== null) {
|
|
553
|
+
triggerElement.dispatchEvent(event);
|
|
554
|
+
}
|
|
555
|
+
const targetLocation = triggerElement.dataset.uri || triggerElement.dataset.href || triggerElement.getAttribute('href');
|
|
556
|
+
if (targetLocation && targetLocation !== '#') {
|
|
557
|
+
triggerElement.ownerDocument.location.href = targetLocation;
|
|
558
|
+
}
|
|
559
|
+
if (triggerElement.getAttribute('type') === 'submit' && (
|
|
560
|
+
triggerElement.tagName === 'BUTTON' || triggerElement.tagName === 'INPUT'
|
|
561
|
+
)) {
|
|
562
|
+
const submitter = triggerElement as HTMLButtonElement|HTMLInputElement;
|
|
563
|
+
submitter.form?.requestSubmit(submitter);
|
|
564
|
+
}
|
|
565
|
+
if (triggerElement.dataset.targetForm) {
|
|
566
|
+
// Submit a possible form in case the trigger has the data-target-form
|
|
567
|
+
// attribute set to a valid form identifier in the ownerDocument.
|
|
568
|
+
(triggerElement.ownerDocument.querySelector('form#' + triggerElement.dataset.targetForm) as HTMLFormElement)?.submit();
|
|
569
|
+
}
|
|
570
|
+
},
|
|
571
|
+
},
|
|
572
|
+
],
|
|
573
|
+
});
|
|
574
|
+
};
|
|
575
|
+
new RegularEvent('click', modalTrigger).delegateTo(theDocument, '.t3js-modal-trigger');
|
|
576
|
+
}
|
|
577
|
+
|
|
578
|
+
/**
|
|
579
|
+
* @param {Configuration} configuration
|
|
580
|
+
*/
|
|
581
|
+
private generate(configuration: PartialConfiguration): ModalElement {
|
|
582
|
+
const currentModal = document.createElement('typo3-backend-modal') as ModalElement;
|
|
583
|
+
|
|
584
|
+
currentModal.type = configuration.type;
|
|
585
|
+
if (typeof configuration.content === 'string') {
|
|
586
|
+
currentModal.content = configuration.content;
|
|
587
|
+
} else if (configuration.type === Types.default) {
|
|
588
|
+
currentModal.type = Types.template;
|
|
589
|
+
currentModal.templateResultContent = configuration.content;
|
|
590
|
+
}
|
|
591
|
+
currentModal.severity = configuration.severity;
|
|
592
|
+
currentModal.variant = configuration.style;
|
|
593
|
+
currentModal.size = configuration.size;
|
|
594
|
+
currentModal.modalTitle = configuration.title;
|
|
595
|
+
currentModal.additionalCssClasses = configuration.additionalCssClasses;
|
|
596
|
+
currentModal.buttons = <Array<Button>>configuration.buttons;
|
|
597
|
+
currentModal.staticBackdrop = configuration.staticBackdrop;
|
|
598
|
+
currentModal.hideCloseButton = configuration.hideCloseButton;
|
|
599
|
+
if (configuration.callback) {
|
|
600
|
+
currentModal.callback = configuration.callback;
|
|
601
|
+
}
|
|
602
|
+
if (configuration.ajaxCallback) {
|
|
603
|
+
currentModal.ajaxCallback = configuration.ajaxCallback;
|
|
604
|
+
}
|
|
605
|
+
|
|
606
|
+
currentModal.addEventListener('typo3-modal-shown', (): void => {
|
|
607
|
+
const backdrop = currentModal.nextElementSibling as HTMLElement;
|
|
608
|
+
|
|
609
|
+
// Stack backdrop zIndexes to overlay existing (opened) modals
|
|
610
|
+
// We use 1000 as the overall base to circumvent a stuttering UI as Bootstrap uses a z-index of 1050 for backdrops
|
|
611
|
+
// on initial rendering - this will clash again when at least five modals are open, which is fine and should never happen
|
|
612
|
+
const baseZIndex = 1000 + (10 * this.instances.length);
|
|
613
|
+
currentModal.zindex = baseZIndex;
|
|
614
|
+
const backdropZIndex = baseZIndex - 5;
|
|
615
|
+
backdrop.style.zIndex = backdropZIndex.toString();
|
|
616
|
+
|
|
617
|
+
// focus the button which was configured as active button
|
|
618
|
+
const activeButton = currentModal.querySelector(`${Identifiers.footer} .t3js-active`) as HTMLInputElement | null;
|
|
619
|
+
if (activeButton !== null) {
|
|
620
|
+
activeButton.focus();
|
|
621
|
+
} else {
|
|
622
|
+
// @todo can be removed once we switch to a native <dialog> tag
|
|
623
|
+
(currentModal.querySelector('[autofocus]') as HTMLInputElement)?.focus();
|
|
624
|
+
}
|
|
625
|
+
});
|
|
626
|
+
|
|
627
|
+
// Remove modal from Modal.instances when hidden
|
|
628
|
+
currentModal.addEventListener('typo3-modal-hide', (): void => {
|
|
629
|
+
if (this.instances.length > 0) {
|
|
630
|
+
const lastIndex = this.instances.length - 1;
|
|
631
|
+
this.instances.splice(lastIndex, 1);
|
|
632
|
+
this.currentModal = this.instances[lastIndex - 1];
|
|
633
|
+
}
|
|
634
|
+
});
|
|
635
|
+
|
|
636
|
+
currentModal.addEventListener('typo3-modal-hidden', (): void => {
|
|
637
|
+
currentModal.remove();
|
|
638
|
+
// Keep class modal-open on body tag as long as open modals exist
|
|
639
|
+
if (this.instances.length > 0) {
|
|
640
|
+
document.body.classList.add('modal-open');
|
|
641
|
+
}
|
|
642
|
+
});
|
|
643
|
+
|
|
644
|
+
// When modal is opened/shown add it to Modal.instances and make it Modal.currentModal
|
|
645
|
+
currentModal.addEventListener('typo3-modal-show', (): void => {
|
|
646
|
+
this.currentModal = currentModal;
|
|
647
|
+
this.instances.push(currentModal);
|
|
648
|
+
});
|
|
649
|
+
|
|
650
|
+
document.body.appendChild(currentModal);
|
|
651
|
+
|
|
652
|
+
return currentModal;
|
|
653
|
+
}
|
|
654
|
+
}
|
|
655
|
+
|
|
656
|
+
let modalObject: Modal = null;
|
|
657
|
+
try {
|
|
658
|
+
if (parent && parent.window.TYPO3 && parent.window.TYPO3.Modal) {
|
|
659
|
+
// fetch from parent
|
|
660
|
+
// we need to trigger the event capturing again, in order to make sure this works inside iframes
|
|
661
|
+
parent.window.TYPO3.Modal.initializeMarkupTrigger(document);
|
|
662
|
+
modalObject = parent.window.TYPO3.Modal;
|
|
663
|
+
} else if (top && top.TYPO3.Modal) {
|
|
664
|
+
// fetch object from outer frame
|
|
665
|
+
// we need to trigger the event capturing again, in order to make sure this works inside iframes
|
|
666
|
+
top.TYPO3.Modal.initializeMarkupTrigger(document);
|
|
667
|
+
modalObject = top.TYPO3.Modal;
|
|
668
|
+
}
|
|
669
|
+
} catch {
|
|
670
|
+
// This only happens if the opener, parent or top is some other url (eg a local file)
|
|
671
|
+
// which loaded the current window. Then the browser's cross domain policy jumps in
|
|
672
|
+
// and raises an exception.
|
|
673
|
+
// For this case we are safe and we can create our global object below.
|
|
674
|
+
}
|
|
675
|
+
|
|
676
|
+
if (!modalObject) {
|
|
677
|
+
modalObject = new Modal();
|
|
678
|
+
|
|
679
|
+
if (typeof TYPO3 !== 'undefined') {
|
|
680
|
+
// expose as global object
|
|
681
|
+
TYPO3.Modal = modalObject;
|
|
682
|
+
}
|
|
683
|
+
}
|
|
684
|
+
|
|
685
|
+
export default modalObject;
|