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,36 @@
|
|
|
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 LinkBrowser from './link-browser';
|
|
15
|
+
import RegularEvent from '@typo3/core/event/regular-event';
|
|
16
|
+
|
|
17
|
+
/**
|
|
18
|
+
* Module: @typo3/backend/url-link-handler
|
|
19
|
+
* @exports @typo3/backend/url-link-handler
|
|
20
|
+
* URL link interaction
|
|
21
|
+
*/
|
|
22
|
+
class UrlLinkHandler {
|
|
23
|
+
constructor() {
|
|
24
|
+
new RegularEvent('submit', (evt: MouseEvent, targetEl: HTMLElement): void => {
|
|
25
|
+
evt.preventDefault();
|
|
26
|
+
const inputField = targetEl.querySelector('[name="lurl"]') as HTMLInputElement;
|
|
27
|
+
const value = inputField.value.trim();
|
|
28
|
+
if (value === '') {
|
|
29
|
+
return;
|
|
30
|
+
}
|
|
31
|
+
LinkBrowser.finalizeFunction(value);
|
|
32
|
+
}).delegateTo(document, '#lurlform');
|
|
33
|
+
}
|
|
34
|
+
}
|
|
35
|
+
|
|
36
|
+
export default new UrlLinkHandler();
|
|
@@ -0,0 +1,255 @@
|
|
|
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 Login from './login';
|
|
15
|
+
import RegularEvent from '@typo3/core/event/regular-event';
|
|
16
|
+
import DocumentService from '@typo3/core/document-service';
|
|
17
|
+
|
|
18
|
+
/**
|
|
19
|
+
* Module: @typo3/backend/user-pass-login
|
|
20
|
+
* JavaScript module for the UsernamePasswordLoginProvider
|
|
21
|
+
* @exports @typo3/backend/user-pass-login
|
|
22
|
+
*/
|
|
23
|
+
class UserPassLogin {
|
|
24
|
+
protected options: any;
|
|
25
|
+
|
|
26
|
+
constructor() {
|
|
27
|
+
this.init();
|
|
28
|
+
}
|
|
29
|
+
|
|
30
|
+
private async init(): Promise<void> {
|
|
31
|
+
await DocumentService.ready();
|
|
32
|
+
this.options = {
|
|
33
|
+
usernameField: '.t3js-login-username-field',
|
|
34
|
+
passwordField: '.t3js-login-password-field',
|
|
35
|
+
copyrightLink: '.t3js-login-copyright-link',
|
|
36
|
+
};
|
|
37
|
+
const usernameField: HTMLInputElement = document.querySelector(this.options.usernameField);
|
|
38
|
+
const passwordField: HTMLInputElement = document.querySelector(this.options.passwordField);
|
|
39
|
+
const copyrightLink: HTMLInputElement = document.querySelector(this.options.copyrightLink);
|
|
40
|
+
|
|
41
|
+
// register submit handler
|
|
42
|
+
Login.options.submitHandler = this.resetPassword;
|
|
43
|
+
|
|
44
|
+
[usernameField, passwordField].forEach((field: HTMLInputElement) => new RegularEvent('keypress', this.showCapslockWarning).bindTo(field));
|
|
45
|
+
['input', 'change'].forEach((eventName: string) => new RegularEvent(eventName, this.showPasswordToggle).bindTo(passwordField));
|
|
46
|
+
new RegularEvent('keydown', this.toggleCopyright).bindTo(copyrightLink);
|
|
47
|
+
|
|
48
|
+
// if the login screen is shown in the login_frameset window for re-login,
|
|
49
|
+
// then try to get the username of the current/former login from opening windows main frame:
|
|
50
|
+
if (parent.opener?.TYPO3?.configuration?.username) {
|
|
51
|
+
usernameField.value = parent.opener.TYPO3.configuration.username;
|
|
52
|
+
}
|
|
53
|
+
|
|
54
|
+
if (usernameField.value === '') {
|
|
55
|
+
usernameField.focus();
|
|
56
|
+
} else {
|
|
57
|
+
passwordField.focus();
|
|
58
|
+
}
|
|
59
|
+
}
|
|
60
|
+
|
|
61
|
+
/**
|
|
62
|
+
* Checks whether capslock is enabled (returns TRUE if enabled, false otherwise)
|
|
63
|
+
* thanks to http://24ways.org/2007/capturing-caps-lock
|
|
64
|
+
*
|
|
65
|
+
* @param {Event} e
|
|
66
|
+
* @returns {boolean}
|
|
67
|
+
*/
|
|
68
|
+
private isCapslockEnabled(e: any): boolean {
|
|
69
|
+
const ev = e ? e : window.event;
|
|
70
|
+
if (!ev) {
|
|
71
|
+
return false;
|
|
72
|
+
}
|
|
73
|
+
// get key pressed
|
|
74
|
+
let pressedKeyAsciiCode = -1;
|
|
75
|
+
if (ev.which) {
|
|
76
|
+
pressedKeyAsciiCode = ev.which;
|
|
77
|
+
} else if (ev.keyCode) {
|
|
78
|
+
pressedKeyAsciiCode = ev.keyCode;
|
|
79
|
+
}
|
|
80
|
+
// get shift status
|
|
81
|
+
let shiftPressed = false;
|
|
82
|
+
if (ev.shiftKey) {
|
|
83
|
+
shiftPressed = ev.shiftKey;
|
|
84
|
+
} else if (ev.modifiers) {
|
|
85
|
+
/* tslint:disable:no-bitwise */
|
|
86
|
+
shiftPressed = !!(ev.modifiers & 4);
|
|
87
|
+
}
|
|
88
|
+
return (pressedKeyAsciiCode >= 65 && pressedKeyAsciiCode <= 90 && !shiftPressed)
|
|
89
|
+
|| (pressedKeyAsciiCode >= 97 && pressedKeyAsciiCode <= 122 && shiftPressed);
|
|
90
|
+
}
|
|
91
|
+
|
|
92
|
+
/**
|
|
93
|
+
* Reset user password field to prevent it from being submitted
|
|
94
|
+
*/
|
|
95
|
+
private readonly resetPassword = (): void => {
|
|
96
|
+
const passwordField: HTMLInputElement = document.querySelector(this.options.passwordField);
|
|
97
|
+
if (passwordField === null || passwordField.value === '') {
|
|
98
|
+
return;
|
|
99
|
+
}
|
|
100
|
+
const userIndent: HTMLInputElement = document.querySelector(Login.options.useridentField);
|
|
101
|
+
if (userIndent) {
|
|
102
|
+
userIndent.value = passwordField.value;
|
|
103
|
+
}
|
|
104
|
+
passwordField.value = '';
|
|
105
|
+
};
|
|
106
|
+
|
|
107
|
+
/**
|
|
108
|
+
* Toggle copyright
|
|
109
|
+
*/
|
|
110
|
+
private readonly toggleCopyright = (event: KeyboardEvent): void => {
|
|
111
|
+
if (event.key === ' ') {
|
|
112
|
+
(event.target as HTMLLinkElement).click();
|
|
113
|
+
}
|
|
114
|
+
};
|
|
115
|
+
|
|
116
|
+
/**
|
|
117
|
+
* Capslock handling
|
|
118
|
+
*/
|
|
119
|
+
private readonly attachCapslockWarning = (element: HTMLInputElement, label: string, message: string) => {
|
|
120
|
+
const targetContainer = element.closest('.input-group');
|
|
121
|
+
if (!targetContainer) {
|
|
122
|
+
return;
|
|
123
|
+
}
|
|
124
|
+
|
|
125
|
+
if (targetContainer.querySelector('.input-group-text-warning-capslock')) {
|
|
126
|
+
return;
|
|
127
|
+
}
|
|
128
|
+
|
|
129
|
+
const parentElement = element.parentElement;
|
|
130
|
+
|
|
131
|
+
// create icon
|
|
132
|
+
const warningIcon = `
|
|
133
|
+
<span class="icon icon-size-small icon-state-default">
|
|
134
|
+
<span class="icon-markup">
|
|
135
|
+
<svg xmlns="http://www.w3.org/2000/svg" viewBox="0 0 16 16"><g fill="currentColor"><path d="m8 5.414 3.536 3.536.707-.707L8 4 3.757 8.243l.707.707L8 5.414zM4 11h8v1H4z"/></g></svg>
|
|
136
|
+
</span>
|
|
137
|
+
</span>
|
|
138
|
+
`;
|
|
139
|
+
|
|
140
|
+
// create message
|
|
141
|
+
const warningMessage = document.createElement('span');
|
|
142
|
+
warningMessage.classList.add('visually-hidden');
|
|
143
|
+
warningMessage.textContent = message;
|
|
144
|
+
|
|
145
|
+
// create element
|
|
146
|
+
const warningElement = document.createElement('span');
|
|
147
|
+
warningElement.classList.add('input-group-text', 'input-group-text-warning' ,'input-group-text-warning-capslock');
|
|
148
|
+
warningElement.role = 'status';
|
|
149
|
+
warningElement.innerHTML = warningIcon;
|
|
150
|
+
warningElement.title = label;
|
|
151
|
+
warningElement.appendChild(warningMessage);
|
|
152
|
+
|
|
153
|
+
if (parentElement.classList.contains('form-control-clearable-wrapper')) {
|
|
154
|
+
parentElement.insertAdjacentElement('afterend', warningElement);
|
|
155
|
+
return;
|
|
156
|
+
}
|
|
157
|
+
|
|
158
|
+
element.insertAdjacentElement('afterend', warningElement);
|
|
159
|
+
};
|
|
160
|
+
|
|
161
|
+
private readonly removeCapslockWarning = (element: HTMLInputElement) => {
|
|
162
|
+
const targetContainer = element.closest('.input-group');
|
|
163
|
+
if (!targetContainer) {
|
|
164
|
+
return;
|
|
165
|
+
}
|
|
166
|
+
|
|
167
|
+
const warningElement = targetContainer.querySelector('.input-group-text-warning-capslock');
|
|
168
|
+
if (!warningElement) {
|
|
169
|
+
return;
|
|
170
|
+
}
|
|
171
|
+
|
|
172
|
+
warningElement.remove();
|
|
173
|
+
};
|
|
174
|
+
|
|
175
|
+
private readonly showCapslockWarning = (event: Event): void => {
|
|
176
|
+
const targetElement = (event.target as HTMLInputElement);
|
|
177
|
+
const title = targetElement.dataset.capslockwarningTitle;
|
|
178
|
+
const message = targetElement.dataset.capslockwarningMessage;
|
|
179
|
+
|
|
180
|
+
if (this.isCapslockEnabled(event)) {
|
|
181
|
+
this.attachCapslockWarning(targetElement, title, message);
|
|
182
|
+
} else {
|
|
183
|
+
this.removeCapslockWarning(targetElement);
|
|
184
|
+
}
|
|
185
|
+
};
|
|
186
|
+
|
|
187
|
+
/**
|
|
188
|
+
* Password toggle handling
|
|
189
|
+
*/
|
|
190
|
+
private readonly attachPasswordToggle = (element: HTMLInputElement) => {
|
|
191
|
+
const container = element.closest('.input-group');
|
|
192
|
+
if (!container) {
|
|
193
|
+
return;
|
|
194
|
+
}
|
|
195
|
+
|
|
196
|
+
if (container.querySelector('.t3js-login-toggle-password')) {
|
|
197
|
+
return;
|
|
198
|
+
}
|
|
199
|
+
|
|
200
|
+
// icon
|
|
201
|
+
const icon = `
|
|
202
|
+
<span class="icon icon-size-small icon-state-default">
|
|
203
|
+
<span class="icon-markup">
|
|
204
|
+
<svg xmlns="http://www.w3.org/2000/svg" viewBox="0 0 16 16"><g fill="currentColor"><path d="M8.07 3C4.112 3 1 5.286 1 8s2.97 5 7 5c3.889 0 7-2.286 7-4.93C15 5.285 11.889 3.142 8.212 3h-.141Zm-.025 1.127c.141 0 .423.141.423.282s-.14.282-.423.282c-.845 0-1.69.704-1.69 1.55 0 .14-.141.282-.423.282-.282 0-.423-.141-.423-.282.141-1.127 1.268-2.114 2.536-2.114ZM2 8.03c0-1.298 1.017-2.591 2.647-3.312-.296.432-.296 1.01-.296 1.587 0 2.02 1.63 3.606 3.703 3.606 2.074 0 3.704-1.587 3.704-3.606 0-.577-.148-1.01-.296-1.443C12.943 5.582 14 6.875 14 8.029c-.148 2.02-2.841 3.924-6 3.971-3.36-.047-6-1.95-6-3.97Z"/></g></svg>
|
|
205
|
+
</span>
|
|
206
|
+
</span>
|
|
207
|
+
`;
|
|
208
|
+
|
|
209
|
+
// button
|
|
210
|
+
const button = document.createElement('button');
|
|
211
|
+
button.type = 'button';
|
|
212
|
+
button.classList.add('btn', 'btn-default', 't3js-login-toggle-password');
|
|
213
|
+
button.ariaLabel = element.dataset.passwordtoggleLabel ?? '';
|
|
214
|
+
button.innerHTML = icon;
|
|
215
|
+
|
|
216
|
+
button.addEventListener('click', () => {
|
|
217
|
+
if (button.classList.contains('active')) {
|
|
218
|
+
button.classList.remove('active');
|
|
219
|
+
element.type = 'password';
|
|
220
|
+
} else {
|
|
221
|
+
button.classList.add('active');
|
|
222
|
+
element.type = 'text';
|
|
223
|
+
}
|
|
224
|
+
});
|
|
225
|
+
|
|
226
|
+
container.insertAdjacentElement('beforeend', button);
|
|
227
|
+
};
|
|
228
|
+
|
|
229
|
+
private readonly removePasswordToggle = (element: HTMLInputElement) => {
|
|
230
|
+
const container = element.closest('.input-group');
|
|
231
|
+
if (!container) {
|
|
232
|
+
return;
|
|
233
|
+
}
|
|
234
|
+
|
|
235
|
+
const button = container.querySelector('.t3js-login-toggle-password');
|
|
236
|
+
if (!button) {
|
|
237
|
+
return;
|
|
238
|
+
}
|
|
239
|
+
|
|
240
|
+
button.remove();
|
|
241
|
+
element.type = 'password';
|
|
242
|
+
};
|
|
243
|
+
|
|
244
|
+
private readonly showPasswordToggle = (event: Event): void => {
|
|
245
|
+
const passwordField: HTMLInputElement = (event.target as HTMLInputElement);
|
|
246
|
+
if (passwordField.value === '') {
|
|
247
|
+
this.removePasswordToggle(passwordField);
|
|
248
|
+
return;
|
|
249
|
+
} else {
|
|
250
|
+
this.attachPasswordToggle(passwordField);
|
|
251
|
+
}
|
|
252
|
+
};
|
|
253
|
+
}
|
|
254
|
+
|
|
255
|
+
export default new UserPassLogin();
|
|
@@ -0,0 +1,189 @@
|
|
|
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 { BroadcastMessage, type BroadcastEvent } from '@typo3/backend/broadcast-message';
|
|
15
|
+
import BroadcastService from '@typo3/backend/broadcast-service';
|
|
16
|
+
|
|
17
|
+
enum Identifier {
|
|
18
|
+
colorSchemeSwitch = 'typo3-backend-color-scheme-switch',
|
|
19
|
+
}
|
|
20
|
+
|
|
21
|
+
export type ColorScheme = 'auto' | 'light' | 'dark';
|
|
22
|
+
export type Theme = 'modern' | 'classic';
|
|
23
|
+
export type TitleFormat = 'titleFirst' | 'sitenameFirst';
|
|
24
|
+
export type Direction = 'rtl' | null;
|
|
25
|
+
|
|
26
|
+
// Event for typo3:color-scheme:update and typo3:color-scheme:broadcast
|
|
27
|
+
export interface ColorSchemeUpdateEventData {
|
|
28
|
+
colorScheme: ColorScheme;
|
|
29
|
+
}
|
|
30
|
+
|
|
31
|
+
// Event for typo3:theme:update and typo3:theme:broadcast
|
|
32
|
+
export interface ThemeUpdateEventData {
|
|
33
|
+
theme: Theme;
|
|
34
|
+
}
|
|
35
|
+
|
|
36
|
+
// Event for typo3:title-format:update and typo3:title-format:broadcast
|
|
37
|
+
export interface TitleFormatUpdateEventData {
|
|
38
|
+
format: TitleFormat;
|
|
39
|
+
}
|
|
40
|
+
|
|
41
|
+
// Event for typo3:backend-language:update and typo3:backend-language:broadcast
|
|
42
|
+
export interface BackendLanguageUpdateEventData {
|
|
43
|
+
language: string;
|
|
44
|
+
direction: Direction;
|
|
45
|
+
}
|
|
46
|
+
|
|
47
|
+
class UserSettingsManager {
|
|
48
|
+
constructor() {
|
|
49
|
+
// triggered by
|
|
50
|
+
// * <typo3-backend-color-scheme-switch> (topbar) or
|
|
51
|
+
// * User setup module (via BackendUtility::setUpdateSignal('updateColorScheme', …))
|
|
52
|
+
document.addEventListener('typo3:color-scheme:update', e => this.onColorSchemeUpdate(e.detail));
|
|
53
|
+
// triggered by user setup module (via BackendUtility::setUpdateSignal('updateColorScheme', …))
|
|
54
|
+
document.addEventListener('typo3:theme:update', e => this.onThemeUpdate(e.detail));
|
|
55
|
+
// triggered by user setup module (via BackendUtility::setUpdateSignal('updateTitleFormat', …))
|
|
56
|
+
document.addEventListener('typo3:title-format:update', e => this.onTitleFormatUpdate(e.detail));
|
|
57
|
+
// triggered by user setup module (via BackendUtility::setUpdateSignal('updateBackendLanguage', …))
|
|
58
|
+
document.addEventListener('typo3:backend-language:update', e => this.onBackendLanguageFormatUpdate(e.detail));
|
|
59
|
+
|
|
60
|
+
// broadcast message by other instances
|
|
61
|
+
document.addEventListener('typo3:color-scheme:broadcast', e => this.activateColorScheme(e.detail.payload.colorScheme));
|
|
62
|
+
document.addEventListener('typo3:theme:broadcast', e => this.activateTheme(e.detail.payload.theme));
|
|
63
|
+
document.addEventListener('typo3:title-format:broadcast', e => this.activateTitleFormat(e.detail.payload.format));
|
|
64
|
+
document.addEventListener('typo3:backend-language:broadcast', e => this.updateBackendLanguage(e.detail.payload.language, e.detail.payload.direction));
|
|
65
|
+
}
|
|
66
|
+
|
|
67
|
+
private onColorSchemeUpdate(data: ColorSchemeUpdateEventData) {
|
|
68
|
+
const { colorScheme } = data;
|
|
69
|
+
this.activateColorScheme(colorScheme);
|
|
70
|
+
|
|
71
|
+
// broadcast to other instances
|
|
72
|
+
BroadcastService.post(new BroadcastMessage<ColorSchemeUpdateEventData>('color-scheme', 'broadcast', { colorScheme }));
|
|
73
|
+
}
|
|
74
|
+
|
|
75
|
+
private onThemeUpdate(data: ThemeUpdateEventData) {
|
|
76
|
+
const { theme } = data;
|
|
77
|
+
this.activateTheme(theme);
|
|
78
|
+
|
|
79
|
+
// broadcast to other instances
|
|
80
|
+
BroadcastService.post(new BroadcastMessage<ThemeUpdateEventData>('theme', 'broadcast', { theme }));
|
|
81
|
+
}
|
|
82
|
+
|
|
83
|
+
private onTitleFormatUpdate(data: TitleFormatUpdateEventData) {
|
|
84
|
+
const { format } = data;
|
|
85
|
+
this.activateTitleFormat(format);
|
|
86
|
+
|
|
87
|
+
// broadcast to other instances
|
|
88
|
+
BroadcastService.post(new BroadcastMessage<TitleFormatUpdateEventData>('title-format', 'broadcast', { format }));
|
|
89
|
+
}
|
|
90
|
+
|
|
91
|
+
private onBackendLanguageFormatUpdate(data: BackendLanguageUpdateEventData) {
|
|
92
|
+
const { language, direction } = data;
|
|
93
|
+
this.updateBackendLanguage(language, direction);
|
|
94
|
+
|
|
95
|
+
// broadcast to other instances
|
|
96
|
+
BroadcastService.post(new BroadcastMessage<BackendLanguageUpdateEventData>('language-update', 'broadcast', { language, direction }));
|
|
97
|
+
}
|
|
98
|
+
|
|
99
|
+
private activateColorScheme(colorScheme: ColorScheme) {
|
|
100
|
+
const colorSchemeSwitch = document.querySelector(Identifier.colorSchemeSwitch);
|
|
101
|
+
if (colorSchemeSwitch) {
|
|
102
|
+
colorSchemeSwitch.activeColorScheme = colorScheme;
|
|
103
|
+
}
|
|
104
|
+
this.setStyleChangingDocumentAttribute('data-color-scheme', colorScheme);
|
|
105
|
+
}
|
|
106
|
+
|
|
107
|
+
private activateTheme(theme: Theme) {
|
|
108
|
+
this.setStyleChangingDocumentAttribute('data-theme', theme);
|
|
109
|
+
}
|
|
110
|
+
|
|
111
|
+
private activateTitleFormat(format: TitleFormat) {
|
|
112
|
+
if (format === 'sitenameFirst') {
|
|
113
|
+
document.querySelector('typo3-backend-module-router')?.setAttribute('sitename-first', '');
|
|
114
|
+
} else {
|
|
115
|
+
document.querySelector('typo3-backend-module-router')?.removeAttribute('sitename-first');
|
|
116
|
+
}
|
|
117
|
+
}
|
|
118
|
+
|
|
119
|
+
private updateBackendLanguage(language: string, direction: Direction): void {
|
|
120
|
+
const rootEl = document.documentElement;
|
|
121
|
+
const frame = window.frames.list_frame?.document.documentElement;
|
|
122
|
+
|
|
123
|
+
rootEl.setAttribute('lang', language);
|
|
124
|
+
frame?.setAttribute('lang', language);
|
|
125
|
+
if (direction !== null) {
|
|
126
|
+
rootEl.setAttribute('dir', direction);
|
|
127
|
+
frame?.setAttribute('dir', direction);
|
|
128
|
+
} else {
|
|
129
|
+
rootEl.removeAttribute('dir');
|
|
130
|
+
frame?.removeAttribute('dir');
|
|
131
|
+
}
|
|
132
|
+
}
|
|
133
|
+
|
|
134
|
+
private async setStyleChangingDocumentAttribute(attributeName: string, attributeValue: string) {
|
|
135
|
+
const rootEl = document.documentElement;
|
|
136
|
+
const frame = window.frames.list_frame?.document.documentElement;
|
|
137
|
+
|
|
138
|
+
const action = () => {
|
|
139
|
+
rootEl.classList.add('t3js-disable-transitions');
|
|
140
|
+
frame?.classList.add('t3js-disable-transitions');
|
|
141
|
+
|
|
142
|
+
rootEl.setAttribute(attributeName, attributeValue);
|
|
143
|
+
frame?.setAttribute(attributeName, attributeValue);
|
|
144
|
+
};
|
|
145
|
+
|
|
146
|
+
const cleanup = () => {
|
|
147
|
+
rootEl.classList.remove('t3js-disable-transitions');
|
|
148
|
+
frame?.classList.remove('t3js-disable-transitions');
|
|
149
|
+
};
|
|
150
|
+
|
|
151
|
+
|
|
152
|
+
if (
|
|
153
|
+
window.matchMedia('(prefers-reduced-motion: reduce)').matches ||
|
|
154
|
+
// The fallback condition in the next line (currently needed for firefox) can be removed
|
|
155
|
+
// once view transitions enter baseline "Widely available":
|
|
156
|
+
// https://webstatus.dev/features/view-transitions?q=view+transition
|
|
157
|
+
!('startViewTransition' in document) || typeof document.startViewTransition !== 'function'
|
|
158
|
+
) {
|
|
159
|
+
action();
|
|
160
|
+
|
|
161
|
+
// await animation frame in order for the transition disable to be
|
|
162
|
+
// considered by the time the change-transitions are being started.
|
|
163
|
+
await new Promise(resolve => requestAnimationFrame(resolve));
|
|
164
|
+
if (frame) {
|
|
165
|
+
await new Promise(resolve => window.frames.list_frame.requestAnimationFrame(resolve));
|
|
166
|
+
}
|
|
167
|
+
cleanup();
|
|
168
|
+
return;
|
|
169
|
+
}
|
|
170
|
+
|
|
171
|
+
await document.startViewTransition(action).finished;
|
|
172
|
+
cleanup();
|
|
173
|
+
}
|
|
174
|
+
}
|
|
175
|
+
|
|
176
|
+
export default new UserSettingsManager();
|
|
177
|
+
|
|
178
|
+
declare global {
|
|
179
|
+
interface DocumentEventMap {
|
|
180
|
+
'typo3:color-scheme:update': CustomEvent<ColorSchemeUpdateEventData>;
|
|
181
|
+
'typo3:color-scheme:broadcast': BroadcastEvent<ColorSchemeUpdateEventData>;
|
|
182
|
+
'typo3:theme:update': CustomEvent<ThemeUpdateEventData>;
|
|
183
|
+
'typo3:theme:broadcast': BroadcastEvent<ThemeUpdateEventData>;
|
|
184
|
+
'typo3:title-format:update': CustomEvent<TitleFormatUpdateEventData>;
|
|
185
|
+
'typo3:title-format:broadcast': BroadcastEvent<TitleFormatUpdateEventData>;
|
|
186
|
+
'typo3:backend-language:update': CustomEvent<BackendLanguageUpdateEventData>;
|
|
187
|
+
'typo3:backend-language:broadcast': BroadcastEvent<BackendLanguageUpdateEventData>;
|
|
188
|
+
}
|
|
189
|
+
}
|
|
@@ -0,0 +1,205 @@
|
|
|
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 Client from '@typo3/backend/storage/client';
|
|
15
|
+
import DocumentService from '@typo3/core/document-service';
|
|
16
|
+
import RegularEvent from '@typo3/core/event/regular-event';
|
|
17
|
+
|
|
18
|
+
/**
|
|
19
|
+
* Utility class to store a collapsible state in the localStorage and to re-apply states.
|
|
20
|
+
* It uses the collapsible id to store the keys, which must be unique.
|
|
21
|
+
*
|
|
22
|
+
* Trigger state persisting by adding 'data-persist-collapse-state="true"' to a collapsible element.
|
|
23
|
+
*
|
|
24
|
+
* To improve performance when dealing with bigger trees:
|
|
25
|
+
* * A 'data-persist-collapse-state-suffix="some-suffix"' on each collapsible element can be defined: This
|
|
26
|
+
* specifies a local storage key instead of "general", states are then stored in this key. This is useful
|
|
27
|
+
* when bigger tree states are stored, moving them to a dedicated local storage key. Default is suffix "global".
|
|
28
|
+
* * A 'data-persist-collapse-state-if-state="shown"' (allowed values "shown" and "hidden"):
|
|
29
|
+
* Usually, both "collapsed" and "shown" states are stored in local storage. However, when a tree is rendered
|
|
30
|
+
* "hidden" or "shown" by default from Fluid, we only need the "opposite" state in local storage. It is good practice
|
|
31
|
+
* to set this to safe local storage space.
|
|
32
|
+
*
|
|
33
|
+
* When dealing with bigger treas, some of them may be search-aware: This is related to 'collapse-state-search.ts',
|
|
34
|
+
* which expands search matches in a tree. We usually do not want to persist collapse / expand state when a search is
|
|
35
|
+
* performed, since this is done by the search javascript. Instead, we want to go back to the previous expand/collapse
|
|
36
|
+
* state when a search value is cleared. To do this, an expand/collapse field can set 'data-persist-collapse-state-not-if-search="true"',
|
|
37
|
+
* which will suppress storing expand/collapse state from/to local storage if a search value is given.
|
|
38
|
+
* When the search value is cleared (empty string), the current expand/collapse state are applied again due to
|
|
39
|
+
* a submit event fired by 'collapse-state-search.ts', so this state class can re-create the expand/collapse state before
|
|
40
|
+
* a search keyword has been given. A search input field needs the attribute 'data-persist-collapse-search-key="some-search-key"'
|
|
41
|
+
* which points to the local storage key of the search term, plus class "t3js-collapse-search-term" to trigger all this search magic.
|
|
42
|
+
*
|
|
43
|
+
* @internal
|
|
44
|
+
*/
|
|
45
|
+
type PersistStateObject = { [key: string]: boolean };
|
|
46
|
+
|
|
47
|
+
export class CollapseStatePersister {
|
|
48
|
+
private readonly localStorageKey: string = 'collapse-states-';
|
|
49
|
+
private readonly localStorageKeyDefaultSuffix: string = 'general';
|
|
50
|
+
private readonly searchValueSelector: string = '.t3js-collapse-search-term';
|
|
51
|
+
private searchField: HTMLInputElement|null = null;
|
|
52
|
+
private searchForm: HTMLFormElement|null = null;
|
|
53
|
+
|
|
54
|
+
private readonly stateCache: Map<string, PersistStateObject>;
|
|
55
|
+
|
|
56
|
+
public constructor() {
|
|
57
|
+
this.stateCache = new Map();
|
|
58
|
+
|
|
59
|
+
DocumentService.ready().then((): void => {
|
|
60
|
+
this.searchField = document.querySelector(this.searchValueSelector);
|
|
61
|
+
if (this.searchField !== null) {
|
|
62
|
+
this.searchForm = this.searchField.closest('form');
|
|
63
|
+
this.searchField.value = Client.get(this.searchField.dataset.persistCollapseSearchKey) ?? '';
|
|
64
|
+
}
|
|
65
|
+
this.registerEventListener();
|
|
66
|
+
this.recoverStates();
|
|
67
|
+
});
|
|
68
|
+
}
|
|
69
|
+
|
|
70
|
+
private registerEventListener(): void {
|
|
71
|
+
const delegateEventTo: string = '.collapse[data-persist-collapse-state="true"]';
|
|
72
|
+
|
|
73
|
+
new RegularEvent('show.bs.collapse', (e: Event): void => {
|
|
74
|
+
const element: HTMLElement = e.target as HTMLElement;
|
|
75
|
+
if (element.dataset.persistCollapseState === 'true'
|
|
76
|
+
&& ((this.searchField !== null && this.searchField.value === '') || element.dataset.persistCollapseStateNotIfSearch === undefined)
|
|
77
|
+
) {
|
|
78
|
+
// Persist state only, if there is no search input field, or no search is performed
|
|
79
|
+
this.toStorage(element, true);
|
|
80
|
+
}
|
|
81
|
+
}).delegateTo(document, delegateEventTo);
|
|
82
|
+
|
|
83
|
+
new RegularEvent('hide.bs.collapse', (e: Event): void => {
|
|
84
|
+
const element: HTMLElement = e.target as HTMLElement;
|
|
85
|
+
if (element.dataset.persistCollapseState === 'true'
|
|
86
|
+
&& ((this.searchField !== null && this.searchField.value === '') || element.dataset.persistCollapseStateNotIfSearch === undefined)
|
|
87
|
+
) {
|
|
88
|
+
// Persist state only, if there is no search input field, or no search is performed
|
|
89
|
+
this.toStorage(element, false);
|
|
90
|
+
}
|
|
91
|
+
}).delegateTo(document, delegateEventTo);
|
|
92
|
+
|
|
93
|
+
if (this.searchForm !== null) {
|
|
94
|
+
new RegularEvent('submit', (e: SubmitEvent): void => {
|
|
95
|
+
e.preventDefault();
|
|
96
|
+
if (this.searchField !== null && this.searchField.value === '') {
|
|
97
|
+
this.recoverStates();
|
|
98
|
+
}
|
|
99
|
+
}).bindTo(this.searchForm);
|
|
100
|
+
}
|
|
101
|
+
}
|
|
102
|
+
|
|
103
|
+
private recoverStates(): void {
|
|
104
|
+
const collapseStateElements: NodeListOf<HTMLElement>|null = document.querySelectorAll('.collapse[data-persist-collapse-state="true"]');
|
|
105
|
+
collapseStateElements.forEach((element: HTMLElement) => {
|
|
106
|
+
const suffix: string = element.dataset.persistCollapseStateSuffix ?? this.localStorageKeyDefaultSuffix;
|
|
107
|
+
const currentStates = this.fromStorage(suffix);
|
|
108
|
+
const id: string = element.id;
|
|
109
|
+
if (id === '' || !this.shallRecoverState(element)) {
|
|
110
|
+
return;
|
|
111
|
+
}
|
|
112
|
+
const storeExpandedState = (element.dataset.persistCollapseStateIfState ?? 'shown') === 'shown';
|
|
113
|
+
const storeHiddenState = (element.dataset.persistCollapseStateIfState ?? 'hidden') === 'hidden';
|
|
114
|
+
const isExpanded = element.classList.contains('show');
|
|
115
|
+
if (storeExpandedState === true) {
|
|
116
|
+
// We're not using BootstrapCollapse.getOrCreateInstance() since this is too slow when
|
|
117
|
+
// dealing with many elements like with System > Configuration with TCA tree.
|
|
118
|
+
if (currentStates[id] === true) {
|
|
119
|
+
if (!isExpanded) {
|
|
120
|
+
const toggle: HTMLElement = document.querySelector('[data-bs-target="#' + id + '"]');
|
|
121
|
+
toggle.classList.remove('collapsed');
|
|
122
|
+
toggle.setAttribute('aria-expanded', 'true');
|
|
123
|
+
element.classList.add('show');
|
|
124
|
+
}
|
|
125
|
+
} else {
|
|
126
|
+
if (isExpanded) {
|
|
127
|
+
const toggle: HTMLElement = document.querySelector('[data-bs-target="#' + id + '"]');
|
|
128
|
+
toggle.classList.add('collapsed');
|
|
129
|
+
toggle.setAttribute('aria-expanded', 'false');
|
|
130
|
+
element.classList.remove('show');
|
|
131
|
+
}
|
|
132
|
+
}
|
|
133
|
+
}
|
|
134
|
+
if (storeHiddenState === true) {
|
|
135
|
+
if (currentStates[id] === false) {
|
|
136
|
+
if (isExpanded) {
|
|
137
|
+
const toggle: HTMLElement = document.querySelector('[data-bs-target="#' + id + '"]');
|
|
138
|
+
toggle.classList.add('collapsed');
|
|
139
|
+
toggle.setAttribute('aria-expanded', 'false');
|
|
140
|
+
element.classList.remove('show');
|
|
141
|
+
}
|
|
142
|
+
} else {
|
|
143
|
+
if (!isExpanded) {
|
|
144
|
+
const toggle: HTMLElement = document.querySelector('[data-bs-target="#' + id + '"]');
|
|
145
|
+
toggle.classList.remove('collapsed');
|
|
146
|
+
toggle.setAttribute('aria-expanded', 'true');
|
|
147
|
+
element.classList.add('show');
|
|
148
|
+
}
|
|
149
|
+
}
|
|
150
|
+
}
|
|
151
|
+
});
|
|
152
|
+
}
|
|
153
|
+
|
|
154
|
+
private shallRecoverState(element: HTMLElement): boolean {
|
|
155
|
+
if (element.dataset.persistCollapseStateNotIfSearch === undefined
|
|
156
|
+
|| element.dataset.persistCollapseStateNotIfSearch === 'false'
|
|
157
|
+
) {
|
|
158
|
+
return true;
|
|
159
|
+
}
|
|
160
|
+
return this.searchField !== null && this.searchField.value === '';
|
|
161
|
+
}
|
|
162
|
+
|
|
163
|
+
private fromStorage(suffix: string): PersistStateObject {
|
|
164
|
+
let result;
|
|
165
|
+
if (this.stateCache.has(this.localStorageKey + suffix)) {
|
|
166
|
+
result = this.stateCache.get(this.localStorageKey + suffix);
|
|
167
|
+
} else {
|
|
168
|
+
const currentStates = Client.get(this.localStorageKey + suffix);
|
|
169
|
+
result = currentStates !== null ? JSON.parse(currentStates) : {};
|
|
170
|
+
this.stateCache.set(this.localStorageKey + suffix, result);
|
|
171
|
+
}
|
|
172
|
+
return result;
|
|
173
|
+
}
|
|
174
|
+
|
|
175
|
+
private toStorage(element: HTMLElement, expanded: boolean) {
|
|
176
|
+
const key = element.id;
|
|
177
|
+
const suffix = element.dataset.persistCollapseStateSuffix ?? this.localStorageKeyDefaultSuffix;
|
|
178
|
+
const currentStates = this.fromStorage(suffix);
|
|
179
|
+
const storeExpandedState = (element.dataset.persistCollapseStateIfState ?? 'shown') === 'shown';
|
|
180
|
+
const storeHiddenState = (element.dataset.persistCollapseStateIfState ?? 'hidden') === 'hidden';
|
|
181
|
+
if (expanded === true && storeExpandedState === true && currentStates[key] !== true) {
|
|
182
|
+
currentStates[key] = true;
|
|
183
|
+
this.updateStates(this.localStorageKey + suffix, currentStates);
|
|
184
|
+
}
|
|
185
|
+
if (expanded === true && storeHiddenState === true && currentStates[key] === false) {
|
|
186
|
+
delete currentStates[key];
|
|
187
|
+
this.updateStates(this.localStorageKey + suffix, currentStates);
|
|
188
|
+
}
|
|
189
|
+
if (expanded === false && storeHiddenState === true && currentStates[key] !== false) {
|
|
190
|
+
currentStates[key] = false;
|
|
191
|
+
this.updateStates(this.localStorageKey + suffix, currentStates);
|
|
192
|
+
}
|
|
193
|
+
if (expanded === false && storeExpandedState === true && currentStates[key] === true) {
|
|
194
|
+
delete currentStates[key];
|
|
195
|
+
this.updateStates(this.localStorageKey + suffix, currentStates);
|
|
196
|
+
}
|
|
197
|
+
}
|
|
198
|
+
|
|
199
|
+
private updateStates(key: string, currentStates: PersistStateObject) {
|
|
200
|
+
Client.set(key, JSON.stringify(currentStates));
|
|
201
|
+
this.stateCache.set(key, currentStates);
|
|
202
|
+
}
|
|
203
|
+
}
|
|
204
|
+
|
|
205
|
+
export default new CollapseStatePersister();
|