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,171 @@
|
|
|
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
|
+
* This processor is used as client-side counterpart of `\TYPO3\CMS\Core\Page\JavaScriptItems
|
|
15
|
+
*
|
|
16
|
+
* @module @typo3/core/java-script-item-processor
|
|
17
|
+
* @internal Use in TYPO3 core only, API can change at any time!
|
|
18
|
+
*/
|
|
19
|
+
|
|
20
|
+
const FLAG_USE_IMPORTMAP = 2;
|
|
21
|
+
const FLAG_USE_TOP_WINDOW = 16;
|
|
22
|
+
const deniedProperties = ['__proto__', 'prototype', 'constructor'];
|
|
23
|
+
const allowedJavaScriptItemTypes = ['assign', 'invoke', 'instance'];
|
|
24
|
+
|
|
25
|
+
export interface JavaScriptInstruction {
|
|
26
|
+
type: string;
|
|
27
|
+
assignments?: object;
|
|
28
|
+
method?: string;
|
|
29
|
+
args: unknown[];
|
|
30
|
+
}
|
|
31
|
+
|
|
32
|
+
export interface JavaScriptItemPayload {
|
|
33
|
+
name: string;
|
|
34
|
+
flags: number;
|
|
35
|
+
exportName?: string;
|
|
36
|
+
items: JavaScriptInstruction[];
|
|
37
|
+
}
|
|
38
|
+
|
|
39
|
+
export interface JavaScriptItem {
|
|
40
|
+
type: 'globalAssignment' | 'javaScriptModuleInstruction';
|
|
41
|
+
payload: JavaScriptItemPayload;
|
|
42
|
+
}
|
|
43
|
+
|
|
44
|
+
export function loadModule(payload: JavaScriptItemPayload): Promise<any> {
|
|
45
|
+
if (!payload.name) {
|
|
46
|
+
throw new Error('JavaScript module name is required');
|
|
47
|
+
}
|
|
48
|
+
|
|
49
|
+
if ((payload.flags & FLAG_USE_IMPORTMAP) === FLAG_USE_IMPORTMAP) {
|
|
50
|
+
if (!(payload.flags & FLAG_USE_TOP_WINDOW)) {
|
|
51
|
+
return import(payload.name);
|
|
52
|
+
} else {
|
|
53
|
+
const event = new CustomEvent<{ specifier: string; importPromise: null|Promise<any>; }>(
|
|
54
|
+
'typo3:import-javascript-module',
|
|
55
|
+
{
|
|
56
|
+
detail: {
|
|
57
|
+
specifier: payload.name,
|
|
58
|
+
importPromise: null
|
|
59
|
+
}
|
|
60
|
+
}
|
|
61
|
+
);
|
|
62
|
+
top.document.dispatchEvent(event);
|
|
63
|
+
return event.detail.importPromise || Promise.reject(new Error('Top-level import failed'));
|
|
64
|
+
}
|
|
65
|
+
}
|
|
66
|
+
|
|
67
|
+
throw new Error('Unknown JavaScript module type');
|
|
68
|
+
}
|
|
69
|
+
|
|
70
|
+
export function resolveSubjectRef(__esModule: any, payload: JavaScriptItemPayload): any {
|
|
71
|
+
const exportName = payload.exportName;
|
|
72
|
+
if (typeof exportName === 'string') {
|
|
73
|
+
return __esModule[exportName];
|
|
74
|
+
}
|
|
75
|
+
return __esModule.default;
|
|
76
|
+
}
|
|
77
|
+
|
|
78
|
+
export function executeJavaScriptModuleInstruction(json: JavaScriptItemPayload): Promise<any[]> {
|
|
79
|
+
// `name` is required
|
|
80
|
+
if (!json.name) {
|
|
81
|
+
throw new Error('JavaScript module name is required');
|
|
82
|
+
}
|
|
83
|
+
if (!json.items) {
|
|
84
|
+
return loadModule(json);
|
|
85
|
+
}
|
|
86
|
+
const items = json.items
|
|
87
|
+
.filter((item) => allowedJavaScriptItemTypes.includes(item.type))
|
|
88
|
+
.map((item) => {
|
|
89
|
+
if (item.type === 'assign') {
|
|
90
|
+
return (__esModule: any) => {
|
|
91
|
+
const subjectRef = resolveSubjectRef(__esModule, json);
|
|
92
|
+
mergeRecursive(subjectRef, item.assignments);
|
|
93
|
+
};
|
|
94
|
+
} else if (item.type === 'invoke') {
|
|
95
|
+
return (__esModule: any): any => {
|
|
96
|
+
const subjectRef = resolveSubjectRef(__esModule, json);
|
|
97
|
+
if ('method' in item && item.method) {
|
|
98
|
+
return subjectRef[item.method](...item.args);
|
|
99
|
+
} else {
|
|
100
|
+
return subjectRef(...item.args);
|
|
101
|
+
}
|
|
102
|
+
};
|
|
103
|
+
} else if (item.type === 'instance') {
|
|
104
|
+
return (__esModule: any) => {
|
|
105
|
+
// this `null` is `thisArg` scope of `Function.bind`,
|
|
106
|
+
// which will be reset when invoking `new`
|
|
107
|
+
const args = [null].concat(item.args);
|
|
108
|
+
const subjectRef = resolveSubjectRef(__esModule, json);
|
|
109
|
+
return new (subjectRef.bind(...args));
|
|
110
|
+
};
|
|
111
|
+
} else {
|
|
112
|
+
return (): void => {
|
|
113
|
+
return;
|
|
114
|
+
};
|
|
115
|
+
}
|
|
116
|
+
});
|
|
117
|
+
|
|
118
|
+
return loadModule(json).then(
|
|
119
|
+
(subjectRef) => items.map((item) => item.call(null, subjectRef))
|
|
120
|
+
);
|
|
121
|
+
}
|
|
122
|
+
|
|
123
|
+
function isObjectInstance(item: any) {
|
|
124
|
+
return item instanceof Object && !(item instanceof Array);
|
|
125
|
+
}
|
|
126
|
+
|
|
127
|
+
function mergeRecursive(target: { [key: string]: any }, source: { [key: string]: any }) {
|
|
128
|
+
Object.keys(source).forEach((property) => {
|
|
129
|
+
if (deniedProperties.indexOf(property) !== -1) {
|
|
130
|
+
throw new Error('Property ' + property + ' is not allowed');
|
|
131
|
+
}
|
|
132
|
+
if (!isObjectInstance(source[property]) || typeof target[property] === 'undefined') {
|
|
133
|
+
Object.assign(target, { [property]:source[property] });
|
|
134
|
+
} else {
|
|
135
|
+
mergeRecursive(target[property], source[property]);
|
|
136
|
+
}
|
|
137
|
+
});
|
|
138
|
+
}
|
|
139
|
+
|
|
140
|
+
export class JavaScriptItemProcessor {
|
|
141
|
+
private readonly invokableNames: string[] = ['globalAssignment', 'javaScriptModuleInstruction'];
|
|
142
|
+
|
|
143
|
+
/**
|
|
144
|
+
* Processes multiple items and delegates to handlers
|
|
145
|
+
* (globalAssignment, javaScriptModuleInstruction)
|
|
146
|
+
*/
|
|
147
|
+
public processItems(items: JavaScriptItem[]) {
|
|
148
|
+
items.forEach((item) => this.invoke(item.type, item.payload));
|
|
149
|
+
}
|
|
150
|
+
|
|
151
|
+
private invoke(name: 'globalAssignment' | 'javaScriptModuleInstruction', data: any) {
|
|
152
|
+
if (!this.invokableNames.includes(name) || typeof this[name] !== 'function') {
|
|
153
|
+
throw new Error('Unknown handler name "' + name + '"');
|
|
154
|
+
}
|
|
155
|
+
this[name].call(this, data);
|
|
156
|
+
}
|
|
157
|
+
|
|
158
|
+
/**
|
|
159
|
+
* Assigns (filtered) variables to `window` object globally.
|
|
160
|
+
*/
|
|
161
|
+
private globalAssignment(payload: { [key: string]: any }) {
|
|
162
|
+
mergeRecursive(window, payload);
|
|
163
|
+
}
|
|
164
|
+
|
|
165
|
+
/**
|
|
166
|
+
* Loads and invokes a JavaScript (ESM) or requires.js (AMD) module.
|
|
167
|
+
*/
|
|
168
|
+
private javaScriptModuleInstruction(payload: JavaScriptItemPayload) {
|
|
169
|
+
executeJavaScriptModuleInstruction(payload);
|
|
170
|
+
}
|
|
171
|
+
}
|
|
@@ -0,0 +1,126 @@
|
|
|
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 CSSResultArray, html, type HTMLTemplateResult, render, nothing, type TemplateResult } from 'lit';
|
|
15
|
+
import type { ClassInfo } from 'lit/directives/class-map';
|
|
16
|
+
import { until } from 'lit/directives/until';
|
|
17
|
+
|
|
18
|
+
interface LitNonceWindow extends Window {
|
|
19
|
+
litNonce?: string;
|
|
20
|
+
}
|
|
21
|
+
|
|
22
|
+
/**
|
|
23
|
+
* @internal
|
|
24
|
+
*/
|
|
25
|
+
export const renderNodes = (result: TemplateResult): NodeList => {
|
|
26
|
+
const anvil = document.createElement('div');
|
|
27
|
+
render(result, anvil);
|
|
28
|
+
return anvil.childNodes;
|
|
29
|
+
};
|
|
30
|
+
|
|
31
|
+
/**
|
|
32
|
+
* @internal
|
|
33
|
+
*/
|
|
34
|
+
export const renderHTML = (result: TemplateResult): string => {
|
|
35
|
+
const anvil = document.createElement('div');
|
|
36
|
+
render(result, anvil);
|
|
37
|
+
return anvil.innerHTML;
|
|
38
|
+
};
|
|
39
|
+
|
|
40
|
+
/**
|
|
41
|
+
* @internal
|
|
42
|
+
*/
|
|
43
|
+
export const lll = (key: string, ...args: any[]): string => {
|
|
44
|
+
let languagePool = null;
|
|
45
|
+
if (window.TYPO3 && window.TYPO3.lang && typeof window.TYPO3.lang[key] === 'string') {
|
|
46
|
+
languagePool = window.TYPO3.lang;
|
|
47
|
+
} else if (top.TYPO3 && top.TYPO3.lang && typeof top.TYPO3.lang[key] === 'string') {
|
|
48
|
+
languagePool = top.TYPO3.lang;
|
|
49
|
+
}
|
|
50
|
+
if (languagePool === null) {
|
|
51
|
+
return '';
|
|
52
|
+
}
|
|
53
|
+
|
|
54
|
+
let index = 0;
|
|
55
|
+
return languagePool[key].replace(/%[sdf]/g, (match) => {
|
|
56
|
+
const arg = args[index++];
|
|
57
|
+
switch (match) {
|
|
58
|
+
case '%s':
|
|
59
|
+
return String(arg);
|
|
60
|
+
case '%d':
|
|
61
|
+
return String(parseInt(arg, 10));
|
|
62
|
+
case '%f':
|
|
63
|
+
return String(parseFloat(arg).toFixed(2));
|
|
64
|
+
default:
|
|
65
|
+
return match;
|
|
66
|
+
}
|
|
67
|
+
});
|
|
68
|
+
};
|
|
69
|
+
|
|
70
|
+
type Writeable<T> = { -readonly [P in keyof T]: T[P] };
|
|
71
|
+
|
|
72
|
+
export const classesArrayToClassInfo = (classes: Array<string>): ClassInfo => {
|
|
73
|
+
return classes.reduce(
|
|
74
|
+
(classInfo: Writeable<ClassInfo>, name: string): Writeable<ClassInfo> => {
|
|
75
|
+
classInfo[name] = true;
|
|
76
|
+
return classInfo;
|
|
77
|
+
},
|
|
78
|
+
{} as Writeable<ClassInfo>
|
|
79
|
+
);
|
|
80
|
+
};
|
|
81
|
+
|
|
82
|
+
/**
|
|
83
|
+
* Creates style tag having using a nonce-value if declared in `window.litNonce`
|
|
84
|
+
* (see https://lit.dev/docs/api/ReactiveElement/#ReactiveElement.styles)
|
|
85
|
+
*
|
|
86
|
+
* @example
|
|
87
|
+
* ```
|
|
88
|
+
* return html`
|
|
89
|
+
* ${styleTag`
|
|
90
|
+
* .my-style { ... }
|
|
91
|
+
* `}
|
|
92
|
+
* <div class="my-style">...</div>
|
|
93
|
+
* `
|
|
94
|
+
* ```
|
|
95
|
+
* produces a template result containing
|
|
96
|
+
* ```
|
|
97
|
+
* <style nonce="...">
|
|
98
|
+
* .my-style { ... }
|
|
99
|
+
* </style>
|
|
100
|
+
* <div class="my-style">...</div>
|
|
101
|
+
* ```
|
|
102
|
+
* @deprecated avoid using dynamic styles in light DOM elements
|
|
103
|
+
*/
|
|
104
|
+
export const styleTag = (strings: string[]|TemplateStringsArray|CSSResultArray, windowRef?: Window): HTMLTemplateResult => {
|
|
105
|
+
const nonce = ((windowRef || window) as LitNonceWindow).litNonce;
|
|
106
|
+
if (nonce) {
|
|
107
|
+
return html`<style nonce="${nonce}">${strings}</style>`;
|
|
108
|
+
}
|
|
109
|
+
return html`<style>${strings}</style>`;
|
|
110
|
+
};
|
|
111
|
+
|
|
112
|
+
/**
|
|
113
|
+
* Delays rendering a renderable by `timeout` milliseconds
|
|
114
|
+
*
|
|
115
|
+
* @example
|
|
116
|
+
*
|
|
117
|
+
* ```
|
|
118
|
+
* return html`${delay(80, () => html`Loading…`)}`
|
|
119
|
+
* ```
|
|
120
|
+
*
|
|
121
|
+
* @internal
|
|
122
|
+
*/
|
|
123
|
+
export const delay = <T>(timeout: number, result: () => T, fallback = () => nothing) => until(
|
|
124
|
+
new Promise<T>((resolve) => window.setTimeout(() => resolve(result()), timeout)),
|
|
125
|
+
fallback()
|
|
126
|
+
);
|
package/core/literals.ts
ADDED
|
@@ -0,0 +1,17 @@
|
|
|
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 const selector = (stringParts: TemplateStringsArray, ...substitutions: string[]): string => String.raw(
|
|
15
|
+
{ raw: stringParts },
|
|
16
|
+
...substitutions.map(substitution => CSS.escape(substitution))
|
|
17
|
+
);
|
|
@@ -0,0 +1,89 @@
|
|
|
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
|
+
/**
|
|
15
|
+
* Module: @typo3/core/security-utility
|
|
16
|
+
* contains method to escape input to prevent XSS and other security related things
|
|
17
|
+
* @exports @typo3/core/security-utility
|
|
18
|
+
*/
|
|
19
|
+
class SecurityUtility {
|
|
20
|
+
private readonly documentRef: Document;
|
|
21
|
+
|
|
22
|
+
/**
|
|
23
|
+
* @param {Document} documentRef
|
|
24
|
+
*/
|
|
25
|
+
constructor(documentRef: Document = document) {
|
|
26
|
+
this.documentRef = documentRef;
|
|
27
|
+
}
|
|
28
|
+
|
|
29
|
+
public getRandomHexValue(length: number): string {
|
|
30
|
+
if (length <= 0 || length !== Math.ceil(length)) {
|
|
31
|
+
throw new SyntaxError('Length must be a positive integer');
|
|
32
|
+
}
|
|
33
|
+
const values = new Uint8Array(Math.ceil(length / 2));
|
|
34
|
+
crypto.getRandomValues(values);
|
|
35
|
+
return Array.from(values)
|
|
36
|
+
.map((item: number): string => item.toString(16).padStart(2, '0'))
|
|
37
|
+
.join('')
|
|
38
|
+
.substr(0, length);
|
|
39
|
+
}
|
|
40
|
+
|
|
41
|
+
/**
|
|
42
|
+
* Encodes HTML to use according entities. Behavior is similar to PHP's
|
|
43
|
+
* htmlspecialchars. Input might contain XSS, output has it encoded.
|
|
44
|
+
*
|
|
45
|
+
* @param {string} value Input value to be encoded
|
|
46
|
+
* @param {boolean} doubleEncode (default `true`)
|
|
47
|
+
* @return {string}
|
|
48
|
+
*/
|
|
49
|
+
public encodeHtml(value: string, doubleEncode: boolean = true): string {
|
|
50
|
+
const anvil: HTMLSpanElement = this.createAnvil();
|
|
51
|
+
if (!doubleEncode) {
|
|
52
|
+
// decode HTML entities step-by-step
|
|
53
|
+
// but NEVER(!) as a whole, since that would allow XSS
|
|
54
|
+
value = value.replace(/&[#A-Za-z0-9]+;/g, (html: string) => {
|
|
55
|
+
anvil.innerHTML = html;
|
|
56
|
+
return anvil.innerText;
|
|
57
|
+
});
|
|
58
|
+
}
|
|
59
|
+
// apply arbitrary data a text node
|
|
60
|
+
// thus browser is capable of properly encoding
|
|
61
|
+
anvil.innerText = value;
|
|
62
|
+
return anvil.innerHTML
|
|
63
|
+
.replace(/"/g, '"')
|
|
64
|
+
.replace(/'/g, ''');
|
|
65
|
+
}
|
|
66
|
+
|
|
67
|
+
public stripHtml(html: string): string {
|
|
68
|
+
const doc = new DOMParser().parseFromString(html, 'text/html');
|
|
69
|
+
return doc.body.textContent || '';
|
|
70
|
+
}
|
|
71
|
+
|
|
72
|
+
/**
|
|
73
|
+
* @param {string} value
|
|
74
|
+
*/
|
|
75
|
+
public debug(value: string): void {
|
|
76
|
+
if (value !== this.encodeHtml(value)) {
|
|
77
|
+
console.warn('XSS?!', value);
|
|
78
|
+
}
|
|
79
|
+
}
|
|
80
|
+
|
|
81
|
+
/**
|
|
82
|
+
* @return {HTMLSpanElement}
|
|
83
|
+
*/
|
|
84
|
+
private createAnvil(): HTMLSpanElement {
|
|
85
|
+
return this.documentRef.createElement('span');
|
|
86
|
+
}
|
|
87
|
+
}
|
|
88
|
+
|
|
89
|
+
export default SecurityUtility;
|
|
@@ -0,0 +1,290 @@
|
|
|
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 AjaxRequest from '@typo3/core/ajax/ajax-request.js';
|
|
15
|
+
import { expect } from '@open-wc/testing';
|
|
16
|
+
import { stub, type SinonStub } from 'sinon';
|
|
17
|
+
import type { AjaxResponse } from '@typo3/core/ajax/ajax-response';
|
|
18
|
+
import type { } from 'mocha';
|
|
19
|
+
|
|
20
|
+
describe('@typo3/core/ajax/ajax-request', (): void => {
|
|
21
|
+
let promiseHelper: {
|
|
22
|
+
resolve: (response: Response) => void,
|
|
23
|
+
reject: (error: Error) => void
|
|
24
|
+
};
|
|
25
|
+
|
|
26
|
+
let fetchStub: SinonStub<Parameters<typeof fetch>, Promise<Response>>;
|
|
27
|
+
|
|
28
|
+
beforeEach((): void => {
|
|
29
|
+
const fetchPromise: Promise<Response> = new Promise((resolve, reject): void => {
|
|
30
|
+
promiseHelper = {
|
|
31
|
+
resolve: resolve,
|
|
32
|
+
reject: reject,
|
|
33
|
+
};
|
|
34
|
+
});
|
|
35
|
+
fetchStub = stub(window, 'fetch');
|
|
36
|
+
fetchStub.returns(fetchPromise);
|
|
37
|
+
});
|
|
38
|
+
|
|
39
|
+
afterEach((): void => {
|
|
40
|
+
fetchStub.restore();
|
|
41
|
+
});
|
|
42
|
+
|
|
43
|
+
it('sends GET request', (): void => {
|
|
44
|
+
(new AjaxRequest('https://example.com')).get();
|
|
45
|
+
expect(fetchStub).calledWithMatch(new Request('https://example.com/', { method: 'GET' }));
|
|
46
|
+
});
|
|
47
|
+
|
|
48
|
+
it('sends POST request with empty object', (): void => {
|
|
49
|
+
(new AjaxRequest('https://example.com')).post({});
|
|
50
|
+
expect(fetchStub).calledWithMatch(new Request('https://example.com/', { method: 'POST', body: '' }));
|
|
51
|
+
});
|
|
52
|
+
|
|
53
|
+
for (const requestMethod of ['POST', 'PUT', 'DELETE']) {
|
|
54
|
+
describe(`send a ${requestMethod} request`, (): void => {
|
|
55
|
+
function* requestDataProvider(): any {
|
|
56
|
+
yield [
|
|
57
|
+
'object as payload',
|
|
58
|
+
requestMethod,
|
|
59
|
+
{ foo: 'bar', bar: 'baz', nested: { works: 'yes' } },
|
|
60
|
+
(): FormData => {
|
|
61
|
+
const expected = new FormData();
|
|
62
|
+
expected.set('foo', 'bar');
|
|
63
|
+
expected.set('bar', 'baz');
|
|
64
|
+
expected.set('nested[works]', 'yes');
|
|
65
|
+
return expected;
|
|
66
|
+
},
|
|
67
|
+
{}
|
|
68
|
+
];
|
|
69
|
+
yield [
|
|
70
|
+
'JSON object as payload',
|
|
71
|
+
requestMethod,
|
|
72
|
+
{ foo: 'bar', bar: 'baz', nested: { works: 'yes' } },
|
|
73
|
+
(): string => {
|
|
74
|
+
return JSON.stringify({ foo: 'bar', bar: 'baz', nested: { works: 'yes' } });
|
|
75
|
+
},
|
|
76
|
+
{ 'Content-Type': 'application/json' }
|
|
77
|
+
];
|
|
78
|
+
yield [
|
|
79
|
+
'JSON string as payload',
|
|
80
|
+
requestMethod,
|
|
81
|
+
JSON.stringify({ foo: 'bar', bar: 'baz', nested: { works: 'yes' } }),
|
|
82
|
+
(): string => {
|
|
83
|
+
return JSON.stringify({ foo: 'bar', bar: 'baz', nested: { works: 'yes' } });
|
|
84
|
+
},
|
|
85
|
+
{ 'Content-Type': 'application/json' }
|
|
86
|
+
];
|
|
87
|
+
}
|
|
88
|
+
|
|
89
|
+
for (const providedData of requestDataProvider()) {
|
|
90
|
+
const [name, requestMethod, payload, expectedFn, headers] = providedData;
|
|
91
|
+
const requestFn: string = requestMethod.toLowerCase();
|
|
92
|
+
it(`with ${name}`, (done): void => {
|
|
93
|
+
const request: any = (new AjaxRequest('https://example.com'));
|
|
94
|
+
request[requestFn](payload, { headers: headers });
|
|
95
|
+
expect(fetchStub).calledWithMatch(new Request('https://example.com/', { method: requestMethod, body: expectedFn() }));
|
|
96
|
+
done();
|
|
97
|
+
});
|
|
98
|
+
}
|
|
99
|
+
});
|
|
100
|
+
}
|
|
101
|
+
|
|
102
|
+
describe('send GET requests', (): void => {
|
|
103
|
+
function* responseDataProvider(): any {
|
|
104
|
+
yield [
|
|
105
|
+
'plaintext',
|
|
106
|
+
'foobar huselpusel',
|
|
107
|
+
{},
|
|
108
|
+
(data: any, responseBody: any): void => {
|
|
109
|
+
expect(typeof data === 'string').to.be.true;
|
|
110
|
+
expect(data).to.be.equal(responseBody);
|
|
111
|
+
}
|
|
112
|
+
];
|
|
113
|
+
yield [
|
|
114
|
+
'JSON',
|
|
115
|
+
JSON.stringify({ foo: 'bar', baz: 'bencer' }),
|
|
116
|
+
{ 'Content-Type': 'application/json' },
|
|
117
|
+
(data: any, responseBody: any): void => {
|
|
118
|
+
expect(typeof data === 'object').to.be.true;
|
|
119
|
+
expect(JSON.stringify(data)).to.equal(responseBody);
|
|
120
|
+
}
|
|
121
|
+
];
|
|
122
|
+
yield [
|
|
123
|
+
'JSON with utf-8',
|
|
124
|
+
JSON.stringify({ foo: 'bar', baz: 'bencer' }),
|
|
125
|
+
{ 'Content-Type': 'application/json; charset=utf-8' },
|
|
126
|
+
(data: any, responseBody: any): void => {
|
|
127
|
+
expect(typeof data === 'object').to.be.true;
|
|
128
|
+
expect(JSON.stringify(data)).to.equal(responseBody);
|
|
129
|
+
}
|
|
130
|
+
];
|
|
131
|
+
}
|
|
132
|
+
|
|
133
|
+
for (const providedData of responseDataProvider()) {
|
|
134
|
+
const [name, responseText, headers, onfulfill] = providedData;
|
|
135
|
+
it('receives a ' + name + ' response', (done): void => {
|
|
136
|
+
const response = new Response(responseText, { headers: headers });
|
|
137
|
+
promiseHelper.resolve(response);
|
|
138
|
+
|
|
139
|
+
(new AjaxRequest(new URL('https://example.com'))).get().then(async (response: AjaxResponse): Promise<void> => {
|
|
140
|
+
const data = await response.resolve();
|
|
141
|
+
expect(fetchStub).calledWithMatch(new Request('https://example.com/', { method: 'GET' }));
|
|
142
|
+
onfulfill(data, responseText);
|
|
143
|
+
done();
|
|
144
|
+
});
|
|
145
|
+
});
|
|
146
|
+
}
|
|
147
|
+
});
|
|
148
|
+
|
|
149
|
+
describe('send requests with different input urls', (): void => {
|
|
150
|
+
function* urlInputDataProvider(): any {
|
|
151
|
+
yield [
|
|
152
|
+
'absolute url with domain',
|
|
153
|
+
new URL('https://example.com'),
|
|
154
|
+
{},
|
|
155
|
+
new URL('https://example.com/'),
|
|
156
|
+
];
|
|
157
|
+
yield [
|
|
158
|
+
'absolute url with domain, with query parameter',
|
|
159
|
+
new URL('https://example.com'),
|
|
160
|
+
{ foo: 'bar', bar: { baz: 'bencer' } },
|
|
161
|
+
new URL('https://example.com/?foo=bar&bar%5Bbaz%5D=bencer'),
|
|
162
|
+
];
|
|
163
|
+
yield [
|
|
164
|
+
'absolute url without domain',
|
|
165
|
+
'/foo/bar',
|
|
166
|
+
{},
|
|
167
|
+
new URL(window.location.origin + '/foo/bar'),
|
|
168
|
+
];
|
|
169
|
+
yield [
|
|
170
|
+
'absolute url without domain, with query parameter',
|
|
171
|
+
'/foo/bar',
|
|
172
|
+
{ foo: 'bar', bar: { baz: 'bencer' } },
|
|
173
|
+
new URL(window.location.origin + '/foo/bar?foo=bar&bar%5Bbaz%5D=bencer'),
|
|
174
|
+
];
|
|
175
|
+
yield [
|
|
176
|
+
'relative url without domain',
|
|
177
|
+
'foo/bar',
|
|
178
|
+
{},
|
|
179
|
+
new URL(window.location.origin + '/foo/bar'),
|
|
180
|
+
];
|
|
181
|
+
yield [
|
|
182
|
+
'relative url without domain, with query parameter',
|
|
183
|
+
'foo/bar',
|
|
184
|
+
{ foo: 'bar', bar: { baz: 'bencer' } },
|
|
185
|
+
new URL(window.location.origin + '/foo/bar?foo=bar&bar%5Bbaz%5D=bencer'),
|
|
186
|
+
];
|
|
187
|
+
yield [
|
|
188
|
+
'fallback to current script if not defined',
|
|
189
|
+
'?foo=bar&baz=bencer',
|
|
190
|
+
{},
|
|
191
|
+
new URL(window.location.origin + window.location.pathname + '?foo=bar&baz=bencer'),
|
|
192
|
+
];
|
|
193
|
+
}
|
|
194
|
+
|
|
195
|
+
for (const providedData of urlInputDataProvider()) {
|
|
196
|
+
const [name, input, queryParameter, expected] = providedData;
|
|
197
|
+
it('with ' + name, (): void => {
|
|
198
|
+
(new AjaxRequest(input)).withQueryArguments(queryParameter).get();
|
|
199
|
+
expect(fetchStub).calledWithMatch(new Request(expected.toString(), { method: 'GET' }));
|
|
200
|
+
});
|
|
201
|
+
}
|
|
202
|
+
});
|
|
203
|
+
|
|
204
|
+
describe('send requests with query arguments', (): void => {
|
|
205
|
+
function* queryArgumentsDataProvider(): any {
|
|
206
|
+
yield [
|
|
207
|
+
'single level of arguments',
|
|
208
|
+
{ foo: 'bar', bar: 'baz' },
|
|
209
|
+
new URL('https://example.com/?foo=bar&bar=baz'),
|
|
210
|
+
];
|
|
211
|
+
yield [
|
|
212
|
+
'nested arguments',
|
|
213
|
+
{ foo: 'bar', bar: { baz: 'bencer' } },
|
|
214
|
+
new URL('https://example.com/?foo=bar&bar%5Bbaz%5D=bencer'),
|
|
215
|
+
];
|
|
216
|
+
yield [
|
|
217
|
+
'string argument',
|
|
218
|
+
'hello=world&foo=bar',
|
|
219
|
+
new URL('https://example.com/?hello=world&foo=bar'),
|
|
220
|
+
];
|
|
221
|
+
yield [
|
|
222
|
+
'array of arguments',
|
|
223
|
+
['foo=bar', 'husel=pusel'],
|
|
224
|
+
new URL('https://example.com/?foo=bar&husel=pusel'),
|
|
225
|
+
];
|
|
226
|
+
yield [
|
|
227
|
+
'object with array',
|
|
228
|
+
{ foo: ['bar', 'baz'] },
|
|
229
|
+
new URL('https://example.com/?foo%5B0%5D=bar&foo%5B1%5D=baz'),
|
|
230
|
+
];
|
|
231
|
+
yield [
|
|
232
|
+
'complex object',
|
|
233
|
+
{
|
|
234
|
+
foo: 'bar',
|
|
235
|
+
nested: {
|
|
236
|
+
husel: 'pusel',
|
|
237
|
+
bar: 'baz',
|
|
238
|
+
array: ['5', '6']
|
|
239
|
+
},
|
|
240
|
+
array: ['1', '2']
|
|
241
|
+
},
|
|
242
|
+
new URL('https://example.com/?foo=bar&nested%5Bhusel%5D=pusel&nested%5Bbar%5D=baz&nested%5Barray%5D%5B0%5D=5&nested%5Barray%5D%5B1%5D=6&array%5B0%5D=1&array%5B1%5D=2'),
|
|
243
|
+
];
|
|
244
|
+
yield [
|
|
245
|
+
'complex, deeply nested object',
|
|
246
|
+
{
|
|
247
|
+
foo: 'bar',
|
|
248
|
+
nested: {
|
|
249
|
+
husel: 'pusel',
|
|
250
|
+
bar: 'baz',
|
|
251
|
+
array: ['5', '6'],
|
|
252
|
+
deep_nested: {
|
|
253
|
+
husel: 'pusel',
|
|
254
|
+
bar: 'baz',
|
|
255
|
+
array: ['5', '6']
|
|
256
|
+
},
|
|
257
|
+
},
|
|
258
|
+
array: ['1', '2']
|
|
259
|
+
},
|
|
260
|
+
new URL('https://example.com/?foo=bar&nested%5Bhusel%5D=pusel&nested%5Bbar%5D=baz&nested%5Barray%5D%5B0%5D=5&nested%5Barray%5D%5B1%5D=6&nested%5Bdeep_nested%5D%5Bhusel%5D=pusel&nested%5Bdeep_nested%5D%5Bbar%5D=baz&nested%5Bdeep_nested%5D%5Barray%5D%5B0%5D=5&nested%5Bdeep_nested%5D%5Barray%5D%5B1%5D=6&array%5B0%5D=1&array%5B1%5D=2'),
|
|
261
|
+
];
|
|
262
|
+
}
|
|
263
|
+
|
|
264
|
+
for (const providedData of queryArgumentsDataProvider()) {
|
|
265
|
+
const [name, input, expected] = providedData;
|
|
266
|
+
it('with ' + name, (): void => {
|
|
267
|
+
(new AjaxRequest('https://example.com/')).withQueryArguments(input).get();
|
|
268
|
+
expect(fetchStub).calledWithMatch(new Request(expected.toString(), { method: 'GET' }));
|
|
269
|
+
});
|
|
270
|
+
}
|
|
271
|
+
});
|
|
272
|
+
|
|
273
|
+
describe('Aborts requests', (): void => {
|
|
274
|
+
it('via abort() method', (): void => {
|
|
275
|
+
const request = new AjaxRequest(new URL('https://example.com'));
|
|
276
|
+
request.get();
|
|
277
|
+
request.abort();
|
|
278
|
+
expect((fetchStub.firstCall.args[0] as Request).signal.aborted).to.be.true;
|
|
279
|
+
});
|
|
280
|
+
|
|
281
|
+
it('via signal option', (): void => {
|
|
282
|
+
const abortController = new AbortController();
|
|
283
|
+
const request = new AjaxRequest(new URL('https://example.com'));
|
|
284
|
+
request.get({ signal: abortController.signal });
|
|
285
|
+
abortController.abort();
|
|
286
|
+
expect(abortController.signal.aborted).to.be.true;
|
|
287
|
+
expect((fetchStub.firstCall.args[0] as Request).signal.aborted).to.be.true;
|
|
288
|
+
});
|
|
289
|
+
});
|
|
290
|
+
});
|