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,1077 @@
|
|
|
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 DocumentService from '@typo3/core/document-service';
|
|
15
|
+
import { SeverityEnum } from './enum/severity';
|
|
16
|
+
import 'bootstrap';
|
|
17
|
+
import { default as Modal, type ModalElement } from '@typo3/backend/modal';
|
|
18
|
+
import SecurityUtility from '@typo3/core/security-utility';
|
|
19
|
+
import { customElement, property } from 'lit/decorators';
|
|
20
|
+
import { html, LitElement, nothing, type TemplateResult } from 'lit';
|
|
21
|
+
import { classMap } from 'lit/directives/class-map';
|
|
22
|
+
import { type StyleInfo, styleMap } from 'lit/directives/style-map';
|
|
23
|
+
import { ref, type Ref, createRef } from 'lit/directives/ref';
|
|
24
|
+
import { CodeMirrorElement } from '@typo3/backend/code-editor/element/code-mirror-element';
|
|
25
|
+
|
|
26
|
+
type Cell = { spanned: number, rowspan: number, colspan: number, name: string, colpos: string, column: number, identifier: string, slideMode: SlideModes };
|
|
27
|
+
|
|
28
|
+
enum SlideModes {
|
|
29
|
+
none = '',
|
|
30
|
+
slide = 'slide',
|
|
31
|
+
collect = 'collect',
|
|
32
|
+
collectReverse = 'collectReverse',
|
|
33
|
+
}
|
|
34
|
+
|
|
35
|
+
/**
|
|
36
|
+
* Module: @typo3/backend/grid-editor
|
|
37
|
+
* @exports @typo3/backend/grid-editor
|
|
38
|
+
*/
|
|
39
|
+
@customElement('typo3-backend-grid-editor')
|
|
40
|
+
export class GridEditor extends LitElement {
|
|
41
|
+
@property({ type: Number }) protected colCount: number = 1;
|
|
42
|
+
@property({ type: Number }) protected rowCount: number = 1;
|
|
43
|
+
@property({ type: Boolean }) protected readOnly: boolean = false;
|
|
44
|
+
@property({ type: String }) protected fieldName: string = '';
|
|
45
|
+
@property({ type: Array }) protected data: any[] = [];
|
|
46
|
+
@property({ type: Object }) protected codeMirrorConfig: Record<string, string> = {};
|
|
47
|
+
|
|
48
|
+
protected field: HTMLInputElement;
|
|
49
|
+
protected previewAreaRef: Ref<HTMLTextAreaElement> = createRef();
|
|
50
|
+
protected codeMirrorRef: Ref<CodeMirrorElement> = createRef();
|
|
51
|
+
protected defaultCell: Cell = { spanned: 0, rowspan: 1, colspan: 1, name: '', colpos: '', column: undefined, identifier: '', slideMode: SlideModes.none };
|
|
52
|
+
|
|
53
|
+
/**
|
|
54
|
+
* Remove all markup
|
|
55
|
+
*
|
|
56
|
+
* @param {String} input
|
|
57
|
+
* @returns {string}
|
|
58
|
+
*/
|
|
59
|
+
public static stripMarkup(input: string): string {
|
|
60
|
+
const securityUtility = new SecurityUtility();
|
|
61
|
+
return securityUtility.stripHtml(input);
|
|
62
|
+
}
|
|
63
|
+
|
|
64
|
+
public override async connectedCallback(): Promise<void> {
|
|
65
|
+
await DocumentService.ready();
|
|
66
|
+
this.field = document.querySelector('input[name="' + this.fieldName + '"]');
|
|
67
|
+
|
|
68
|
+
this.addVisibilityObserver(this);
|
|
69
|
+
super.connectedCallback();
|
|
70
|
+
}
|
|
71
|
+
|
|
72
|
+
protected override firstUpdated(): void {
|
|
73
|
+
this.writeConfig(this.export2LayoutRecord());
|
|
74
|
+
}
|
|
75
|
+
|
|
76
|
+
protected override createRenderRoot(): HTMLElement | ShadowRoot {
|
|
77
|
+
// @todo Switch to Shadow DOM once Bootstrap CSS style can be applied correctly
|
|
78
|
+
return this;
|
|
79
|
+
}
|
|
80
|
+
|
|
81
|
+
protected override render(): TemplateResult {
|
|
82
|
+
return html`
|
|
83
|
+
<div class=${classMap({ 'grideditor': true, 'grideditor-readonly': this.readOnly })}>
|
|
84
|
+
${!this.readOnly ? this.renderControls('top', false) : nothing}
|
|
85
|
+
<div class="grideditor-editor">
|
|
86
|
+
<div class="t3js-grideditor">
|
|
87
|
+
${this.renderEditorGrid()}
|
|
88
|
+
</div>
|
|
89
|
+
</div>
|
|
90
|
+
${!this.readOnly ? this.renderControls('right', true) : nothing}
|
|
91
|
+
${!this.readOnly ? this.renderControls('bottom', false) : nothing}
|
|
92
|
+
<div class="grideditor-preview">
|
|
93
|
+
${this.renderPreview()}
|
|
94
|
+
</div>
|
|
95
|
+
</div>
|
|
96
|
+
`;
|
|
97
|
+
}
|
|
98
|
+
|
|
99
|
+
protected renderControls(position: string, vertical: boolean): TemplateResult {
|
|
100
|
+
const addHandlerMapping: Record<string, (e: Event) => void> = {
|
|
101
|
+
top: this.addRowTopHandler,
|
|
102
|
+
right: this.addColumnHandler,
|
|
103
|
+
bottom: this.addRowBottomHandler
|
|
104
|
+
};
|
|
105
|
+
|
|
106
|
+
const addLocaleMapping: Record<string, string> = {
|
|
107
|
+
top: TYPO3.lang.grid_addRow,
|
|
108
|
+
right: TYPO3.lang.grid_addColumn,
|
|
109
|
+
bottom: TYPO3.lang.grid_addRow
|
|
110
|
+
};
|
|
111
|
+
|
|
112
|
+
const removeHandlerMapping: Record<string, (e: Event) => void> = {
|
|
113
|
+
top: this.removeRowTopHandler,
|
|
114
|
+
right: this.removeColumnHandler,
|
|
115
|
+
bottom: this.removeRowBottomHandler
|
|
116
|
+
};
|
|
117
|
+
|
|
118
|
+
const removeLocaleMapping: Record<string, string> = {
|
|
119
|
+
top: TYPO3.lang.grid_removeRow,
|
|
120
|
+
right: TYPO3.lang.grid_removeColumn,
|
|
121
|
+
bottom: TYPO3.lang.grid_removeRow
|
|
122
|
+
};
|
|
123
|
+
|
|
124
|
+
return html`
|
|
125
|
+
<div class="grideditor-control grideditor-control-${position}">
|
|
126
|
+
<div class=${classMap({ 'btn-group': !vertical, 'btn-group-vertical': vertical })}>
|
|
127
|
+
<button @click=${addHandlerMapping[position]} class="btn btn-default btn-sm" title=${addLocaleMapping[position]}>
|
|
128
|
+
<typo3-backend-icon identifier="actions-plus" size="small"></typo3-backend-icon>
|
|
129
|
+
</button>
|
|
130
|
+
<button @click=${removeHandlerMapping[position]} class="btn btn-default btn-sm" title=${removeLocaleMapping[position]}>
|
|
131
|
+
<typo3-backend-icon identifier="actions-minus" size="small"></typo3-backend-icon>
|
|
132
|
+
</button>
|
|
133
|
+
</div>
|
|
134
|
+
</div>
|
|
135
|
+
`;
|
|
136
|
+
}
|
|
137
|
+
|
|
138
|
+
protected renderEditorGrid(): TemplateResult {
|
|
139
|
+
const cells: TemplateResult[] = [];
|
|
140
|
+
|
|
141
|
+
for (let row = 0; row < this.rowCount; row++) {
|
|
142
|
+
const rowData = this.data[row];
|
|
143
|
+
if (rowData.length === 0) {
|
|
144
|
+
continue;
|
|
145
|
+
}
|
|
146
|
+
|
|
147
|
+
for (let col = 0; col < this.colCount; col++) {
|
|
148
|
+
const cell = this.data[row][col];
|
|
149
|
+
if (cell.spanned === 1) {
|
|
150
|
+
continue;
|
|
151
|
+
}
|
|
152
|
+
|
|
153
|
+
cells.push(this.renderGridCell(row, col, cell));
|
|
154
|
+
}
|
|
155
|
+
}
|
|
156
|
+
|
|
157
|
+
return html`
|
|
158
|
+
<div class="grideditor-editor-grid">
|
|
159
|
+
${cells}
|
|
160
|
+
</div>
|
|
161
|
+
`;
|
|
162
|
+
}
|
|
163
|
+
|
|
164
|
+
protected renderGridCell(row: number, col: number, cell: Cell): TemplateResult {
|
|
165
|
+
const styleMapping: StyleInfo = {
|
|
166
|
+
'--grideditor-cell-col': col + 1,
|
|
167
|
+
'--grideditor-cell-colspan': cell.colspan,
|
|
168
|
+
'--grideditor-cell-row': row + 1,
|
|
169
|
+
'--grideditor-cell-rowspan': cell.rowspan
|
|
170
|
+
};
|
|
171
|
+
|
|
172
|
+
return html`
|
|
173
|
+
<div class="grideditor-cell" style=${styleMap(styleMapping)}>
|
|
174
|
+
<div class="grideditor-cell-actions">
|
|
175
|
+
${!this.readOnly ?
|
|
176
|
+
html`
|
|
177
|
+
<button
|
|
178
|
+
@click=${this.linkEditorHandler}
|
|
179
|
+
class="t3js-grideditor-link-editor grideditor-action grideditor-action-edit"
|
|
180
|
+
data-row=${row}
|
|
181
|
+
data-col=${col}
|
|
182
|
+
title=${TYPO3.lang.grid_editCell}>
|
|
183
|
+
<typo3-backend-icon identifier="actions-open" size="small"></typo3-backend-icon>
|
|
184
|
+
</button>
|
|
185
|
+
${this.cellCanSpanRight(col, row) ?
|
|
186
|
+
html`
|
|
187
|
+
<button
|
|
188
|
+
@click=${this.linkExpandRightHandler}
|
|
189
|
+
class="t3js-grideditor-link-expand-right grideditor-action grideditor-action-expand-right"
|
|
190
|
+
data-row=${row}
|
|
191
|
+
data-col=${col}
|
|
192
|
+
title=${TYPO3.lang.grid_cell_merge_right}>
|
|
193
|
+
<typo3-backend-icon identifier="actions-caret-right" size="small"></typo3-backend-icon>
|
|
194
|
+
</button>
|
|
195
|
+
`
|
|
196
|
+
: nothing}
|
|
197
|
+
${this.cellCanShrinkLeft(col, row) ?
|
|
198
|
+
html`
|
|
199
|
+
<button
|
|
200
|
+
@click=${this.linkShrinkLeftHandler}
|
|
201
|
+
class="t3js-grideditor-link-shrink-left grideditor-action grideditor-action-shrink-left"
|
|
202
|
+
data-row=${row}
|
|
203
|
+
data-col=${col}
|
|
204
|
+
title=${TYPO3.lang.grid_cell_split_horizontal}>
|
|
205
|
+
<typo3-backend-icon identifier="actions-caret-left" size="small"></typo3-backend-icon>
|
|
206
|
+
</button>
|
|
207
|
+
`
|
|
208
|
+
: nothing}
|
|
209
|
+
${this.cellCanSpanDown(col, row) ?
|
|
210
|
+
html`
|
|
211
|
+
<button
|
|
212
|
+
@click=${this.linkExpandDownHandler}
|
|
213
|
+
class="t3js-grideditor-link-expand-down grideditor-action grideditor-action-expand-down"
|
|
214
|
+
data-row=${row}
|
|
215
|
+
data-col=${col}
|
|
216
|
+
title=${TYPO3.lang.grid_cell_merge_down}>
|
|
217
|
+
<typo3-backend-icon identifier="actions-caret-down" size="small"></typo3-backend-icon>
|
|
218
|
+
</button>
|
|
219
|
+
`
|
|
220
|
+
: nothing}
|
|
221
|
+
${this.cellCanShrinkUp(col, row) ?
|
|
222
|
+
html`
|
|
223
|
+
<button
|
|
224
|
+
@click=${this.linkShrinkUpHandler}
|
|
225
|
+
class="t3js-grideditor-link-shrink-up grideditor-action grideditor-action-shrink-up"
|
|
226
|
+
data-row=${row}
|
|
227
|
+
data-col=${col}
|
|
228
|
+
title=${TYPO3.lang.grid_cell_split_vertical}>
|
|
229
|
+
<typo3-backend-icon identifier="actions-caret-up" size="small"></typo3-backend-icon>
|
|
230
|
+
</button>
|
|
231
|
+
`
|
|
232
|
+
: nothing}
|
|
233
|
+
`
|
|
234
|
+
: nothing}
|
|
235
|
+
</div>
|
|
236
|
+
|
|
237
|
+
<div class="grideditor-cell-info">
|
|
238
|
+
<strong>${TYPO3.lang.grid_name}:</strong>
|
|
239
|
+
${cell.name ? GridEditor.stripMarkup(cell.name) : TYPO3.lang.grid_notSet}
|
|
240
|
+
<br/>
|
|
241
|
+
<strong>${TYPO3.lang.grid_column}:</strong>
|
|
242
|
+
${typeof cell.column === 'undefined' || isNaN(cell.column) ? TYPO3.lang.grid_notSet : cell.column}
|
|
243
|
+
${cell.identifier?.length ? html`<br/><strong>${TYPO3.lang.grid_identifier}:</strong> ${cell.identifier}` : ''}
|
|
244
|
+
${(cell.slideMode?.toString() || '') !== '' ? html`<br/><strong>${TYPO3.lang.grid_slideMode}:</strong> ${cell.slideMode.toString()}` : ''}
|
|
245
|
+
</div>
|
|
246
|
+
</div>
|
|
247
|
+
`;
|
|
248
|
+
}
|
|
249
|
+
|
|
250
|
+
protected renderPreview(): TemplateResult {
|
|
251
|
+
if (Object.keys(this.codeMirrorConfig).length === 0) {
|
|
252
|
+
return html`
|
|
253
|
+
<label>${TYPO3.lang['buttons.pageTsConfig']}</label>
|
|
254
|
+
<div class="t3js-grideditor-preview-config grideditor-preview">
|
|
255
|
+
<textarea class="t3js-tsconfig-preview-area form-control" rows="25" readonly ${ref(this.previewAreaRef)}></textarea>
|
|
256
|
+
</div>
|
|
257
|
+
`;
|
|
258
|
+
}
|
|
259
|
+
|
|
260
|
+
return html`
|
|
261
|
+
<typo3-t3editor-codemirror
|
|
262
|
+
class="t3js-grideditor-preview-config grideditor-preview"
|
|
263
|
+
label=${this.codeMirrorConfig.label}
|
|
264
|
+
panel=${this.codeMirrorConfig.panel}
|
|
265
|
+
mode=${this.codeMirrorConfig.mode}
|
|
266
|
+
nolazyload=true
|
|
267
|
+
readonly=true
|
|
268
|
+
${ref(this.codeMirrorRef)}>
|
|
269
|
+
<textarea class="t3js-tsconfig-preview-area form-control" ${ref(this.previewAreaRef)}></textarea>
|
|
270
|
+
</typo3-t3editor-codemirror>
|
|
271
|
+
`;
|
|
272
|
+
}
|
|
273
|
+
|
|
274
|
+
/**
|
|
275
|
+
*
|
|
276
|
+
* @param {Event} e
|
|
277
|
+
*/
|
|
278
|
+
protected modalButtonClickHandler = (e: Event) => {
|
|
279
|
+
const button = e.target as HTMLButtonElement;
|
|
280
|
+
const modal: ModalElement = e.currentTarget as ModalElement;
|
|
281
|
+
if (button.name === 'cancel') {
|
|
282
|
+
modal.hideModal();
|
|
283
|
+
} else if (button.name === 'ok') {
|
|
284
|
+
this.setName(
|
|
285
|
+
(modal.querySelector('.t3js-grideditor-field-name') as HTMLInputElement).value,
|
|
286
|
+
modal.userData.col,
|
|
287
|
+
modal.userData.row,
|
|
288
|
+
);
|
|
289
|
+
this.setColumn(
|
|
290
|
+
parseInt((modal.querySelector('.t3js-grideditor-field-colpos') as HTMLInputElement).value, 10),
|
|
291
|
+
modal.userData.col,
|
|
292
|
+
modal.userData.row,
|
|
293
|
+
);
|
|
294
|
+
this.setIdentifier(
|
|
295
|
+
(modal.querySelector('.t3js-grideditor-field-identifier') as HTMLInputElement).value,
|
|
296
|
+
modal.userData.col,
|
|
297
|
+
modal.userData.row,
|
|
298
|
+
);
|
|
299
|
+
this.setSlideMode(
|
|
300
|
+
(modal.querySelector('.t3js-grideditor-field-slide-mode') as HTMLSelectElement).value,
|
|
301
|
+
modal.userData.col,
|
|
302
|
+
modal.userData.row,
|
|
303
|
+
);
|
|
304
|
+
this.requestUpdate();
|
|
305
|
+
this.writeConfig(this.export2LayoutRecord());
|
|
306
|
+
modal.hideModal();
|
|
307
|
+
}
|
|
308
|
+
};
|
|
309
|
+
|
|
310
|
+
/**
|
|
311
|
+
*
|
|
312
|
+
* @param {Event} e
|
|
313
|
+
*/
|
|
314
|
+
protected addColumnHandler = (e: Event) => {
|
|
315
|
+
e.preventDefault();
|
|
316
|
+
this.addColumn();
|
|
317
|
+
this.requestUpdate();
|
|
318
|
+
this.writeConfig(this.export2LayoutRecord());
|
|
319
|
+
};
|
|
320
|
+
|
|
321
|
+
/**
|
|
322
|
+
*
|
|
323
|
+
* @param {Event} e
|
|
324
|
+
*/
|
|
325
|
+
protected removeColumnHandler = (e: Event) => {
|
|
326
|
+
e.preventDefault();
|
|
327
|
+
this.removeColumn();
|
|
328
|
+
this.requestUpdate();
|
|
329
|
+
this.writeConfig(this.export2LayoutRecord());
|
|
330
|
+
};
|
|
331
|
+
|
|
332
|
+
/**
|
|
333
|
+
*
|
|
334
|
+
* @param {Event} e
|
|
335
|
+
*/
|
|
336
|
+
protected addRowTopHandler = (e: Event) => {
|
|
337
|
+
e.preventDefault();
|
|
338
|
+
this.addRowTop();
|
|
339
|
+
this.requestUpdate();
|
|
340
|
+
this.writeConfig(this.export2LayoutRecord());
|
|
341
|
+
};
|
|
342
|
+
|
|
343
|
+
/**
|
|
344
|
+
*
|
|
345
|
+
* @param {Event} e
|
|
346
|
+
*/
|
|
347
|
+
protected addRowBottomHandler = (e: Event) => {
|
|
348
|
+
e.preventDefault();
|
|
349
|
+
this.addRowBottom();
|
|
350
|
+
this.requestUpdate();
|
|
351
|
+
this.writeConfig(this.export2LayoutRecord());
|
|
352
|
+
};
|
|
353
|
+
|
|
354
|
+
/**
|
|
355
|
+
*
|
|
356
|
+
* @param {Event} e
|
|
357
|
+
*/
|
|
358
|
+
protected removeRowTopHandler = (e: Event) => {
|
|
359
|
+
e.preventDefault();
|
|
360
|
+
this.removeRowTop();
|
|
361
|
+
this.requestUpdate();
|
|
362
|
+
this.writeConfig(this.export2LayoutRecord());
|
|
363
|
+
};
|
|
364
|
+
|
|
365
|
+
/**
|
|
366
|
+
*
|
|
367
|
+
* @param {Event} e
|
|
368
|
+
*/
|
|
369
|
+
protected removeRowBottomHandler = (e: Event) => {
|
|
370
|
+
e.preventDefault();
|
|
371
|
+
this.removeRowBottom();
|
|
372
|
+
this.requestUpdate();
|
|
373
|
+
this.writeConfig(this.export2LayoutRecord());
|
|
374
|
+
};
|
|
375
|
+
|
|
376
|
+
/**
|
|
377
|
+
*
|
|
378
|
+
* @param {Event} e
|
|
379
|
+
*/
|
|
380
|
+
protected linkEditorHandler = (e: Event) => {
|
|
381
|
+
e.preventDefault();
|
|
382
|
+
const element = e.currentTarget as HTMLElement;
|
|
383
|
+
this.showOptions(Number(element.dataset.col), Number(element.dataset.row));
|
|
384
|
+
};
|
|
385
|
+
|
|
386
|
+
/**
|
|
387
|
+
*
|
|
388
|
+
* @param {Event} e
|
|
389
|
+
*/
|
|
390
|
+
protected linkExpandRightHandler = (e: Event) => {
|
|
391
|
+
e.preventDefault();
|
|
392
|
+
const element = e.currentTarget as HTMLElement;
|
|
393
|
+
this.addColspan(Number(element.dataset.col), Number(element.dataset.row));
|
|
394
|
+
this.requestUpdate();
|
|
395
|
+
this.writeConfig(this.export2LayoutRecord());
|
|
396
|
+
};
|
|
397
|
+
|
|
398
|
+
/**
|
|
399
|
+
*
|
|
400
|
+
* @param {Event} e
|
|
401
|
+
*/
|
|
402
|
+
protected linkShrinkLeftHandler = (e: Event) => {
|
|
403
|
+
e.preventDefault();
|
|
404
|
+
const element = e.currentTarget as HTMLElement;
|
|
405
|
+
this.removeColspan(Number(element.dataset.col), Number(element.dataset.row));
|
|
406
|
+
this.requestUpdate();
|
|
407
|
+
this.writeConfig(this.export2LayoutRecord());
|
|
408
|
+
};
|
|
409
|
+
|
|
410
|
+
/**
|
|
411
|
+
*
|
|
412
|
+
* @param {Event} e
|
|
413
|
+
*/
|
|
414
|
+
protected linkExpandDownHandler = (e: Event) => {
|
|
415
|
+
e.preventDefault();
|
|
416
|
+
const element = e.currentTarget as HTMLElement;
|
|
417
|
+
this.addRowspan(Number(element.dataset.col), Number(element.dataset.row));
|
|
418
|
+
this.requestUpdate();
|
|
419
|
+
this.writeConfig(this.export2LayoutRecord());
|
|
420
|
+
};
|
|
421
|
+
|
|
422
|
+
/**
|
|
423
|
+
*
|
|
424
|
+
* @param {Event} e
|
|
425
|
+
*/
|
|
426
|
+
protected linkShrinkUpHandler = (e: Event) => {
|
|
427
|
+
e.preventDefault();
|
|
428
|
+
const element = e.currentTarget as HTMLElement;
|
|
429
|
+
this.removeRowspan(Number(element.dataset.col), Number(element.dataset.row));
|
|
430
|
+
this.requestUpdate();
|
|
431
|
+
this.writeConfig(this.export2LayoutRecord());
|
|
432
|
+
};
|
|
433
|
+
|
|
434
|
+
/**
|
|
435
|
+
* Create a new cell from defaultCell
|
|
436
|
+
* @returns {Object}
|
|
437
|
+
*/
|
|
438
|
+
protected getNewCell(): Cell {
|
|
439
|
+
return structuredClone(this.defaultCell);
|
|
440
|
+
}
|
|
441
|
+
|
|
442
|
+
/**
|
|
443
|
+
* write data back to hidden field
|
|
444
|
+
*
|
|
445
|
+
* @param data
|
|
446
|
+
*/
|
|
447
|
+
protected writeConfig(data: string): void {
|
|
448
|
+
this.field.value = data;
|
|
449
|
+
const configLines = data.split('\n');
|
|
450
|
+
let config = '';
|
|
451
|
+
for (const line of configLines) {
|
|
452
|
+
if (line) {
|
|
453
|
+
config += '\t\t\t' + line + '\n';
|
|
454
|
+
}
|
|
455
|
+
}
|
|
456
|
+
|
|
457
|
+
const content = 'mod.web_layout.BackendLayouts {\n' +
|
|
458
|
+
' exampleKey {\n' +
|
|
459
|
+
' title = Example\n' +
|
|
460
|
+
' icon = content-container-columns-2\n' +
|
|
461
|
+
' config {\n' +
|
|
462
|
+
config.replace(new RegExp('\\t', 'g'), ' ') +
|
|
463
|
+
' }\n' +
|
|
464
|
+
' }\n' +
|
|
465
|
+
'}\n';
|
|
466
|
+
|
|
467
|
+
const previewArea: HTMLTextAreaElement | undefined = this.previewAreaRef.value;
|
|
468
|
+
// Update previewArea value if instantiated
|
|
469
|
+
if (previewArea instanceof HTMLTextAreaElement) {
|
|
470
|
+
previewArea.value = content;
|
|
471
|
+
}
|
|
472
|
+
|
|
473
|
+
// Update CodeMirror content if instantiated
|
|
474
|
+
const codemirror: CodeMirrorElement | undefined = this.codeMirrorRef.value;
|
|
475
|
+
if (codemirror instanceof CodeMirrorElement) {
|
|
476
|
+
codemirror.setContent(content);
|
|
477
|
+
}
|
|
478
|
+
}
|
|
479
|
+
|
|
480
|
+
/**
|
|
481
|
+
* Add a new row at the top
|
|
482
|
+
*/
|
|
483
|
+
protected addRowTop(): void {
|
|
484
|
+
const newRow = [];
|
|
485
|
+
for (let i = 0; i < this.colCount; i++) {
|
|
486
|
+
const newCell = this.getNewCell();
|
|
487
|
+
newCell.name = i + 'x' + this.data.length;
|
|
488
|
+
newRow[i] = newCell;
|
|
489
|
+
}
|
|
490
|
+
this.data.unshift(newRow);
|
|
491
|
+
this.rowCount++;
|
|
492
|
+
}
|
|
493
|
+
|
|
494
|
+
/**
|
|
495
|
+
* Add a new row at the bottom
|
|
496
|
+
*/
|
|
497
|
+
protected addRowBottom(): void {
|
|
498
|
+
const newRow = [];
|
|
499
|
+
for (let i = 0; i < this.colCount; i++) {
|
|
500
|
+
const newCell = this.getNewCell();
|
|
501
|
+
newCell.name = i + 'x' + this.data.length;
|
|
502
|
+
newRow[i] = newCell;
|
|
503
|
+
}
|
|
504
|
+
this.data.push(newRow);
|
|
505
|
+
this.rowCount++;
|
|
506
|
+
}
|
|
507
|
+
|
|
508
|
+
/**
|
|
509
|
+
* Removes the first row of the grid and adjusts all cells that might be effected
|
|
510
|
+
* by that change. (Removing colspans)
|
|
511
|
+
*/
|
|
512
|
+
protected removeRowTop(): boolean {
|
|
513
|
+
if (this.rowCount <= 1) {
|
|
514
|
+
return false;
|
|
515
|
+
}
|
|
516
|
+
const newData = [];
|
|
517
|
+
for (let rowIndex = 1; rowIndex < this.rowCount; rowIndex++) {
|
|
518
|
+
newData.push(this.data[rowIndex]);
|
|
519
|
+
}
|
|
520
|
+
|
|
521
|
+
// fix rowspan in former last row
|
|
522
|
+
for (let colIndex = 0; colIndex < this.colCount; colIndex++) {
|
|
523
|
+
if (this.data[0][colIndex].spanned === 1) {
|
|
524
|
+
this.findUpperCellWidthRowspanAndDecreaseByOne(colIndex, 0);
|
|
525
|
+
}
|
|
526
|
+
}
|
|
527
|
+
|
|
528
|
+
this.data = newData;
|
|
529
|
+
this.rowCount--;
|
|
530
|
+
return true;
|
|
531
|
+
}
|
|
532
|
+
|
|
533
|
+
/**
|
|
534
|
+
* Removes the last row of the grid and adjusts all cells that might be effected
|
|
535
|
+
* by that change. (Removing colspans)
|
|
536
|
+
*/
|
|
537
|
+
protected removeRowBottom(): boolean {
|
|
538
|
+
if (this.rowCount <= 1) {
|
|
539
|
+
return false;
|
|
540
|
+
}
|
|
541
|
+
const newData = [];
|
|
542
|
+
for (let rowIndex = 0; rowIndex < this.rowCount - 1; rowIndex++) {
|
|
543
|
+
newData.push(this.data[rowIndex]);
|
|
544
|
+
}
|
|
545
|
+
|
|
546
|
+
// fix rowspan in former last row
|
|
547
|
+
for (let colIndex = 0; colIndex < this.colCount; colIndex++) {
|
|
548
|
+
if (this.data[this.rowCount - 1][colIndex].spanned === 1) {
|
|
549
|
+
this.findUpperCellWidthRowspanAndDecreaseByOne(colIndex, this.rowCount - 1);
|
|
550
|
+
}
|
|
551
|
+
}
|
|
552
|
+
|
|
553
|
+
this.data = newData;
|
|
554
|
+
this.rowCount--;
|
|
555
|
+
return true;
|
|
556
|
+
}
|
|
557
|
+
|
|
558
|
+
/**
|
|
559
|
+
* Takes a cell and looks above it if there are any cells that have colspans that
|
|
560
|
+
* spans into the given cell. This is used when a row was removed from the grid
|
|
561
|
+
* to make sure that no cell with wrong colspans exists in the grid.
|
|
562
|
+
*
|
|
563
|
+
* @param {number} col
|
|
564
|
+
* @param {number} row integer
|
|
565
|
+
*/
|
|
566
|
+
protected findUpperCellWidthRowspanAndDecreaseByOne(col: number, row: number): boolean {
|
|
567
|
+
const upperCell = this.getCell(col, row - 1);
|
|
568
|
+
if (!upperCell) {
|
|
569
|
+
return false;
|
|
570
|
+
}
|
|
571
|
+
|
|
572
|
+
if (upperCell.spanned === 1) {
|
|
573
|
+
this.findUpperCellWidthRowspanAndDecreaseByOne(col, row - 1);
|
|
574
|
+
} else {
|
|
575
|
+
if (upperCell.rowspan > 1) {
|
|
576
|
+
this.removeRowspan(col, row - 1);
|
|
577
|
+
}
|
|
578
|
+
}
|
|
579
|
+
return true;
|
|
580
|
+
}
|
|
581
|
+
|
|
582
|
+
/**
|
|
583
|
+
* Removes the outermost right column from the grid.
|
|
584
|
+
*/
|
|
585
|
+
protected removeColumn(): boolean {
|
|
586
|
+
if (this.colCount <= 1) {
|
|
587
|
+
return false;
|
|
588
|
+
}
|
|
589
|
+
const newData = [];
|
|
590
|
+
|
|
591
|
+
for (let rowIndex = 0; rowIndex < this.rowCount; rowIndex++) {
|
|
592
|
+
const newRow = [];
|
|
593
|
+
for (let colIndex = 0; colIndex < this.colCount - 1; colIndex++) {
|
|
594
|
+
newRow.push(this.data[rowIndex][colIndex]);
|
|
595
|
+
}
|
|
596
|
+
if (this.data[rowIndex][this.colCount - 1].spanned === 1) {
|
|
597
|
+
this.findLeftCellWidthColspanAndDecreaseByOne(this.colCount - 1, rowIndex);
|
|
598
|
+
}
|
|
599
|
+
newData.push(newRow);
|
|
600
|
+
}
|
|
601
|
+
|
|
602
|
+
this.data = newData;
|
|
603
|
+
this.colCount--;
|
|
604
|
+
return true;
|
|
605
|
+
}
|
|
606
|
+
|
|
607
|
+
/**
|
|
608
|
+
* Checks if there are any cells on the left side of a given cell with a
|
|
609
|
+
* rowspan that spans over the given cell.
|
|
610
|
+
*
|
|
611
|
+
* @param {number} col
|
|
612
|
+
* @param {number} row
|
|
613
|
+
*/
|
|
614
|
+
protected findLeftCellWidthColspanAndDecreaseByOne(col: number, row: number): boolean {
|
|
615
|
+
const leftCell = this.getCell(col - 1, row);
|
|
616
|
+
if (!leftCell) {
|
|
617
|
+
return false;
|
|
618
|
+
}
|
|
619
|
+
|
|
620
|
+
if (leftCell.spanned === 1) {
|
|
621
|
+
this.findLeftCellWidthColspanAndDecreaseByOne(col - 1, row);
|
|
622
|
+
} else {
|
|
623
|
+
if (leftCell.colspan > 1) {
|
|
624
|
+
this.removeColspan(col - 1, row);
|
|
625
|
+
}
|
|
626
|
+
}
|
|
627
|
+
return true;
|
|
628
|
+
}
|
|
629
|
+
|
|
630
|
+
/**
|
|
631
|
+
* Adds a column at the right side of the grid.
|
|
632
|
+
*/
|
|
633
|
+
protected addColumn(): void {
|
|
634
|
+
for (let rowIndex = 0; rowIndex < this.rowCount; rowIndex++) {
|
|
635
|
+
const newCell = this.getNewCell();
|
|
636
|
+
newCell.name = this.colCount + 'x' + rowIndex;
|
|
637
|
+
this.data[rowIndex].push(newCell);
|
|
638
|
+
}
|
|
639
|
+
this.colCount++;
|
|
640
|
+
}
|
|
641
|
+
|
|
642
|
+
/**
|
|
643
|
+
* Sets the name of a certain grid element.
|
|
644
|
+
*
|
|
645
|
+
* @param {String} newName
|
|
646
|
+
* @param {number} col
|
|
647
|
+
* @param {number} row
|
|
648
|
+
*
|
|
649
|
+
* @returns {Boolean}
|
|
650
|
+
*/
|
|
651
|
+
protected setName(newName: string, col: number, row: number): boolean {
|
|
652
|
+
const cell = this.getCell(col, row);
|
|
653
|
+
if (!cell) {
|
|
654
|
+
return false;
|
|
655
|
+
}
|
|
656
|
+
cell.name = GridEditor.stripMarkup(newName);
|
|
657
|
+
return true;
|
|
658
|
+
}
|
|
659
|
+
|
|
660
|
+
/**
|
|
661
|
+
* Sets the column field for a certain grid element. This is NOT the column of the
|
|
662
|
+
* element itself.
|
|
663
|
+
*
|
|
664
|
+
* @param {number} newColumn
|
|
665
|
+
* @param {number} col
|
|
666
|
+
* @param {number} row
|
|
667
|
+
*
|
|
668
|
+
* @returns {Boolean}
|
|
669
|
+
*/
|
|
670
|
+
protected setColumn(newColumn: number, col: number, row: number): boolean {
|
|
671
|
+
const cell = this.getCell(col, row);
|
|
672
|
+
if (!cell) {
|
|
673
|
+
return false;
|
|
674
|
+
}
|
|
675
|
+
cell.column = parseInt(newColumn.toString(), 10);
|
|
676
|
+
return true;
|
|
677
|
+
}
|
|
678
|
+
|
|
679
|
+
protected setIdentifier(newIdentifier: string, col: number, row: number): boolean {
|
|
680
|
+
const cell = this.getCell(col, row);
|
|
681
|
+
if (!cell) {
|
|
682
|
+
return false;
|
|
683
|
+
}
|
|
684
|
+
cell.identifier = GridEditor.stripMarkup(newIdentifier);
|
|
685
|
+
return true;
|
|
686
|
+
}
|
|
687
|
+
|
|
688
|
+
protected setSlideMode(newSlideMode: string, col: number, row: number): boolean {
|
|
689
|
+
const cell = this.getCell(col, row);
|
|
690
|
+
if (!cell) {
|
|
691
|
+
return false;
|
|
692
|
+
}
|
|
693
|
+
cell.slideMode = SlideModes[newSlideMode as keyof typeof SlideModes];
|
|
694
|
+
return true;
|
|
695
|
+
}
|
|
696
|
+
|
|
697
|
+
/**
|
|
698
|
+
* Creates an Modal with two input fields and shows it. On save, the data
|
|
699
|
+
* is written into the grid element.
|
|
700
|
+
*
|
|
701
|
+
* @param {number} col
|
|
702
|
+
* @param {number} row
|
|
703
|
+
*
|
|
704
|
+
* @returns {Boolean}
|
|
705
|
+
*/
|
|
706
|
+
protected showOptions(col: number, row: number): boolean {
|
|
707
|
+
const cell = this.getCell(col, row);
|
|
708
|
+
if (!cell) {
|
|
709
|
+
return false;
|
|
710
|
+
}
|
|
711
|
+
let colPos;
|
|
712
|
+
if (cell.column === 0) {
|
|
713
|
+
colPos = 0;
|
|
714
|
+
} else if (cell.column) {
|
|
715
|
+
colPos = parseInt(cell.column.toString(), 10);
|
|
716
|
+
} else {
|
|
717
|
+
colPos = '';
|
|
718
|
+
}
|
|
719
|
+
|
|
720
|
+
const markup = document.createElement('div');
|
|
721
|
+
const formGroup = document.createElement('div');
|
|
722
|
+
formGroup.classList.add('form-group');
|
|
723
|
+
const label = document.createElement('label');
|
|
724
|
+
label.classList.add('form-label');
|
|
725
|
+
const input = document.createElement('input');
|
|
726
|
+
input.classList.add('form-control');
|
|
727
|
+
|
|
728
|
+
const nameFormGroup = formGroup.cloneNode(true) as HTMLElement;
|
|
729
|
+
const nameLabel = label.cloneNode(true) as HTMLLabelElement;
|
|
730
|
+
nameLabel.innerText = TYPO3.lang.grid_nameHelp;
|
|
731
|
+
nameLabel.htmlFor = 'grideditor-field-name';
|
|
732
|
+
const nameInput = input.cloneNode(true) as HTMLInputElement;
|
|
733
|
+
nameInput.id = 'grideditor-field-name';
|
|
734
|
+
nameInput.type = 'text';
|
|
735
|
+
nameInput.classList.add('t3js-grideditor-field-name');
|
|
736
|
+
nameInput.name = 'name';
|
|
737
|
+
nameInput.value = GridEditor.stripMarkup(cell.name) || '';
|
|
738
|
+
|
|
739
|
+
nameFormGroup.append(nameLabel, nameInput);
|
|
740
|
+
|
|
741
|
+
const columnFormGroup = formGroup.cloneNode(true) as HTMLElement;
|
|
742
|
+
const columnLabel = label.cloneNode(true) as HTMLLabelElement;
|
|
743
|
+
columnLabel.innerText = TYPO3.lang.grid_columnHelp;
|
|
744
|
+
columnLabel.htmlFor = 'grideditor-field-colpos';
|
|
745
|
+
const columnInput = input.cloneNode(true) as HTMLInputElement;
|
|
746
|
+
columnInput.type = 'text';
|
|
747
|
+
columnInput.classList.add('t3js-grideditor-field-colpos');
|
|
748
|
+
columnInput.id = 'grideditor-field-colpos';
|
|
749
|
+
columnInput.name = 'column';
|
|
750
|
+
columnInput.value = colPos.toString();
|
|
751
|
+
|
|
752
|
+
columnFormGroup.append(columnLabel, columnInput);
|
|
753
|
+
|
|
754
|
+
const identifierFormGroup = formGroup.cloneNode(true) as HTMLElement;
|
|
755
|
+
const identifierLabel = label.cloneNode(true) as HTMLLabelElement;
|
|
756
|
+
identifierLabel.innerText = TYPO3.lang.grid_identifierHelp;
|
|
757
|
+
identifierLabel.htmlFor = 'grideditor-field-identifier';
|
|
758
|
+
const identifierInput = input.cloneNode(true) as HTMLInputElement;
|
|
759
|
+
nameInput.type = 'text';
|
|
760
|
+
identifierInput.classList.add('t3js-grideditor-field-identifier');
|
|
761
|
+
identifierInput.id = 'grideditor-field-identifier';
|
|
762
|
+
identifierInput.name = 'identifier';
|
|
763
|
+
identifierInput.value = typeof(cell.identifier) === 'string' ? GridEditor.stripMarkup(cell.identifier) : '';
|
|
764
|
+
|
|
765
|
+
identifierFormGroup.append(identifierLabel, identifierInput);
|
|
766
|
+
|
|
767
|
+
const slideModeFormGroup = formGroup.cloneNode(true) as HTMLElement;
|
|
768
|
+
const slideModeLabel = label.cloneNode(true) as HTMLLabelElement;
|
|
769
|
+
slideModeLabel.innerText = TYPO3.lang.grid_slideModeHelp;
|
|
770
|
+
slideModeLabel.htmlFor = 'grideditor-field-slide-mode';
|
|
771
|
+
const slideModeSelect = document.createElement('select');
|
|
772
|
+
slideModeSelect.classList.add('form-select', 't3js-grideditor-field-slide-mode');
|
|
773
|
+
slideModeSelect.id = 'grideditor-field-slide-mode';
|
|
774
|
+
slideModeSelect.name = 'slideMode';
|
|
775
|
+
slideModeSelect.value = GridEditor.stripMarkup(cell.slideMode?.toString()) || '';
|
|
776
|
+
|
|
777
|
+
(Object.keys(SlideModes) as Array<keyof typeof SlideModes>).map((key) => {
|
|
778
|
+
const text = key !== 'none' ? key : '';
|
|
779
|
+
const value = SlideModes[key as keyof typeof SlideModes];
|
|
780
|
+
const option = document.createElement('option');
|
|
781
|
+
option.value = value;
|
|
782
|
+
option.text = text;
|
|
783
|
+
option.selected = value === cell.slideMode?.toString();
|
|
784
|
+
slideModeSelect.appendChild(option);
|
|
785
|
+
});
|
|
786
|
+
|
|
787
|
+
slideModeFormGroup.append(slideModeLabel, slideModeSelect);
|
|
788
|
+
|
|
789
|
+
markup.append(nameFormGroup, columnFormGroup, identifierFormGroup, slideModeFormGroup);
|
|
790
|
+
|
|
791
|
+
const modal = Modal.show(TYPO3.lang.grid_windowTitle, markup, SeverityEnum.notice, [
|
|
792
|
+
{
|
|
793
|
+
active: true,
|
|
794
|
+
btnClass: 'btn-default',
|
|
795
|
+
name: 'cancel',
|
|
796
|
+
text: TYPO3.lang['button.cancel'] || 'Cancel',
|
|
797
|
+
},
|
|
798
|
+
{
|
|
799
|
+
btnClass: 'btn-primary',
|
|
800
|
+
name: 'ok',
|
|
801
|
+
text: TYPO3.lang['button.ok'] || 'OK',
|
|
802
|
+
},
|
|
803
|
+
]);
|
|
804
|
+
modal.userData.col = col;
|
|
805
|
+
modal.userData.row = row;
|
|
806
|
+
modal.addEventListener('button.clicked', this.modalButtonClickHandler);
|
|
807
|
+
return true;
|
|
808
|
+
}
|
|
809
|
+
|
|
810
|
+
/**
|
|
811
|
+
* Returns a cell element from the grid.
|
|
812
|
+
*
|
|
813
|
+
* @param {number} col
|
|
814
|
+
* @param {number} row
|
|
815
|
+
*/
|
|
816
|
+
protected getCell(col: number, row: number): Cell|false|null {
|
|
817
|
+
if (col > this.colCount - 1) {
|
|
818
|
+
return false;
|
|
819
|
+
}
|
|
820
|
+
if (row > this.rowCount - 1) {
|
|
821
|
+
return false;
|
|
822
|
+
}
|
|
823
|
+
if (this.data.length > row - 1 && this.data[row].length > col - 1) {
|
|
824
|
+
return this.data[row][col];
|
|
825
|
+
}
|
|
826
|
+
return null;
|
|
827
|
+
}
|
|
828
|
+
|
|
829
|
+
/**
|
|
830
|
+
* Checks whether a cell can span to the right or not. A cell can span to the right
|
|
831
|
+
* if it is not in the last column and if there is no cell beside it that is
|
|
832
|
+
* already overspanned by some other cell.
|
|
833
|
+
*
|
|
834
|
+
* @param {number} col
|
|
835
|
+
* @param {number} row
|
|
836
|
+
* @returns {Boolean}
|
|
837
|
+
*/
|
|
838
|
+
protected cellCanSpanRight(col: number, row: number): boolean {
|
|
839
|
+
if (col === this.colCount - 1) {
|
|
840
|
+
return false;
|
|
841
|
+
}
|
|
842
|
+
|
|
843
|
+
const cell = this.getCell(col, row);
|
|
844
|
+
if (!cell) {
|
|
845
|
+
return false;
|
|
846
|
+
}
|
|
847
|
+
|
|
848
|
+
let checkCell;
|
|
849
|
+
if (cell.rowspan > 1) {
|
|
850
|
+
for (let rowIndex = row; rowIndex < row + cell.rowspan; rowIndex++) {
|
|
851
|
+
checkCell = this.getCell(col + cell.colspan, rowIndex);
|
|
852
|
+
if (!checkCell || checkCell.spanned === 1 || checkCell.colspan > 1 || checkCell.rowspan > 1) {
|
|
853
|
+
return false;
|
|
854
|
+
}
|
|
855
|
+
}
|
|
856
|
+
} else {
|
|
857
|
+
checkCell = this.getCell(col + cell.colspan, row);
|
|
858
|
+
if (!checkCell || cell.spanned === 1 || checkCell.spanned === 1 || checkCell.colspan > 1
|
|
859
|
+
|| checkCell.rowspan > 1) {
|
|
860
|
+
return false;
|
|
861
|
+
}
|
|
862
|
+
}
|
|
863
|
+
|
|
864
|
+
return true;
|
|
865
|
+
}
|
|
866
|
+
|
|
867
|
+
/**
|
|
868
|
+
* Checks whether a cell can span down or not.
|
|
869
|
+
*
|
|
870
|
+
* @param {number} col
|
|
871
|
+
* @param {number} row
|
|
872
|
+
* @returns {Boolean}
|
|
873
|
+
*/
|
|
874
|
+
protected cellCanSpanDown(col: number, row: number): boolean {
|
|
875
|
+
if (row === this.rowCount - 1) {
|
|
876
|
+
return false;
|
|
877
|
+
}
|
|
878
|
+
|
|
879
|
+
const cell = this.getCell(col, row);
|
|
880
|
+
if (!cell) {
|
|
881
|
+
return false;
|
|
882
|
+
}
|
|
883
|
+
|
|
884
|
+
let checkCell;
|
|
885
|
+
if (cell.colspan > 1) {
|
|
886
|
+
// we have to check all cells on the right side for the complete colspan
|
|
887
|
+
for (let colIndex = col; colIndex < col + cell.colspan; colIndex++) {
|
|
888
|
+
checkCell = this.getCell(colIndex, row + cell.rowspan);
|
|
889
|
+
if (!checkCell || checkCell.spanned === 1 || checkCell.colspan > 1 || checkCell.rowspan > 1) {
|
|
890
|
+
return false;
|
|
891
|
+
}
|
|
892
|
+
}
|
|
893
|
+
} else {
|
|
894
|
+
checkCell = this.getCell(col, row + cell.rowspan);
|
|
895
|
+
if (!checkCell || cell.spanned === 1 || checkCell.spanned === 1 || checkCell.colspan > 1
|
|
896
|
+
|| checkCell.rowspan > 1) {
|
|
897
|
+
return false;
|
|
898
|
+
}
|
|
899
|
+
}
|
|
900
|
+
|
|
901
|
+
return true;
|
|
902
|
+
}
|
|
903
|
+
|
|
904
|
+
/**
|
|
905
|
+
* Checks if a cell can shrink to the left. It can shrink if the colspan of the
|
|
906
|
+
* cell is bigger than 1.
|
|
907
|
+
*
|
|
908
|
+
* @param {number} col
|
|
909
|
+
* @param {number} row
|
|
910
|
+
* @returns {Boolean}
|
|
911
|
+
*/
|
|
912
|
+
protected cellCanShrinkLeft(col: number, row: number): boolean {
|
|
913
|
+
return (this.data[row][col].colspan > 1);
|
|
914
|
+
}
|
|
915
|
+
|
|
916
|
+
/**
|
|
917
|
+
* Returns if a cell can shrink up. This is the case if a cell has at least
|
|
918
|
+
* a rowspan of 2.
|
|
919
|
+
*
|
|
920
|
+
* @param {number} col
|
|
921
|
+
* @param {number} row
|
|
922
|
+
* @returns {Boolean}
|
|
923
|
+
*/
|
|
924
|
+
protected cellCanShrinkUp(col: number, row: number): boolean {
|
|
925
|
+
return (this.data[row][col].rowspan > 1);
|
|
926
|
+
}
|
|
927
|
+
|
|
928
|
+
/**
|
|
929
|
+
* Adds a colspan to a grid element.
|
|
930
|
+
*
|
|
931
|
+
* @param {number} col
|
|
932
|
+
* @param {number} row
|
|
933
|
+
* @returns {Boolean}
|
|
934
|
+
*/
|
|
935
|
+
protected addColspan(col: number, row: number): boolean {
|
|
936
|
+
const cell = this.getCell(col, row);
|
|
937
|
+
if (!cell || !this.cellCanSpanRight(col, row)) {
|
|
938
|
+
return false;
|
|
939
|
+
}
|
|
940
|
+
|
|
941
|
+
for (let rowIndex = row; rowIndex < row + cell.rowspan; rowIndex++) {
|
|
942
|
+
this.data[rowIndex][col + cell.colspan].spanned = 1;
|
|
943
|
+
}
|
|
944
|
+
cell.colspan += 1;
|
|
945
|
+
return true;
|
|
946
|
+
}
|
|
947
|
+
|
|
948
|
+
/**
|
|
949
|
+
* Adds a rowspan to grid element.
|
|
950
|
+
*
|
|
951
|
+
* @param {number} col
|
|
952
|
+
* @param {number} row
|
|
953
|
+
* @returns {Boolean}
|
|
954
|
+
*/
|
|
955
|
+
protected addRowspan(col: number, row: number): boolean {
|
|
956
|
+
const cell = this.getCell(col, row);
|
|
957
|
+
if (!cell || !this.cellCanSpanDown(col, row)) {
|
|
958
|
+
return false;
|
|
959
|
+
}
|
|
960
|
+
|
|
961
|
+
for (let colIndex = col; colIndex < col + cell.colspan; colIndex++) {
|
|
962
|
+
this.data[row + cell.rowspan][colIndex].spanned = 1;
|
|
963
|
+
}
|
|
964
|
+
cell.rowspan += 1;
|
|
965
|
+
return true;
|
|
966
|
+
}
|
|
967
|
+
|
|
968
|
+
/**
|
|
969
|
+
* Removes a colspan from a grid element.
|
|
970
|
+
*
|
|
971
|
+
* @param {number} col
|
|
972
|
+
* @param {number} row
|
|
973
|
+
* @returns {Boolean}
|
|
974
|
+
*/
|
|
975
|
+
protected removeColspan(col: number, row: number): boolean {
|
|
976
|
+
const cell = this.getCell(col, row);
|
|
977
|
+
if (!cell || !this.cellCanShrinkLeft(col, row)) {
|
|
978
|
+
return false;
|
|
979
|
+
}
|
|
980
|
+
|
|
981
|
+
cell.colspan -= 1;
|
|
982
|
+
|
|
983
|
+
for (let rowIndex = row; rowIndex < row + cell.rowspan; rowIndex++) {
|
|
984
|
+
this.data[rowIndex][col + cell.colspan].spanned = 0;
|
|
985
|
+
}
|
|
986
|
+
return true;
|
|
987
|
+
}
|
|
988
|
+
|
|
989
|
+
/**
|
|
990
|
+
* Removes a rowspan from a grid element.
|
|
991
|
+
*
|
|
992
|
+
* @param {number} col
|
|
993
|
+
* @param {number} row
|
|
994
|
+
* @returns {Boolean}
|
|
995
|
+
*/
|
|
996
|
+
protected removeRowspan(col: number, row: number): boolean {
|
|
997
|
+
const cell = this.getCell(col, row);
|
|
998
|
+
if (!cell || !this.cellCanShrinkUp(col, row)) {
|
|
999
|
+
return false;
|
|
1000
|
+
}
|
|
1001
|
+
|
|
1002
|
+
cell.rowspan -= 1;
|
|
1003
|
+
for (let colIndex = col; colIndex < col + cell.colspan; colIndex++) {
|
|
1004
|
+
this.data[row + cell.rowspan][colIndex].spanned = 0;
|
|
1005
|
+
}
|
|
1006
|
+
return true;
|
|
1007
|
+
}
|
|
1008
|
+
|
|
1009
|
+
/**
|
|
1010
|
+
* Exports the current grid to a TypoScript notation that can be read by the
|
|
1011
|
+
* page module and is human readable.
|
|
1012
|
+
*
|
|
1013
|
+
* @returns {String}
|
|
1014
|
+
*/
|
|
1015
|
+
protected export2LayoutRecord(): string {
|
|
1016
|
+
let result = 'backend_layout {\n\tcolCount = ' + this.colCount + '\n\trowCount = ' + this.rowCount + '\n\trows {\n';
|
|
1017
|
+
for (let row = 0; row < this.rowCount; row++) {
|
|
1018
|
+
result += '\t\t' + (row + 1) + ' {\n';
|
|
1019
|
+
result += '\t\t\tcolumns {\n';
|
|
1020
|
+
let colIndex = 0;
|
|
1021
|
+
for (let col = 0; col < this.colCount; col++) {
|
|
1022
|
+
const cell = this.getCell(col, row);
|
|
1023
|
+
if (cell) {
|
|
1024
|
+
if (!cell.spanned) {
|
|
1025
|
+
const cellName: string = GridEditor.stripMarkup(cell.name) || '';
|
|
1026
|
+
colIndex++;
|
|
1027
|
+
result += '\t\t\t\t' + (colIndex) + ' {\n';
|
|
1028
|
+
result += '\t\t\t\t\tname = ' + ((!cellName) ? col + 'x' + row : cellName) + '\n';
|
|
1029
|
+
if (cell.colspan > 1) {
|
|
1030
|
+
result += '\t\t\t\t\tcolspan = ' + cell.colspan + '\n';
|
|
1031
|
+
}
|
|
1032
|
+
if (cell.rowspan > 1) {
|
|
1033
|
+
result += '\t\t\t\t\trowspan = ' + cell.rowspan + '\n';
|
|
1034
|
+
}
|
|
1035
|
+
if (typeof(cell.column) === 'number') {
|
|
1036
|
+
result += '\t\t\t\t\tcolPos = ' + cell.column + '\n';
|
|
1037
|
+
}
|
|
1038
|
+
if (typeof(cell.identifier) === 'string' && cell.identifier.length) {
|
|
1039
|
+
result += '\t\t\t\t\tidentifier = ' + cell.identifier + '\n';
|
|
1040
|
+
}
|
|
1041
|
+
if (cell.slideMode !== undefined && cell.slideMode !== SlideModes.none) {
|
|
1042
|
+
result += '\t\t\t\t\tslideMode = ' + cell.slideMode.toString() + '\n';
|
|
1043
|
+
}
|
|
1044
|
+
result += '\t\t\t\t}\n';
|
|
1045
|
+
}
|
|
1046
|
+
}
|
|
1047
|
+
|
|
1048
|
+
}
|
|
1049
|
+
result += '\t\t\t}\n';
|
|
1050
|
+
result += '\t\t}\n';
|
|
1051
|
+
}
|
|
1052
|
+
|
|
1053
|
+
result += '\t}\n}\n';
|
|
1054
|
+
return result;
|
|
1055
|
+
}
|
|
1056
|
+
|
|
1057
|
+
/**
|
|
1058
|
+
* Observe the editors' visibility, since codeMirror needs to be refreshed as soon as it becomes
|
|
1059
|
+
* visible in the viewport. Otherwise, if this element is not in the first visible FormEngine tab,
|
|
1060
|
+
* it will not display any value, unless the grid gets manually updated.
|
|
1061
|
+
*/
|
|
1062
|
+
protected addVisibilityObserver(gridEditor: HTMLElement) {
|
|
1063
|
+
if (gridEditor.offsetParent !== null) {
|
|
1064
|
+
// In case the editor is already visible, we don't have to add the observer
|
|
1065
|
+
return;
|
|
1066
|
+
}
|
|
1067
|
+
new IntersectionObserver((entries: IntersectionObserverEntry[]) => {
|
|
1068
|
+
entries.forEach(entry => {
|
|
1069
|
+
const codemirror: CodeMirrorElement | undefined = this.codeMirrorRef.value;
|
|
1070
|
+
// Update CodeMirror if instantiated
|
|
1071
|
+
if (entry.intersectionRatio > 0 && codemirror instanceof CodeMirrorElement) {
|
|
1072
|
+
codemirror.requestUpdate();
|
|
1073
|
+
}
|
|
1074
|
+
});
|
|
1075
|
+
}).observe(gridEditor);
|
|
1076
|
+
}
|
|
1077
|
+
}
|