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,44 @@
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 { MultiRecordSelectionSelectors } from '@typo3/backend/multi-record-selection';
15
+
16
+ /**
17
+ * Module: @typo3/backend/multi-record-selection-action
18
+ */
19
+
20
+ export interface ActionConfiguration {
21
+ idField: string;
22
+ }
23
+
24
+ export interface ActionEventDetails {
25
+ identifier: string,
26
+ checkboxes: NodeListOf<HTMLInputElement>,
27
+ configuration: any
28
+ }
29
+
30
+ export class MultiRecordSelectionAction {
31
+
32
+ public static getEntityIdentifiers(eventDetails: ActionEventDetails): Array<string>
33
+ {
34
+ // Evaluate all checked records and if valid, add their uid to the list
35
+ const entityIdentifiers: Array<string> = [];
36
+ eventDetails.checkboxes.forEach((checkbox: HTMLInputElement): void => {
37
+ const checkboxContainer: HTMLElement = checkbox.closest(MultiRecordSelectionSelectors.elementSelector);
38
+ if (checkboxContainer !== null && checkboxContainer.dataset[eventDetails.configuration.idField]) {
39
+ entityIdentifiers.push(checkboxContainer.dataset[eventDetails.configuration.idField]);
40
+ }
41
+ });
42
+ return entityIdentifiers;
43
+ }
44
+ }
@@ -0,0 +1,108 @@
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 RegularEvent from '@typo3/core/event/regular-event';
15
+ import {
16
+ type ActionConfiguration,
17
+ type ActionEventDetails,
18
+ MultiRecordSelectionAction
19
+ } from '@typo3/backend/multi-record-selection-action';
20
+ import Modal, { type ModalElement } from '@typo3/backend/modal';
21
+ import { SeverityEnum } from '@typo3/backend/enum/severity';
22
+ import Severity from '@typo3/backend/severity';
23
+ import AjaxDataHandler from '@typo3/backend/ajax-data-handler';
24
+ import Notification from '@typo3/backend/notification';
25
+
26
+ interface DeleteActionConfiguration extends ActionConfiguration {
27
+ tableName: string;
28
+ returnUrl: string;
29
+ title: string;
30
+ content: string;
31
+ ok: string;
32
+ cancel: string;
33
+ }
34
+
35
+ interface DatahandlerCommand {
36
+ delete?: number
37
+ }
38
+
39
+ /**
40
+ * Module: @typo3/backend/multi-record-selection-delete-action
41
+ * @exports @typo3/backend/multi-record-selection-delete-action
42
+ */
43
+ class MultiRecordSelectionDeleteAction {
44
+ public constructor() {
45
+ new RegularEvent('multiRecordSelection:action:delete', this.delete).bindTo(document);
46
+ }
47
+
48
+ private delete(event: CustomEvent): void {
49
+ event.preventDefault();
50
+
51
+ const eventDetails: ActionEventDetails = event.detail as ActionEventDetails;
52
+ const entityIdentifiers: Array<string> = MultiRecordSelectionAction.getEntityIdentifiers(eventDetails);
53
+ if (!entityIdentifiers.length) {
54
+ // Return in case no records to delete were found
55
+ return;
56
+ }
57
+
58
+ const configuration: DeleteActionConfiguration = eventDetails.configuration;
59
+ const tableName: string = configuration.tableName || '';
60
+ if (tableName === '') {
61
+ return;
62
+ }
63
+ const returnUrl: string = configuration.returnUrl || '';
64
+
65
+ Modal.advanced({
66
+ title: configuration.title || 'Delete',
67
+ content: configuration.content || 'Are you sure you want to delete those records?',
68
+ severity: SeverityEnum.warning,
69
+ buttons: [
70
+ {
71
+ text: configuration.cancel || TYPO3.lang['button.cancel'] || 'Cancel',
72
+ active: true,
73
+ btnClass: 'btn-default',
74
+ name: 'cancel',
75
+ trigger: (e: Event, modal: ModalElement) => modal.hideModal(),
76
+ },
77
+ {
78
+ text: configuration.ok || TYPO3.lang['button.delete'] || 'OK',
79
+ btnClass: 'btn-' + Severity.getCssClass(SeverityEnum.warning),
80
+ name: 'delete',
81
+ trigger: async (e: Event, modal: ModalElement): Promise<void> => {
82
+ modal.hideModal();
83
+ try {
84
+ const result = await AjaxDataHandler.process({
85
+ cmd: {
86
+ [tableName]: Object.fromEntries(entityIdentifiers.map((identifier: string): [string, DatahandlerCommand] => [
87
+ identifier, { delete: 1 }
88
+ ]))
89
+ }
90
+ });
91
+ if (result.hasErrors) {
92
+ throw result.messages;
93
+ } else if (returnUrl !== '') {
94
+ (event.target as HTMLElement).ownerDocument.location.href = returnUrl;
95
+ } else {
96
+ (event.target as HTMLElement).ownerDocument.location.reload();
97
+ }
98
+ } catch {
99
+ Notification.error('Could not delete records');
100
+ }
101
+ }
102
+ }
103
+ ]
104
+ });
105
+ }
106
+ }
107
+
108
+ export default new MultiRecordSelectionDeleteAction();
@@ -0,0 +1,56 @@
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 RegularEvent from '@typo3/core/event/regular-event';
15
+ import {
16
+ type ActionConfiguration,
17
+ type ActionEventDetails,
18
+ MultiRecordSelectionAction
19
+ } from '@typo3/backend/multi-record-selection-action';
20
+
21
+ interface EditActionConfiguration extends ActionConfiguration {
22
+ tableName: string;
23
+ returnUrl: string;
24
+ }
25
+
26
+ /**
27
+ * Module: @typo3/backend/multi-record-selection-edit-action
28
+ * @exports @typo3/backend/multi-record-selection-edit-action
29
+ */
30
+ class MultiRecordSelectionEditAction {
31
+ public constructor() {
32
+ new RegularEvent('multiRecordSelection:action:edit', this.edit).bindTo(document);
33
+ }
34
+
35
+ private edit(event: CustomEvent): void {
36
+ event.preventDefault();
37
+ const eventDetails: ActionEventDetails = event.detail as ActionEventDetails;
38
+ const entityIdentifiers: Array<string> = MultiRecordSelectionAction.getEntityIdentifiers(eventDetails);
39
+ if (!entityIdentifiers.length) {
40
+ // Return in case no records to edit were found
41
+ return;
42
+ }
43
+
44
+ const configuration: EditActionConfiguration = eventDetails.configuration;
45
+ const tableName: string = configuration.tableName || '';
46
+ if (tableName === '') {
47
+ return;
48
+ }
49
+
50
+ window.location.href = top.TYPO3.settings.FormEngine.moduleUrl
51
+ + '&edit[' + tableName + '][' + entityIdentifiers.join(',') + ']=edit'
52
+ + '&returnUrl=' + encodeURIComponent(configuration.returnUrl || '');
53
+ }
54
+ }
55
+
56
+ export default new MultiRecordSelectionEditAction();
@@ -0,0 +1,468 @@
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 Notification from '@typo3/backend/notification';
15
+ import DocumentService from '@typo3/core/document-service';
16
+ import RegularEvent from '@typo3/core/event/regular-event';
17
+ import { selector } from '@typo3/core/literals';
18
+ import type { ActionConfiguration, ActionEventDetails } from '@typo3/backend/multi-record-selection-action';
19
+
20
+ export enum MultiRecordSelectionSelectors {
21
+ actionsSelector = '.t3js-multi-record-selection-actions',
22
+ checkboxSelector = '.t3js-multi-record-selection-check',
23
+ checkboxActionsSelector = '.t3js-multi-record-selection-check-actions',
24
+ checkboxActionsToggleSelector = '.t3js-multi-record-selection-check-actions-toggle',
25
+ elementSelector = '[data-multi-record-selection-element]',
26
+ }
27
+
28
+ enum Buttons {
29
+ actionButton = 'button[data-multi-record-selection-action]',
30
+ checkboxActionButton = 'button[data-multi-record-selection-check-action]',
31
+ }
32
+
33
+ enum CheckboxActions {
34
+ checkAll = 'check-all',
35
+ checkNone = 'check-none',
36
+ toggle = 'toggle'
37
+ }
38
+
39
+ enum CheckboxState {
40
+ any = '',
41
+ checked = ':checked',
42
+ unchecked = ':not(:checked)'
43
+ }
44
+
45
+ /**
46
+ * Module: @typo3/backend/multi-record-selection
47
+ */
48
+ class MultiRecordSelection {
49
+ static activeClass: string = 'active';
50
+ private lastChecked: HTMLInputElement = null;
51
+
52
+ constructor() {
53
+ DocumentService.ready().then((): void => {
54
+ MultiRecordSelection.restoreTemporaryState();
55
+ this.registerActions();
56
+ this.registerActionsEventHandlers();
57
+ this.registerCheckboxActions();
58
+ this.registerCheckboxKeyboardActions();
59
+ this.registerCheckboxTableRowSelectionAction();
60
+ this.registerToggleCheckboxActions();
61
+ this.registerDispatchCheckboxStateChangedEvent();
62
+ this.registerCheckboxStateChangedEventHandler();
63
+ });
64
+ }
65
+
66
+ private static getCheckboxes(state: CheckboxState = CheckboxState.any, identifier: string = ''): NodeListOf<HTMLInputElement> {
67
+ return document.querySelectorAll(MultiRecordSelection.getCombinedSelector(MultiRecordSelectionSelectors.checkboxSelector + state, identifier));
68
+ }
69
+
70
+ private static getCombinedSelector(query: string, identifier: string): string {
71
+ return identifier !== '' ? [selector`[data-multi-record-selection-identifier="${identifier}"]`, query].join (' ') : query;
72
+ }
73
+
74
+ private static getIdentifier(element: HTMLElement): string {
75
+ return (element.closest('[data-multi-record-selection-identifier]') as HTMLElement)?.dataset.multiRecordSelectionIdentifier || '';
76
+ }
77
+
78
+ private static changeCheckboxState(checkbox: HTMLInputElement, check: boolean): void {
79
+ if (checkbox.disabled || checkbox.checked === check || checkbox.dataset.manuallyChanged) {
80
+ // Return in case the checkbox is disabled, the state did not change or another component has already changed it
81
+ return;
82
+ }
83
+ checkbox.checked = check;
84
+ checkbox.dispatchEvent(new Event('change', { bubbles: true }));
85
+ }
86
+
87
+ /**
88
+ * This restores (initializes) a temporary state, which is required in case
89
+ * the user returns to the listing using the browsers' history back feature,
90
+ * which will not result in a new request.
91
+ */
92
+ private static restoreTemporaryState(): void {
93
+ const checked: NodeListOf<HTMLInputElement> = MultiRecordSelection.getCheckboxes(CheckboxState.checked);
94
+ // In case nothing is checked we don't have to do anything here
95
+ if (!checked.length) {
96
+ return;
97
+ }
98
+ // Highlight each checked checkbox and toggle the corresponding actions. Since
99
+ // the evaluation for toggling actions does a lot of things, we don't want to
100
+ // perform this for every checked checkbox. Therefore we store the identifiers,
101
+ // which were already evaluated and do not call the evaluation for them again.
102
+ let actionsToggled: boolean = false;
103
+ const identifiers: Array<string> = [];
104
+ checked.forEach((checkbox: HTMLInputElement) => {
105
+ (checkbox.closest(MultiRecordSelectionSelectors.elementSelector) as HTMLElement)?.classList.add(MultiRecordSelection.activeClass);
106
+ const identifier: string = MultiRecordSelection.getIdentifier(checkbox);
107
+ if (identifier !== '' && !identifiers.includes(identifier)) {
108
+ identifiers.push(identifier);
109
+ actionsToggled = true;
110
+ MultiRecordSelection.toggleActionsState(identifier);
111
+ }
112
+ });
113
+ // If none of the checked checkboxes contain an identifier, call the toggling one time anyways.
114
+ if (!actionsToggled) {
115
+ MultiRecordSelection.toggleActionsState();
116
+ }
117
+ }
118
+
119
+ /**
120
+ * Toggles the state of the actions, depending on the
121
+ * currently selected elements and their nature.
122
+ */
123
+ private static toggleActionsState(identifier: string = ''): void {
124
+ const actionContainers: NodeListOf<HTMLElement> = document.querySelectorAll(
125
+ MultiRecordSelection.getCombinedSelector(MultiRecordSelectionSelectors.actionsSelector, identifier)
126
+ );
127
+
128
+ if (!actionContainers.length) {
129
+ // Early return in case no action containers are defined
130
+ return;
131
+ }
132
+
133
+ if (!MultiRecordSelection.getCheckboxes(CheckboxState.checked, identifier).length) {
134
+ // In case no checkbox is checked, hide all action containers and return
135
+ actionContainers.forEach((container: HTMLElement): void => MultiRecordSelection.changeActionContainerVisibility(container, false));
136
+ return;
137
+ }
138
+
139
+ // Remove hidden state of all action containers, since checked checkboxes exist
140
+ actionContainers.forEach((container: HTMLElement): void => MultiRecordSelection.changeActionContainerVisibility(container));
141
+
142
+ const actions: NodeListOf<HTMLButtonElement> = document.querySelectorAll(
143
+ [MultiRecordSelection.getCombinedSelector(MultiRecordSelectionSelectors.actionsSelector, identifier), Buttons.actionButton].join(' ')
144
+ );
145
+
146
+ if (!actions.length) {
147
+ // Early return in case no action is defined
148
+ return;
149
+ }
150
+
151
+ actions.forEach((action: HTMLButtonElement): void => {
152
+ if (!action.dataset.multiRecordSelectionActionConfig) {
153
+ // In case the action does not define any configuration, no toggling is possible
154
+ return;
155
+ }
156
+ const configuration: ActionConfiguration = JSON.parse(action.dataset.multiRecordSelectionActionConfig);
157
+ if (!configuration.idField) {
158
+ // Return in case the idField (where to find the id on selected elements) is not defined
159
+ return;
160
+ }
161
+ // Start the evaluation by disabling the action
162
+ action.disabled = true;
163
+ // Get all currently checked elements
164
+ const checked: NodeListOf<HTMLInputElement> = MultiRecordSelection.getCheckboxes(CheckboxState.checked, identifier);
165
+ for (let i = 0; i < checked.length; i++) {
166
+ // Evaluate each checked element if it contains the specified idField
167
+ if ((checked[i].closest(MultiRecordSelectionSelectors.elementSelector) as HTMLElement)?.dataset[configuration.idField]) {
168
+ // If a checked element contains the idField, remove the "disabled"
169
+ // state and end the search since the action can be performed.
170
+ action.disabled = false;
171
+ break;
172
+ }
173
+ }
174
+ });
175
+ }
176
+
177
+ /**
178
+ * This primarily just adds/removes the "hidden" class of the container. In case
179
+ * the container is in a panel, it also toggles the other panel heading elements.
180
+ * Note: This only works in case the container is not in the wrapper class, which
181
+ * should only be used for containers, outside of a panel.
182
+ *
183
+ * @param {HTMLElement} container The container to change the visibility for
184
+ * @param {boolean} visible Whether the container should be visible or not
185
+ */
186
+ private static changeActionContainerVisibility(container: HTMLElement, visible: boolean = true): void {
187
+ const panelElements: HTMLCollection = container.closest('.multi-record-selection-panel')?.children;
188
+ if (visible) {
189
+ if (panelElements) {
190
+ for (let i = 0; i < panelElements.length; i++) { panelElements[i].classList.add('hidden'); }
191
+ }
192
+ container.classList.remove('hidden');
193
+ } else {
194
+ if (panelElements) {
195
+ for (let i = 0; i < panelElements.length; i++) { panelElements[i].classList.remove('hidden'); }
196
+ }
197
+ container.classList.add('hidden');
198
+ }
199
+ }
200
+
201
+ /**
202
+ * The manually changed attribute can be set by components, using
203
+ * this module while implementing custom logic to change checkbox
204
+ * state. To not cancel each others action, all actions in this
205
+ * module respect this attribute before changing checkbox state.
206
+ * Therefore, this method is called prior to every action in
207
+ * this module, which changes checkbox states. Otherwise old
208
+ * state would may led to misbehaviour.
209
+ */
210
+ private static unsetManuallyChangedAttribute(identifier: string): void {
211
+ MultiRecordSelection.getCheckboxes(CheckboxState.any, identifier).forEach((checkbox: HTMLInputElement): void => {
212
+ checkbox.removeAttribute('data-manually-changed');
213
+ });
214
+ }
215
+
216
+ private registerActions(): void {
217
+ new RegularEvent('click', (e: Event, target: HTMLButtonElement): void => {
218
+ if (!target.dataset.multiRecordSelectionAction) {
219
+ // Return if we don't deal with a valid action
220
+ }
221
+
222
+ const identifier: string = MultiRecordSelection.getIdentifier(target);
223
+ const configuration: any = JSON.parse((target.dataset.multiRecordSelectionActionConfig || '{}'));
224
+ const checked: NodeListOf<HTMLInputElement> = MultiRecordSelection.getCheckboxes(CheckboxState.checked, identifier);
225
+
226
+ if (!checked.length) {
227
+ // Return in case there is currently no element checked to perform the action on.
228
+ return;
229
+ }
230
+
231
+ // This component does not implement any specific action itself, but just dispatches
232
+ // an event so the implementing components can react on the triggered action. To decrease
233
+ // selections in those components, most of the information are passed within the custom event.
234
+ // Those are e.g. the checked checkboxes, the instance identifier and the action configuration.
235
+ target.dispatchEvent(new CustomEvent(
236
+ 'multiRecordSelection:action:' + target.dataset.multiRecordSelectionAction,
237
+ {
238
+ detail: <ActionEventDetails> { identifier: identifier, checkboxes: checked, configuration: configuration },
239
+ bubbles: true,
240
+ cancelable: false
241
+ }
242
+ ));
243
+ }).delegateTo(document, [MultiRecordSelectionSelectors.actionsSelector, Buttons.actionButton].join(' '));
244
+ }
245
+
246
+ /**
247
+ * Other components can dispatch the "multiRecordSelection:actions"
248
+ * events to influence the display depending on their custom logic.
249
+ */
250
+ private registerActionsEventHandlers(): void {
251
+ new RegularEvent('multiRecordSelection:actions:show', (e: CustomEvent): void => {
252
+ const identifier: string = e.detail?.identifier || '';
253
+ const actionContainers: NodeListOf<HTMLElement> = document.querySelectorAll(MultiRecordSelection.getCombinedSelector(MultiRecordSelectionSelectors.actionsSelector, identifier));
254
+ actionContainers.forEach((container: HTMLElement): void => MultiRecordSelection.changeActionContainerVisibility(container));
255
+ }).bindTo(document);
256
+ new RegularEvent('multiRecordSelection:actions:hide', (e: CustomEvent): void => {
257
+ const identifier: string = e.detail?.identifier || '';
258
+ const actionContainers: NodeListOf<HTMLElement> = document.querySelectorAll(MultiRecordSelection.getCombinedSelector(MultiRecordSelectionSelectors.actionsSelector, identifier));
259
+ actionContainers.forEach((container: HTMLElement): void => MultiRecordSelection.changeActionContainerVisibility(container, false));
260
+ }).bindTo(document);
261
+ new RegularEvent('multiRecordSelection:checkboxes:check', (e: CustomEvent): void => {
262
+ const identifier: string = e.detail?.identifier || '';
263
+ MultiRecordSelection.getCheckboxes(CheckboxState.any, identifier).forEach((checkbox: HTMLInputElement): void => MultiRecordSelection.changeCheckboxState(checkbox, true));
264
+ }).bindTo(document);
265
+ new RegularEvent('multiRecordSelection:checkboxes:uncheck', (e: CustomEvent): void => {
266
+ const identifier: string = e.detail?.identifier || '';
267
+ MultiRecordSelection.getCheckboxes(CheckboxState.any, identifier).forEach((checkbox: HTMLInputElement): void => MultiRecordSelection.changeCheckboxState(checkbox, false));
268
+ }).bindTo(document);
269
+ }
270
+
271
+ private registerCheckboxActions(): void {
272
+ new RegularEvent('click', (e: Event, target: HTMLButtonElement): void => {
273
+ e.preventDefault();
274
+
275
+ if (!target.dataset.multiRecordSelectionCheckAction) {
276
+ // Return if we don't deal with a valid action
277
+ return;
278
+ }
279
+
280
+ const identifier: string = MultiRecordSelection.getIdentifier(target);
281
+ const checkboxes: NodeListOf<HTMLInputElement> = MultiRecordSelection.getCheckboxes(CheckboxState.any, identifier);
282
+
283
+ if (!checkboxes.length) {
284
+ // Return in case there are no checkboxes (elements) to perform the action on.
285
+ return;
286
+ }
287
+
288
+ // Unset manually changed attribute so we can be sure, in case this is
289
+ // set on a checkbox, while executing the requested action, the checkbox
290
+ // was already changed by another component.
291
+ MultiRecordSelection.unsetManuallyChangedAttribute(identifier);
292
+
293
+ // Perform requested action
294
+ switch (target.dataset.multiRecordSelectionCheckAction) {
295
+ case CheckboxActions.checkAll:
296
+ checkboxes.forEach((checkbox: HTMLInputElement) => {
297
+ MultiRecordSelection.changeCheckboxState(checkbox, true);
298
+ });
299
+ break;
300
+ case CheckboxActions.checkNone:
301
+ checkboxes.forEach((checkbox: HTMLInputElement) => {
302
+ MultiRecordSelection.changeCheckboxState(checkbox, false);
303
+ });
304
+ break;
305
+ case CheckboxActions.toggle:
306
+ checkboxes.forEach((checkbox: HTMLInputElement) => {
307
+ MultiRecordSelection.changeCheckboxState(checkbox, !checkbox.checked);
308
+ });
309
+ break;
310
+ default:
311
+ // Unknown action
312
+ Notification.warning('Unknown checkbox action');
313
+ }
314
+
315
+ // To prevent possible side effects we simply clean up and unset the attribute here again
316
+ MultiRecordSelection.unsetManuallyChangedAttribute(identifier);
317
+ }).delegateTo(document, [MultiRecordSelectionSelectors.checkboxActionsSelector, Buttons.checkboxActionButton].join(' '));
318
+ }
319
+
320
+ private registerCheckboxKeyboardActions(): void {
321
+ new RegularEvent('click', (e: PointerEvent, target: HTMLInputElement): void => this.handleCheckboxKeyboardActions(e, target))
322
+ .delegateTo(document, MultiRecordSelectionSelectors.checkboxSelector);
323
+ }
324
+
325
+ private registerCheckboxTableRowSelectionAction(): void {
326
+ new RegularEvent('click', (e: PointerEvent, target: HTMLElement): void => {
327
+ const eventTargetTagName: string = (e.target as HTMLElement).tagName;
328
+ if (eventTargetTagName !== 'TH' && eventTargetTagName !== 'TD') {
329
+ // Only change checkbox state if the target is the row itself
330
+ return;
331
+ }
332
+ const checkbox: HTMLInputElement = target.querySelector(MultiRecordSelectionSelectors.checkboxSelector);
333
+ if (checkbox === null) {
334
+ // Return in case the table row does not contain a checkbox, handled by this component
335
+ return;
336
+ }
337
+ // Note: Since we only change the state of one checkbox, we don't have to unset the
338
+ // manually changed flag and also do not need to evaluate any instance identifier.
339
+ MultiRecordSelection.changeCheckboxState(checkbox, !checkbox.checked);
340
+ // After changing the target checkbox state, let's check if a keyboard action
341
+ // should be performed as well. We also prevent the keyboard actions from unsetting
342
+ // any state, e.g. the "manually changed flag", as this might have been set by any
343
+ // component triggered by the above checkbox state change operation.
344
+ this.handleCheckboxKeyboardActions(e, checkbox, false);
345
+ }).delegateTo(document, MultiRecordSelectionSelectors.elementSelector);
346
+
347
+ // In case row selection is enabled and a keyboard "shortcut" is used, prevent text selection on the rows
348
+ new RegularEvent('mousedown', (e: PointerEvent): void => (e.shiftKey || e.altKey || e.ctrlKey) && e.preventDefault())
349
+ .delegateTo(document, MultiRecordSelectionSelectors.elementSelector);
350
+ }
351
+
352
+ private registerDispatchCheckboxStateChangedEvent(): void {
353
+ new RegularEvent('change', (e: Event, target: HTMLInputElement): void => {
354
+ target.dispatchEvent(new CustomEvent('multiRecordSelection:checkbox:state:changed',{
355
+ detail: { identifier: MultiRecordSelection.getIdentifier(target) }, bubbles: true, cancelable: false
356
+ }));
357
+ }).delegateTo(document, MultiRecordSelectionSelectors.checkboxSelector);
358
+ }
359
+
360
+ private registerCheckboxStateChangedEventHandler(): void {
361
+ new RegularEvent('multiRecordSelection:checkbox:state:changed', (e: CustomEvent): void => {
362
+ const checkbox: HTMLInputElement = <HTMLInputElement>e.target;
363
+ const identifier: string = e.detail?.identifier || '';
364
+
365
+ if (checkbox.checked) {
366
+ checkbox.closest(MultiRecordSelectionSelectors.elementSelector).classList.add(MultiRecordSelection.activeClass);
367
+ } else {
368
+ checkbox.closest(MultiRecordSelectionSelectors.elementSelector).classList.remove(MultiRecordSelection.activeClass);
369
+ }
370
+
371
+ // Toggle actions for changed checkbox state
372
+ MultiRecordSelection.toggleActionsState(identifier);
373
+ }).bindTo(document);
374
+ }
375
+
376
+ private registerToggleCheckboxActions(): void {
377
+ new RegularEvent('click', (e: Event, target: HTMLButtonElement): void => {
378
+ const identifier: string = MultiRecordSelection.getIdentifier(target);
379
+
380
+ const checkAll: HTMLButtonElement = document.querySelector([
381
+ MultiRecordSelection.getCombinedSelector(MultiRecordSelectionSelectors.checkboxActionsSelector, identifier),
382
+ 'button[data-multi-record-selection-check-action="' + CheckboxActions.checkAll + '"]'
383
+ ].join(' '));
384
+
385
+ if (checkAll !== null) {
386
+ checkAll.disabled = !MultiRecordSelection.getCheckboxes(CheckboxState.unchecked, identifier).length;
387
+ }
388
+
389
+ const checkNone: HTMLButtonElement = document.querySelector([
390
+ MultiRecordSelection.getCombinedSelector(MultiRecordSelectionSelectors.checkboxActionsSelector, identifier),
391
+ 'button[data-multi-record-selection-check-action="' + CheckboxActions.checkNone + '"]'
392
+ ].join(' '));
393
+
394
+ if (checkNone !== null) {
395
+ checkNone.disabled = !MultiRecordSelection.getCheckboxes(CheckboxState.checked, identifier).length;
396
+ }
397
+
398
+ const toggle: HTMLButtonElement = document.querySelector([
399
+ MultiRecordSelection.getCombinedSelector(MultiRecordSelectionSelectors.checkboxActionsSelector, identifier),
400
+ 'button[data-multi-record-selection-check-action="' + CheckboxActions.toggle + '"]'
401
+ ].join(' '));
402
+
403
+ if (toggle !== null) {
404
+ toggle.disabled = !MultiRecordSelection.getCheckboxes(CheckboxState.any, identifier).length;
405
+ }
406
+ }).delegateTo(document, MultiRecordSelectionSelectors.checkboxActionsToggleSelector);
407
+ }
408
+
409
+ private handleCheckboxKeyboardActions(e: PointerEvent, target: HTMLInputElement, cleanUpState: boolean = true): void {
410
+ const identifier: string = MultiRecordSelection.getIdentifier(target);
411
+
412
+ // If lastChecked is not set, does no longer exist in visible DOM (e.g. because the list is paginated
413
+ // and lastChecked is on a prev/next page), is not in the same table as current target (according to
414
+ // the identifier) or no shortcut is used at all, add the current target as lastChecked and return.
415
+ if (!this.lastChecked
416
+ || !document.body.contains(this.lastChecked)
417
+ || MultiRecordSelection.getIdentifier(this.lastChecked) !== identifier
418
+ || (!e.shiftKey && !e.altKey && !e.ctrlKey)
419
+ ) {
420
+ this.lastChecked = target;
421
+ return;
422
+ }
423
+
424
+ if (cleanUpState) {
425
+ // In case clean up is *NOT* prevented, unset manually changed attribute.
426
+ // Usually clean up will be prevented by actions, which have already
427
+ // performed checkbox change operations.
428
+ MultiRecordSelection.unsetManuallyChangedAttribute(identifier);
429
+ }
430
+
431
+ // With the shift key, it's possible to check / uncheck a range of checkboxes
432
+ if (e.shiftKey) {
433
+ // To easily calculate the start and end position we need checkboxes as an array
434
+ const checkboxes: Array<HTMLInputElement> = Array.from(MultiRecordSelection.getCheckboxes(CheckboxState.any, identifier));
435
+ // The current target is the start position
436
+ const start = checkboxes.indexOf(target);
437
+ // The last manually clicked / checked checkbox is the end
438
+ const end = checkboxes.indexOf(this.lastChecked);
439
+ // Get the checkboxes which should be changed (we use min() and max() to allow ranges in both directions)
440
+ const checkboxesToChange = checkboxes.slice(Math.min(start, end), Math.max(start, end) + 1);
441
+ checkboxesToChange.forEach((checkbox: HTMLInputElement): void => {
442
+ // Change the state of each checkbox in question. Do not change the current target since we
443
+ // use it's current checked state, making both "check all" and "uncheck all" possible.
444
+ if (checkbox !== target) {
445
+ MultiRecordSelection.changeCheckboxState(checkbox, target.checked);
446
+ }
447
+ });
448
+ }
449
+
450
+ // We can now store the current target as lastChecked so it can be used in the next run
451
+ this.lastChecked = target;
452
+
453
+ // With the alt or ctrl key, it's possible to toggle the current selection
454
+ if (e.altKey || e.ctrlKey) {
455
+ MultiRecordSelection.getCheckboxes(CheckboxState.any, identifier).forEach((checkbox: HTMLInputElement): void => {
456
+ // Toggle all checkboxes except the current target as this was already done by clicking on it
457
+ if (checkbox !== target) {
458
+ MultiRecordSelection.changeCheckboxState(checkbox, !checkbox.checked);
459
+ }
460
+ });
461
+ }
462
+
463
+ // To prevent possible side effects we simply clean up and unset the attribute here again
464
+ MultiRecordSelection.unsetManuallyChangedAttribute(identifier);
465
+ }
466
+ }
467
+
468
+ export default new MultiRecordSelection();