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,44 @@
|
|
|
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 { MultiRecordSelectionSelectors } from '@typo3/backend/multi-record-selection';
|
|
15
|
+
|
|
16
|
+
/**
|
|
17
|
+
* Module: @typo3/backend/multi-record-selection-action
|
|
18
|
+
*/
|
|
19
|
+
|
|
20
|
+
export interface ActionConfiguration {
|
|
21
|
+
idField: string;
|
|
22
|
+
}
|
|
23
|
+
|
|
24
|
+
export interface ActionEventDetails {
|
|
25
|
+
identifier: string,
|
|
26
|
+
checkboxes: NodeListOf<HTMLInputElement>,
|
|
27
|
+
configuration: any
|
|
28
|
+
}
|
|
29
|
+
|
|
30
|
+
export class MultiRecordSelectionAction {
|
|
31
|
+
|
|
32
|
+
public static getEntityIdentifiers(eventDetails: ActionEventDetails): Array<string>
|
|
33
|
+
{
|
|
34
|
+
// Evaluate all checked records and if valid, add their uid to the list
|
|
35
|
+
const entityIdentifiers: Array<string> = [];
|
|
36
|
+
eventDetails.checkboxes.forEach((checkbox: HTMLInputElement): void => {
|
|
37
|
+
const checkboxContainer: HTMLElement = checkbox.closest(MultiRecordSelectionSelectors.elementSelector);
|
|
38
|
+
if (checkboxContainer !== null && checkboxContainer.dataset[eventDetails.configuration.idField]) {
|
|
39
|
+
entityIdentifiers.push(checkboxContainer.dataset[eventDetails.configuration.idField]);
|
|
40
|
+
}
|
|
41
|
+
});
|
|
42
|
+
return entityIdentifiers;
|
|
43
|
+
}
|
|
44
|
+
}
|
|
@@ -0,0 +1,108 @@
|
|
|
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 RegularEvent from '@typo3/core/event/regular-event';
|
|
15
|
+
import {
|
|
16
|
+
type ActionConfiguration,
|
|
17
|
+
type ActionEventDetails,
|
|
18
|
+
MultiRecordSelectionAction
|
|
19
|
+
} from '@typo3/backend/multi-record-selection-action';
|
|
20
|
+
import Modal, { type ModalElement } from '@typo3/backend/modal';
|
|
21
|
+
import { SeverityEnum } from '@typo3/backend/enum/severity';
|
|
22
|
+
import Severity from '@typo3/backend/severity';
|
|
23
|
+
import AjaxDataHandler from '@typo3/backend/ajax-data-handler';
|
|
24
|
+
import Notification from '@typo3/backend/notification';
|
|
25
|
+
|
|
26
|
+
interface DeleteActionConfiguration extends ActionConfiguration {
|
|
27
|
+
tableName: string;
|
|
28
|
+
returnUrl: string;
|
|
29
|
+
title: string;
|
|
30
|
+
content: string;
|
|
31
|
+
ok: string;
|
|
32
|
+
cancel: string;
|
|
33
|
+
}
|
|
34
|
+
|
|
35
|
+
interface DatahandlerCommand {
|
|
36
|
+
delete?: number
|
|
37
|
+
}
|
|
38
|
+
|
|
39
|
+
/**
|
|
40
|
+
* Module: @typo3/backend/multi-record-selection-delete-action
|
|
41
|
+
* @exports @typo3/backend/multi-record-selection-delete-action
|
|
42
|
+
*/
|
|
43
|
+
class MultiRecordSelectionDeleteAction {
|
|
44
|
+
public constructor() {
|
|
45
|
+
new RegularEvent('multiRecordSelection:action:delete', this.delete).bindTo(document);
|
|
46
|
+
}
|
|
47
|
+
|
|
48
|
+
private delete(event: CustomEvent): void {
|
|
49
|
+
event.preventDefault();
|
|
50
|
+
|
|
51
|
+
const eventDetails: ActionEventDetails = event.detail as ActionEventDetails;
|
|
52
|
+
const entityIdentifiers: Array<string> = MultiRecordSelectionAction.getEntityIdentifiers(eventDetails);
|
|
53
|
+
if (!entityIdentifiers.length) {
|
|
54
|
+
// Return in case no records to delete were found
|
|
55
|
+
return;
|
|
56
|
+
}
|
|
57
|
+
|
|
58
|
+
const configuration: DeleteActionConfiguration = eventDetails.configuration;
|
|
59
|
+
const tableName: string = configuration.tableName || '';
|
|
60
|
+
if (tableName === '') {
|
|
61
|
+
return;
|
|
62
|
+
}
|
|
63
|
+
const returnUrl: string = configuration.returnUrl || '';
|
|
64
|
+
|
|
65
|
+
Modal.advanced({
|
|
66
|
+
title: configuration.title || 'Delete',
|
|
67
|
+
content: configuration.content || 'Are you sure you want to delete those records?',
|
|
68
|
+
severity: SeverityEnum.warning,
|
|
69
|
+
buttons: [
|
|
70
|
+
{
|
|
71
|
+
text: configuration.cancel || TYPO3.lang['button.cancel'] || 'Cancel',
|
|
72
|
+
active: true,
|
|
73
|
+
btnClass: 'btn-default',
|
|
74
|
+
name: 'cancel',
|
|
75
|
+
trigger: (e: Event, modal: ModalElement) => modal.hideModal(),
|
|
76
|
+
},
|
|
77
|
+
{
|
|
78
|
+
text: configuration.ok || TYPO3.lang['button.delete'] || 'OK',
|
|
79
|
+
btnClass: 'btn-' + Severity.getCssClass(SeverityEnum.warning),
|
|
80
|
+
name: 'delete',
|
|
81
|
+
trigger: async (e: Event, modal: ModalElement): Promise<void> => {
|
|
82
|
+
modal.hideModal();
|
|
83
|
+
try {
|
|
84
|
+
const result = await AjaxDataHandler.process({
|
|
85
|
+
cmd: {
|
|
86
|
+
[tableName]: Object.fromEntries(entityIdentifiers.map((identifier: string): [string, DatahandlerCommand] => [
|
|
87
|
+
identifier, { delete: 1 }
|
|
88
|
+
]))
|
|
89
|
+
}
|
|
90
|
+
});
|
|
91
|
+
if (result.hasErrors) {
|
|
92
|
+
throw result.messages;
|
|
93
|
+
} else if (returnUrl !== '') {
|
|
94
|
+
(event.target as HTMLElement).ownerDocument.location.href = returnUrl;
|
|
95
|
+
} else {
|
|
96
|
+
(event.target as HTMLElement).ownerDocument.location.reload();
|
|
97
|
+
}
|
|
98
|
+
} catch {
|
|
99
|
+
Notification.error('Could not delete records');
|
|
100
|
+
}
|
|
101
|
+
}
|
|
102
|
+
}
|
|
103
|
+
]
|
|
104
|
+
});
|
|
105
|
+
}
|
|
106
|
+
}
|
|
107
|
+
|
|
108
|
+
export default new MultiRecordSelectionDeleteAction();
|
|
@@ -0,0 +1,56 @@
|
|
|
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 RegularEvent from '@typo3/core/event/regular-event';
|
|
15
|
+
import {
|
|
16
|
+
type ActionConfiguration,
|
|
17
|
+
type ActionEventDetails,
|
|
18
|
+
MultiRecordSelectionAction
|
|
19
|
+
} from '@typo3/backend/multi-record-selection-action';
|
|
20
|
+
|
|
21
|
+
interface EditActionConfiguration extends ActionConfiguration {
|
|
22
|
+
tableName: string;
|
|
23
|
+
returnUrl: string;
|
|
24
|
+
}
|
|
25
|
+
|
|
26
|
+
/**
|
|
27
|
+
* Module: @typo3/backend/multi-record-selection-edit-action
|
|
28
|
+
* @exports @typo3/backend/multi-record-selection-edit-action
|
|
29
|
+
*/
|
|
30
|
+
class MultiRecordSelectionEditAction {
|
|
31
|
+
public constructor() {
|
|
32
|
+
new RegularEvent('multiRecordSelection:action:edit', this.edit).bindTo(document);
|
|
33
|
+
}
|
|
34
|
+
|
|
35
|
+
private edit(event: CustomEvent): void {
|
|
36
|
+
event.preventDefault();
|
|
37
|
+
const eventDetails: ActionEventDetails = event.detail as ActionEventDetails;
|
|
38
|
+
const entityIdentifiers: Array<string> = MultiRecordSelectionAction.getEntityIdentifiers(eventDetails);
|
|
39
|
+
if (!entityIdentifiers.length) {
|
|
40
|
+
// Return in case no records to edit were found
|
|
41
|
+
return;
|
|
42
|
+
}
|
|
43
|
+
|
|
44
|
+
const configuration: EditActionConfiguration = eventDetails.configuration;
|
|
45
|
+
const tableName: string = configuration.tableName || '';
|
|
46
|
+
if (tableName === '') {
|
|
47
|
+
return;
|
|
48
|
+
}
|
|
49
|
+
|
|
50
|
+
window.location.href = top.TYPO3.settings.FormEngine.moduleUrl
|
|
51
|
+
+ '&edit[' + tableName + '][' + entityIdentifiers.join(',') + ']=edit'
|
|
52
|
+
+ '&returnUrl=' + encodeURIComponent(configuration.returnUrl || '');
|
|
53
|
+
}
|
|
54
|
+
}
|
|
55
|
+
|
|
56
|
+
export default new MultiRecordSelectionEditAction();
|
|
@@ -0,0 +1,468 @@
|
|
|
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 Notification from '@typo3/backend/notification';
|
|
15
|
+
import DocumentService from '@typo3/core/document-service';
|
|
16
|
+
import RegularEvent from '@typo3/core/event/regular-event';
|
|
17
|
+
import { selector } from '@typo3/core/literals';
|
|
18
|
+
import type { ActionConfiguration, ActionEventDetails } from '@typo3/backend/multi-record-selection-action';
|
|
19
|
+
|
|
20
|
+
export enum MultiRecordSelectionSelectors {
|
|
21
|
+
actionsSelector = '.t3js-multi-record-selection-actions',
|
|
22
|
+
checkboxSelector = '.t3js-multi-record-selection-check',
|
|
23
|
+
checkboxActionsSelector = '.t3js-multi-record-selection-check-actions',
|
|
24
|
+
checkboxActionsToggleSelector = '.t3js-multi-record-selection-check-actions-toggle',
|
|
25
|
+
elementSelector = '[data-multi-record-selection-element]',
|
|
26
|
+
}
|
|
27
|
+
|
|
28
|
+
enum Buttons {
|
|
29
|
+
actionButton = 'button[data-multi-record-selection-action]',
|
|
30
|
+
checkboxActionButton = 'button[data-multi-record-selection-check-action]',
|
|
31
|
+
}
|
|
32
|
+
|
|
33
|
+
enum CheckboxActions {
|
|
34
|
+
checkAll = 'check-all',
|
|
35
|
+
checkNone = 'check-none',
|
|
36
|
+
toggle = 'toggle'
|
|
37
|
+
}
|
|
38
|
+
|
|
39
|
+
enum CheckboxState {
|
|
40
|
+
any = '',
|
|
41
|
+
checked = ':checked',
|
|
42
|
+
unchecked = ':not(:checked)'
|
|
43
|
+
}
|
|
44
|
+
|
|
45
|
+
/**
|
|
46
|
+
* Module: @typo3/backend/multi-record-selection
|
|
47
|
+
*/
|
|
48
|
+
class MultiRecordSelection {
|
|
49
|
+
static activeClass: string = 'active';
|
|
50
|
+
private lastChecked: HTMLInputElement = null;
|
|
51
|
+
|
|
52
|
+
constructor() {
|
|
53
|
+
DocumentService.ready().then((): void => {
|
|
54
|
+
MultiRecordSelection.restoreTemporaryState();
|
|
55
|
+
this.registerActions();
|
|
56
|
+
this.registerActionsEventHandlers();
|
|
57
|
+
this.registerCheckboxActions();
|
|
58
|
+
this.registerCheckboxKeyboardActions();
|
|
59
|
+
this.registerCheckboxTableRowSelectionAction();
|
|
60
|
+
this.registerToggleCheckboxActions();
|
|
61
|
+
this.registerDispatchCheckboxStateChangedEvent();
|
|
62
|
+
this.registerCheckboxStateChangedEventHandler();
|
|
63
|
+
});
|
|
64
|
+
}
|
|
65
|
+
|
|
66
|
+
private static getCheckboxes(state: CheckboxState = CheckboxState.any, identifier: string = ''): NodeListOf<HTMLInputElement> {
|
|
67
|
+
return document.querySelectorAll(MultiRecordSelection.getCombinedSelector(MultiRecordSelectionSelectors.checkboxSelector + state, identifier));
|
|
68
|
+
}
|
|
69
|
+
|
|
70
|
+
private static getCombinedSelector(query: string, identifier: string): string {
|
|
71
|
+
return identifier !== '' ? [selector`[data-multi-record-selection-identifier="${identifier}"]`, query].join (' ') : query;
|
|
72
|
+
}
|
|
73
|
+
|
|
74
|
+
private static getIdentifier(element: HTMLElement): string {
|
|
75
|
+
return (element.closest('[data-multi-record-selection-identifier]') as HTMLElement)?.dataset.multiRecordSelectionIdentifier || '';
|
|
76
|
+
}
|
|
77
|
+
|
|
78
|
+
private static changeCheckboxState(checkbox: HTMLInputElement, check: boolean): void {
|
|
79
|
+
if (checkbox.disabled || checkbox.checked === check || checkbox.dataset.manuallyChanged) {
|
|
80
|
+
// Return in case the checkbox is disabled, the state did not change or another component has already changed it
|
|
81
|
+
return;
|
|
82
|
+
}
|
|
83
|
+
checkbox.checked = check;
|
|
84
|
+
checkbox.dispatchEvent(new Event('change', { bubbles: true }));
|
|
85
|
+
}
|
|
86
|
+
|
|
87
|
+
/**
|
|
88
|
+
* This restores (initializes) a temporary state, which is required in case
|
|
89
|
+
* the user returns to the listing using the browsers' history back feature,
|
|
90
|
+
* which will not result in a new request.
|
|
91
|
+
*/
|
|
92
|
+
private static restoreTemporaryState(): void {
|
|
93
|
+
const checked: NodeListOf<HTMLInputElement> = MultiRecordSelection.getCheckboxes(CheckboxState.checked);
|
|
94
|
+
// In case nothing is checked we don't have to do anything here
|
|
95
|
+
if (!checked.length) {
|
|
96
|
+
return;
|
|
97
|
+
}
|
|
98
|
+
// Highlight each checked checkbox and toggle the corresponding actions. Since
|
|
99
|
+
// the evaluation for toggling actions does a lot of things, we don't want to
|
|
100
|
+
// perform this for every checked checkbox. Therefore we store the identifiers,
|
|
101
|
+
// which were already evaluated and do not call the evaluation for them again.
|
|
102
|
+
let actionsToggled: boolean = false;
|
|
103
|
+
const identifiers: Array<string> = [];
|
|
104
|
+
checked.forEach((checkbox: HTMLInputElement) => {
|
|
105
|
+
(checkbox.closest(MultiRecordSelectionSelectors.elementSelector) as HTMLElement)?.classList.add(MultiRecordSelection.activeClass);
|
|
106
|
+
const identifier: string = MultiRecordSelection.getIdentifier(checkbox);
|
|
107
|
+
if (identifier !== '' && !identifiers.includes(identifier)) {
|
|
108
|
+
identifiers.push(identifier);
|
|
109
|
+
actionsToggled = true;
|
|
110
|
+
MultiRecordSelection.toggleActionsState(identifier);
|
|
111
|
+
}
|
|
112
|
+
});
|
|
113
|
+
// If none of the checked checkboxes contain an identifier, call the toggling one time anyways.
|
|
114
|
+
if (!actionsToggled) {
|
|
115
|
+
MultiRecordSelection.toggleActionsState();
|
|
116
|
+
}
|
|
117
|
+
}
|
|
118
|
+
|
|
119
|
+
/**
|
|
120
|
+
* Toggles the state of the actions, depending on the
|
|
121
|
+
* currently selected elements and their nature.
|
|
122
|
+
*/
|
|
123
|
+
private static toggleActionsState(identifier: string = ''): void {
|
|
124
|
+
const actionContainers: NodeListOf<HTMLElement> = document.querySelectorAll(
|
|
125
|
+
MultiRecordSelection.getCombinedSelector(MultiRecordSelectionSelectors.actionsSelector, identifier)
|
|
126
|
+
);
|
|
127
|
+
|
|
128
|
+
if (!actionContainers.length) {
|
|
129
|
+
// Early return in case no action containers are defined
|
|
130
|
+
return;
|
|
131
|
+
}
|
|
132
|
+
|
|
133
|
+
if (!MultiRecordSelection.getCheckboxes(CheckboxState.checked, identifier).length) {
|
|
134
|
+
// In case no checkbox is checked, hide all action containers and return
|
|
135
|
+
actionContainers.forEach((container: HTMLElement): void => MultiRecordSelection.changeActionContainerVisibility(container, false));
|
|
136
|
+
return;
|
|
137
|
+
}
|
|
138
|
+
|
|
139
|
+
// Remove hidden state of all action containers, since checked checkboxes exist
|
|
140
|
+
actionContainers.forEach((container: HTMLElement): void => MultiRecordSelection.changeActionContainerVisibility(container));
|
|
141
|
+
|
|
142
|
+
const actions: NodeListOf<HTMLButtonElement> = document.querySelectorAll(
|
|
143
|
+
[MultiRecordSelection.getCombinedSelector(MultiRecordSelectionSelectors.actionsSelector, identifier), Buttons.actionButton].join(' ')
|
|
144
|
+
);
|
|
145
|
+
|
|
146
|
+
if (!actions.length) {
|
|
147
|
+
// Early return in case no action is defined
|
|
148
|
+
return;
|
|
149
|
+
}
|
|
150
|
+
|
|
151
|
+
actions.forEach((action: HTMLButtonElement): void => {
|
|
152
|
+
if (!action.dataset.multiRecordSelectionActionConfig) {
|
|
153
|
+
// In case the action does not define any configuration, no toggling is possible
|
|
154
|
+
return;
|
|
155
|
+
}
|
|
156
|
+
const configuration: ActionConfiguration = JSON.parse(action.dataset.multiRecordSelectionActionConfig);
|
|
157
|
+
if (!configuration.idField) {
|
|
158
|
+
// Return in case the idField (where to find the id on selected elements) is not defined
|
|
159
|
+
return;
|
|
160
|
+
}
|
|
161
|
+
// Start the evaluation by disabling the action
|
|
162
|
+
action.disabled = true;
|
|
163
|
+
// Get all currently checked elements
|
|
164
|
+
const checked: NodeListOf<HTMLInputElement> = MultiRecordSelection.getCheckboxes(CheckboxState.checked, identifier);
|
|
165
|
+
for (let i = 0; i < checked.length; i++) {
|
|
166
|
+
// Evaluate each checked element if it contains the specified idField
|
|
167
|
+
if ((checked[i].closest(MultiRecordSelectionSelectors.elementSelector) as HTMLElement)?.dataset[configuration.idField]) {
|
|
168
|
+
// If a checked element contains the idField, remove the "disabled"
|
|
169
|
+
// state and end the search since the action can be performed.
|
|
170
|
+
action.disabled = false;
|
|
171
|
+
break;
|
|
172
|
+
}
|
|
173
|
+
}
|
|
174
|
+
});
|
|
175
|
+
}
|
|
176
|
+
|
|
177
|
+
/**
|
|
178
|
+
* This primarily just adds/removes the "hidden" class of the container. In case
|
|
179
|
+
* the container is in a panel, it also toggles the other panel heading elements.
|
|
180
|
+
* Note: This only works in case the container is not in the wrapper class, which
|
|
181
|
+
* should only be used for containers, outside of a panel.
|
|
182
|
+
*
|
|
183
|
+
* @param {HTMLElement} container The container to change the visibility for
|
|
184
|
+
* @param {boolean} visible Whether the container should be visible or not
|
|
185
|
+
*/
|
|
186
|
+
private static changeActionContainerVisibility(container: HTMLElement, visible: boolean = true): void {
|
|
187
|
+
const panelElements: HTMLCollection = container.closest('.multi-record-selection-panel')?.children;
|
|
188
|
+
if (visible) {
|
|
189
|
+
if (panelElements) {
|
|
190
|
+
for (let i = 0; i < panelElements.length; i++) { panelElements[i].classList.add('hidden'); }
|
|
191
|
+
}
|
|
192
|
+
container.classList.remove('hidden');
|
|
193
|
+
} else {
|
|
194
|
+
if (panelElements) {
|
|
195
|
+
for (let i = 0; i < panelElements.length; i++) { panelElements[i].classList.remove('hidden'); }
|
|
196
|
+
}
|
|
197
|
+
container.classList.add('hidden');
|
|
198
|
+
}
|
|
199
|
+
}
|
|
200
|
+
|
|
201
|
+
/**
|
|
202
|
+
* The manually changed attribute can be set by components, using
|
|
203
|
+
* this module while implementing custom logic to change checkbox
|
|
204
|
+
* state. To not cancel each others action, all actions in this
|
|
205
|
+
* module respect this attribute before changing checkbox state.
|
|
206
|
+
* Therefore, this method is called prior to every action in
|
|
207
|
+
* this module, which changes checkbox states. Otherwise old
|
|
208
|
+
* state would may led to misbehaviour.
|
|
209
|
+
*/
|
|
210
|
+
private static unsetManuallyChangedAttribute(identifier: string): void {
|
|
211
|
+
MultiRecordSelection.getCheckboxes(CheckboxState.any, identifier).forEach((checkbox: HTMLInputElement): void => {
|
|
212
|
+
checkbox.removeAttribute('data-manually-changed');
|
|
213
|
+
});
|
|
214
|
+
}
|
|
215
|
+
|
|
216
|
+
private registerActions(): void {
|
|
217
|
+
new RegularEvent('click', (e: Event, target: HTMLButtonElement): void => {
|
|
218
|
+
if (!target.dataset.multiRecordSelectionAction) {
|
|
219
|
+
// Return if we don't deal with a valid action
|
|
220
|
+
}
|
|
221
|
+
|
|
222
|
+
const identifier: string = MultiRecordSelection.getIdentifier(target);
|
|
223
|
+
const configuration: any = JSON.parse((target.dataset.multiRecordSelectionActionConfig || '{}'));
|
|
224
|
+
const checked: NodeListOf<HTMLInputElement> = MultiRecordSelection.getCheckboxes(CheckboxState.checked, identifier);
|
|
225
|
+
|
|
226
|
+
if (!checked.length) {
|
|
227
|
+
// Return in case there is currently no element checked to perform the action on.
|
|
228
|
+
return;
|
|
229
|
+
}
|
|
230
|
+
|
|
231
|
+
// This component does not implement any specific action itself, but just dispatches
|
|
232
|
+
// an event so the implementing components can react on the triggered action. To decrease
|
|
233
|
+
// selections in those components, most of the information are passed within the custom event.
|
|
234
|
+
// Those are e.g. the checked checkboxes, the instance identifier and the action configuration.
|
|
235
|
+
target.dispatchEvent(new CustomEvent(
|
|
236
|
+
'multiRecordSelection:action:' + target.dataset.multiRecordSelectionAction,
|
|
237
|
+
{
|
|
238
|
+
detail: <ActionEventDetails> { identifier: identifier, checkboxes: checked, configuration: configuration },
|
|
239
|
+
bubbles: true,
|
|
240
|
+
cancelable: false
|
|
241
|
+
}
|
|
242
|
+
));
|
|
243
|
+
}).delegateTo(document, [MultiRecordSelectionSelectors.actionsSelector, Buttons.actionButton].join(' '));
|
|
244
|
+
}
|
|
245
|
+
|
|
246
|
+
/**
|
|
247
|
+
* Other components can dispatch the "multiRecordSelection:actions"
|
|
248
|
+
* events to influence the display depending on their custom logic.
|
|
249
|
+
*/
|
|
250
|
+
private registerActionsEventHandlers(): void {
|
|
251
|
+
new RegularEvent('multiRecordSelection:actions:show', (e: CustomEvent): void => {
|
|
252
|
+
const identifier: string = e.detail?.identifier || '';
|
|
253
|
+
const actionContainers: NodeListOf<HTMLElement> = document.querySelectorAll(MultiRecordSelection.getCombinedSelector(MultiRecordSelectionSelectors.actionsSelector, identifier));
|
|
254
|
+
actionContainers.forEach((container: HTMLElement): void => MultiRecordSelection.changeActionContainerVisibility(container));
|
|
255
|
+
}).bindTo(document);
|
|
256
|
+
new RegularEvent('multiRecordSelection:actions:hide', (e: CustomEvent): void => {
|
|
257
|
+
const identifier: string = e.detail?.identifier || '';
|
|
258
|
+
const actionContainers: NodeListOf<HTMLElement> = document.querySelectorAll(MultiRecordSelection.getCombinedSelector(MultiRecordSelectionSelectors.actionsSelector, identifier));
|
|
259
|
+
actionContainers.forEach((container: HTMLElement): void => MultiRecordSelection.changeActionContainerVisibility(container, false));
|
|
260
|
+
}).bindTo(document);
|
|
261
|
+
new RegularEvent('multiRecordSelection:checkboxes:check', (e: CustomEvent): void => {
|
|
262
|
+
const identifier: string = e.detail?.identifier || '';
|
|
263
|
+
MultiRecordSelection.getCheckboxes(CheckboxState.any, identifier).forEach((checkbox: HTMLInputElement): void => MultiRecordSelection.changeCheckboxState(checkbox, true));
|
|
264
|
+
}).bindTo(document);
|
|
265
|
+
new RegularEvent('multiRecordSelection:checkboxes:uncheck', (e: CustomEvent): void => {
|
|
266
|
+
const identifier: string = e.detail?.identifier || '';
|
|
267
|
+
MultiRecordSelection.getCheckboxes(CheckboxState.any, identifier).forEach((checkbox: HTMLInputElement): void => MultiRecordSelection.changeCheckboxState(checkbox, false));
|
|
268
|
+
}).bindTo(document);
|
|
269
|
+
}
|
|
270
|
+
|
|
271
|
+
private registerCheckboxActions(): void {
|
|
272
|
+
new RegularEvent('click', (e: Event, target: HTMLButtonElement): void => {
|
|
273
|
+
e.preventDefault();
|
|
274
|
+
|
|
275
|
+
if (!target.dataset.multiRecordSelectionCheckAction) {
|
|
276
|
+
// Return if we don't deal with a valid action
|
|
277
|
+
return;
|
|
278
|
+
}
|
|
279
|
+
|
|
280
|
+
const identifier: string = MultiRecordSelection.getIdentifier(target);
|
|
281
|
+
const checkboxes: NodeListOf<HTMLInputElement> = MultiRecordSelection.getCheckboxes(CheckboxState.any, identifier);
|
|
282
|
+
|
|
283
|
+
if (!checkboxes.length) {
|
|
284
|
+
// Return in case there are no checkboxes (elements) to perform the action on.
|
|
285
|
+
return;
|
|
286
|
+
}
|
|
287
|
+
|
|
288
|
+
// Unset manually changed attribute so we can be sure, in case this is
|
|
289
|
+
// set on a checkbox, while executing the requested action, the checkbox
|
|
290
|
+
// was already changed by another component.
|
|
291
|
+
MultiRecordSelection.unsetManuallyChangedAttribute(identifier);
|
|
292
|
+
|
|
293
|
+
// Perform requested action
|
|
294
|
+
switch (target.dataset.multiRecordSelectionCheckAction) {
|
|
295
|
+
case CheckboxActions.checkAll:
|
|
296
|
+
checkboxes.forEach((checkbox: HTMLInputElement) => {
|
|
297
|
+
MultiRecordSelection.changeCheckboxState(checkbox, true);
|
|
298
|
+
});
|
|
299
|
+
break;
|
|
300
|
+
case CheckboxActions.checkNone:
|
|
301
|
+
checkboxes.forEach((checkbox: HTMLInputElement) => {
|
|
302
|
+
MultiRecordSelection.changeCheckboxState(checkbox, false);
|
|
303
|
+
});
|
|
304
|
+
break;
|
|
305
|
+
case CheckboxActions.toggle:
|
|
306
|
+
checkboxes.forEach((checkbox: HTMLInputElement) => {
|
|
307
|
+
MultiRecordSelection.changeCheckboxState(checkbox, !checkbox.checked);
|
|
308
|
+
});
|
|
309
|
+
break;
|
|
310
|
+
default:
|
|
311
|
+
// Unknown action
|
|
312
|
+
Notification.warning('Unknown checkbox action');
|
|
313
|
+
}
|
|
314
|
+
|
|
315
|
+
// To prevent possible side effects we simply clean up and unset the attribute here again
|
|
316
|
+
MultiRecordSelection.unsetManuallyChangedAttribute(identifier);
|
|
317
|
+
}).delegateTo(document, [MultiRecordSelectionSelectors.checkboxActionsSelector, Buttons.checkboxActionButton].join(' '));
|
|
318
|
+
}
|
|
319
|
+
|
|
320
|
+
private registerCheckboxKeyboardActions(): void {
|
|
321
|
+
new RegularEvent('click', (e: PointerEvent, target: HTMLInputElement): void => this.handleCheckboxKeyboardActions(e, target))
|
|
322
|
+
.delegateTo(document, MultiRecordSelectionSelectors.checkboxSelector);
|
|
323
|
+
}
|
|
324
|
+
|
|
325
|
+
private registerCheckboxTableRowSelectionAction(): void {
|
|
326
|
+
new RegularEvent('click', (e: PointerEvent, target: HTMLElement): void => {
|
|
327
|
+
const eventTargetTagName: string = (e.target as HTMLElement).tagName;
|
|
328
|
+
if (eventTargetTagName !== 'TH' && eventTargetTagName !== 'TD') {
|
|
329
|
+
// Only change checkbox state if the target is the row itself
|
|
330
|
+
return;
|
|
331
|
+
}
|
|
332
|
+
const checkbox: HTMLInputElement = target.querySelector(MultiRecordSelectionSelectors.checkboxSelector);
|
|
333
|
+
if (checkbox === null) {
|
|
334
|
+
// Return in case the table row does not contain a checkbox, handled by this component
|
|
335
|
+
return;
|
|
336
|
+
}
|
|
337
|
+
// Note: Since we only change the state of one checkbox, we don't have to unset the
|
|
338
|
+
// manually changed flag and also do not need to evaluate any instance identifier.
|
|
339
|
+
MultiRecordSelection.changeCheckboxState(checkbox, !checkbox.checked);
|
|
340
|
+
// After changing the target checkbox state, let's check if a keyboard action
|
|
341
|
+
// should be performed as well. We also prevent the keyboard actions from unsetting
|
|
342
|
+
// any state, e.g. the "manually changed flag", as this might have been set by any
|
|
343
|
+
// component triggered by the above checkbox state change operation.
|
|
344
|
+
this.handleCheckboxKeyboardActions(e, checkbox, false);
|
|
345
|
+
}).delegateTo(document, MultiRecordSelectionSelectors.elementSelector);
|
|
346
|
+
|
|
347
|
+
// In case row selection is enabled and a keyboard "shortcut" is used, prevent text selection on the rows
|
|
348
|
+
new RegularEvent('mousedown', (e: PointerEvent): void => (e.shiftKey || e.altKey || e.ctrlKey) && e.preventDefault())
|
|
349
|
+
.delegateTo(document, MultiRecordSelectionSelectors.elementSelector);
|
|
350
|
+
}
|
|
351
|
+
|
|
352
|
+
private registerDispatchCheckboxStateChangedEvent(): void {
|
|
353
|
+
new RegularEvent('change', (e: Event, target: HTMLInputElement): void => {
|
|
354
|
+
target.dispatchEvent(new CustomEvent('multiRecordSelection:checkbox:state:changed',{
|
|
355
|
+
detail: { identifier: MultiRecordSelection.getIdentifier(target) }, bubbles: true, cancelable: false
|
|
356
|
+
}));
|
|
357
|
+
}).delegateTo(document, MultiRecordSelectionSelectors.checkboxSelector);
|
|
358
|
+
}
|
|
359
|
+
|
|
360
|
+
private registerCheckboxStateChangedEventHandler(): void {
|
|
361
|
+
new RegularEvent('multiRecordSelection:checkbox:state:changed', (e: CustomEvent): void => {
|
|
362
|
+
const checkbox: HTMLInputElement = <HTMLInputElement>e.target;
|
|
363
|
+
const identifier: string = e.detail?.identifier || '';
|
|
364
|
+
|
|
365
|
+
if (checkbox.checked) {
|
|
366
|
+
checkbox.closest(MultiRecordSelectionSelectors.elementSelector).classList.add(MultiRecordSelection.activeClass);
|
|
367
|
+
} else {
|
|
368
|
+
checkbox.closest(MultiRecordSelectionSelectors.elementSelector).classList.remove(MultiRecordSelection.activeClass);
|
|
369
|
+
}
|
|
370
|
+
|
|
371
|
+
// Toggle actions for changed checkbox state
|
|
372
|
+
MultiRecordSelection.toggleActionsState(identifier);
|
|
373
|
+
}).bindTo(document);
|
|
374
|
+
}
|
|
375
|
+
|
|
376
|
+
private registerToggleCheckboxActions(): void {
|
|
377
|
+
new RegularEvent('click', (e: Event, target: HTMLButtonElement): void => {
|
|
378
|
+
const identifier: string = MultiRecordSelection.getIdentifier(target);
|
|
379
|
+
|
|
380
|
+
const checkAll: HTMLButtonElement = document.querySelector([
|
|
381
|
+
MultiRecordSelection.getCombinedSelector(MultiRecordSelectionSelectors.checkboxActionsSelector, identifier),
|
|
382
|
+
'button[data-multi-record-selection-check-action="' + CheckboxActions.checkAll + '"]'
|
|
383
|
+
].join(' '));
|
|
384
|
+
|
|
385
|
+
if (checkAll !== null) {
|
|
386
|
+
checkAll.disabled = !MultiRecordSelection.getCheckboxes(CheckboxState.unchecked, identifier).length;
|
|
387
|
+
}
|
|
388
|
+
|
|
389
|
+
const checkNone: HTMLButtonElement = document.querySelector([
|
|
390
|
+
MultiRecordSelection.getCombinedSelector(MultiRecordSelectionSelectors.checkboxActionsSelector, identifier),
|
|
391
|
+
'button[data-multi-record-selection-check-action="' + CheckboxActions.checkNone + '"]'
|
|
392
|
+
].join(' '));
|
|
393
|
+
|
|
394
|
+
if (checkNone !== null) {
|
|
395
|
+
checkNone.disabled = !MultiRecordSelection.getCheckboxes(CheckboxState.checked, identifier).length;
|
|
396
|
+
}
|
|
397
|
+
|
|
398
|
+
const toggle: HTMLButtonElement = document.querySelector([
|
|
399
|
+
MultiRecordSelection.getCombinedSelector(MultiRecordSelectionSelectors.checkboxActionsSelector, identifier),
|
|
400
|
+
'button[data-multi-record-selection-check-action="' + CheckboxActions.toggle + '"]'
|
|
401
|
+
].join(' '));
|
|
402
|
+
|
|
403
|
+
if (toggle !== null) {
|
|
404
|
+
toggle.disabled = !MultiRecordSelection.getCheckboxes(CheckboxState.any, identifier).length;
|
|
405
|
+
}
|
|
406
|
+
}).delegateTo(document, MultiRecordSelectionSelectors.checkboxActionsToggleSelector);
|
|
407
|
+
}
|
|
408
|
+
|
|
409
|
+
private handleCheckboxKeyboardActions(e: PointerEvent, target: HTMLInputElement, cleanUpState: boolean = true): void {
|
|
410
|
+
const identifier: string = MultiRecordSelection.getIdentifier(target);
|
|
411
|
+
|
|
412
|
+
// If lastChecked is not set, does no longer exist in visible DOM (e.g. because the list is paginated
|
|
413
|
+
// and lastChecked is on a prev/next page), is not in the same table as current target (according to
|
|
414
|
+
// the identifier) or no shortcut is used at all, add the current target as lastChecked and return.
|
|
415
|
+
if (!this.lastChecked
|
|
416
|
+
|| !document.body.contains(this.lastChecked)
|
|
417
|
+
|| MultiRecordSelection.getIdentifier(this.lastChecked) !== identifier
|
|
418
|
+
|| (!e.shiftKey && !e.altKey && !e.ctrlKey)
|
|
419
|
+
) {
|
|
420
|
+
this.lastChecked = target;
|
|
421
|
+
return;
|
|
422
|
+
}
|
|
423
|
+
|
|
424
|
+
if (cleanUpState) {
|
|
425
|
+
// In case clean up is *NOT* prevented, unset manually changed attribute.
|
|
426
|
+
// Usually clean up will be prevented by actions, which have already
|
|
427
|
+
// performed checkbox change operations.
|
|
428
|
+
MultiRecordSelection.unsetManuallyChangedAttribute(identifier);
|
|
429
|
+
}
|
|
430
|
+
|
|
431
|
+
// With the shift key, it's possible to check / uncheck a range of checkboxes
|
|
432
|
+
if (e.shiftKey) {
|
|
433
|
+
// To easily calculate the start and end position we need checkboxes as an array
|
|
434
|
+
const checkboxes: Array<HTMLInputElement> = Array.from(MultiRecordSelection.getCheckboxes(CheckboxState.any, identifier));
|
|
435
|
+
// The current target is the start position
|
|
436
|
+
const start = checkboxes.indexOf(target);
|
|
437
|
+
// The last manually clicked / checked checkbox is the end
|
|
438
|
+
const end = checkboxes.indexOf(this.lastChecked);
|
|
439
|
+
// Get the checkboxes which should be changed (we use min() and max() to allow ranges in both directions)
|
|
440
|
+
const checkboxesToChange = checkboxes.slice(Math.min(start, end), Math.max(start, end) + 1);
|
|
441
|
+
checkboxesToChange.forEach((checkbox: HTMLInputElement): void => {
|
|
442
|
+
// Change the state of each checkbox in question. Do not change the current target since we
|
|
443
|
+
// use it's current checked state, making both "check all" and "uncheck all" possible.
|
|
444
|
+
if (checkbox !== target) {
|
|
445
|
+
MultiRecordSelection.changeCheckboxState(checkbox, target.checked);
|
|
446
|
+
}
|
|
447
|
+
});
|
|
448
|
+
}
|
|
449
|
+
|
|
450
|
+
// We can now store the current target as lastChecked so it can be used in the next run
|
|
451
|
+
this.lastChecked = target;
|
|
452
|
+
|
|
453
|
+
// With the alt or ctrl key, it's possible to toggle the current selection
|
|
454
|
+
if (e.altKey || e.ctrlKey) {
|
|
455
|
+
MultiRecordSelection.getCheckboxes(CheckboxState.any, identifier).forEach((checkbox: HTMLInputElement): void => {
|
|
456
|
+
// Toggle all checkboxes except the current target as this was already done by clicking on it
|
|
457
|
+
if (checkbox !== target) {
|
|
458
|
+
MultiRecordSelection.changeCheckboxState(checkbox, !checkbox.checked);
|
|
459
|
+
}
|
|
460
|
+
});
|
|
461
|
+
}
|
|
462
|
+
|
|
463
|
+
// To prevent possible side effects we simply clean up and unset the attribute here again
|
|
464
|
+
MultiRecordSelection.unsetManuallyChangedAttribute(identifier);
|
|
465
|
+
}
|
|
466
|
+
}
|
|
467
|
+
|
|
468
|
+
export default new MultiRecordSelection();
|