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,291 @@
|
|
|
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 type { AjaxResponse } from '@typo3/core/ajax/ajax-response';
|
|
15
|
+
import RegularEvent from '@typo3/core/event/regular-event';
|
|
16
|
+
import AjaxRequest from '@typo3/core/ajax/ajax-request';
|
|
17
|
+
|
|
18
|
+
/**
|
|
19
|
+
* Module: @typo3/beuser/permissions
|
|
20
|
+
* Javascript functions regarding the permissions module
|
|
21
|
+
*/
|
|
22
|
+
class Permissions {
|
|
23
|
+
private readonly options: any = {
|
|
24
|
+
containerSelector: '#typo3-permissionList',
|
|
25
|
+
editControllerSelector: '#PermissionControllerEdit',
|
|
26
|
+
};
|
|
27
|
+
|
|
28
|
+
private readonly ajaxUrl: string = TYPO3.settings.ajaxUrls.user_access_permissions;
|
|
29
|
+
|
|
30
|
+
constructor() {
|
|
31
|
+
this.initializeCheckboxGroups();
|
|
32
|
+
this.initializeEvents();
|
|
33
|
+
}
|
|
34
|
+
|
|
35
|
+
/**
|
|
36
|
+
* Changes the value of the permissions in the form
|
|
37
|
+
*/
|
|
38
|
+
private static setPermissionCheckboxes(checknames: string, permissionValue: number): void {
|
|
39
|
+
const permissionCheckboxes: NodeListOf<HTMLInputElement> = document.querySelectorAll(`input[type="checkbox"][name^="${checknames}"]`);
|
|
40
|
+
for (const permissionCheckbox of permissionCheckboxes) {
|
|
41
|
+
const value = parseInt(permissionCheckbox.value, 10);
|
|
42
|
+
permissionCheckbox.checked = (permissionValue & value) === value;
|
|
43
|
+
}
|
|
44
|
+
}
|
|
45
|
+
|
|
46
|
+
/**
|
|
47
|
+
* checks for a change of the permissions in the form
|
|
48
|
+
*/
|
|
49
|
+
private static updatePermissionValue(checknames: string, varname: string): void {
|
|
50
|
+
let permissionValue = 0;
|
|
51
|
+
const checkedPermissionCheckboxes: NodeListOf<HTMLInputElement> = document.querySelectorAll(`input[type="checkbox"][name^="${checknames}"]:checked`);
|
|
52
|
+
for (const permissionCheckbox of checkedPermissionCheckboxes) {
|
|
53
|
+
permissionValue |= parseInt(permissionCheckbox.value, 10);
|
|
54
|
+
}
|
|
55
|
+
document.forms.namedItem('editform')[varname].value = permissionValue | (checknames === 'check[perms_user]' ? 1 : 0);
|
|
56
|
+
}
|
|
57
|
+
|
|
58
|
+
/**
|
|
59
|
+
* Changes permissions by sending an AJAX request to the server
|
|
60
|
+
*/
|
|
61
|
+
private setPermissions(element: HTMLElement): void {
|
|
62
|
+
const page = element.dataset.page;
|
|
63
|
+
const who = element.dataset.who;
|
|
64
|
+
const bits = element.dataset.bits;
|
|
65
|
+
|
|
66
|
+
(new AjaxRequest(this.ajaxUrl)).post({
|
|
67
|
+
page: page,
|
|
68
|
+
who: who,
|
|
69
|
+
permissions: element.dataset.permissions,
|
|
70
|
+
mode: element.dataset.mode,
|
|
71
|
+
bits: element.dataset.bits,
|
|
72
|
+
}).then(async (response: AjaxResponse): Promise<void> => {
|
|
73
|
+
const data = await response.resolve();
|
|
74
|
+
const parentElement = element.parentElement;
|
|
75
|
+
parentElement.innerHTML = data;
|
|
76
|
+
const targetElement = parentElement.querySelector('button[data-bits="' + bits + '"]') as HTMLButtonElement;
|
|
77
|
+
targetElement.focus();
|
|
78
|
+
});
|
|
79
|
+
}
|
|
80
|
+
|
|
81
|
+
/**
|
|
82
|
+
* changes the flag to lock the editing on a page by sending an AJAX request
|
|
83
|
+
*/
|
|
84
|
+
private toggleEditLock(element: HTMLElement): void {
|
|
85
|
+
const page = element.dataset.page;
|
|
86
|
+
(new AjaxRequest(this.ajaxUrl)).post({
|
|
87
|
+
action: 'toggle_edit_lock',
|
|
88
|
+
page: page,
|
|
89
|
+
editLockState: element.dataset.lockstate,
|
|
90
|
+
}).then(async (response: AjaxResponse): Promise<void> => {
|
|
91
|
+
const data = await response.resolve();
|
|
92
|
+
const parentElement = element.parentElement;
|
|
93
|
+
element.outerHTML = data;
|
|
94
|
+
const targetElement = parentElement.querySelector('button[data-page="' + page + '"]') as HTMLButtonElement;
|
|
95
|
+
targetElement.focus();
|
|
96
|
+
});
|
|
97
|
+
}
|
|
98
|
+
|
|
99
|
+
/**
|
|
100
|
+
* Owner-related: Set the new owner of a page by executing an ajax call
|
|
101
|
+
*/
|
|
102
|
+
private changeOwner(element: HTMLElement): void {
|
|
103
|
+
const page = element.dataset.page;
|
|
104
|
+
const container: HTMLElement = document.getElementById('o_' + page);
|
|
105
|
+
|
|
106
|
+
(new AjaxRequest(this.ajaxUrl)).post({
|
|
107
|
+
action: 'change_owner',
|
|
108
|
+
page: page,
|
|
109
|
+
ownerUid: element.dataset.owner,
|
|
110
|
+
newOwnerUid: (container.getElementsByTagName('select')[0] as HTMLSelectElement).value,
|
|
111
|
+
}).then(async (response: AjaxResponse): Promise<void> => {
|
|
112
|
+
// Replace content
|
|
113
|
+
container.outerHTML = await response.resolve();
|
|
114
|
+
});
|
|
115
|
+
}
|
|
116
|
+
|
|
117
|
+
/**
|
|
118
|
+
* Owner-related: load the selector for selecting
|
|
119
|
+
* the owner of a page by executing an ajax call
|
|
120
|
+
*/
|
|
121
|
+
private showChangeOwnerSelector(element: HTMLElement): void {
|
|
122
|
+
const page = element.dataset.page;
|
|
123
|
+
|
|
124
|
+
(new AjaxRequest(this.ajaxUrl)).post({
|
|
125
|
+
action: 'show_change_owner_selector',
|
|
126
|
+
page: page,
|
|
127
|
+
ownerUid: element.dataset.owner,
|
|
128
|
+
username: element.dataset.username,
|
|
129
|
+
}).then(async (response: AjaxResponse): Promise<void> => {
|
|
130
|
+
// Replace content
|
|
131
|
+
document.getElementById('o_' + page).outerHTML = await response.resolve();
|
|
132
|
+
});
|
|
133
|
+
}
|
|
134
|
+
|
|
135
|
+
/**
|
|
136
|
+
* Owner-related: Update the HTML view and show the original owner
|
|
137
|
+
*/
|
|
138
|
+
private restoreOwner(element: HTMLElement): void {
|
|
139
|
+
const page = element.dataset.page;
|
|
140
|
+
const username = element.dataset.username ?? element.dataset.ifNotSet;
|
|
141
|
+
const span = document.createElement('span');
|
|
142
|
+
span.setAttribute('id', `o_${page}`);
|
|
143
|
+
|
|
144
|
+
const buttonSelector = document.createElement('button');
|
|
145
|
+
buttonSelector.classList.add('ug_selector', 'changeowner', 'btn', 'btn-sm', 'btn-link');
|
|
146
|
+
buttonSelector.setAttribute('type', 'button');
|
|
147
|
+
buttonSelector.setAttribute('data-page', page);
|
|
148
|
+
buttonSelector.setAttribute('data-owner', element.dataset.owner);
|
|
149
|
+
buttonSelector.setAttribute('data-username', username);
|
|
150
|
+
buttonSelector.innerText = username;
|
|
151
|
+
span.appendChild(buttonSelector);
|
|
152
|
+
|
|
153
|
+
// Replace content
|
|
154
|
+
const container = document.getElementById('o_' + page);
|
|
155
|
+
container.parentNode.replaceChild(span, container);
|
|
156
|
+
}
|
|
157
|
+
|
|
158
|
+
/**
|
|
159
|
+
* Group-related: Update the HTML view and show the original group
|
|
160
|
+
*/
|
|
161
|
+
private restoreGroup(element: HTMLElement): void {
|
|
162
|
+
const page = element.dataset.page;
|
|
163
|
+
const groupname = element.dataset.groupname ?? element.dataset.ifNotSet;
|
|
164
|
+
const span = document.createElement('span');
|
|
165
|
+
span.setAttribute('id', `g_${page}`);
|
|
166
|
+
|
|
167
|
+
const buttonSelector = document.createElement('button');
|
|
168
|
+
buttonSelector.classList.add('ug_selector', 'changegroup', 'btn', 'btn-sm', 'btn-link');
|
|
169
|
+
buttonSelector.setAttribute('type', 'button');
|
|
170
|
+
buttonSelector.setAttribute('data-page', page);
|
|
171
|
+
buttonSelector.setAttribute('data-group-id', element.dataset.groupId);
|
|
172
|
+
buttonSelector.setAttribute('data-groupname', groupname);
|
|
173
|
+
buttonSelector.innerText = groupname;
|
|
174
|
+
span.appendChild(buttonSelector);
|
|
175
|
+
|
|
176
|
+
// Replace content
|
|
177
|
+
const container = document.getElementById('g_' + page);
|
|
178
|
+
container.parentNode.replaceChild(span, container);
|
|
179
|
+
}
|
|
180
|
+
|
|
181
|
+
/**
|
|
182
|
+
* Group-related: Set the new group by executing an ajax call
|
|
183
|
+
*/
|
|
184
|
+
private changeGroup(element: HTMLElement): void {
|
|
185
|
+
const page = element.dataset.page;
|
|
186
|
+
const container: HTMLElement = document.getElementById('g_' + page);
|
|
187
|
+
|
|
188
|
+
(new AjaxRequest(this.ajaxUrl)).post({
|
|
189
|
+
action: 'change_group',
|
|
190
|
+
page: page,
|
|
191
|
+
groupUid: element.dataset.groupId,
|
|
192
|
+
newGroupUid: (container.getElementsByTagName('select')[0] as HTMLSelectElement).value,
|
|
193
|
+
}).then(async (response: AjaxResponse): Promise<void> => {
|
|
194
|
+
// Replace content
|
|
195
|
+
container.outerHTML = await response.resolve();
|
|
196
|
+
});
|
|
197
|
+
}
|
|
198
|
+
|
|
199
|
+
/**
|
|
200
|
+
* Group-related: Load the selector by executing an ajax call
|
|
201
|
+
*/
|
|
202
|
+
private showChangeGroupSelector(element: HTMLElement): void {
|
|
203
|
+
const page = element.dataset.page;
|
|
204
|
+
(new AjaxRequest(this.ajaxUrl)).post({
|
|
205
|
+
action: 'show_change_group_selector',
|
|
206
|
+
page: page,
|
|
207
|
+
groupUid: element.dataset.groupId,
|
|
208
|
+
groupname: element.dataset.groupname,
|
|
209
|
+
}).then(async (response: AjaxResponse): Promise<void> => {
|
|
210
|
+
// Replace content
|
|
211
|
+
document.getElementById('g_' + page).outerHTML = await response.resolve();
|
|
212
|
+
});
|
|
213
|
+
}
|
|
214
|
+
|
|
215
|
+
private initializeCheckboxGroups(): void {
|
|
216
|
+
const checkboxGroups: NodeListOf<HTMLInputElement> = document.querySelectorAll('[data-checkbox-group]');
|
|
217
|
+
checkboxGroups.forEach((checkboxGroupCheckbox): void => {
|
|
218
|
+
const permissionGroup = checkboxGroupCheckbox.dataset.checkboxGroup;
|
|
219
|
+
const permissionValue = parseInt(checkboxGroupCheckbox.value, 10);
|
|
220
|
+
Permissions.setPermissionCheckboxes(permissionGroup, permissionValue);
|
|
221
|
+
});
|
|
222
|
+
}
|
|
223
|
+
|
|
224
|
+
/**
|
|
225
|
+
* initializes events using deferred bound to document
|
|
226
|
+
* so AJAX reloads are no problem
|
|
227
|
+
*/
|
|
228
|
+
private initializeEvents(): void {
|
|
229
|
+
const containerSelector = document.querySelector(this.options.containerSelector);
|
|
230
|
+
const editControllerSelector = document.querySelector(this.options.editControllerSelector);
|
|
231
|
+
|
|
232
|
+
if (containerSelector !== null) {
|
|
233
|
+
new RegularEvent('click', (e: Event, currentTarget: Element): void => {
|
|
234
|
+
e.preventDefault();
|
|
235
|
+
this.setPermissions(currentTarget as HTMLElement);
|
|
236
|
+
}).delegateTo(containerSelector, '.change-permission');
|
|
237
|
+
|
|
238
|
+
// Click event for lock state
|
|
239
|
+
new RegularEvent('click', (e: Event, currentTarget: Element): void => {
|
|
240
|
+
e.preventDefault();
|
|
241
|
+
this.toggleEditLock(currentTarget as HTMLElement);
|
|
242
|
+
}).delegateTo(containerSelector, '.editlock');
|
|
243
|
+
|
|
244
|
+
// Click event to change owner
|
|
245
|
+
new RegularEvent('click', (e: Event, currentTarget: Element): void => {
|
|
246
|
+
e.preventDefault();
|
|
247
|
+
this.showChangeOwnerSelector(currentTarget as HTMLElement);
|
|
248
|
+
}).delegateTo(containerSelector, '.changeowner');
|
|
249
|
+
|
|
250
|
+
// Click event to change group
|
|
251
|
+
new RegularEvent('click', (e: Event, currentTarget: Element): void => {
|
|
252
|
+
e.preventDefault();
|
|
253
|
+
this.showChangeGroupSelector(currentTarget as HTMLElement);
|
|
254
|
+
}).delegateTo(containerSelector, '.changegroup');
|
|
255
|
+
|
|
256
|
+
// Add click handler for restoring previous owner
|
|
257
|
+
new RegularEvent('click', (e: Event, currentTarget: Element): void => {
|
|
258
|
+
e.preventDefault();
|
|
259
|
+
this.restoreOwner(currentTarget as HTMLElement);
|
|
260
|
+
}).delegateTo(containerSelector, '.restoreowner');
|
|
261
|
+
|
|
262
|
+
// Add click handler for saving owner
|
|
263
|
+
new RegularEvent('click', (e: Event, currentTarget: Element): void => {
|
|
264
|
+
e.preventDefault();
|
|
265
|
+
this.changeOwner(currentTarget as HTMLElement);
|
|
266
|
+
}).delegateTo(containerSelector, '.saveowner');
|
|
267
|
+
|
|
268
|
+
// Add click handler for restoring previous group
|
|
269
|
+
new RegularEvent('click', (e: Event, currentTarget: Element): void => {
|
|
270
|
+
e.preventDefault();
|
|
271
|
+
this.restoreGroup(currentTarget as HTMLElement);
|
|
272
|
+
}).delegateTo(containerSelector, '.restoregroup');
|
|
273
|
+
|
|
274
|
+
// Add click handler for saving group
|
|
275
|
+
new RegularEvent('click', (e: Event, currentTarget: Element): void => {
|
|
276
|
+
e.preventDefault();
|
|
277
|
+
this.changeGroup(currentTarget as HTMLElement);
|
|
278
|
+
}).delegateTo(containerSelector, '.savegroup');
|
|
279
|
+
}
|
|
280
|
+
|
|
281
|
+
if (editControllerSelector !== null) {
|
|
282
|
+
// Click events to change permissions (in template Edit.html)
|
|
283
|
+
new RegularEvent('click', (e: Event, currentTarget: Element): void => {
|
|
284
|
+
const args = (currentTarget as HTMLElement).dataset.checkChangePermissions.split(',').map((item: string) => item.trim());
|
|
285
|
+
Permissions.updatePermissionValue.apply(this, args);
|
|
286
|
+
}).delegateTo(editControllerSelector, '[data-check-change-permissions]');
|
|
287
|
+
}
|
|
288
|
+
}
|
|
289
|
+
}
|
|
290
|
+
|
|
291
|
+
export default new Permissions();
|
|
@@ -0,0 +1,15 @@
|
|
|
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
|
+
export type RequestHandler = (request: Request) => Promise<Response>;
|
|
15
|
+
export type RequestMiddleware = (request: Request, next: RequestHandler) => Promise<Response>;
|
|
@@ -0,0 +1,202 @@
|
|
|
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 { AjaxResponse } from '@typo3/core/ajax/ajax-response';
|
|
15
|
+
import { InputTransformer, type GenericKeyValue } from './input-transformer';
|
|
16
|
+
import type { RequestMiddleware, RequestHandler } from '@typo3/core/ajax/ajax-request-types';
|
|
17
|
+
|
|
18
|
+
/**
|
|
19
|
+
* @example send data as `Content-Type: multipart/form-data` (default)
|
|
20
|
+
* const request = new AjaxRequest('/endpoint');
|
|
21
|
+
* const response = request.post({item: { first: 'value'}});
|
|
22
|
+
* // sends `item[first]=value` in request body (analogous)
|
|
23
|
+
* // can be used like this server-side
|
|
24
|
+
* // `$value = ServerRequest::getParsedBody()['item']['first']`
|
|
25
|
+
*
|
|
26
|
+
* @example send data as `Content-Type: application/json` (must be set explicit)
|
|
27
|
+
* const request = new AjaxRequest('/endpoint');
|
|
28
|
+
* const response = request.post({item: { first: 'value'}});
|
|
29
|
+
* // sends `{"item":{"first":"value"}}` in request body
|
|
30
|
+
* // can be used like this server-side
|
|
31
|
+
* // `$value = json_decode((string)ServerRequest::getBody(), true)['item']['first']`
|
|
32
|
+
*/
|
|
33
|
+
class AjaxRequest {
|
|
34
|
+
private static readonly defaultOptions: RequestInit = {
|
|
35
|
+
credentials: 'same-origin'
|
|
36
|
+
};
|
|
37
|
+
|
|
38
|
+
private readonly url: URL;
|
|
39
|
+
private readonly abortController: AbortController;
|
|
40
|
+
private fetch: RequestHandler;
|
|
41
|
+
|
|
42
|
+
constructor(url: URL|string) {
|
|
43
|
+
this.url = url instanceof URL ? url : new URL(url, window.location.origin + window.location.pathname);
|
|
44
|
+
this.abortController = new AbortController();
|
|
45
|
+
this.fetch = (request: Request) => fetch(request);
|
|
46
|
+
}
|
|
47
|
+
|
|
48
|
+
/**
|
|
49
|
+
* Clones the AjaxRequest object, generates the final query string and uses it for the request
|
|
50
|
+
*
|
|
51
|
+
* @param {string|array|GenericKeyValue} data
|
|
52
|
+
* @return {AjaxRequest}
|
|
53
|
+
*/
|
|
54
|
+
public withQueryArguments(data: string | Array<string> | GenericKeyValue | URLSearchParams): AjaxRequest {
|
|
55
|
+
const clone = this.clone();
|
|
56
|
+
|
|
57
|
+
if (!(data instanceof URLSearchParams)) {
|
|
58
|
+
data = new URLSearchParams(InputTransformer.toSearchParams(data));
|
|
59
|
+
}
|
|
60
|
+
for (const [key, value] of data.entries()) {
|
|
61
|
+
this.url.searchParams.append(key, value);
|
|
62
|
+
}
|
|
63
|
+
return clone;
|
|
64
|
+
}
|
|
65
|
+
|
|
66
|
+
/**
|
|
67
|
+
* Executes a regular GET request
|
|
68
|
+
*
|
|
69
|
+
* @param {RequestInit} init
|
|
70
|
+
* @return {Promise<Response>}
|
|
71
|
+
*/
|
|
72
|
+
public async get(init: RequestInit = {}): Promise<AjaxResponse> {
|
|
73
|
+
const localDefaultOptions: RequestInit = {
|
|
74
|
+
method: 'GET',
|
|
75
|
+
};
|
|
76
|
+
|
|
77
|
+
const response = await this.send({ ...localDefaultOptions, ...init });
|
|
78
|
+
return new AjaxResponse(response);
|
|
79
|
+
}
|
|
80
|
+
|
|
81
|
+
/**
|
|
82
|
+
* Executes a (by default uncached) POST request
|
|
83
|
+
*
|
|
84
|
+
* @param {string | FormData | GenericKeyValue} data
|
|
85
|
+
* @param {RequestInit} init
|
|
86
|
+
* @return {Promise<Response>}
|
|
87
|
+
*/
|
|
88
|
+
public async post(data: string | FormData | GenericKeyValue, init: RequestInit = {}): Promise<AjaxResponse> {
|
|
89
|
+
const localDefaultOptions: RequestInit = {
|
|
90
|
+
body: typeof data === 'string' || data instanceof FormData ? data : ( Object.keys(data).length ? InputTransformer.byHeader(data, init?.headers) : ''),
|
|
91
|
+
cache: 'no-cache',
|
|
92
|
+
method: 'POST',
|
|
93
|
+
};
|
|
94
|
+
|
|
95
|
+
const response = await this.send({ ...localDefaultOptions, ...init });
|
|
96
|
+
return new AjaxResponse(response);
|
|
97
|
+
}
|
|
98
|
+
|
|
99
|
+
/**
|
|
100
|
+
* Executes a (by default uncached) PUT request
|
|
101
|
+
*
|
|
102
|
+
* @param {string | FormData | GenericKeyValue} data
|
|
103
|
+
* @param {RequestInit} init
|
|
104
|
+
* @return {Promise<Response>}
|
|
105
|
+
*/
|
|
106
|
+
public async put(data: string | FormData | GenericKeyValue, init: RequestInit = {}): Promise<AjaxResponse> {
|
|
107
|
+
const localDefaultOptions: RequestInit = {
|
|
108
|
+
body: typeof data === 'string' || data instanceof FormData ? data : InputTransformer.byHeader(data, init?.headers),
|
|
109
|
+
cache: 'no-cache',
|
|
110
|
+
method: 'PUT',
|
|
111
|
+
};
|
|
112
|
+
|
|
113
|
+
const response = await this.send({ ...localDefaultOptions, ...init });
|
|
114
|
+
return new AjaxResponse(response);
|
|
115
|
+
}
|
|
116
|
+
|
|
117
|
+
/**
|
|
118
|
+
* Executes a regular DELETE request
|
|
119
|
+
*
|
|
120
|
+
* @param {string | FormData | GenericKeyValue} data
|
|
121
|
+
* @param {RequestInit} init
|
|
122
|
+
* @return {Promise<Response>}
|
|
123
|
+
*/
|
|
124
|
+
public async delete(data: string | FormData | GenericKeyValue = {}, init: RequestInit = {}): Promise<AjaxResponse> {
|
|
125
|
+
const localDefaultOptions: RequestInit = {
|
|
126
|
+
cache: 'no-cache',
|
|
127
|
+
method: 'DELETE',
|
|
128
|
+
};
|
|
129
|
+
|
|
130
|
+
if ((typeof data === 'string' && data.length > 0) || data instanceof FormData) {
|
|
131
|
+
localDefaultOptions.body = data;
|
|
132
|
+
} else if (typeof data === 'object' && Object.keys(data).length > 0) {
|
|
133
|
+
localDefaultOptions.body = InputTransformer.byHeader(data, init?.headers);
|
|
134
|
+
}
|
|
135
|
+
|
|
136
|
+
const response = await this.send({ ...localDefaultOptions, ...init });
|
|
137
|
+
return new AjaxResponse(response);
|
|
138
|
+
}
|
|
139
|
+
|
|
140
|
+
/**
|
|
141
|
+
* Aborts the current request by using the AbortController
|
|
142
|
+
*/
|
|
143
|
+
public abort(): void {
|
|
144
|
+
this.abortController.abort();
|
|
145
|
+
}
|
|
146
|
+
|
|
147
|
+
/**
|
|
148
|
+
* Adds an outer middleware around the fetch invocation.
|
|
149
|
+
* Previous registered middlewares are handled after
|
|
150
|
+
* the one(s) that is/are added here.
|
|
151
|
+
*
|
|
152
|
+
* @param {RequestMiddleware | RequestMiddleware[]} middleware
|
|
153
|
+
* @return {AjaxRequest}
|
|
154
|
+
*/
|
|
155
|
+
public addMiddleware(middleware: RequestMiddleware | RequestMiddleware[]): AjaxRequest {
|
|
156
|
+
if (Array.isArray(middleware)) {
|
|
157
|
+
middleware.forEach(middleware => this.addMiddleware(middleware));
|
|
158
|
+
return this;
|
|
159
|
+
}
|
|
160
|
+
|
|
161
|
+
const next = this.fetch;
|
|
162
|
+
this.fetch = (request: Request) => middleware(request, next);
|
|
163
|
+
return this;
|
|
164
|
+
}
|
|
165
|
+
|
|
166
|
+
/**
|
|
167
|
+
* Clones the current AjaxRequest object
|
|
168
|
+
*
|
|
169
|
+
* @return {AjaxRequest}
|
|
170
|
+
*/
|
|
171
|
+
private clone(): AjaxRequest {
|
|
172
|
+
return Object.assign(Object.create(this), this);
|
|
173
|
+
}
|
|
174
|
+
|
|
175
|
+
/**
|
|
176
|
+
* Sends the requests by using the fetch API
|
|
177
|
+
*
|
|
178
|
+
* @param {RequestInit} init
|
|
179
|
+
* @return {Promise<Response>}
|
|
180
|
+
*/
|
|
181
|
+
private async send(init: RequestInit = {}): Promise<Response> {
|
|
182
|
+
const response = await this.fetch(new Request(this.url, this.getMergedOptions(init)));
|
|
183
|
+
if (!response.ok) {
|
|
184
|
+
throw new AjaxResponse(response);
|
|
185
|
+
}
|
|
186
|
+
return response;
|
|
187
|
+
}
|
|
188
|
+
|
|
189
|
+
/**
|
|
190
|
+
* Merge the incoming RequestInit object with the pre-defined default options
|
|
191
|
+
*
|
|
192
|
+
* @param {RequestInit} init
|
|
193
|
+
* @return {RequestInit}
|
|
194
|
+
*/
|
|
195
|
+
private getMergedOptions(init: RequestInit): RequestInit {
|
|
196
|
+
const { signal, ...initOptions } = init;
|
|
197
|
+
signal?.addEventListener('abort', () => this.abortController.abort());
|
|
198
|
+
return { ...AjaxRequest.defaultOptions, ...initOptions, signal: this.abortController.signal };
|
|
199
|
+
}
|
|
200
|
+
}
|
|
201
|
+
|
|
202
|
+
export default AjaxRequest;
|
|
@@ -0,0 +1,57 @@
|
|
|
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 type SimpleResponseInterface from './simple-response-interface';
|
|
15
|
+
|
|
16
|
+
export class AjaxResponse {
|
|
17
|
+
public readonly response: Response;
|
|
18
|
+
private resolvedBody: string | any;
|
|
19
|
+
|
|
20
|
+
constructor(response: Response) {
|
|
21
|
+
this.response = response;
|
|
22
|
+
}
|
|
23
|
+
|
|
24
|
+
public async resolve(expectedType?: string): Promise<string | any> {
|
|
25
|
+
// streams can only be read once
|
|
26
|
+
// (otherwise response would have to be cloned)
|
|
27
|
+
if (typeof this.resolvedBody !== 'undefined') {
|
|
28
|
+
return this.resolvedBody;
|
|
29
|
+
}
|
|
30
|
+
const contentType: string = this.response.headers.get('Content-Type') ?? '';
|
|
31
|
+
if (expectedType === 'json' || contentType.startsWith('application/json')) {
|
|
32
|
+
this.resolvedBody = await this.response.json();
|
|
33
|
+
} else {
|
|
34
|
+
this.resolvedBody = await this.response.text();
|
|
35
|
+
}
|
|
36
|
+
return this.resolvedBody;
|
|
37
|
+
}
|
|
38
|
+
|
|
39
|
+
public raw(): Response {
|
|
40
|
+
return this.response;
|
|
41
|
+
}
|
|
42
|
+
|
|
43
|
+
/**
|
|
44
|
+
* Dereferences response data from current `window` scope. A dereferenced
|
|
45
|
+
* response (`SimpleResponseInterface`) can be used in events or messages
|
|
46
|
+
* for broadcasting to other windows/frames.
|
|
47
|
+
*/
|
|
48
|
+
public async dereference(): Promise<SimpleResponseInterface> {
|
|
49
|
+
const headers = new Map<string, string>();
|
|
50
|
+
this.response.headers.forEach((value: string, name: string) => headers.set(name, value));
|
|
51
|
+
return {
|
|
52
|
+
status: this.response.status,
|
|
53
|
+
headers: headers,
|
|
54
|
+
body: await this.resolve()
|
|
55
|
+
} as SimpleResponseInterface;
|
|
56
|
+
}
|
|
57
|
+
}
|
|
@@ -0,0 +1,92 @@
|
|
|
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
|
+
export type GenericKeyValue = { [key: string]: any};
|
|
15
|
+
|
|
16
|
+
export class InputTransformer {
|
|
17
|
+
/**
|
|
18
|
+
* Transforms data by its incoming headers
|
|
19
|
+
*
|
|
20
|
+
* @param data
|
|
21
|
+
* @param headers
|
|
22
|
+
*/
|
|
23
|
+
public static byHeader(data: GenericKeyValue, headers: GenericKeyValue = {}): FormData | string {
|
|
24
|
+
if ('Content-Type' in headers && headers['Content-Type'].includes('application/json')) {
|
|
25
|
+
return JSON.stringify(data);
|
|
26
|
+
}
|
|
27
|
+
|
|
28
|
+
return InputTransformer.toFormData(data);
|
|
29
|
+
}
|
|
30
|
+
|
|
31
|
+
/**
|
|
32
|
+
* Transforms the incoming object to a flat FormData object used for POST and PUT
|
|
33
|
+
*
|
|
34
|
+
* @param {GenericKeyValue} data
|
|
35
|
+
* @return {FormData}
|
|
36
|
+
*/
|
|
37
|
+
public static toFormData(data: GenericKeyValue): FormData {
|
|
38
|
+
const flattenedData = InputTransformer.filter(InputTransformer.flattenObject(data));
|
|
39
|
+
const formData = new FormData();
|
|
40
|
+
for (const [key, value] of Object.entries(flattenedData)) {
|
|
41
|
+
formData.set(key, value);
|
|
42
|
+
}
|
|
43
|
+
|
|
44
|
+
return formData;
|
|
45
|
+
}
|
|
46
|
+
|
|
47
|
+
/**
|
|
48
|
+
* Transforms the incoming object to a flat URLSearchParams object used for GET
|
|
49
|
+
*
|
|
50
|
+
* @param {string | Array<string> | GenericKeyValue} data
|
|
51
|
+
* @return {string}
|
|
52
|
+
*/
|
|
53
|
+
public static toSearchParams(data: string | Array<string> | GenericKeyValue): string {
|
|
54
|
+
if (typeof data === 'string') {
|
|
55
|
+
return data;
|
|
56
|
+
}
|
|
57
|
+
|
|
58
|
+
if (data instanceof Array) {
|
|
59
|
+
return data.join('&');
|
|
60
|
+
}
|
|
61
|
+
|
|
62
|
+
const flattenedData = InputTransformer.filter(InputTransformer.flattenObject(data));
|
|
63
|
+
const searchParams = new URLSearchParams();
|
|
64
|
+
for (const [key, value] of Object.entries(flattenedData)) {
|
|
65
|
+
searchParams.set(key, value);
|
|
66
|
+
}
|
|
67
|
+
|
|
68
|
+
return decodeURI(searchParams.toString());
|
|
69
|
+
}
|
|
70
|
+
|
|
71
|
+
private static flattenObject(obj: GenericKeyValue, prefix: string = ''): GenericKeyValue {
|
|
72
|
+
return Object.keys(obj).reduce((accumulator: GenericKeyValue, currentValue: any) => {
|
|
73
|
+
const objPrefix = prefix.length ? prefix + '[' : '';
|
|
74
|
+
const objSuffix = prefix.length ? ']' : '';
|
|
75
|
+
if (typeof obj[currentValue] === 'object' && obj[currentValue] !== null) {
|
|
76
|
+
Object.assign(accumulator, InputTransformer.flattenObject(obj[currentValue], objPrefix + currentValue + objSuffix));
|
|
77
|
+
} else {
|
|
78
|
+
accumulator[objPrefix + currentValue + objSuffix] = obj[currentValue];
|
|
79
|
+
}
|
|
80
|
+
return accumulator;
|
|
81
|
+
}, {});
|
|
82
|
+
}
|
|
83
|
+
|
|
84
|
+
private static filter(obj: GenericKeyValue): GenericKeyValue {
|
|
85
|
+
Object.keys(obj).forEach((key: string): void => {
|
|
86
|
+
if (typeof obj[key] === 'undefined') {
|
|
87
|
+
delete obj[key];
|
|
88
|
+
}
|
|
89
|
+
});
|
|
90
|
+
return obj;
|
|
91
|
+
}
|
|
92
|
+
}
|