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,195 @@
|
|
|
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 'bootstrap';
|
|
15
|
+
import { AbstractInteractableModule, type ModuleLoadedResponseWithButtons } from '../abstract-interactable-module';
|
|
16
|
+
import Modal from '@typo3/backend/modal';
|
|
17
|
+
import Notification from '@typo3/backend/notification';
|
|
18
|
+
import AjaxRequest from '@typo3/core/ajax/ajax-request';
|
|
19
|
+
import { InfoBox } from '../../renderable/info-box';
|
|
20
|
+
import Severity from '../../renderable/severity';
|
|
21
|
+
import Router from '../../router';
|
|
22
|
+
import RegularEvent from '@typo3/core/event/regular-event';
|
|
23
|
+
import type { AjaxResponse } from '@typo3/core/ajax/ajax-response';
|
|
24
|
+
import type { ModalElement } from '@typo3/backend/modal';
|
|
25
|
+
import type MessageInterface from '@typo3/install/message-interface';
|
|
26
|
+
|
|
27
|
+
enum Identifiers {
|
|
28
|
+
checkTrigger = '.t3js-extensionCompatTester-check',
|
|
29
|
+
uninstallTrigger = '.t3js-extensionCompatTester-uninstall',
|
|
30
|
+
outputContainer = '.t3js-extensionCompatTester-output'
|
|
31
|
+
}
|
|
32
|
+
|
|
33
|
+
interface BrokenExtension {
|
|
34
|
+
name: string;
|
|
35
|
+
isProtected: boolean;
|
|
36
|
+
}
|
|
37
|
+
|
|
38
|
+
/**
|
|
39
|
+
* Module: @typo3/install/module/extension-compat-tester
|
|
40
|
+
*/
|
|
41
|
+
class ExtensionCompatTester extends AbstractInteractableModule {
|
|
42
|
+
public override initialize(currentModal: ModalElement): void {
|
|
43
|
+
super.initialize(currentModal);
|
|
44
|
+
this.loadModuleFrameAgnostic('@typo3/install/renderable/info-box.js').then((): void => {
|
|
45
|
+
this.getLoadedExtensionList();
|
|
46
|
+
});
|
|
47
|
+
|
|
48
|
+
new RegularEvent('click', (): void => {
|
|
49
|
+
this.findInModal(Identifiers.uninstallTrigger)?.classList?.add('hidden');
|
|
50
|
+
|
|
51
|
+
const outputContainer = this.findInModal(Identifiers.outputContainer);
|
|
52
|
+
if (outputContainer) {
|
|
53
|
+
outputContainer.innerHTML = '';
|
|
54
|
+
}
|
|
55
|
+
this.getLoadedExtensionList();
|
|
56
|
+
}).delegateTo(currentModal, Identifiers.checkTrigger);
|
|
57
|
+
|
|
58
|
+
new RegularEvent('click', (event: Event, target: HTMLElement): void => {
|
|
59
|
+
this.uninstallExtension(target.dataset.extension);
|
|
60
|
+
}).delegateTo(currentModal, Identifiers.uninstallTrigger);
|
|
61
|
+
}
|
|
62
|
+
|
|
63
|
+
private getLoadedExtensionList(): void {
|
|
64
|
+
this.setModalButtonsState(false);
|
|
65
|
+
const modalContent = this.getModalBody();
|
|
66
|
+
const outputContainer = this.findInModal(Identifiers.outputContainer);
|
|
67
|
+
if (outputContainer) {
|
|
68
|
+
this.renderProgressBar(outputContainer, {}, 'append');
|
|
69
|
+
}
|
|
70
|
+
|
|
71
|
+
(new AjaxRequest(Router.getUrl('extensionCompatTesterLoadedExtensionList')))
|
|
72
|
+
.get({ cache: 'no-cache' })
|
|
73
|
+
.then(
|
|
74
|
+
async (response: AjaxResponse): Promise<void> => {
|
|
75
|
+
const data: ModuleLoadedResponseWithButtons = await response.resolve();
|
|
76
|
+
modalContent.innerHTML = data.html;
|
|
77
|
+
Modal.setButtons(data.buttons);
|
|
78
|
+
const innerOutputContainer = this.findInModal(Identifiers.outputContainer);
|
|
79
|
+
this.renderProgressBar(innerOutputContainer, {}, 'append');
|
|
80
|
+
|
|
81
|
+
if (data.success === true) {
|
|
82
|
+
this.loadExtLocalconf().then((): void => {
|
|
83
|
+
innerOutputContainer.append(InfoBox.create(Severity.ok, 'ext_localconf.php of all loaded extensions successfully loaded'));
|
|
84
|
+
this.loadExtTables().then((): void => {
|
|
85
|
+
innerOutputContainer.append(InfoBox.create(Severity.ok, 'ext_tables.php of all loaded extensions successfully loaded'));
|
|
86
|
+
}, async (error: AjaxResponse): Promise<void> => {
|
|
87
|
+
this.renderFailureMessages('ext_tables.php', (await error.response.json()).brokenExtensions, innerOutputContainer);
|
|
88
|
+
}).finally((): void => {
|
|
89
|
+
this.unlockModal();
|
|
90
|
+
});
|
|
91
|
+
}, async (error: AjaxResponse): Promise<void> => {
|
|
92
|
+
this.renderFailureMessages('ext_localconf.php', (await error.response.json()).brokenExtensions, innerOutputContainer);
|
|
93
|
+
innerOutputContainer.append(InfoBox.create(Severity.notice, 'Skipped scanning ext_tables.php files due to previous errors'));
|
|
94
|
+
this.unlockModal();
|
|
95
|
+
});
|
|
96
|
+
} else {
|
|
97
|
+
Notification.error('Something went wrong', 'The request was not processed successfully. Please check the browser\'s console and TYPO3\'s log.');
|
|
98
|
+
this.unlockModal();
|
|
99
|
+
}
|
|
100
|
+
},
|
|
101
|
+
(error: AjaxResponse): void => {
|
|
102
|
+
Router.handleAjaxError(error, modalContent);
|
|
103
|
+
this.unlockModal();
|
|
104
|
+
}
|
|
105
|
+
);
|
|
106
|
+
}
|
|
107
|
+
|
|
108
|
+
private unlockModal(): void {
|
|
109
|
+
this.findInModal(Identifiers.outputContainer)?.querySelector('typo3-backend-progress-bar')?.remove();
|
|
110
|
+
this.setModalButtonsState(true);
|
|
111
|
+
}
|
|
112
|
+
|
|
113
|
+
private renderFailureMessages(scope: string, brokenExtensions: Array<BrokenExtension>, outputContainer: HTMLElement): void {
|
|
114
|
+
for (const extension of brokenExtensions) {
|
|
115
|
+
let uninstallAction;
|
|
116
|
+
if (!extension.isProtected) {
|
|
117
|
+
uninstallAction = document.createElement('button');
|
|
118
|
+
uninstallAction.classList.add('btn', 'btn-danger', 't3js-extensionCompatTester-uninstall');
|
|
119
|
+
uninstallAction.dataset.extension = extension.name;
|
|
120
|
+
uninstallAction.innerText = 'Uninstall extension "' + extension.name + '"';
|
|
121
|
+
}
|
|
122
|
+
outputContainer.append(
|
|
123
|
+
InfoBox.create(
|
|
124
|
+
Severity.error,
|
|
125
|
+
'Loading ' + scope + ' of extension "' + extension.name + '" failed',
|
|
126
|
+
extension.isProtected ? 'Extension is mandatory and cannot be uninstalled.' : ''
|
|
127
|
+
),
|
|
128
|
+
uninstallAction,
|
|
129
|
+
);
|
|
130
|
+
}
|
|
131
|
+
|
|
132
|
+
this.unlockModal();
|
|
133
|
+
}
|
|
134
|
+
|
|
135
|
+
private loadExtLocalconf(): Promise<AjaxResponse> {
|
|
136
|
+
const executeToken = this.getModuleContent().dataset.extensionCompatTesterLoadExt_localconfToken;
|
|
137
|
+
return new AjaxRequest(Router.getUrl()).post({
|
|
138
|
+
'install': {
|
|
139
|
+
'action': 'extensionCompatTesterLoadExtLocalconf',
|
|
140
|
+
'token': executeToken,
|
|
141
|
+
},
|
|
142
|
+
});
|
|
143
|
+
}
|
|
144
|
+
|
|
145
|
+
private loadExtTables(): Promise<AjaxResponse> {
|
|
146
|
+
const executeToken = this.getModuleContent().dataset.extensionCompatTesterLoadExt_tablesToken;
|
|
147
|
+
return new AjaxRequest(Router.getUrl()).post({
|
|
148
|
+
'install': {
|
|
149
|
+
'action': 'extensionCompatTesterLoadExtTables',
|
|
150
|
+
'token': executeToken,
|
|
151
|
+
},
|
|
152
|
+
});
|
|
153
|
+
}
|
|
154
|
+
|
|
155
|
+
/**
|
|
156
|
+
* Send an ajax request to uninstall an extension (or multiple extensions)
|
|
157
|
+
*
|
|
158
|
+
* @param extension string of extension(s) - may be comma separated
|
|
159
|
+
*/
|
|
160
|
+
private uninstallExtension(extension: string): void {
|
|
161
|
+
const executeToken = this.getModuleContent().dataset.extensionCompatTesterUninstallExtensionToken;
|
|
162
|
+
const modalContent = this.getModalBody();
|
|
163
|
+
const outputContainer = this.findInModal(Identifiers.outputContainer);
|
|
164
|
+
this.renderProgressBar(outputContainer, {}, 'append');
|
|
165
|
+
(new AjaxRequest(Router.getUrl()))
|
|
166
|
+
.post({
|
|
167
|
+
install: {
|
|
168
|
+
action: 'extensionCompatTesterUninstallExtension',
|
|
169
|
+
token: executeToken,
|
|
170
|
+
extension: extension,
|
|
171
|
+
},
|
|
172
|
+
})
|
|
173
|
+
.then(
|
|
174
|
+
async (response: AjaxResponse): Promise<void> => {
|
|
175
|
+
const data = await response.resolve();
|
|
176
|
+
if (data.success) {
|
|
177
|
+
if (Array.isArray(data.status)) {
|
|
178
|
+
data.status.forEach((element: MessageInterface): void => {
|
|
179
|
+
modalContent.querySelector(Identifiers.outputContainer).replaceChildren(InfoBox.create(element.severity, element.title, element.message));
|
|
180
|
+
});
|
|
181
|
+
}
|
|
182
|
+
this.findInModal(Identifiers.uninstallTrigger).classList.add('hidden');
|
|
183
|
+
this.getLoadedExtensionList();
|
|
184
|
+
} else {
|
|
185
|
+
Notification.error('Something went wrong', 'The request was not processed successfully. Please check the browser\'s console and TYPO3\'s log.');
|
|
186
|
+
}
|
|
187
|
+
},
|
|
188
|
+
(error: AjaxResponse): void => {
|
|
189
|
+
Router.handleAjaxError(error, modalContent);
|
|
190
|
+
}
|
|
191
|
+
);
|
|
192
|
+
}
|
|
193
|
+
}
|
|
194
|
+
|
|
195
|
+
export default new ExtensionCompatTester();
|
|
@@ -0,0 +1,381 @@
|
|
|
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 'bootstrap';
|
|
15
|
+
import AjaxRequest from '@typo3/core/ajax/ajax-request';
|
|
16
|
+
import { AbstractInteractableModule, type ModuleLoadedResponseWithButtons } from '../abstract-interactable-module';
|
|
17
|
+
import type { ModalElement } from '@typo3/backend/modal';
|
|
18
|
+
import Modal from '@typo3/backend/modal';
|
|
19
|
+
import Notification from '@typo3/backend/notification';
|
|
20
|
+
import AjaxQueue from '../../ajax/ajax-queue';
|
|
21
|
+
import Router from '../../router';
|
|
22
|
+
import RegularEvent from '@typo3/core/event/regular-event';
|
|
23
|
+
import type { AjaxResponse } from '@typo3/core/ajax/ajax-response';
|
|
24
|
+
import type { ProgressBarElement } from '@typo3/backend/element/progress-bar-element';
|
|
25
|
+
|
|
26
|
+
enum Identifiers {
|
|
27
|
+
extensionContainer = '.t3js-extensionScanner-extension',
|
|
28
|
+
numberOfFiles = '.t3js-extensionScanner-number-of-files',
|
|
29
|
+
scanSingleTrigger = '.t3js-extensionScanner-scan-single',
|
|
30
|
+
extensionScanButton = '.t3js-extensionScanner-scan-all'
|
|
31
|
+
}
|
|
32
|
+
|
|
33
|
+
type Match = {
|
|
34
|
+
uniqueId: string;
|
|
35
|
+
message: string;
|
|
36
|
+
indicator: string;
|
|
37
|
+
silenced: boolean;
|
|
38
|
+
lineContent: string;
|
|
39
|
+
line: number;
|
|
40
|
+
restFiles: RestFile[];
|
|
41
|
+
};
|
|
42
|
+
|
|
43
|
+
type RestFile = {
|
|
44
|
+
uniqueId: string;
|
|
45
|
+
version: string;
|
|
46
|
+
headline: string;
|
|
47
|
+
content: string;
|
|
48
|
+
class: string;
|
|
49
|
+
file_hash: string;
|
|
50
|
+
};
|
|
51
|
+
|
|
52
|
+
type ExtensionScannerFilesResponse = {
|
|
53
|
+
files: string[],
|
|
54
|
+
success: boolean,
|
|
55
|
+
};
|
|
56
|
+
|
|
57
|
+
type ExtensionScannerScanFileResponse = {
|
|
58
|
+
effectiveCodeLines: number,
|
|
59
|
+
ignoredLines: number,
|
|
60
|
+
isFileIgnored: boolean,
|
|
61
|
+
matches: Match[],
|
|
62
|
+
success: boolean,
|
|
63
|
+
};
|
|
64
|
+
|
|
65
|
+
class ExtensionScanner extends AbstractInteractableModule {
|
|
66
|
+
private readonly listOfAffectedRestFileHashes: string[] = [];
|
|
67
|
+
|
|
68
|
+
public override initialize(currentModal: ModalElement): void {
|
|
69
|
+
super.initialize(currentModal);
|
|
70
|
+
|
|
71
|
+
Promise.all([
|
|
72
|
+
this.loadModuleFrameAgnostic('@typo3/backend/element/progress-bar-element.js'),
|
|
73
|
+
]).then((): void => {
|
|
74
|
+
this.getData();
|
|
75
|
+
});
|
|
76
|
+
|
|
77
|
+
new RegularEvent('typo3-modal-hide', (): void => {
|
|
78
|
+
AjaxQueue.flush();
|
|
79
|
+
}).bindTo(currentModal);
|
|
80
|
+
|
|
81
|
+
new RegularEvent('click', (event: Event, target: HTMLElement): void => {
|
|
82
|
+
// Scan a single extension by clicking "Rescan"
|
|
83
|
+
event.preventDefault();
|
|
84
|
+
const extension = target.closest<HTMLElement>(Identifiers.extensionContainer).dataset.extension;
|
|
85
|
+
this.scanSingleExtension(extension);
|
|
86
|
+
}).delegateTo(currentModal, Identifiers.scanSingleTrigger);
|
|
87
|
+
|
|
88
|
+
new RegularEvent('click', (event: Event): void => {
|
|
89
|
+
// Scan all button
|
|
90
|
+
event.preventDefault();
|
|
91
|
+
this.setModalButtonsState(false);
|
|
92
|
+
const extensions = currentModal.querySelectorAll<HTMLElement>(Identifiers.extensionContainer);
|
|
93
|
+
this.scanAll(extensions);
|
|
94
|
+
}).delegateTo(currentModal, Identifiers.extensionScanButton);
|
|
95
|
+
}
|
|
96
|
+
|
|
97
|
+
private getData(): void {
|
|
98
|
+
const modalContent = this.getModalBody();
|
|
99
|
+
(new AjaxRequest(Router.getUrl('extensionScannerGetData'))).get().then(
|
|
100
|
+
async (response: AjaxResponse): Promise<void> => {
|
|
101
|
+
const data: ModuleLoadedResponseWithButtons = await response.resolve();
|
|
102
|
+
if (data.success === true) {
|
|
103
|
+
modalContent.innerHTML = data.html;
|
|
104
|
+
Modal.setButtons(data.buttons);
|
|
105
|
+
this.setupEventListeners();
|
|
106
|
+
} else {
|
|
107
|
+
Notification.error('Something went wrong', 'The request was not processed successfully. Please check the browser\'s console and TYPO3\'s log.');
|
|
108
|
+
}
|
|
109
|
+
},
|
|
110
|
+
(error: AjaxResponse): void => {
|
|
111
|
+
Router.handleAjaxError(error, modalContent);
|
|
112
|
+
}
|
|
113
|
+
);
|
|
114
|
+
}
|
|
115
|
+
|
|
116
|
+
private setupEventListeners(): void {
|
|
117
|
+
this.currentModal.querySelectorAll(Identifiers.extensionContainer).forEach((extensionContainer: HTMLElement) => {
|
|
118
|
+
new RegularEvent('show.bs.collapse', (event: Event): void => {
|
|
119
|
+
// Scan a single extension by opening the panel
|
|
120
|
+
const target = event.currentTarget as HTMLElement;
|
|
121
|
+
if (typeof target.dataset.scanned === 'undefined') {
|
|
122
|
+
const extension = target.dataset.extension;
|
|
123
|
+
this.scanSingleExtension(extension);
|
|
124
|
+
target.dataset.scanned = String(true);
|
|
125
|
+
}
|
|
126
|
+
}).bindTo(extensionContainer);
|
|
127
|
+
});
|
|
128
|
+
}
|
|
129
|
+
|
|
130
|
+
private getExtensionSelector(extension: string): string {
|
|
131
|
+
return Identifiers.extensionContainer + '-' + extension;
|
|
132
|
+
}
|
|
133
|
+
|
|
134
|
+
private async scanAll(extensions: NodeListOf<HTMLElement>): Promise<void> {
|
|
135
|
+
extensions.forEach(extensionContainer => {
|
|
136
|
+
extensionContainer.classList.remove('panel-danger', 'panel-warning', 'panel-success');
|
|
137
|
+
|
|
138
|
+
const panelProgress = extensionContainer.querySelector<HTMLElement>('.panel-progress-bar');
|
|
139
|
+
panelProgress.style.width = String(0);
|
|
140
|
+
panelProgress.setAttribute('aria-valuenow', String(0));
|
|
141
|
+
panelProgress.querySelector('span').innerText = '0%';
|
|
142
|
+
});
|
|
143
|
+
|
|
144
|
+
this.setProgressForAll();
|
|
145
|
+
|
|
146
|
+
const scannerPromises = [...extensions].map(async (element: HTMLElement) => {
|
|
147
|
+
const extension = element.dataset.extension;
|
|
148
|
+
try {
|
|
149
|
+
await this.scanSingleExtension(extension);
|
|
150
|
+
} finally {
|
|
151
|
+
element.dataset.scanned = String(true);
|
|
152
|
+
}
|
|
153
|
+
});
|
|
154
|
+
|
|
155
|
+
try {
|
|
156
|
+
await Promise.allSettled(scannerPromises);
|
|
157
|
+
} finally {
|
|
158
|
+
this.setModalButtonsState(true);
|
|
159
|
+
|
|
160
|
+
Notification.success('Scan finished', 'All extensions have been scanned.');
|
|
161
|
+
|
|
162
|
+
try {
|
|
163
|
+
const response = await new AjaxRequest(Router.getUrl()).post({
|
|
164
|
+
install: {
|
|
165
|
+
action: 'extensionScannerMarkFullyScannedRestFiles',
|
|
166
|
+
token: this.getModuleContent().dataset.extensionScannerMarkFullyScannedRestFilesToken,
|
|
167
|
+
hashes: Array.from(new Set(this.listOfAffectedRestFileHashes)),
|
|
168
|
+
},
|
|
169
|
+
});
|
|
170
|
+
const data = await response.resolve();
|
|
171
|
+
if (data.success === true) {
|
|
172
|
+
Notification.success('Marked not affected files', 'Marked ' + data.markedAsNotAffected + ' ReST files as not affected.');
|
|
173
|
+
}
|
|
174
|
+
} catch (error: unknown) {
|
|
175
|
+
Router.handleAjaxError(error as AjaxResponse, this.getModalBody());
|
|
176
|
+
}
|
|
177
|
+
}
|
|
178
|
+
}
|
|
179
|
+
|
|
180
|
+
private setStatusMessageForScan(extension: string, doneFiles: number, numberOfFiles: number): void {
|
|
181
|
+
const extensionContainer = this.findInModal(this.getExtensionSelector(extension));
|
|
182
|
+
const numberOfFilesElement = extensionContainer.querySelector<HTMLElement>(Identifiers.numberOfFiles);
|
|
183
|
+
numberOfFilesElement.innerText = 'Checked ' + doneFiles + ' of ' + numberOfFiles + ' files';
|
|
184
|
+
}
|
|
185
|
+
|
|
186
|
+
private setProgressForScan(extension: string, doneFiles: number, numberOfFiles: number): void {
|
|
187
|
+
const percent = (doneFiles / numberOfFiles) * 100;
|
|
188
|
+
const extensionContainer = this.findInModal(this.getExtensionSelector(extension));
|
|
189
|
+
const panelProgress = extensionContainer.querySelector<HTMLElement>('.panel-progress-bar');
|
|
190
|
+
panelProgress.style.width = percent + '%';
|
|
191
|
+
panelProgress.setAttribute('aria-valuenow', String(percent));
|
|
192
|
+
panelProgress.querySelector('span').innerText = percent + '%';
|
|
193
|
+
}
|
|
194
|
+
|
|
195
|
+
/**
|
|
196
|
+
* @todo: this method should be called by an event handler with fine-grained information (e.g. is the scan still in progress?)
|
|
197
|
+
*/
|
|
198
|
+
private setProgressForAll(): void {
|
|
199
|
+
const numberOfExtensions: number = this.currentModal.querySelectorAll(Identifiers.extensionContainer).length;
|
|
200
|
+
const numberOfScannedExtensions: number = this.currentModal.querySelectorAll(Identifiers.extensionContainer + '.t3js-extensionscan-finished').length;
|
|
201
|
+
|
|
202
|
+
const inProgressLabel: string = `Scanning extensions (${numberOfScannedExtensions} of ${numberOfExtensions} done)…`;
|
|
203
|
+
const extensionProgressBar = this.findInModal('.t3js-extensionScanner-progress-all-extension') as ProgressBarElement;
|
|
204
|
+
extensionProgressBar.removeAttribute('hidden');
|
|
205
|
+
extensionProgressBar.max = numberOfExtensions;
|
|
206
|
+
extensionProgressBar.value = numberOfScannedExtensions;
|
|
207
|
+
extensionProgressBar.label = inProgressLabel;
|
|
208
|
+
}
|
|
209
|
+
|
|
210
|
+
/**
|
|
211
|
+
* Handle a single extension scan
|
|
212
|
+
*/
|
|
213
|
+
private async scanSingleExtension(extension: string): Promise<void> {
|
|
214
|
+
const executeToken = this.getModuleContent().dataset.extensionScannerFilesToken;
|
|
215
|
+
const modalContent = this.getModalBody();
|
|
216
|
+
const extensionContainer = this.findInModal(this.getExtensionSelector(extension));
|
|
217
|
+
const hitTemplate = '#t3js-extensionScanner-file-hit-template';
|
|
218
|
+
const restTemplate = '#t3js-extensionScanner-file-hit-rest-template';
|
|
219
|
+
let hitFound = false;
|
|
220
|
+
extensionContainer.classList.add('panel-default');
|
|
221
|
+
extensionContainer.classList.remove('panel-danger', 'panel-warning', 'panel-success', 't3js-extensionscan-finished');
|
|
222
|
+
extensionContainer.dataset.hasRun = String('true');
|
|
223
|
+
|
|
224
|
+
const scanSingle = extensionContainer.querySelector<HTMLButtonElement>('.t3js-extensionScanner-scan-single');
|
|
225
|
+
scanSingle.innerText = 'Scanning...';
|
|
226
|
+
scanSingle.disabled = true;
|
|
227
|
+
|
|
228
|
+
extensionContainer.querySelector<HTMLElement>('.t3js-extensionScanner-extension-body-loc').innerText = '0';
|
|
229
|
+
extensionContainer.querySelector<HTMLElement>('.t3js-extensionScanner-extension-body-ignored-files').innerText = '0';
|
|
230
|
+
extensionContainer.querySelector<HTMLElement>('.t3js-extensionScanner-extension-body-ignored-lines').innerText = '0';
|
|
231
|
+
|
|
232
|
+
this.setProgressForAll();
|
|
233
|
+
|
|
234
|
+
try {
|
|
235
|
+
const response = await new AjaxRequest(Router.getUrl()).post({
|
|
236
|
+
install: {
|
|
237
|
+
action: 'extensionScannerFiles',
|
|
238
|
+
token: executeToken,
|
|
239
|
+
extension: extension,
|
|
240
|
+
},
|
|
241
|
+
});
|
|
242
|
+
const data: ExtensionScannerFilesResponse = await response.resolve();
|
|
243
|
+
if (data.success === true && Array.isArray(data.files)) {
|
|
244
|
+
const numberOfFiles = data.files.length;
|
|
245
|
+
if (numberOfFiles <= 0) {
|
|
246
|
+
Notification.warning('No files found', 'The extension ' + extension + ' contains no scannable files');
|
|
247
|
+
return;
|
|
248
|
+
}
|
|
249
|
+
|
|
250
|
+
this.setStatusMessageForScan(extension, 0, numberOfFiles);
|
|
251
|
+
extensionContainer.querySelector<HTMLElement>('.t3js-extensionScanner-extension-body').innerText = '';
|
|
252
|
+
extensionContainer.classList.add('panel-has-progress');
|
|
253
|
+
let doneFiles = 0;
|
|
254
|
+
const filePromises = data.files.map((file: string): Promise<void> => new Promise<void>((resolve, reject): void => {
|
|
255
|
+
AjaxQueue.add({
|
|
256
|
+
method: 'POST',
|
|
257
|
+
data: {
|
|
258
|
+
install: {
|
|
259
|
+
action: 'extensionScannerScanFile',
|
|
260
|
+
token: this.getModuleContent().dataset.extensionScannerScanFileToken,
|
|
261
|
+
extension: extension,
|
|
262
|
+
file: file,
|
|
263
|
+
},
|
|
264
|
+
},
|
|
265
|
+
url: Router.getUrl(),
|
|
266
|
+
onfulfilled: async (response: AjaxResponse): Promise<void> => {
|
|
267
|
+
const fileData: ExtensionScannerScanFileResponse = await response.resolve();
|
|
268
|
+
doneFiles++;
|
|
269
|
+
this.setStatusMessageForScan(extension, doneFiles, numberOfFiles);
|
|
270
|
+
this.setProgressForScan(extension, doneFiles, numberOfFiles);
|
|
271
|
+
if (fileData.success && Array.isArray(fileData.matches)) {
|
|
272
|
+
fileData.matches.forEach((match: Match): void => {
|
|
273
|
+
hitFound = true;
|
|
274
|
+
const aMatch = modalContent.querySelector(hitTemplate + ' .panel').cloneNode(true) as HTMLElement;
|
|
275
|
+
aMatch.querySelector<HTMLElement>('.t3js-extensionScanner-hit-file-panel-head').setAttribute('data-bs-target', '#collapse' + match.uniqueId);
|
|
276
|
+
aMatch.querySelector<HTMLElement>('.t3js-extensionScanner-hit-file-panel-head').setAttribute('aria-controls', 'collapse' + match.uniqueId);
|
|
277
|
+
aMatch.querySelector<HTMLElement>('.t3js-extensionScanner-hit-file-panel-body').setAttribute('id', 'collapse' + match.uniqueId);
|
|
278
|
+
aMatch.querySelector<HTMLElement>('.t3js-extensionScanner-hit-filename').innerText = file;
|
|
279
|
+
aMatch.querySelector<HTMLElement>('.t3js-extensionScanner-hit-message').innerText = match.message;
|
|
280
|
+
if (match.indicator === 'strong') {
|
|
281
|
+
aMatch.querySelector<HTMLElement>('.t3js-extensionScanner-hit-file-panel-head .t3js-extensionScanner-hit-badges')
|
|
282
|
+
.innerHTML += '<span class="badge badge-danger" title="Reliable match, false positive unlikely">strong</span>';
|
|
283
|
+
} else {
|
|
284
|
+
aMatch.querySelector<HTMLElement>('.t3js-extensionScanner-hit-file-panel-head .t3js-extensionScanner-hit-badges')
|
|
285
|
+
.innerHTML += '<span class="badge badge-warning" title="Probable match, but can be a false positive">weak</span>';
|
|
286
|
+
}
|
|
287
|
+
if (match.silenced === true) {
|
|
288
|
+
aMatch.querySelector<HTMLElement>('.t3js-extensionScanner-hit-file-panel-head .t3js-extensionScanner-hit-badges')
|
|
289
|
+
.innerHTML += '<span class="badge badge-info" title="Match has been annotated by extension author' +
|
|
290
|
+
' as false positive match">silenced</span>';
|
|
291
|
+
}
|
|
292
|
+
aMatch.querySelector<HTMLElement>('.t3js-extensionScanner-hit-file-lineContent').innerText = match.lineContent;
|
|
293
|
+
aMatch.querySelector<HTMLElement>('.t3js-extensionScanner-hit-file-line').innerText = match.line + ': ';
|
|
294
|
+
if (Array.isArray(match.restFiles)) {
|
|
295
|
+
match.restFiles.forEach((restFile: RestFile): void => {
|
|
296
|
+
const aRest = modalContent.querySelector(restTemplate + ' .panel').cloneNode(true) as HTMLElement;
|
|
297
|
+
aRest.querySelector<HTMLElement>('.t3js-extensionScanner-hit-rest-panel-head').setAttribute('data-bs-target', '#collapse' + restFile.uniqueId);
|
|
298
|
+
aRest.querySelector<HTMLElement>('.t3js-extensionScanner-hit-rest-panel-head').setAttribute('aria-controls', 'collapse' + restFile.uniqueId);
|
|
299
|
+
aRest.querySelector<HTMLElement>('.t3js-extensionScanner-hit-rest-panel-head .t3js-extensionScanner-hit-rest-badge').innerText = restFile.version;
|
|
300
|
+
aRest.querySelector<HTMLElement>('.t3js-extensionScanner-hit-rest-panel-body').setAttribute('id', 'collapse' + restFile.uniqueId);
|
|
301
|
+
aRest.querySelector<HTMLElement>('.t3js-extensionScanner-hit-rest-headline').innerText = restFile.headline;
|
|
302
|
+
aRest.querySelector<HTMLElement>('.t3js-extensionScanner-hit-rest-body').innerText = restFile.content;
|
|
303
|
+
aRest.classList.add('panel-' + restFile.class);
|
|
304
|
+
aMatch.querySelector<HTMLElement>('.t3js-extensionScanner-hit-file-rest-container').append(aRest);
|
|
305
|
+
this.listOfAffectedRestFileHashes.push(restFile.file_hash);
|
|
306
|
+
});
|
|
307
|
+
}
|
|
308
|
+
const panelClass =
|
|
309
|
+
aMatch.querySelectorAll('.panel-breaking, .t3js-extensionScanner-hit-file-rest-container').length > 0
|
|
310
|
+
? 'panel-danger'
|
|
311
|
+
: 'panel-warning';
|
|
312
|
+
aMatch.classList.add(panelClass);
|
|
313
|
+
aMatch.classList.remove('panel-default');
|
|
314
|
+
const extensionBody = extensionContainer.querySelector<HTMLElement>('.t3js-extensionScanner-extension-body');
|
|
315
|
+
extensionBody.classList.remove('hide');
|
|
316
|
+
extensionBody.append(aMatch);
|
|
317
|
+
extensionContainer.classList.remove('panel-default');
|
|
318
|
+
if (panelClass === 'panel-danger') {
|
|
319
|
+
extensionContainer.classList.remove('panel-warning');
|
|
320
|
+
extensionContainer.classList.add(panelClass);
|
|
321
|
+
}
|
|
322
|
+
if (panelClass === 'panel-warning' && !extensionContainer.classList.contains('panel-danger')) {
|
|
323
|
+
extensionContainer.classList.add(panelClass);
|
|
324
|
+
}
|
|
325
|
+
});
|
|
326
|
+
}
|
|
327
|
+
if (fileData.success) {
|
|
328
|
+
const currentLinesOfCode = parseInt(extensionContainer.querySelector<HTMLElement>('.t3js-extensionScanner-extension-body-loc').innerText, 10);
|
|
329
|
+
extensionContainer.querySelector<HTMLElement>('.t3js-extensionScanner-extension-body-loc')
|
|
330
|
+
.innerText = String(currentLinesOfCode + fileData.effectiveCodeLines);
|
|
331
|
+
if (fileData.isFileIgnored) {
|
|
332
|
+
const currentIgnoredFiles = parseInt(
|
|
333
|
+
extensionContainer.querySelector<HTMLElement>('.t3js-extensionScanner-extension-body-ignored-files').innerText,
|
|
334
|
+
10,
|
|
335
|
+
);
|
|
336
|
+
extensionContainer.querySelector<HTMLElement>('.t3js-extensionScanner-extension-body-ignored-files').innerText = String(currentIgnoredFiles + 1);
|
|
337
|
+
}
|
|
338
|
+
const currentIgnoredLines = parseInt(
|
|
339
|
+
extensionContainer.querySelector<HTMLElement>('.t3js-extensionScanner-extension-body-ignored-lines').innerText,
|
|
340
|
+
10,
|
|
341
|
+
);
|
|
342
|
+
extensionContainer.querySelector<HTMLElement>('.t3js-extensionScanner-extension-body-ignored-lines')
|
|
343
|
+
.innerText = String(currentIgnoredLines + fileData.ignoredLines);
|
|
344
|
+
}
|
|
345
|
+
resolve();
|
|
346
|
+
},
|
|
347
|
+
onrejected: (reason: string): void => {
|
|
348
|
+
reject();
|
|
349
|
+
doneFiles = doneFiles + 1;
|
|
350
|
+
this.setStatusMessageForScan(extension, doneFiles, numberOfFiles);
|
|
351
|
+
this.setProgressForScan(extension, doneFiles, numberOfFiles);
|
|
352
|
+
extensionContainer.classList.remove('panel-has-progress');
|
|
353
|
+
this.setProgressForAll();
|
|
354
|
+
console.error(reason);
|
|
355
|
+
},
|
|
356
|
+
});
|
|
357
|
+
}));
|
|
358
|
+
|
|
359
|
+
await Promise.allSettled(filePromises);
|
|
360
|
+
|
|
361
|
+
if (!hitFound) {
|
|
362
|
+
extensionContainer.classList.remove('panel-default');
|
|
363
|
+
extensionContainer.classList.add('panel-success');
|
|
364
|
+
}
|
|
365
|
+
extensionContainer.classList.add('t3js-extensionscan-finished');
|
|
366
|
+
extensionContainer.classList.remove('panel-has-progress');
|
|
367
|
+
this.setProgressForAll();
|
|
368
|
+
const scanSingle = extensionContainer.querySelector<HTMLButtonElement>('.t3js-extensionScanner-scan-single');
|
|
369
|
+
scanSingle.innerText = 'Rescan';
|
|
370
|
+
scanSingle.disabled = false;
|
|
371
|
+
} else {
|
|
372
|
+
Notification.error('Oops, an error occurred', 'Please look at the browser console output for details');
|
|
373
|
+
console.error(data);
|
|
374
|
+
}
|
|
375
|
+
} catch (error: unknown) {
|
|
376
|
+
Router.handleAjaxError(error as AjaxResponse, modalContent);
|
|
377
|
+
}
|
|
378
|
+
}
|
|
379
|
+
}
|
|
380
|
+
|
|
381
|
+
export default new ExtensionScanner();
|
|
@@ -0,0 +1,93 @@
|
|
|
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 { AbstractInteractableModule, type ModuleLoadedResponseWithButtons } from '../abstract-interactable-module';
|
|
15
|
+
import Modal from '@typo3/backend/modal';
|
|
16
|
+
import Notification from '@typo3/backend/notification';
|
|
17
|
+
import AjaxRequest from '@typo3/core/ajax/ajax-request';
|
|
18
|
+
import { InfoBox } from '../../renderable/info-box';
|
|
19
|
+
import Severity from '../../renderable/severity';
|
|
20
|
+
import Router from '../../router';
|
|
21
|
+
import RegularEvent from '@typo3/core/event/regular-event';
|
|
22
|
+
import type { AjaxResponse } from '@typo3/core/ajax/ajax-response';
|
|
23
|
+
import type { ModalElement } from '@typo3/backend/modal';
|
|
24
|
+
import type MessageInterface from '@typo3/install/message-interface';
|
|
25
|
+
|
|
26
|
+
enum Identifiers {
|
|
27
|
+
checkTrigger = '.t3js-tcaExtTablesCheck-check',
|
|
28
|
+
outputContainer = '.t3js-tcaExtTablesCheck-output'
|
|
29
|
+
}
|
|
30
|
+
|
|
31
|
+
type TcaCheckResponse = ModuleLoadedResponseWithButtons & {
|
|
32
|
+
status: MessageInterface[]
|
|
33
|
+
};
|
|
34
|
+
|
|
35
|
+
/**
|
|
36
|
+
* Module: @typo3/install/module/tca-ext-tables-check
|
|
37
|
+
*/
|
|
38
|
+
class TcaExtTablesCheck extends AbstractInteractableModule {
|
|
39
|
+
public override initialize(currentModal: ModalElement): void {
|
|
40
|
+
super.initialize(currentModal);
|
|
41
|
+
this.loadModuleFrameAgnostic('@typo3/install/renderable/info-box.js').then((): void => {
|
|
42
|
+
this.check();
|
|
43
|
+
});
|
|
44
|
+
|
|
45
|
+
new RegularEvent('click', (event: Event): void => {
|
|
46
|
+
event.preventDefault();
|
|
47
|
+
this.check();
|
|
48
|
+
}).delegateTo(currentModal, Identifiers.checkTrigger);
|
|
49
|
+
}
|
|
50
|
+
|
|
51
|
+
private check(): void {
|
|
52
|
+
this.setModalButtonsState(false);
|
|
53
|
+
|
|
54
|
+
const outputContainer: HTMLElement = document.querySelector(Identifiers.outputContainer);
|
|
55
|
+
if (outputContainer !== null) {
|
|
56
|
+
this.renderProgressBar(outputContainer, {}, 'append');
|
|
57
|
+
}
|
|
58
|
+
const modalContent: HTMLElement = this.getModalBody();
|
|
59
|
+
(new AjaxRequest(Router.getUrl('tcaExtTablesCheck')))
|
|
60
|
+
.get({ cache: 'no-cache' })
|
|
61
|
+
.then(
|
|
62
|
+
async (response: AjaxResponse): Promise<void> => {
|
|
63
|
+
const data: TcaCheckResponse = await response.resolve();
|
|
64
|
+
modalContent.innerHTML = data.html;
|
|
65
|
+
Modal.setButtons(data.buttons);
|
|
66
|
+
if (data.success === true && Array.isArray(data.status)) {
|
|
67
|
+
if (data.status.length > 0) {
|
|
68
|
+
modalContent.querySelector(Identifiers.outputContainer).append(InfoBox.create(
|
|
69
|
+
Severity.warning,
|
|
70
|
+
'Following extensions change TCA in ext_tables.php',
|
|
71
|
+
'Check ext_tables.php files, look for ExtensionManagementUtility calls and $GLOBALS[\'TCA\'] modifications'
|
|
72
|
+
));
|
|
73
|
+
|
|
74
|
+
data.status.forEach((element: MessageInterface): void => {
|
|
75
|
+
modalContent.querySelector(Identifiers.outputContainer).append(InfoBox.create(element.severity, element.title, element.message));
|
|
76
|
+
});
|
|
77
|
+
} else {
|
|
78
|
+
modalContent.querySelector(Identifiers.outputContainer).append(InfoBox.create(Severity.ok, 'No TCA changes in ext_tables.php files. Good job!'));
|
|
79
|
+
}
|
|
80
|
+
} else {
|
|
81
|
+
Notification.error('Something went wrong', 'Please use the module "Check for broken extensions" to find a possible extension causing this issue.');
|
|
82
|
+
}
|
|
83
|
+
},
|
|
84
|
+
(error: AjaxResponse): void => {
|
|
85
|
+
Router.handleAjaxError(error, modalContent);
|
|
86
|
+
}
|
|
87
|
+
).finally((): void => {
|
|
88
|
+
this.setModalButtonsState(true);
|
|
89
|
+
});
|
|
90
|
+
}
|
|
91
|
+
}
|
|
92
|
+
|
|
93
|
+
export default new TcaExtTablesCheck();
|