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,36 @@
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 LinkBrowser from './link-browser';
15
+ import RegularEvent from '@typo3/core/event/regular-event';
16
+
17
+ /**
18
+ * Module: @typo3/backend/url-link-handler
19
+ * @exports @typo3/backend/url-link-handler
20
+ * URL link interaction
21
+ */
22
+ class UrlLinkHandler {
23
+ constructor() {
24
+ new RegularEvent('submit', (evt: MouseEvent, targetEl: HTMLElement): void => {
25
+ evt.preventDefault();
26
+ const inputField = targetEl.querySelector('[name="lurl"]') as HTMLInputElement;
27
+ const value = inputField.value.trim();
28
+ if (value === '') {
29
+ return;
30
+ }
31
+ LinkBrowser.finalizeFunction(value);
32
+ }).delegateTo(document, '#lurlform');
33
+ }
34
+ }
35
+
36
+ export default new UrlLinkHandler();
@@ -0,0 +1,255 @@
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 Login from './login';
15
+ import RegularEvent from '@typo3/core/event/regular-event';
16
+ import DocumentService from '@typo3/core/document-service';
17
+
18
+ /**
19
+ * Module: @typo3/backend/user-pass-login
20
+ * JavaScript module for the UsernamePasswordLoginProvider
21
+ * @exports @typo3/backend/user-pass-login
22
+ */
23
+ class UserPassLogin {
24
+ protected options: any;
25
+
26
+ constructor() {
27
+ this.init();
28
+ }
29
+
30
+ private async init(): Promise<void> {
31
+ await DocumentService.ready();
32
+ this.options = {
33
+ usernameField: '.t3js-login-username-field',
34
+ passwordField: '.t3js-login-password-field',
35
+ copyrightLink: '.t3js-login-copyright-link',
36
+ };
37
+ const usernameField: HTMLInputElement = document.querySelector(this.options.usernameField);
38
+ const passwordField: HTMLInputElement = document.querySelector(this.options.passwordField);
39
+ const copyrightLink: HTMLInputElement = document.querySelector(this.options.copyrightLink);
40
+
41
+ // register submit handler
42
+ Login.options.submitHandler = this.resetPassword;
43
+
44
+ [usernameField, passwordField].forEach((field: HTMLInputElement) => new RegularEvent('keypress', this.showCapslockWarning).bindTo(field));
45
+ ['input', 'change'].forEach((eventName: string) => new RegularEvent(eventName, this.showPasswordToggle).bindTo(passwordField));
46
+ new RegularEvent('keydown', this.toggleCopyright).bindTo(copyrightLink);
47
+
48
+ // if the login screen is shown in the login_frameset window for re-login,
49
+ // then try to get the username of the current/former login from opening windows main frame:
50
+ if (parent.opener?.TYPO3?.configuration?.username) {
51
+ usernameField.value = parent.opener.TYPO3.configuration.username;
52
+ }
53
+
54
+ if (usernameField.value === '') {
55
+ usernameField.focus();
56
+ } else {
57
+ passwordField.focus();
58
+ }
59
+ }
60
+
61
+ /**
62
+ * Checks whether capslock is enabled (returns TRUE if enabled, false otherwise)
63
+ * thanks to http://24ways.org/2007/capturing-caps-lock
64
+ *
65
+ * @param {Event} e
66
+ * @returns {boolean}
67
+ */
68
+ private isCapslockEnabled(e: any): boolean {
69
+ const ev = e ? e : window.event;
70
+ if (!ev) {
71
+ return false;
72
+ }
73
+ // get key pressed
74
+ let pressedKeyAsciiCode = -1;
75
+ if (ev.which) {
76
+ pressedKeyAsciiCode = ev.which;
77
+ } else if (ev.keyCode) {
78
+ pressedKeyAsciiCode = ev.keyCode;
79
+ }
80
+ // get shift status
81
+ let shiftPressed = false;
82
+ if (ev.shiftKey) {
83
+ shiftPressed = ev.shiftKey;
84
+ } else if (ev.modifiers) {
85
+ /* tslint:disable:no-bitwise */
86
+ shiftPressed = !!(ev.modifiers & 4);
87
+ }
88
+ return (pressedKeyAsciiCode >= 65 && pressedKeyAsciiCode <= 90 && !shiftPressed)
89
+ || (pressedKeyAsciiCode >= 97 && pressedKeyAsciiCode <= 122 && shiftPressed);
90
+ }
91
+
92
+ /**
93
+ * Reset user password field to prevent it from being submitted
94
+ */
95
+ private readonly resetPassword = (): void => {
96
+ const passwordField: HTMLInputElement = document.querySelector(this.options.passwordField);
97
+ if (passwordField === null || passwordField.value === '') {
98
+ return;
99
+ }
100
+ const userIndent: HTMLInputElement = document.querySelector(Login.options.useridentField);
101
+ if (userIndent) {
102
+ userIndent.value = passwordField.value;
103
+ }
104
+ passwordField.value = '';
105
+ };
106
+
107
+ /**
108
+ * Toggle copyright
109
+ */
110
+ private readonly toggleCopyright = (event: KeyboardEvent): void => {
111
+ if (event.key === ' ') {
112
+ (event.target as HTMLLinkElement).click();
113
+ }
114
+ };
115
+
116
+ /**
117
+ * Capslock handling
118
+ */
119
+ private readonly attachCapslockWarning = (element: HTMLInputElement, label: string, message: string) => {
120
+ const targetContainer = element.closest('.input-group');
121
+ if (!targetContainer) {
122
+ return;
123
+ }
124
+
125
+ if (targetContainer.querySelector('.input-group-text-warning-capslock')) {
126
+ return;
127
+ }
128
+
129
+ const parentElement = element.parentElement;
130
+
131
+ // create icon
132
+ const warningIcon = `
133
+ <span class="icon icon-size-small icon-state-default">
134
+ <span class="icon-markup">
135
+ <svg xmlns="http://www.w3.org/2000/svg" viewBox="0 0 16 16"><g fill="currentColor"><path d="m8 5.414 3.536 3.536.707-.707L8 4 3.757 8.243l.707.707L8 5.414zM4 11h8v1H4z"/></g></svg>
136
+ </span>
137
+ </span>
138
+ `;
139
+
140
+ // create message
141
+ const warningMessage = document.createElement('span');
142
+ warningMessage.classList.add('visually-hidden');
143
+ warningMessage.textContent = message;
144
+
145
+ // create element
146
+ const warningElement = document.createElement('span');
147
+ warningElement.classList.add('input-group-text', 'input-group-text-warning' ,'input-group-text-warning-capslock');
148
+ warningElement.role = 'status';
149
+ warningElement.innerHTML = warningIcon;
150
+ warningElement.title = label;
151
+ warningElement.appendChild(warningMessage);
152
+
153
+ if (parentElement.classList.contains('form-control-clearable-wrapper')) {
154
+ parentElement.insertAdjacentElement('afterend', warningElement);
155
+ return;
156
+ }
157
+
158
+ element.insertAdjacentElement('afterend', warningElement);
159
+ };
160
+
161
+ private readonly removeCapslockWarning = (element: HTMLInputElement) => {
162
+ const targetContainer = element.closest('.input-group');
163
+ if (!targetContainer) {
164
+ return;
165
+ }
166
+
167
+ const warningElement = targetContainer.querySelector('.input-group-text-warning-capslock');
168
+ if (!warningElement) {
169
+ return;
170
+ }
171
+
172
+ warningElement.remove();
173
+ };
174
+
175
+ private readonly showCapslockWarning = (event: Event): void => {
176
+ const targetElement = (event.target as HTMLInputElement);
177
+ const title = targetElement.dataset.capslockwarningTitle;
178
+ const message = targetElement.dataset.capslockwarningMessage;
179
+
180
+ if (this.isCapslockEnabled(event)) {
181
+ this.attachCapslockWarning(targetElement, title, message);
182
+ } else {
183
+ this.removeCapslockWarning(targetElement);
184
+ }
185
+ };
186
+
187
+ /**
188
+ * Password toggle handling
189
+ */
190
+ private readonly attachPasswordToggle = (element: HTMLInputElement) => {
191
+ const container = element.closest('.input-group');
192
+ if (!container) {
193
+ return;
194
+ }
195
+
196
+ if (container.querySelector('.t3js-login-toggle-password')) {
197
+ return;
198
+ }
199
+
200
+ // icon
201
+ const icon = `
202
+ <span class="icon icon-size-small icon-state-default">
203
+ <span class="icon-markup">
204
+ <svg xmlns="http://www.w3.org/2000/svg" viewBox="0 0 16 16"><g fill="currentColor"><path d="M8.07 3C4.112 3 1 5.286 1 8s2.97 5 7 5c3.889 0 7-2.286 7-4.93C15 5.285 11.889 3.142 8.212 3h-.141Zm-.025 1.127c.141 0 .423.141.423.282s-.14.282-.423.282c-.845 0-1.69.704-1.69 1.55 0 .14-.141.282-.423.282-.282 0-.423-.141-.423-.282.141-1.127 1.268-2.114 2.536-2.114ZM2 8.03c0-1.298 1.017-2.591 2.647-3.312-.296.432-.296 1.01-.296 1.587 0 2.02 1.63 3.606 3.703 3.606 2.074 0 3.704-1.587 3.704-3.606 0-.577-.148-1.01-.296-1.443C12.943 5.582 14 6.875 14 8.029c-.148 2.02-2.841 3.924-6 3.971-3.36-.047-6-1.95-6-3.97Z"/></g></svg>
205
+ </span>
206
+ </span>
207
+ `;
208
+
209
+ // button
210
+ const button = document.createElement('button');
211
+ button.type = 'button';
212
+ button.classList.add('btn', 'btn-default', 't3js-login-toggle-password');
213
+ button.ariaLabel = element.dataset.passwordtoggleLabel ?? '';
214
+ button.innerHTML = icon;
215
+
216
+ button.addEventListener('click', () => {
217
+ if (button.classList.contains('active')) {
218
+ button.classList.remove('active');
219
+ element.type = 'password';
220
+ } else {
221
+ button.classList.add('active');
222
+ element.type = 'text';
223
+ }
224
+ });
225
+
226
+ container.insertAdjacentElement('beforeend', button);
227
+ };
228
+
229
+ private readonly removePasswordToggle = (element: HTMLInputElement) => {
230
+ const container = element.closest('.input-group');
231
+ if (!container) {
232
+ return;
233
+ }
234
+
235
+ const button = container.querySelector('.t3js-login-toggle-password');
236
+ if (!button) {
237
+ return;
238
+ }
239
+
240
+ button.remove();
241
+ element.type = 'password';
242
+ };
243
+
244
+ private readonly showPasswordToggle = (event: Event): void => {
245
+ const passwordField: HTMLInputElement = (event.target as HTMLInputElement);
246
+ if (passwordField.value === '') {
247
+ this.removePasswordToggle(passwordField);
248
+ return;
249
+ } else {
250
+ this.attachPasswordToggle(passwordField);
251
+ }
252
+ };
253
+ }
254
+
255
+ export default new UserPassLogin();
@@ -0,0 +1,189 @@
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 { BroadcastMessage, type BroadcastEvent } from '@typo3/backend/broadcast-message';
15
+ import BroadcastService from '@typo3/backend/broadcast-service';
16
+
17
+ enum Identifier {
18
+ colorSchemeSwitch = 'typo3-backend-color-scheme-switch',
19
+ }
20
+
21
+ export type ColorScheme = 'auto' | 'light' | 'dark';
22
+ export type Theme = 'modern' | 'classic';
23
+ export type TitleFormat = 'titleFirst' | 'sitenameFirst';
24
+ export type Direction = 'rtl' | null;
25
+
26
+ // Event for typo3:color-scheme:update and typo3:color-scheme:broadcast
27
+ export interface ColorSchemeUpdateEventData {
28
+ colorScheme: ColorScheme;
29
+ }
30
+
31
+ // Event for typo3:theme:update and typo3:theme:broadcast
32
+ export interface ThemeUpdateEventData {
33
+ theme: Theme;
34
+ }
35
+
36
+ // Event for typo3:title-format:update and typo3:title-format:broadcast
37
+ export interface TitleFormatUpdateEventData {
38
+ format: TitleFormat;
39
+ }
40
+
41
+ // Event for typo3:backend-language:update and typo3:backend-language:broadcast
42
+ export interface BackendLanguageUpdateEventData {
43
+ language: string;
44
+ direction: Direction;
45
+ }
46
+
47
+ class UserSettingsManager {
48
+ constructor() {
49
+ // triggered by
50
+ // * <typo3-backend-color-scheme-switch> (topbar) or
51
+ // * User setup module (via BackendUtility::setUpdateSignal('updateColorScheme', …))
52
+ document.addEventListener('typo3:color-scheme:update', e => this.onColorSchemeUpdate(e.detail));
53
+ // triggered by user setup module (via BackendUtility::setUpdateSignal('updateColorScheme', …))
54
+ document.addEventListener('typo3:theme:update', e => this.onThemeUpdate(e.detail));
55
+ // triggered by user setup module (via BackendUtility::setUpdateSignal('updateTitleFormat', …))
56
+ document.addEventListener('typo3:title-format:update', e => this.onTitleFormatUpdate(e.detail));
57
+ // triggered by user setup module (via BackendUtility::setUpdateSignal('updateBackendLanguage', …))
58
+ document.addEventListener('typo3:backend-language:update', e => this.onBackendLanguageFormatUpdate(e.detail));
59
+
60
+ // broadcast message by other instances
61
+ document.addEventListener('typo3:color-scheme:broadcast', e => this.activateColorScheme(e.detail.payload.colorScheme));
62
+ document.addEventListener('typo3:theme:broadcast', e => this.activateTheme(e.detail.payload.theme));
63
+ document.addEventListener('typo3:title-format:broadcast', e => this.activateTitleFormat(e.detail.payload.format));
64
+ document.addEventListener('typo3:backend-language:broadcast', e => this.updateBackendLanguage(e.detail.payload.language, e.detail.payload.direction));
65
+ }
66
+
67
+ private onColorSchemeUpdate(data: ColorSchemeUpdateEventData) {
68
+ const { colorScheme } = data;
69
+ this.activateColorScheme(colorScheme);
70
+
71
+ // broadcast to other instances
72
+ BroadcastService.post(new BroadcastMessage<ColorSchemeUpdateEventData>('color-scheme', 'broadcast', { colorScheme }));
73
+ }
74
+
75
+ private onThemeUpdate(data: ThemeUpdateEventData) {
76
+ const { theme } = data;
77
+ this.activateTheme(theme);
78
+
79
+ // broadcast to other instances
80
+ BroadcastService.post(new BroadcastMessage<ThemeUpdateEventData>('theme', 'broadcast', { theme }));
81
+ }
82
+
83
+ private onTitleFormatUpdate(data: TitleFormatUpdateEventData) {
84
+ const { format } = data;
85
+ this.activateTitleFormat(format);
86
+
87
+ // broadcast to other instances
88
+ BroadcastService.post(new BroadcastMessage<TitleFormatUpdateEventData>('title-format', 'broadcast', { format }));
89
+ }
90
+
91
+ private onBackendLanguageFormatUpdate(data: BackendLanguageUpdateEventData) {
92
+ const { language, direction } = data;
93
+ this.updateBackendLanguage(language, direction);
94
+
95
+ // broadcast to other instances
96
+ BroadcastService.post(new BroadcastMessage<BackendLanguageUpdateEventData>('language-update', 'broadcast', { language, direction }));
97
+ }
98
+
99
+ private activateColorScheme(colorScheme: ColorScheme) {
100
+ const colorSchemeSwitch = document.querySelector(Identifier.colorSchemeSwitch);
101
+ if (colorSchemeSwitch) {
102
+ colorSchemeSwitch.activeColorScheme = colorScheme;
103
+ }
104
+ this.setStyleChangingDocumentAttribute('data-color-scheme', colorScheme);
105
+ }
106
+
107
+ private activateTheme(theme: Theme) {
108
+ this.setStyleChangingDocumentAttribute('data-theme', theme);
109
+ }
110
+
111
+ private activateTitleFormat(format: TitleFormat) {
112
+ if (format === 'sitenameFirst') {
113
+ document.querySelector('typo3-backend-module-router')?.setAttribute('sitename-first', '');
114
+ } else {
115
+ document.querySelector('typo3-backend-module-router')?.removeAttribute('sitename-first');
116
+ }
117
+ }
118
+
119
+ private updateBackendLanguage(language: string, direction: Direction): void {
120
+ const rootEl = document.documentElement;
121
+ const frame = window.frames.list_frame?.document.documentElement;
122
+
123
+ rootEl.setAttribute('lang', language);
124
+ frame?.setAttribute('lang', language);
125
+ if (direction !== null) {
126
+ rootEl.setAttribute('dir', direction);
127
+ frame?.setAttribute('dir', direction);
128
+ } else {
129
+ rootEl.removeAttribute('dir');
130
+ frame?.removeAttribute('dir');
131
+ }
132
+ }
133
+
134
+ private async setStyleChangingDocumentAttribute(attributeName: string, attributeValue: string) {
135
+ const rootEl = document.documentElement;
136
+ const frame = window.frames.list_frame?.document.documentElement;
137
+
138
+ const action = () => {
139
+ rootEl.classList.add('t3js-disable-transitions');
140
+ frame?.classList.add('t3js-disable-transitions');
141
+
142
+ rootEl.setAttribute(attributeName, attributeValue);
143
+ frame?.setAttribute(attributeName, attributeValue);
144
+ };
145
+
146
+ const cleanup = () => {
147
+ rootEl.classList.remove('t3js-disable-transitions');
148
+ frame?.classList.remove('t3js-disable-transitions');
149
+ };
150
+
151
+
152
+ if (
153
+ window.matchMedia('(prefers-reduced-motion: reduce)').matches ||
154
+ // The fallback condition in the next line (currently needed for firefox) can be removed
155
+ // once view transitions enter baseline "Widely available":
156
+ // https://webstatus.dev/features/view-transitions?q=view+transition
157
+ !('startViewTransition' in document) || typeof document.startViewTransition !== 'function'
158
+ ) {
159
+ action();
160
+
161
+ // await animation frame in order for the transition disable to be
162
+ // considered by the time the change-transitions are being started.
163
+ await new Promise(resolve => requestAnimationFrame(resolve));
164
+ if (frame) {
165
+ await new Promise(resolve => window.frames.list_frame.requestAnimationFrame(resolve));
166
+ }
167
+ cleanup();
168
+ return;
169
+ }
170
+
171
+ await document.startViewTransition(action).finished;
172
+ cleanup();
173
+ }
174
+ }
175
+
176
+ export default new UserSettingsManager();
177
+
178
+ declare global {
179
+ interface DocumentEventMap {
180
+ 'typo3:color-scheme:update': CustomEvent<ColorSchemeUpdateEventData>;
181
+ 'typo3:color-scheme:broadcast': BroadcastEvent<ColorSchemeUpdateEventData>;
182
+ 'typo3:theme:update': CustomEvent<ThemeUpdateEventData>;
183
+ 'typo3:theme:broadcast': BroadcastEvent<ThemeUpdateEventData>;
184
+ 'typo3:title-format:update': CustomEvent<TitleFormatUpdateEventData>;
185
+ 'typo3:title-format:broadcast': BroadcastEvent<TitleFormatUpdateEventData>;
186
+ 'typo3:backend-language:update': CustomEvent<BackendLanguageUpdateEventData>;
187
+ 'typo3:backend-language:broadcast': BroadcastEvent<BackendLanguageUpdateEventData>;
188
+ }
189
+ }
@@ -0,0 +1,205 @@
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 Client from '@typo3/backend/storage/client';
15
+ import DocumentService from '@typo3/core/document-service';
16
+ import RegularEvent from '@typo3/core/event/regular-event';
17
+
18
+ /**
19
+ * Utility class to store a collapsible state in the localStorage and to re-apply states.
20
+ * It uses the collapsible id to store the keys, which must be unique.
21
+ *
22
+ * Trigger state persisting by adding 'data-persist-collapse-state="true"' to a collapsible element.
23
+ *
24
+ * To improve performance when dealing with bigger trees:
25
+ * * A 'data-persist-collapse-state-suffix="some-suffix"' on each collapsible element can be defined: This
26
+ * specifies a local storage key instead of "general", states are then stored in this key. This is useful
27
+ * when bigger tree states are stored, moving them to a dedicated local storage key. Default is suffix "global".
28
+ * * A 'data-persist-collapse-state-if-state="shown"' (allowed values "shown" and "hidden"):
29
+ * Usually, both "collapsed" and "shown" states are stored in local storage. However, when a tree is rendered
30
+ * "hidden" or "shown" by default from Fluid, we only need the "opposite" state in local storage. It is good practice
31
+ * to set this to safe local storage space.
32
+ *
33
+ * When dealing with bigger treas, some of them may be search-aware: This is related to 'collapse-state-search.ts',
34
+ * which expands search matches in a tree. We usually do not want to persist collapse / expand state when a search is
35
+ * performed, since this is done by the search javascript. Instead, we want to go back to the previous expand/collapse
36
+ * state when a search value is cleared. To do this, an expand/collapse field can set 'data-persist-collapse-state-not-if-search="true"',
37
+ * which will suppress storing expand/collapse state from/to local storage if a search value is given.
38
+ * When the search value is cleared (empty string), the current expand/collapse state are applied again due to
39
+ * a submit event fired by 'collapse-state-search.ts', so this state class can re-create the expand/collapse state before
40
+ * a search keyword has been given. A search input field needs the attribute 'data-persist-collapse-search-key="some-search-key"'
41
+ * which points to the local storage key of the search term, plus class "t3js-collapse-search-term" to trigger all this search magic.
42
+ *
43
+ * @internal
44
+ */
45
+ type PersistStateObject = { [key: string]: boolean };
46
+
47
+ export class CollapseStatePersister {
48
+ private readonly localStorageKey: string = 'collapse-states-';
49
+ private readonly localStorageKeyDefaultSuffix: string = 'general';
50
+ private readonly searchValueSelector: string = '.t3js-collapse-search-term';
51
+ private searchField: HTMLInputElement|null = null;
52
+ private searchForm: HTMLFormElement|null = null;
53
+
54
+ private readonly stateCache: Map<string, PersistStateObject>;
55
+
56
+ public constructor() {
57
+ this.stateCache = new Map();
58
+
59
+ DocumentService.ready().then((): void => {
60
+ this.searchField = document.querySelector(this.searchValueSelector);
61
+ if (this.searchField !== null) {
62
+ this.searchForm = this.searchField.closest('form');
63
+ this.searchField.value = Client.get(this.searchField.dataset.persistCollapseSearchKey) ?? '';
64
+ }
65
+ this.registerEventListener();
66
+ this.recoverStates();
67
+ });
68
+ }
69
+
70
+ private registerEventListener(): void {
71
+ const delegateEventTo: string = '.collapse[data-persist-collapse-state="true"]';
72
+
73
+ new RegularEvent('show.bs.collapse', (e: Event): void => {
74
+ const element: HTMLElement = e.target as HTMLElement;
75
+ if (element.dataset.persistCollapseState === 'true'
76
+ && ((this.searchField !== null && this.searchField.value === '') || element.dataset.persistCollapseStateNotIfSearch === undefined)
77
+ ) {
78
+ // Persist state only, if there is no search input field, or no search is performed
79
+ this.toStorage(element, true);
80
+ }
81
+ }).delegateTo(document, delegateEventTo);
82
+
83
+ new RegularEvent('hide.bs.collapse', (e: Event): void => {
84
+ const element: HTMLElement = e.target as HTMLElement;
85
+ if (element.dataset.persistCollapseState === 'true'
86
+ && ((this.searchField !== null && this.searchField.value === '') || element.dataset.persistCollapseStateNotIfSearch === undefined)
87
+ ) {
88
+ // Persist state only, if there is no search input field, or no search is performed
89
+ this.toStorage(element, false);
90
+ }
91
+ }).delegateTo(document, delegateEventTo);
92
+
93
+ if (this.searchForm !== null) {
94
+ new RegularEvent('submit', (e: SubmitEvent): void => {
95
+ e.preventDefault();
96
+ if (this.searchField !== null && this.searchField.value === '') {
97
+ this.recoverStates();
98
+ }
99
+ }).bindTo(this.searchForm);
100
+ }
101
+ }
102
+
103
+ private recoverStates(): void {
104
+ const collapseStateElements: NodeListOf<HTMLElement>|null = document.querySelectorAll('.collapse[data-persist-collapse-state="true"]');
105
+ collapseStateElements.forEach((element: HTMLElement) => {
106
+ const suffix: string = element.dataset.persistCollapseStateSuffix ?? this.localStorageKeyDefaultSuffix;
107
+ const currentStates = this.fromStorage(suffix);
108
+ const id: string = element.id;
109
+ if (id === '' || !this.shallRecoverState(element)) {
110
+ return;
111
+ }
112
+ const storeExpandedState = (element.dataset.persistCollapseStateIfState ?? 'shown') === 'shown';
113
+ const storeHiddenState = (element.dataset.persistCollapseStateIfState ?? 'hidden') === 'hidden';
114
+ const isExpanded = element.classList.contains('show');
115
+ if (storeExpandedState === true) {
116
+ // We're not using BootstrapCollapse.getOrCreateInstance() since this is too slow when
117
+ // dealing with many elements like with System > Configuration with TCA tree.
118
+ if (currentStates[id] === true) {
119
+ if (!isExpanded) {
120
+ const toggle: HTMLElement = document.querySelector('[data-bs-target="#' + id + '"]');
121
+ toggle.classList.remove('collapsed');
122
+ toggle.setAttribute('aria-expanded', 'true');
123
+ element.classList.add('show');
124
+ }
125
+ } else {
126
+ if (isExpanded) {
127
+ const toggle: HTMLElement = document.querySelector('[data-bs-target="#' + id + '"]');
128
+ toggle.classList.add('collapsed');
129
+ toggle.setAttribute('aria-expanded', 'false');
130
+ element.classList.remove('show');
131
+ }
132
+ }
133
+ }
134
+ if (storeHiddenState === true) {
135
+ if (currentStates[id] === false) {
136
+ if (isExpanded) {
137
+ const toggle: HTMLElement = document.querySelector('[data-bs-target="#' + id + '"]');
138
+ toggle.classList.add('collapsed');
139
+ toggle.setAttribute('aria-expanded', 'false');
140
+ element.classList.remove('show');
141
+ }
142
+ } else {
143
+ if (!isExpanded) {
144
+ const toggle: HTMLElement = document.querySelector('[data-bs-target="#' + id + '"]');
145
+ toggle.classList.remove('collapsed');
146
+ toggle.setAttribute('aria-expanded', 'true');
147
+ element.classList.add('show');
148
+ }
149
+ }
150
+ }
151
+ });
152
+ }
153
+
154
+ private shallRecoverState(element: HTMLElement): boolean {
155
+ if (element.dataset.persistCollapseStateNotIfSearch === undefined
156
+ || element.dataset.persistCollapseStateNotIfSearch === 'false'
157
+ ) {
158
+ return true;
159
+ }
160
+ return this.searchField !== null && this.searchField.value === '';
161
+ }
162
+
163
+ private fromStorage(suffix: string): PersistStateObject {
164
+ let result;
165
+ if (this.stateCache.has(this.localStorageKey + suffix)) {
166
+ result = this.stateCache.get(this.localStorageKey + suffix);
167
+ } else {
168
+ const currentStates = Client.get(this.localStorageKey + suffix);
169
+ result = currentStates !== null ? JSON.parse(currentStates) : {};
170
+ this.stateCache.set(this.localStorageKey + suffix, result);
171
+ }
172
+ return result;
173
+ }
174
+
175
+ private toStorage(element: HTMLElement, expanded: boolean) {
176
+ const key = element.id;
177
+ const suffix = element.dataset.persistCollapseStateSuffix ?? this.localStorageKeyDefaultSuffix;
178
+ const currentStates = this.fromStorage(suffix);
179
+ const storeExpandedState = (element.dataset.persistCollapseStateIfState ?? 'shown') === 'shown';
180
+ const storeHiddenState = (element.dataset.persistCollapseStateIfState ?? 'hidden') === 'hidden';
181
+ if (expanded === true && storeExpandedState === true && currentStates[key] !== true) {
182
+ currentStates[key] = true;
183
+ this.updateStates(this.localStorageKey + suffix, currentStates);
184
+ }
185
+ if (expanded === true && storeHiddenState === true && currentStates[key] === false) {
186
+ delete currentStates[key];
187
+ this.updateStates(this.localStorageKey + suffix, currentStates);
188
+ }
189
+ if (expanded === false && storeHiddenState === true && currentStates[key] !== false) {
190
+ currentStates[key] = false;
191
+ this.updateStates(this.localStorageKey + suffix, currentStates);
192
+ }
193
+ if (expanded === false && storeExpandedState === true && currentStates[key] === true) {
194
+ delete currentStates[key];
195
+ this.updateStates(this.localStorageKey + suffix, currentStates);
196
+ }
197
+ }
198
+
199
+ private updateStates(key: string, currentStates: PersistStateObject) {
200
+ Client.set(key, JSON.stringify(currentStates));
201
+ this.stateCache.set(key, currentStates);
202
+ }
203
+ }
204
+
205
+ export default new CollapseStatePersister();