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.
Files changed (415) hide show
  1. package/.github/workflows/sync-and-publish.yml +265 -0
  2. package/.last-synced-tag +1 -0
  3. package/LICENSE.txt +339 -0
  4. package/README-TYPO3.md +166 -0
  5. package/README.md +28 -0
  6. package/adminpanel/admin-panel.ts +375 -0
  7. package/adminpanel/modules/cache.ts +27 -0
  8. package/adminpanel/modules/preview.ts +75 -0
  9. package/backend/action-button/abstract-action.ts +22 -0
  10. package/backend/action-button/deferred-action.ts +41 -0
  11. package/backend/action-button/immediate-action.ts +31 -0
  12. package/backend/action-dispatcher.ts +104 -0
  13. package/backend/ajax-data-handler/message-interface.ts +18 -0
  14. package/backend/ajax-data-handler/response-interface.ts +20 -0
  15. package/backend/ajax-data-handler.ts +214 -0
  16. package/backend/backend-exception.ts +22 -0
  17. package/backend/broadcast-message.ts +50 -0
  18. package/backend/broadcast-service.ts +52 -0
  19. package/backend/browse-database.ts +38 -0
  20. package/backend/clear-cache.ts +88 -0
  21. package/backend/clipboard-panel.ts +240 -0
  22. package/backend/close-current-window.ts +2 -0
  23. package/backend/code-editor/autocomplete/completion-result.ts +105 -0
  24. package/backend/code-editor/autocomplete/ts-code-completion.ts +142 -0
  25. package/backend/code-editor/autocomplete/ts-parser.ts +485 -0
  26. package/backend/code-editor/autocomplete/ts-ref.ts +164 -0
  27. package/backend/code-editor/element/code-mirror-element.ts +282 -0
  28. package/backend/code-editor/language/typoscript.ts +181 -0
  29. package/backend/code-editor/stream-parser/typoscript.ts +1600 -0
  30. package/backend/color-picker.ts +158 -0
  31. package/backend/color-scheme-switch.ts +179 -0
  32. package/backend/column-selector-button.ts +302 -0
  33. package/backend/context-help.ts +68 -0
  34. package/backend/context-menu-actions.ts +322 -0
  35. package/backend/context-menu.ts +751 -0
  36. package/backend/copy-to-clipboard.ts +79 -0
  37. package/backend/date-time-picker.ts +270 -0
  38. package/backend/document-save-actions.ts +159 -0
  39. package/backend/drag-tooltip.ts +285 -0
  40. package/backend/drag-uploader.ts +914 -0
  41. package/backend/element/alert-element.ts +116 -0
  42. package/backend/element/dispatch-modal-button.ts +50 -0
  43. package/backend/element/draggable-resizable-element.ts +249 -0
  44. package/backend/element/editable-page-title.ts +306 -0
  45. package/backend/element/icon-element.ts +84 -0
  46. package/backend/element/immediate-action-element.ts +89 -0
  47. package/backend/element/pagination.ts +59 -0
  48. package/backend/element/progress-bar-element.ts +172 -0
  49. package/backend/element/progress-tracker-element.ts +119 -0
  50. package/backend/element/pseudo-button.ts +58 -0
  51. package/backend/element/spinner-element.ts +51 -0
  52. package/backend/element/thumbnail-element.ts +80 -0
  53. package/backend/element-browser.ts +182 -0
  54. package/backend/enum/data-transfer-types.ts +21 -0
  55. package/backend/enum/icon-types.ts +31 -0
  56. package/backend/enum/key-types.ts +27 -0
  57. package/backend/enum/severity.ts +20 -0
  58. package/backend/enum/viewport/scaffold-identifier.ts +24 -0
  59. package/backend/event/client-request.ts +25 -0
  60. package/backend/event/consumable.ts +18 -0
  61. package/backend/event/consumer-scope.ts +54 -0
  62. package/backend/event/event-dispatcher.ts +26 -0
  63. package/backend/event/interaction-request-assignment.ts +24 -0
  64. package/backend/event/interaction-request-map.ts +75 -0
  65. package/backend/event/interaction-request.ts +48 -0
  66. package/backend/event/trigger-request.ts +56 -0
  67. package/backend/form/submit-interceptor.ts +66 -0
  68. package/backend/form-engine/container/files-control-container.ts +716 -0
  69. package/backend/form-engine/container/flex-form-container-container.ts +166 -0
  70. package/backend/form-engine/container/flex-form-section-container.ts +210 -0
  71. package/backend/form-engine/container/inline-control-container.ts +1230 -0
  72. package/backend/form-engine/container/site-language-container.ts +616 -0
  73. package/backend/form-engine/element/abstract-sortable-select-items.ts +186 -0
  74. package/backend/form-engine/element/category-element.ts +160 -0
  75. package/backend/form-engine/element/color-element.ts +81 -0
  76. package/backend/form-engine/element/datetime-element.ts +66 -0
  77. package/backend/form-engine/element/extra/char-counter.ts +112 -0
  78. package/backend/form-engine/element/extra/select-box-filter.ts +85 -0
  79. package/backend/form-engine/element/folder-element.ts +66 -0
  80. package/backend/form-engine/element/group-element.ts +47 -0
  81. package/backend/form-engine/element/json-element.ts +52 -0
  82. package/backend/form-engine/element/link-element.ts +121 -0
  83. package/backend/form-engine/element/mfa-info-element.ts +169 -0
  84. package/backend/form-engine/element/modifier/resizable.ts +27 -0
  85. package/backend/form-engine/element/modifier/tabbable.ts +29 -0
  86. package/backend/form-engine/element/online-media-form-element.ts +65 -0
  87. package/backend/form-engine/element/password-element.ts +71 -0
  88. package/backend/form-engine/element/select-multiple-side-by-side-element.ts +83 -0
  89. package/backend/form-engine/element/select-single-element.ts +82 -0
  90. package/backend/form-engine/element/select-tree-element.ts +148 -0
  91. package/backend/form-engine/element/select-tree-toolbar.ts +118 -0
  92. package/backend/form-engine/element/select-tree.ts +210 -0
  93. package/backend/form-engine/element/slug-element.ts +243 -0
  94. package/backend/form-engine/element/suggest/result-container.ts +118 -0
  95. package/backend/form-engine/element/suggest/result-item.ts +90 -0
  96. package/backend/form-engine/element/table-permission-element.ts +101 -0
  97. package/backend/form-engine/element/table-wizard-element.ts +427 -0
  98. package/backend/form-engine/element/text-element.ts +52 -0
  99. package/backend/form-engine/element/text-table-element.ts +31 -0
  100. package/backend/form-engine/field-control/add-record.ts +40 -0
  101. package/backend/form-engine/field-control/edit-popup.ts +64 -0
  102. package/backend/form-engine/field-control/insert-clipboard.ts +50 -0
  103. package/backend/form-engine/field-control/link-popup.ts +53 -0
  104. package/backend/form-engine/field-control/list-module.ts +40 -0
  105. package/backend/form-engine/field-control/password-generator.ts +102 -0
  106. package/backend/form-engine/field-control/reset-selection.ts +48 -0
  107. package/backend/form-engine/field-wizard/localization-state-selector.ts +67 -0
  108. package/backend/form-engine/field-wizard/value-picker.ts +123 -0
  109. package/backend/form-engine/field-wizard/value-slider.ts +86 -0
  110. package/backend/form-engine/inline-relation/ajax-dispatcher.ts +124 -0
  111. package/backend/form-engine/inline-relation/inline-response-interface.ts +41 -0
  112. package/backend/form-engine-link-browser-adapter.ts +129 -0
  113. package/backend/form-engine-review.ts +155 -0
  114. package/backend/form-engine-suggest.ts +133 -0
  115. package/backend/form-engine-validation.ts +686 -0
  116. package/backend/form-engine.ts +1391 -0
  117. package/backend/global-event-handler.ts +252 -0
  118. package/backend/grid-editor.ts +1077 -0
  119. package/backend/hashing/md5.ts +252 -0
  120. package/backend/helper.ts +24 -0
  121. package/backend/hotkeys/hotkey-storage.ts +63 -0
  122. package/backend/hotkeys.ts +216 -0
  123. package/backend/icons.ts +236 -0
  124. package/backend/image-manipulation.ts +885 -0
  125. package/backend/info-window.ts +46 -0
  126. package/backend/input/clearable.ts +128 -0
  127. package/backend/input/index.d.ts +8 -0
  128. package/backend/java-script-module-import-event-handler.ts +19 -0
  129. package/backend/key-bindings.ts +42 -0
  130. package/backend/layout-module/drag-drop.ts +359 -0
  131. package/backend/layout-module/paste.ts +165 -0
  132. package/backend/link-browser.ts +89 -0
  133. package/backend/live-search/element/backend-search.ts +34 -0
  134. package/backend/live-search/element/hint.ts +33 -0
  135. package/backend/live-search/element/provider/default-result-item.ts +52 -0
  136. package/backend/live-search/element/provider/page-provider-result-item.ts +52 -0
  137. package/backend/live-search/element/result/item/action/action-container.ts +135 -0
  138. package/backend/live-search/element/result/item/action/action.ts +56 -0
  139. package/backend/live-search/element/result/item/item-container.ts +224 -0
  140. package/backend/live-search/element/result/item/item.ts +74 -0
  141. package/backend/live-search/element/result/result-container.ts +110 -0
  142. package/backend/live-search/element/result/result-detail-container.ts +50 -0
  143. package/backend/live-search/element/result/result-pagination.ts +122 -0
  144. package/backend/live-search/element/search-option-item.ts +70 -0
  145. package/backend/live-search/live-search-configurator.ts +54 -0
  146. package/backend/live-search/live-search-shortcut.ts +29 -0
  147. package/backend/live-search/result-types/backend-module-result-type.ts +8 -0
  148. package/backend/live-search/result-types/default-result-type.ts +21 -0
  149. package/backend/live-search/result-types/page-result-type.ts +23 -0
  150. package/backend/localization.ts +390 -0
  151. package/backend/login-refresh.ts +525 -0
  152. package/backend/login.ts +179 -0
  153. package/backend/mail-link-handler.ts +45 -0
  154. package/backend/modal-interface.ts +19 -0
  155. package/backend/modal.ts +685 -0
  156. package/backend/module/iframe.ts +125 -0
  157. package/backend/module/router.ts +275 -0
  158. package/backend/module-menu.ts +550 -0
  159. package/backend/module.ts +133 -0
  160. package/backend/multi-record-selection-action.ts +44 -0
  161. package/backend/multi-record-selection-delete-action.ts +108 -0
  162. package/backend/multi-record-selection-edit-action.ts +56 -0
  163. package/backend/multi-record-selection.ts +468 -0
  164. package/backend/multi-step-wizard.ts +568 -0
  165. package/backend/new-content-element-wizard-button.ts +51 -0
  166. package/backend/new-multiple-pages.ts +108 -0
  167. package/backend/new-record-wizard.ts +680 -0
  168. package/backend/notification.ts +366 -0
  169. package/backend/offset.ts +40 -0
  170. package/backend/online-media.ts +110 -0
  171. package/backend/page-actions.ts +91 -0
  172. package/backend/page-link-handler.ts +51 -0
  173. package/backend/pagetsconfig/pagetsconfig-includes.ts +77 -0
  174. package/backend/popover.ts +165 -0
  175. package/backend/record-download-button.ts +104 -0
  176. package/backend/record-link-handler.ts +31 -0
  177. package/backend/record-search.ts +44 -0
  178. package/backend/recordlist.ts +230 -0
  179. package/backend/resource/resource.ts +35 -0
  180. package/backend/security/element/csp-reports.ts +406 -0
  181. package/backend/security/element/sudo-mode.ts +249 -0
  182. package/backend/security/sudo-mode-interceptor.ts +19 -0
  183. package/backend/settings/editor/editable-setting.ts +231 -0
  184. package/backend/settings/editor.ts +451 -0
  185. package/backend/settings/enum/settings-mode.enum.ts +24 -0
  186. package/backend/settings/type/base.ts +200 -0
  187. package/backend/settings/type/bool.ts +56 -0
  188. package/backend/settings/type/color.ts +64 -0
  189. package/backend/settings/type/int.ts +85 -0
  190. package/backend/settings/type/number.ts +61 -0
  191. package/backend/settings/type/page.ts +100 -0
  192. package/backend/settings/type/string.ts +77 -0
  193. package/backend/settings/type/stringlist.ts +87 -0
  194. package/backend/severity.ts +88 -0
  195. package/backend/site-inline-actions.ts +32 -0
  196. package/backend/sortable-table.ts +208 -0
  197. package/backend/storage/abstract-client-storage.ts +76 -0
  198. package/backend/storage/browser-session.ts +28 -0
  199. package/backend/storage/client.ts +28 -0
  200. package/backend/storage/module-state-storage.ts +118 -0
  201. package/backend/storage/persistent.ts +204 -0
  202. package/backend/switch-user.ts +82 -0
  203. package/backend/tabs.ts +72 -0
  204. package/backend/telephone-link-handler.ts +40 -0
  205. package/backend/tests/backend/storage/browser-storage-test.ts +87 -0
  206. package/backend/tests/backend/storage/client-test.ts +87 -0
  207. package/backend/tests/backend/utility/dom-helper-test.ts +51 -0
  208. package/backend/tests/backend-exception-test.ts +28 -0
  209. package/backend/tests/element/immediate-action-element-test.ts +81 -0
  210. package/backend/tests/form-engine-validation-test.ts +304 -0
  211. package/backend/tests/grid-editor-test.ts +29 -0
  212. package/backend/tests/hashing/md5Test.ts +28 -0
  213. package/backend/tests/icons-test.ts +23 -0
  214. package/backend/tests/notification-test.ts +161 -0
  215. package/backend/tests/popover-test.ts +83 -0
  216. package/backend/toolbar/clear-cache-menu.ts +88 -0
  217. package/backend/toolbar/live-search.ts +284 -0
  218. package/backend/toolbar/shortcut-menu.ts +254 -0
  219. package/backend/toolbar/system-information-menu.ts +161 -0
  220. package/backend/toolbar.ts +41 -0
  221. package/backend/tree/file-storage-browser.ts +194 -0
  222. package/backend/tree/file-storage-tree-container.ts +465 -0
  223. package/backend/tree/file-storage-tree.ts +42 -0
  224. package/backend/tree/page-browser.ts +272 -0
  225. package/backend/tree/page-tree-element.ts +602 -0
  226. package/backend/tree/page-tree.ts +152 -0
  227. package/backend/tree/tree-module-state.ts +159 -0
  228. package/backend/tree/tree-node-toggle.ts +31 -0
  229. package/backend/tree/tree-node.ts +97 -0
  230. package/backend/tree/tree-toolbar.ts +117 -0
  231. package/backend/tree/tree.ts +1595 -0
  232. package/backend/url-link-handler.ts +36 -0
  233. package/backend/user-pass-login.ts +255 -0
  234. package/backend/user-settings-manager.ts +189 -0
  235. package/backend/utility/collapse-state-persister.ts +205 -0
  236. package/backend/utility/collapse-state-search.ts +183 -0
  237. package/backend/utility/dom-helper.ts +91 -0
  238. package/backend/utility/drag-drop-utility.ts +47 -0
  239. package/backend/utility/message-utility.ts +45 -0
  240. package/backend/utility/top-level-module-import.ts +32 -0
  241. package/backend/utility.ts +194 -0
  242. package/backend/viewport/abstract-container.ts +22 -0
  243. package/backend/viewport/content-container.ts +98 -0
  244. package/backend/viewport/loader.ts +28 -0
  245. package/backend/viewport/navigation-container.ts +119 -0
  246. package/backend/viewport/resizable-navigation.ts +176 -0
  247. package/backend/viewport/toolbar.ts +27 -0
  248. package/backend/viewport/topbar.ts +39 -0
  249. package/backend/viewport.ts +46 -0
  250. package/backend/window-manager.ts +84 -0
  251. package/backend/wizard/move-content-element.ts +107 -0
  252. package/backend/wizard/move-page.ts +74 -0
  253. package/backend/wizard.ts +331 -0
  254. package/belog/backend-log.ts +88 -0
  255. package/beuser/backend-user-listing.ts +40 -0
  256. package/beuser/permissions.ts +291 -0
  257. package/core/ajax/ajax-request-types.ts +15 -0
  258. package/core/ajax/ajax-request.ts +202 -0
  259. package/core/ajax/ajax-response.ts +57 -0
  260. package/core/ajax/input-transformer.ts +92 -0
  261. package/core/ajax/simple-response-interface.ts +5 -0
  262. package/core/authentication/mfa-provider/totp.ts +54 -0
  263. package/core/cache/dedupe-async-task.ts +95 -0
  264. package/core/directive/markdown.ts +82 -0
  265. package/core/directive/nl2br.ts +16 -0
  266. package/core/document-service.ts +35 -0
  267. package/core/event/debounce-event.ts +40 -0
  268. package/core/event/event-interface.ts +24 -0
  269. package/core/event/regular-event.ts +58 -0
  270. package/core/event/request-animation-frame-event.ts +42 -0
  271. package/core/event/throttle-event.ts +54 -0
  272. package/core/java-script-item-handler.ts +29 -0
  273. package/core/java-script-item-processor.ts +171 -0
  274. package/core/lit-helper.ts +126 -0
  275. package/core/literals.ts +17 -0
  276. package/core/referrer-refresh.ts +2 -0
  277. package/core/security-utility.ts +89 -0
  278. package/core/tests/ajax/ajax-request-test.ts +290 -0
  279. package/core/tests/ajax/input-transformer-test.ts +64 -0
  280. package/core/tests/cache/dedupe-async-task-test.ts +152 -0
  281. package/core/tests/event/throttle-event-test.ts +47 -0
  282. package/core/tests/literals-test.ts +24 -0
  283. package/core/tests/security-utility-test.ts +50 -0
  284. package/core/utility/types.ts +9 -0
  285. package/dashboard/chart-initializer.ts +136 -0
  286. package/dashboard/dashboard.ts +1487 -0
  287. package/extensionmanager/distribution-image.ts +55 -0
  288. package/extensionmanager/main.ts +291 -0
  289. package/extensionmanager/repository.ts +195 -0
  290. package/extensionmanager/update.ts +118 -0
  291. package/extensionmanager/upload-form.ts +42 -0
  292. package/filelist/browse-files.ts +148 -0
  293. package/filelist/browse-folders.ts +94 -0
  294. package/filelist/context-menu-actions.ts +335 -0
  295. package/filelist/create-folder.ts +69 -0
  296. package/filelist/file-delete.ts +69 -0
  297. package/filelist/file-list-actions.ts +132 -0
  298. package/filelist/file-list-dragdrop.ts +139 -0
  299. package/filelist/file-list-rename-handler.ts +128 -0
  300. package/filelist/file-list-transfer-handler.ts +138 -0
  301. package/filelist/file-list.ts +396 -0
  302. package/filelist/file-replace.ts +37 -0
  303. package/filelist/linkbrowser-file-handler.ts +94 -0
  304. package/filelist/linkbrowser-folder-handler.ts +74 -0
  305. package/filelist/rename-file.ts +109 -0
  306. package/form/backend/form-editor/component/property-grid-editor.ts +340 -0
  307. package/form/backend/form-editor/core.ts +2104 -0
  308. package/form/backend/form-editor/helper.ts +226 -0
  309. package/form/backend/form-editor/inspector-component.ts +2323 -0
  310. package/form/backend/form-editor/mediator.ts +941 -0
  311. package/form/backend/form-editor/modals-component.ts +433 -0
  312. package/form/backend/form-editor/stage-component.ts +908 -0
  313. package/form/backend/form-editor/tree-component.ts +548 -0
  314. package/form/backend/form-editor/view-model.ts +1343 -0
  315. package/form/backend/form-editor.ts +846 -0
  316. package/form/backend/form-manager/main.ts +39 -0
  317. package/form/backend/form-manager/view-model.ts +789 -0
  318. package/form/backend/form-manager.ts +180 -0
  319. package/form/backend/helper.ts +60 -0
  320. package/form/frontend/date-picker.ts +38 -0
  321. package/frontend/default_frontend.ts +82 -0
  322. package/impexp/context-menu-actions.ts +50 -0
  323. package/impexp/import-export.ts +62 -0
  324. package/indexed-search/pagination.ts +26 -0
  325. package/indexed-search/statistics.ts +50 -0
  326. package/info/translation-status.ts +48 -0
  327. package/install/ajax/ajax-queue.ts +83 -0
  328. package/install/init-install.ts +2 -0
  329. package/install/init-installer.ts +2 -0
  330. package/install/install.ts +25 -0
  331. package/install/installer.ts +458 -0
  332. package/install/message-interface.ts +18 -0
  333. package/install/module/abstract-inline-module.ts +27 -0
  334. package/install/module/abstract-interactable-module.ts +107 -0
  335. package/install/module/environment/environment-check.ts +92 -0
  336. package/install/module/environment/folder-structure.ts +145 -0
  337. package/install/module/environment/image-processing.ts +141 -0
  338. package/install/module/environment/mail-test.ts +127 -0
  339. package/install/module/environment/php-info.ts +50 -0
  340. package/install/module/environment/system-information.ts +50 -0
  341. package/install/module/maintenance/cache.ts +59 -0
  342. package/install/module/maintenance/clear-tables.ts +134 -0
  343. package/install/module/maintenance/clear-typo3temp-files.ts +137 -0
  344. package/install/module/maintenance/create-admin.ts +126 -0
  345. package/install/module/maintenance/database-analyzer.ts +266 -0
  346. package/install/module/maintenance/dump-autoload.ts +58 -0
  347. package/install/module/maintenance/language-packs.ts +338 -0
  348. package/install/module/maintenance/reset-backend-user-uc.ts +58 -0
  349. package/install/module/password-strength.ts +56 -0
  350. package/install/module/settings/change-install-tool-password.ts +101 -0
  351. package/install/module/settings/extension-configuration.ts +224 -0
  352. package/install/module/settings/features.ts +102 -0
  353. package/install/module/settings/local-configuration.ts +316 -0
  354. package/install/module/settings/presets.ts +147 -0
  355. package/install/module/settings/system-maintainer.ts +111 -0
  356. package/install/module/upgrade/core-update.ts +255 -0
  357. package/install/module/upgrade/extension-compat-tester.ts +195 -0
  358. package/install/module/upgrade/extension-scanner.ts +381 -0
  359. package/install/module/upgrade/tca-ext-tables-check.ts +93 -0
  360. package/install/module/upgrade/tca-migrations-check.ts +101 -0
  361. package/install/module/upgrade/upgrade-docs.ts +310 -0
  362. package/install/module/upgrade/upgrade-wizards.ts +612 -0
  363. package/install/renderable/clearable.ts +113 -0
  364. package/install/renderable/flash-message.ts +64 -0
  365. package/install/renderable/info-box.ts +66 -0
  366. package/install/renderable/language-packs.ts +304 -0
  367. package/install/renderable/offset-group.ts +38 -0
  368. package/install/renderable/severity.ts +49 -0
  369. package/install/renderable/wrap-group.ts +36 -0
  370. package/install/router.ts +468 -0
  371. package/linkvalidator/linkvalidator-modal.ts +45 -0
  372. package/linkvalidator/linkvalidator.ts +101 -0
  373. package/lowlevel/query-generator.ts +132 -0
  374. package/lowlevel/reference-index.ts +44 -0
  375. package/opendocs/toolbar/opendocs-menu.ts +117 -0
  376. package/package.json +34 -0
  377. package/recycler/recycler.ts +539 -0
  378. package/redirects/event-handler.ts +108 -0
  379. package/redirects/form-engine-evaluation.ts +34 -0
  380. package/redirects/redirects-module.ts +58 -0
  381. package/rte-ckeditor/ckeditor5.ts +402 -0
  382. package/rte-ckeditor/css-prefixer.ts +94 -0
  383. package/rte-ckeditor/legacy/ckeditor5-bundle.ts +17 -0
  384. package/rte-ckeditor/legacy/ckeditor5-inspector.ts +2 -0
  385. package/rte-ckeditor/plugin/typo3-link.ts +810 -0
  386. package/rte-ckeditor/plugin/whitespace.ts +114 -0
  387. package/rte-ckeditor/rte-link-browser.ts +112 -0
  388. package/rte-ckeditor/tests/css-prefixer-test.ts +314 -0
  389. package/scheduler/scheduler-add-group.ts +119 -0
  390. package/scheduler/scheduler-editable-group-name.ts +307 -0
  391. package/scheduler/scheduler-sortable-groups.ts +59 -0
  392. package/scheduler/scheduler.ts +466 -0
  393. package/setup/setup-module.ts +122 -0
  394. package/styleguide/checkbox-demo.ts +5 -0
  395. package/styleguide/element/theme-switcher-element.ts +101 -0
  396. package/styleguide/filter.ts +22 -0
  397. package/styleguide/find-icons.ts +78 -0
  398. package/styleguide/processing-indicator.ts +78 -0
  399. package/styleguide/render-notifications.ts +64 -0
  400. package/sys-note/element/delete-button.ts +78 -0
  401. package/tstemplate/constant-editor.ts +64 -0
  402. package/tstemplate/information-module.ts +31 -0
  403. package/tstemplate/template-analyzer.ts +77 -0
  404. package/viewpage/main.ts +253 -0
  405. package/workspaces/backend.ts +979 -0
  406. package/workspaces/preview.ts +232 -0
  407. package/workspaces/renderable/comment-view.ts +79 -0
  408. package/workspaces/renderable/diff-view.ts +58 -0
  409. package/workspaces/renderable/history-view.ts +97 -0
  410. package/workspaces/renderable/record-information.ts +118 -0
  411. package/workspaces/renderable/record-table.ts +355 -0
  412. package/workspaces/renderable/send-to-stage-form.ts +108 -0
  413. package/workspaces/toolbar/workspaces-menu.ts +190 -0
  414. package/workspaces/utility/icon-helper.ts +57 -0
  415. 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
+ }