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,2104 @@
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
+ /**
15
+ * Module: @typo3/form/backend/form-editor/core
16
+ */
17
+ import $ from 'jquery';
18
+
19
+ export type EditorConfiguration = {
20
+ identifier: string,
21
+ additionalElementPropertyPaths?: string[],
22
+ browsableType?: string,
23
+ buttonLabel?: string,
24
+ configurationOptions?: {
25
+ numbersOfColumnsToUse?: {
26
+ label: string,
27
+ propertyPath: string,
28
+ fieldExplanationText: string,
29
+ },
30
+ validationErrorMessage?: {
31
+ label: string,
32
+ propertyPath: string,
33
+ fieldExplanationText?: string,
34
+ errorCodes?: string[]
35
+ },
36
+ viewPorts?: Array<{
37
+ viewPortIdentifier: string,
38
+ label: string
39
+ }>
40
+ },
41
+ doNotSetIfPropertyValueIsEmpty?: boolean,
42
+ enableAddRow?: boolean,
43
+ enableDeleteRow?: boolean,
44
+ enableFormelementSelectionButton?: boolean,
45
+ errorCodes?: string[],
46
+ fieldExplanationText?: string,
47
+ gridColumns?: Array<{
48
+ name: string,
49
+ title: string,
50
+ }>,
51
+ iconIdentifier?: string,
52
+ isSortable?: boolean,
53
+ label?: string,
54
+ multiSelection?: boolean,
55
+ placeholder?: string,
56
+ propertyPath?: string,
57
+ propertyValue?: string,
58
+ propertyValidators?: ValidatorsConfig,
59
+ propertyValidatorsMode?: 'OR' | 'AND',
60
+ removeLastAvailableRowFlashMessageTitle?: string,
61
+ removeLastAvailableRowFlashMessageMessage?: string,
62
+ selectOptions?: Array<{
63
+ value: string,
64
+ label: string,
65
+ }>
66
+ templateName?: string,
67
+ useLabelAsFallbackValue?: boolean,
68
+ validatorIdentifier?: string,
69
+ };
70
+
71
+ export type BaseFormElementDefinition = {
72
+ type: string,
73
+ identifier: string,
74
+ label: string,
75
+ group?: string,
76
+ renderables?: FormElementDefinition[]
77
+ groupSorting?: number,
78
+ iconIdentifier?: string,
79
+ predefinedDefaults?: Record<string, unknown>,
80
+ editors?: Array<EditorConfiguration>
81
+ propertyCollections?: {
82
+ // @todo: be explicit about key being 'finishers' | 'validators' (?)
83
+ [key: string]: Array<{
84
+ identifier: string,
85
+ editors: Array<EditorConfiguration>
86
+ }>
87
+ },
88
+ _isTopLevelFormElement?: boolean,
89
+ _isCompositeFormElement?: boolean,
90
+ _isGridRowFormElement?: boolean,
91
+ };
92
+
93
+ type RootFormElementDefinition = {
94
+ inspectorEditorFormElementSelectorNoElements: string,
95
+ modalCloseCancelButton: string,
96
+ modalCloseConfirmButton: string,
97
+ modalCloseDialogMessage: string,
98
+ modalCloseDialogTitle: string,
99
+ modalInsertElementsDialogTitle: string,
100
+ modalInsertPagesDialogTitle: string,
101
+ modalRemoveElementCancelButton: string,
102
+ modalRemoveElementConfirmButton: string,
103
+ modalRemoveElementDialogMessage: string,
104
+ modalRemoveElementDialogTitle: string,
105
+ modalRemoveElementLastAvailablePageFlashMessageMessage: string,
106
+ modalRemoveElementLastAvailablePageFlashMessageTitle: string,
107
+ modalValidationErrorsConfirmButton: string,
108
+ modalValidationErrorsDialogTitle: string,
109
+ paginationTitle: string,
110
+ saveErrorFlashMessageMessage: string,
111
+ saveErrorFlashMessageTitle: string,
112
+ saveSuccessFlashMessageMessage: string,
113
+ saveSuccessFlashMessageTitle: string,
114
+ };
115
+
116
+ export type FormElementDefinition = BaseFormElementDefinition & Partial<RootFormElementDefinition>;
117
+
118
+ export interface AjaxRequests {
119
+ saveForm?: JQueryXHR;
120
+ renderFormDefinitionPage?: JQueryXHR;
121
+ }
122
+
123
+ export interface Endpoints {
124
+ saveForm?: string;
125
+ formPageRenderer?: string;
126
+ }
127
+
128
+ export type FinisherDefinition = {
129
+ label: string
130
+ iconIdentifier?: string,
131
+ predefinedDefaults?: Record<string, unknown>,
132
+ };
133
+
134
+ export type FormElementPropertyValidatorDefinition = {
135
+ errorMessage: string
136
+ };
137
+
138
+ type ValidatorDefinition = {
139
+ label: string
140
+ iconIdentifier?: string,
141
+ };
142
+
143
+ export type FormEditorDefinitions = {
144
+ finishers: Record<string, FinisherDefinition>,
145
+ formElementPropertyValidators: Record<string, FormElementPropertyValidatorDefinition>
146
+ formElements: Record<string, FormElementDefinition>
147
+ validators: Record<string, ValidatorDefinition>
148
+ };
149
+
150
+ type ModelData<T extends object> = T & {
151
+ __parentRenderable: FormElement,
152
+ __identifierPath: string,
153
+ renderables: boolean | null | Array<Model<T, ModelData<T>>>
154
+ };
155
+
156
+ type PartialFormElementModelData = Partial<Omit<FormElementDefinition, 'renderables'>>;
157
+ type FormElementModelData = PartialFormElementModelData & ModelData<PartialFormElementModelData>;
158
+
159
+ export type FormElement = Model<PartialFormElementModelData, ModelData<PartialFormElementModelData>>;
160
+ export type RootFormElement = FormElement;
161
+
162
+ export type Validator = (formElement: FormElement, propertyPath: string) => string | undefined;
163
+
164
+ type ValidatorsConfig = string[];
165
+
166
+ type Validators = {
167
+ [key: string]: Validator;
168
+ };
169
+
170
+ export type ValidationResults = string[];
171
+
172
+ export type ValidationResultsWithPath = Array<{
173
+ propertyPath: string,
174
+ validationResults: ValidationResults,
175
+ }>;
176
+
177
+ export type ValidationResultsRecursive = Array<{
178
+ formElementIdentifierPath: string,
179
+ validationResults: ValidationResultsWithPath,
180
+ }>;
181
+
182
+ type PropertyValidatorConfiguration = {
183
+ propertyValidatorsMode: 'OR' | 'AND';
184
+ };
185
+
186
+ export type CollectionEntry = {
187
+ identifier: string,
188
+ editors?: Array<EditorConfiguration>,
189
+ };
190
+
191
+ export type Collection = CollectionEntry[];
192
+
193
+ /* Factory */
194
+
195
+ // @todo
196
+ export type CollectionElementConfiguration = {
197
+ identifier: string,
198
+ };
199
+
200
+ // @todo
201
+ export type PropertyCollectionElement = CollectionElementConfiguration;
202
+
203
+ export interface ApplicationState {
204
+ formDefinition?: RootFormElement;
205
+ currentlySelectedPageIndex?: number;
206
+ currentlySelectedFormElementIdentifierPath?: string;
207
+ propertyValidationServiceRegisteredValidators?: Record<string, Record<string, {validators: ValidatorsConfig, configuration: PropertyValidatorConfiguration}>>
208
+ }
209
+ type ApplicationStateType = keyof ApplicationState;
210
+
211
+ type PublisherSubscriberTopic = keyof PublisherSubscriberTopicArgumentsMap;
212
+
213
+ interface PublisherSubscriberFunction<T extends PublisherSubscriberTopic> {
214
+ (topic: T, args: NoInfer<PublisherSubscriberTopicArgumentsMap[T]>): void;
215
+ }
216
+
217
+ interface PublisherSubscriberEntry<T extends PublisherSubscriberTopic> {
218
+ token: string
219
+ func: PublisherSubscriberFunction<T>,
220
+ }
221
+
222
+ type PublisherSubscriberTopics = {
223
+ [T in PublisherSubscriberTopic]: PublisherSubscriberEntry<T>[];
224
+ };
225
+
226
+ export function assert(test: boolean|(() => boolean), message: string, messageCode: number): void {
227
+ if (typeof test === 'function') {
228
+ test = (test() !== false);
229
+ }
230
+ if (!test) {
231
+ message = message || 'Assertion failed';
232
+ if (messageCode) {
233
+ message = message + ' (' + messageCode + ')';
234
+ }
235
+ if ('undefined' !== typeof Error) {
236
+ throw new Error(message);
237
+ }
238
+ throw message;
239
+ }
240
+ }
241
+
242
+ export class Utility {
243
+
244
+ public assert(test: boolean|(() => boolean), message: string, messageCode: number): void {
245
+ assert(test, message, messageCode);
246
+ }
247
+
248
+ public isUndefinedOrNull(value: Array<unknown> | object | undefined | null | string | number | boolean | symbol): boolean {
249
+ return value === undefined || value === null;
250
+ }
251
+
252
+ public isNonEmptyArray(value: Array<unknown> | object | undefined | null | string | number | boolean | symbol): boolean {
253
+ return Array.isArray(value) && value.length > 0;
254
+ }
255
+
256
+ public isNonEmptyString(value: Array<unknown> | object | undefined | null | string | number | boolean | symbol): boolean {
257
+ return typeof value === 'string' && value.length > 0;
258
+ }
259
+
260
+ public canBeInterpretedAsInteger(value: Array<unknown> | object | undefined | null | string | number | boolean | symbol): boolean {
261
+ if (typeof value === 'number') {
262
+ return true;
263
+ }
264
+
265
+ if (typeof value !== 'string') {
266
+ return false;
267
+ }
268
+
269
+ const v: string = value;
270
+ return (v as unknown as number * 1).toString() === v.toString() && v.toString().indexOf('.') === -1;
271
+ }
272
+
273
+ /**
274
+ * @throws 1475412569
275
+ * @throws 1475412570
276
+ * @throws 1475415988
277
+ * @throws 1475663210
278
+ */
279
+ public buildPropertyPath(
280
+ propertyPath: string,
281
+ collectionElementIdentifier: string,
282
+ collectionName: string,
283
+ formElement: FormElement,
284
+ allowEmptyReturnValue?: boolean
285
+ ): string {
286
+ let newPropertyPath = '';
287
+
288
+ allowEmptyReturnValue = !!allowEmptyReturnValue;
289
+ if (this.isNonEmptyString(collectionElementIdentifier) || this.isNonEmptyString(collectionName)) {
290
+ assert(this.isNonEmptyString(collectionElementIdentifier), 'Invalid parameter "collectionElementIdentifier"', 1475412569);
291
+ assert(this.isNonEmptyString(collectionName), 'Invalid parameter "collectionName"', 1475412570);
292
+ newPropertyPath = collectionName + '.' + repository.getIndexFromPropertyCollectionElementByIdentifier(collectionElementIdentifier, collectionName, formElement);
293
+ } else {
294
+ newPropertyPath = '';
295
+ }
296
+
297
+ if (!this.isUndefinedOrNull(propertyPath)) {
298
+ assert(this.isNonEmptyString(propertyPath), 'Invalid parameter "propertyPath"', 1475415988);
299
+ if (this.isNonEmptyString(newPropertyPath)) {
300
+ newPropertyPath = newPropertyPath + '.' + propertyPath;
301
+ } else {
302
+ newPropertyPath = propertyPath;
303
+ }
304
+ }
305
+
306
+ if (!allowEmptyReturnValue) {
307
+ assert(this.isNonEmptyString(newPropertyPath), 'The property path could not be resolved', 1475663210);
308
+ }
309
+ return newPropertyPath;
310
+ }
311
+
312
+ /**
313
+ * @throws 1475377782
314
+ */
315
+ public convertToSimpleObject(formElement: object): object {
316
+ assert('object' === $.type(formElement), 'Invalid parameter "formElement"', 1475377782);
317
+
318
+ const simpleObject: Record<string, unknown> & { renderables? : Array<object> } = {};
319
+ const objectData = ('getObjectData' in formElement && typeof formElement.getObjectData === 'function') ? formElement.getObjectData() : formElement;
320
+ const childFormElements = objectData.renderables;
321
+ delete objectData.renderables;
322
+
323
+ for (const [key, value] of Object.entries(objectData)) {
324
+ if (key.match(/^__/)) {
325
+ continue;
326
+ }
327
+
328
+ if (value !== null && typeof value === 'object' && !Array.isArray(value)) {
329
+ simpleObject[key] = this.convertToSimpleObject(value);
330
+ } else if ('function' !== $.type(value) && 'undefined' !== $.type(value)) {
331
+ simpleObject[key] = value;
332
+ }
333
+ }
334
+
335
+ if ('array' === $.type(childFormElements)) {
336
+ simpleObject.renderables = [];
337
+ for (let i = 0, len = childFormElements.length; i < len; ++i) {
338
+ simpleObject.renderables.push(this.convertToSimpleObject(childFormElements[i]));
339
+ }
340
+ }
341
+
342
+ return simpleObject;
343
+ }
344
+ }
345
+
346
+ export class PropertyValidationService {
347
+ private validators: Validators = {};
348
+
349
+ /**
350
+ * @throws 1475661025
351
+ * @throws 1475661026
352
+ * @throws 1479238074
353
+ */
354
+ public addValidatorIdentifiersToFormElementProperty(
355
+ formElement: FormElement,
356
+ validators: ValidatorsConfig,
357
+ propertyPath: string,
358
+ collectionElementIdentifier: string,
359
+ collectionName: string,
360
+ configuration: PropertyValidatorConfiguration
361
+ ): void {
362
+ assert('object' === $.type(formElement), 'Invalid parameter "formElement"', 1475661025);
363
+ assert('array' === $.type(validators), 'Invalid parameter "validators"', 1475661026);
364
+ assert('array' === $.type(validators), 'Invalid parameter "validators"', 1479238074);
365
+
366
+ const formElementIdentifierPath = formElement.get('__identifierPath');
367
+ propertyPath = utility.buildPropertyPath(propertyPath, collectionElementIdentifier, collectionName, formElement);
368
+
369
+ const propertyValidationServiceRegisteredValidators = getApplicationStateStack().getCurrentState('propertyValidationServiceRegisteredValidators');
370
+ if (utility.isUndefinedOrNull(propertyValidationServiceRegisteredValidators[formElementIdentifierPath])) {
371
+ propertyValidationServiceRegisteredValidators[formElementIdentifierPath] = {};
372
+ }
373
+ if (utility.isUndefinedOrNull(propertyValidationServiceRegisteredValidators[formElementIdentifierPath][propertyPath])) {
374
+ propertyValidationServiceRegisteredValidators[formElementIdentifierPath][propertyPath] = {
375
+ validators: <ValidatorsConfig>[],
376
+ configuration: configuration
377
+ };
378
+ }
379
+ for (const validator of validators) {
380
+ if (propertyValidationServiceRegisteredValidators[formElementIdentifierPath][propertyPath].validators.indexOf(validator) === -1) {
381
+ propertyValidationServiceRegisteredValidators[formElementIdentifierPath][propertyPath].validators.push(validator);
382
+ }
383
+ }
384
+ getApplicationStateStack().setCurrentState('propertyValidationServiceRegisteredValidators', propertyValidationServiceRegisteredValidators);
385
+ }
386
+
387
+ /**
388
+ * @throws 1475700618
389
+ * @throws 1475706896
390
+ */
391
+ public removeValidatorIdentifiersFromFormElementProperty(
392
+ formElement: FormElement,
393
+ propertyPath: string
394
+ ): void {
395
+ assert('object' === $.type(formElement), 'Invalid parameter "formElement"', 1475700618);
396
+ assert(utility.isNonEmptyString(propertyPath), 'Invalid parameter "propertyPath"', 1475706896);
397
+
398
+ const formElementIdentifierPath = formElement.get('__identifierPath');
399
+
400
+ const registeredValidators: {[key: string]: {validators: ValidatorsConfig, configuration: PropertyValidatorConfiguration}} = {};
401
+ const propertyValidationServiceRegisteredValidators = getApplicationStateStack().getCurrentState('propertyValidationServiceRegisteredValidators');
402
+ if (formElementIdentifierPath in propertyValidationServiceRegisteredValidators) {
403
+ for (const registeredPropertyPath of Object.keys(propertyValidationServiceRegisteredValidators[formElementIdentifierPath] || {})) {
404
+ if (registeredPropertyPath.indexOf(propertyPath) > -1) {
405
+ continue;
406
+ }
407
+ registeredValidators[registeredPropertyPath] = propertyValidationServiceRegisteredValidators[formElementIdentifierPath][registeredPropertyPath];
408
+ }
409
+ }
410
+ propertyValidationServiceRegisteredValidators[formElementIdentifierPath] = registeredValidators;
411
+ getApplicationStateStack().setCurrentState('propertyValidationServiceRegisteredValidators', propertyValidationServiceRegisteredValidators);
412
+ }
413
+
414
+ /**
415
+ * @throws 1475668189
416
+ */
417
+ public removeAllValidatorIdentifiersFromFormElement(formElement: FormElement): void {
418
+ assert('object' === $.type(formElement), 'Invalid parameter "formElement"', 1475668189);
419
+
420
+ const registeredValidators: Record<string, {[key: string]: {validators: ValidatorsConfig, configuration: PropertyValidatorConfiguration}}> = {};
421
+ const propertyValidationServiceRegisteredValidators = getApplicationStateStack().getCurrentState('propertyValidationServiceRegisteredValidators');
422
+ for (const formElementIdentifierPath of Object.keys(propertyValidationServiceRegisteredValidators || {})) {
423
+ if (
424
+ formElementIdentifierPath === formElement.get('__identifierPath')
425
+ || formElementIdentifierPath.indexOf(formElement.get('__identifierPath') + '/') > -1
426
+ ) {
427
+ continue;
428
+ }
429
+ registeredValidators[formElementIdentifierPath] = propertyValidationServiceRegisteredValidators[formElementIdentifierPath];
430
+ }
431
+ getApplicationStateStack().setCurrentState('propertyValidationServiceRegisteredValidators', registeredValidators);
432
+ }
433
+
434
+ /**
435
+ * @throws 1475669143
436
+ * @throws 1475669144
437
+ * @throws 1475669145
438
+ */
439
+ public addValidator(validatorIdentifier: string, func: Validator): void {
440
+ assert(utility.isNonEmptyString(validatorIdentifier), 'Invalid parameter "validatorIdentifier"', 1475669143);
441
+ assert('function' === $.type(func), 'Invalid parameter "func"', 1475669144);
442
+ assert('function' !== $.type(this.validators[validatorIdentifier]), 'The validator "' + validatorIdentifier + '" is already registered', 1475669145);
443
+
444
+ this.validators[validatorIdentifier] = func;
445
+ }
446
+
447
+ /**
448
+ * @throws 1475676517
449
+ * @throws 1475676518
450
+ */
451
+ public validateFormElementProperty(
452
+ formElement: FormElement,
453
+ propertyPath: string
454
+ ): ValidationResults {
455
+ let configuration;
456
+ assert('object' === $.type(formElement), 'Invalid parameter "formElement"', 1475676517);
457
+ assert(utility.isNonEmptyString(propertyPath), 'Invalid parameter "propertyPath"', 1475676518);
458
+
459
+ const formElementIdentifierPath = formElement.get('__identifierPath');
460
+
461
+ const validationResults: ValidationResults = [];
462
+ const propertyValidationServiceRegisteredValidators = getApplicationStateStack().getCurrentState('propertyValidationServiceRegisteredValidators');
463
+ configuration = {
464
+ propertyValidatorsMode: 'AND'
465
+ };
466
+
467
+ if (
468
+ !utility.isUndefinedOrNull(propertyValidationServiceRegisteredValidators[formElementIdentifierPath])
469
+ && 'object' === $.type(propertyValidationServiceRegisteredValidators[formElementIdentifierPath][propertyPath])
470
+ && 'array' === $.type(propertyValidationServiceRegisteredValidators[formElementIdentifierPath][propertyPath].validators)
471
+ ) {
472
+ configuration = propertyValidationServiceRegisteredValidators[formElementIdentifierPath][propertyPath].configuration;
473
+ for (let i = 0, len = propertyValidationServiceRegisteredValidators[formElementIdentifierPath][propertyPath].validators.length; i < len; ++i) {
474
+ const validatorIdentifier = propertyValidationServiceRegisteredValidators[formElementIdentifierPath][propertyPath].validators[i];
475
+ if ('function' !== $.type(this.validators[validatorIdentifier])) {
476
+ continue;
477
+ }
478
+ const validationResult = this.validators[validatorIdentifier](formElement, propertyPath);
479
+
480
+ if (utility.isNonEmptyString(validationResult)) {
481
+ validationResults.push(validationResult);
482
+ }
483
+ }
484
+ }
485
+
486
+ if (
487
+ validationResults.length > 0
488
+ && configuration.propertyValidatorsMode === 'OR'
489
+ && validationResults.length !== propertyValidationServiceRegisteredValidators[formElementIdentifierPath][propertyPath].validators.length
490
+ ) {
491
+ return [];
492
+ }
493
+
494
+ return validationResults;
495
+ }
496
+
497
+ /**
498
+ * @throws 1475749668
499
+ */
500
+ public validateFormElement(formElement: FormElement): ValidationResultsWithPath {
501
+ assert('object' === $.type(formElement), 'Invalid parameter "formElement"', 1475749668);
502
+
503
+ const formElementIdentifierPath = formElement.get('__identifierPath');
504
+ const validationResults: ValidationResultsWithPath = [];
505
+ const propertyValidationServiceRegisteredValidators = getApplicationStateStack().getCurrentState('propertyValidationServiceRegisteredValidators');
506
+ if (!utility.isUndefinedOrNull(propertyValidationServiceRegisteredValidators[formElementIdentifierPath])) {
507
+ for (const registeredPropertyPath of Object.keys(propertyValidationServiceRegisteredValidators[formElementIdentifierPath])) {
508
+ validationResults.push({
509
+ propertyPath: registeredPropertyPath,
510
+ validationResults: this.validateFormElementProperty(formElement, registeredPropertyPath)
511
+ });
512
+ }
513
+ }
514
+ return validationResults;
515
+ }
516
+
517
+ /**
518
+ * @throws 1478613477
519
+ */
520
+ public validationResultsHasErrors(
521
+ validationResults: ValidationResultsRecursive
522
+ ): boolean {
523
+ assert('array' === $.type(validationResults), 'Invalid parameter "validationResults"', 1478613477);
524
+
525
+ for (let i = 0, len = validationResults.length; i < len; ++i) {
526
+ for (let j = 0, len2 = validationResults[i].validationResults.length; j < len2; ++j) {
527
+ if (
528
+ validationResults[i].validationResults[j].validationResults
529
+ && validationResults[i].validationResults[j].validationResults.length > 0
530
+ ) {
531
+ return true;
532
+ }
533
+ }
534
+ }
535
+ return false;
536
+ }
537
+
538
+ /**
539
+ * @throws 1475749668
540
+ */
541
+ public validateFormElementRecursive(
542
+ formElement: FormElement,
543
+ returnAfterFirstMatch: boolean,
544
+ validationResults?: ValidationResultsRecursive
545
+ ): ValidationResultsRecursive {
546
+ assert('object' === $.type(formElement), 'Invalid parameter "formElement"', 1475756764);
547
+ returnAfterFirstMatch = !!returnAfterFirstMatch;
548
+
549
+ validationResults = validationResults || <ValidationResultsRecursive>[];
550
+ validationResults.push({
551
+ formElementIdentifierPath: formElement.get('__identifierPath'),
552
+ validationResults: this.validateFormElement(formElement)
553
+ });
554
+
555
+ if (returnAfterFirstMatch && this.validationResultsHasErrors(validationResults)) {
556
+ return validationResults;
557
+ }
558
+
559
+ const formElements = formElement.get('renderables');
560
+ if ('array' === $.type(formElements)) {
561
+ for (let i = 0, len = formElements.length; i < len; ++i) {
562
+ this.validateFormElementRecursive(formElements[i], returnAfterFirstMatch, validationResults);
563
+ if (returnAfterFirstMatch && this.validationResultsHasErrors(validationResults)) {
564
+ return validationResults;
565
+ }
566
+ }
567
+ }
568
+
569
+ return validationResults;
570
+ }
571
+
572
+ /**
573
+ * @throws 1475707334
574
+ */
575
+ public addValidatorIdentifiersFromFormElementPropertyCollections(
576
+ formElement: FormElement
577
+ ): void {
578
+ assert('object' === $.type(formElement), 'Invalid parameter "formElement"', 1475707334);
579
+
580
+ const formElementTypeDefinition = repository.getFormEditorDefinition('formElements', formElement.get('type'));
581
+
582
+ if (!utility.isUndefinedOrNull(formElementTypeDefinition.propertyCollections)) {
583
+ for (const collectionName of Object.keys(formElementTypeDefinition.propertyCollections)) {
584
+ if (
585
+ !Array.isArray(formElementTypeDefinition.propertyCollections[collectionName])
586
+ ) {
587
+ continue;
588
+ }
589
+ for (let i = 0, len1 = formElementTypeDefinition.propertyCollections[collectionName].length; i < len1; ++i) {
590
+ if (
591
+ 'array' !== $.type(formElementTypeDefinition.propertyCollections[collectionName][i].editors)
592
+ || repository.getIndexFromPropertyCollectionElementByIdentifier(formElementTypeDefinition.propertyCollections[collectionName][i].identifier, collectionName, formElement) === -1
593
+ ) {
594
+ continue;
595
+ }
596
+ for (let j = 0, len2 = formElementTypeDefinition.propertyCollections[collectionName][i].editors.length; j < len2; ++j) {
597
+ if ('array' !== $.type(formElementTypeDefinition.propertyCollections[collectionName][i].editors[j].propertyValidators)) {
598
+ continue;
599
+ }
600
+ const propertyValidatorConfiguration: PropertyValidatorConfiguration = {
601
+ propertyValidatorsMode: 'AND'
602
+ };
603
+ if (
604
+ !utility.isUndefinedOrNull(formElementTypeDefinition.propertyCollections[collectionName][i].editors[j].propertyValidatorsMode)
605
+ && formElementTypeDefinition.propertyCollections[collectionName][i].editors[j].propertyValidatorsMode === 'OR'
606
+ ) {
607
+ propertyValidatorConfiguration.propertyValidatorsMode = 'OR';
608
+ }
609
+ this.addValidatorIdentifiersToFormElementProperty(
610
+ formElement,
611
+ formElementTypeDefinition.propertyCollections[collectionName][i].editors[j].propertyValidators,
612
+ formElementTypeDefinition.propertyCollections[collectionName][i].editors[j].propertyPath,
613
+ formElementTypeDefinition.propertyCollections[collectionName][i].identifier,
614
+ collectionName,
615
+ propertyValidatorConfiguration
616
+ );
617
+ }
618
+ }
619
+ }
620
+ }
621
+ }
622
+ }
623
+
624
+ /**
625
+ * Implements the "Publish/Subscribe Pattern"
626
+ * @credits Addy Osmani https://addyosmani.com/resources/essentialjsdesignpatterns/book/#highlighter_634280
627
+ */
628
+ export class PublisherSubscriber {
629
+
630
+ private topics: PublisherSubscriberTopics = <PublisherSubscriberTopics>{};
631
+
632
+ private subscriberUid: number = -1;
633
+
634
+ /**
635
+ * @throws 1475358066
636
+ */
637
+ public publish<T extends PublisherSubscriberTopic>(
638
+ topic: T,
639
+ args?: NoInfer<PublisherSubscriberTopicArgumentsMap[T]>
640
+ ): void {
641
+ assert(utility.isNonEmptyString(topic), 'Invalid parameter "topic"', 1475358066);
642
+ if (utility.isUndefinedOrNull(this.topics[topic])) {
643
+ return;
644
+ }
645
+
646
+ const topicFunctions = this.topics[topic];
647
+ for (const entry of topicFunctions) {
648
+ entry.func(topic, args);
649
+ }
650
+ }
651
+
652
+ /**
653
+ * @throws 1475358067
654
+ */
655
+ public subscribe<T extends PublisherSubscriberTopic>(
656
+ topic: T,
657
+ func: NoInfer<PublisherSubscriberFunction<T>>
658
+ ): string {
659
+ assert(utility.isNonEmptyString(topic), 'Invalid parameter "topic"', 1475358067);
660
+ assert('function' === $.type(func), 'Invalid parameter "func"', 1475411986);
661
+
662
+ if (utility.isUndefinedOrNull(this.topics[topic])) {
663
+ this.topics[topic] = <PublisherSubscriberTopics[T]>[];
664
+ }
665
+
666
+ const token = (++this.subscriberUid).toString();
667
+ this.topics[topic].push({
668
+ token: token,
669
+ //func: func as PublisherSubscriberFunction<U, U>
670
+ func: func
671
+ //func: func as F
672
+ });
673
+ return token;
674
+ }
675
+
676
+ /**
677
+ * @throws 1475358068
678
+ */
679
+ public unsubscribe(token: string): null | string {
680
+ assert(utility.isNonEmptyString(token), 'Invalid parameter "token"', 1475358068);
681
+
682
+ for (const tmp of Object.values(this.topics)) {
683
+ const entries = <PublisherSubscriberEntry<PublisherSubscriberTopic>[]>tmp;
684
+ for (let i = 0, len = entries.length; i < len; ++i) {
685
+ if (entries[i].token === token) {
686
+ entries.splice(i, 1);
687
+ return token;
688
+ }
689
+ }
690
+ }
691
+ return null;
692
+ }
693
+ }
694
+
695
+ /**
696
+ * @throws 1474640022
697
+ * @throws 1475358069
698
+ * @throws 1475358070
699
+ * @publish core/formElement/somePropertyChanged
700
+ */
701
+ function extendModel<D extends object, T extends ModelData<D>>(
702
+ modelToExtend: Model<D, T>,
703
+ modelExtension: T | [] | Record<string, never>,
704
+ pathPrefix: string,
705
+ disablePublishersOnSet: boolean
706
+ ): void {
707
+ assert('object' === $.type(modelToExtend), 'Invalid parameter "modelToExtend"', 1475358069);
708
+ assert('object' === $.type(modelExtension) || 'array' === $.type(modelExtension), 'Invalid parameter "modelExtension"', 1475358070);
709
+
710
+ disablePublishersOnSet = !!disablePublishersOnSet;
711
+ pathPrefix = pathPrefix || '';
712
+
713
+ if ($.isEmptyObject(modelExtension)) {
714
+ assert('' !== pathPrefix, 'Empty path is not allowed', 1474640022);
715
+ modelToExtend.on(pathPrefix, 'core/formElement/somePropertyChanged');
716
+ modelToExtend.set(pathPrefix, modelExtension, disablePublishersOnSet);
717
+ } else {
718
+ const _modelExtension = { ...modelExtension } as Record<string, T | [] | Record<string, never>>;
719
+ for (const key of Object.keys(_modelExtension)) {
720
+ const path = (pathPrefix === '') ? key : pathPrefix + '.' + key;
721
+
722
+ modelToExtend.on(path, 'core/formElement/somePropertyChanged');
723
+
724
+ if (_modelExtension[key] !== null && (typeof (_modelExtension[key]) === 'object' || Array.isArray(_modelExtension[key]))) {
725
+ extendModel(modelToExtend, _modelExtension[key], path, disablePublishersOnSet);
726
+ } else if (pathPrefix === 'properties.options') {
727
+ modelToExtend.set(pathPrefix, modelExtension, disablePublishersOnSet);
728
+ } else {
729
+ modelToExtend.set(path, _modelExtension[key], disablePublishersOnSet);
730
+ }
731
+ }
732
+ }
733
+ }
734
+
735
+ export class Model<D extends object, T extends ModelData<D>> {
736
+
737
+ private readonly objectData: T = <T>{};
738
+
739
+ private publisherTopics: {[key: string]: string[]} = {};
740
+
741
+ /**
742
+ * @throws 1475361755
743
+ */
744
+ public get(key: string): any | undefined {
745
+ let firstPartOfPath: string;
746
+ let obj: Record<string, unknown>;
747
+ assert(utility.isNonEmptyString(key), 'Invalid parameter "key"', 1475361755);
748
+
749
+ obj = this.objectData;
750
+ while (key.indexOf('.') > 0) {
751
+ firstPartOfPath = key.slice(0, key.indexOf('.'));
752
+ key = key.slice(firstPartOfPath.length + 1);
753
+ if (!(firstPartOfPath in obj)) {
754
+ return undefined;
755
+ }
756
+ obj = obj[firstPartOfPath] as Record<string, unknown>;
757
+ }
758
+
759
+ return obj[key];
760
+ }
761
+
762
+ /**
763
+ * @throws 1475361756
764
+ * @publish mixed
765
+ */
766
+ public set(key: string, value: unknown, disablePublishersOnSet?: boolean): void {
767
+ let path: string;
768
+ let firstPartOfPath: string | number;
769
+ let nextPartOfPath: string | number;
770
+ let index: number;
771
+ let obj: Record<string, unknown>;
772
+ assert(utility.isNonEmptyString(key), 'Invalid parameter "key"', 1475361756);
773
+ disablePublishersOnSet = !!disablePublishersOnSet;
774
+
775
+ const oldValue = this.get(key);
776
+ obj = this.objectData;
777
+ path = key;
778
+
779
+ while (path.indexOf('.') > 0) {
780
+ firstPartOfPath = path.slice(0, path.indexOf('.'));
781
+ path = path.slice(firstPartOfPath.length + 1);
782
+
783
+ if ($.isNumeric(firstPartOfPath)) {
784
+ firstPartOfPath = parseInt(firstPartOfPath, 10);
785
+ }
786
+
787
+ index = path.indexOf('.');
788
+ nextPartOfPath = index === -1 ? path : path.slice(0, index);
789
+
790
+ // initialize objects case they are undefined by looking up the type
791
+ // of the next path segment, the target type is guessed(!), thus e.g.
792
+ // "key" results in having an object, "123" results in having an array
793
+ if ('undefined' === $.type(obj[firstPartOfPath])) {
794
+ if ($.isNumeric(nextPartOfPath)) {
795
+ obj[firstPartOfPath] = [];
796
+ } else {
797
+ obj[firstPartOfPath] = {};
798
+ }
799
+ // in case the previous guess was wrong, the initialized array
800
+ // is converted to an object when a non-numeric path segment is found
801
+ } else if (false === $.isNumeric(nextPartOfPath) && 'array' === $.type(obj[firstPartOfPath])) {
802
+ obj[firstPartOfPath] = { ...(obj[firstPartOfPath] as Array<unknown>) };
803
+ }
804
+ obj = obj[firstPartOfPath] as Record<string, unknown>;
805
+ }
806
+ obj[path] = value;
807
+
808
+ if (!utility.isUndefinedOrNull(this.publisherTopics[key]) && !disablePublishersOnSet) {
809
+ for (let i = 0, len = this.publisherTopics[key].length; i < len; ++i) {
810
+ publisherSubscriber.publish<'core/formElement/somePropertyChanged'>(
811
+ this.publisherTopics[key][i] as 'core/formElement/somePropertyChanged',
812
+ [key, value, oldValue, this.objectData.__identifierPath]
813
+ );
814
+ }
815
+ }
816
+ }
817
+
818
+ /**
819
+ * @throws 1489321637
820
+ * @throws 1489319753
821
+ * @publish mixed
822
+ */
823
+ public unset(key: string, disablePublishersOnSet?: boolean): void {
824
+ let parentPropertyData, parentPropertyPath, propertyToRemove;
825
+ assert(utility.isNonEmptyString(key), 'Invalid parameter "key"', 1489321637);
826
+ disablePublishersOnSet = !!disablePublishersOnSet;
827
+
828
+ const oldValue = this.get(key);
829
+
830
+ if (key.indexOf('.') > 0) {
831
+ parentPropertyPath = key.split('.');
832
+ propertyToRemove = parentPropertyPath.pop();
833
+ parentPropertyPath = parentPropertyPath.join('.');
834
+ parentPropertyData = this.get(parentPropertyPath);
835
+ if (typeof parentPropertyData !== 'undefined') {
836
+ delete parentPropertyData[propertyToRemove];
837
+ }
838
+ } else {
839
+ assert(false, 'remove toplevel properties is not supported', 1489319753);
840
+ }
841
+
842
+ if (!utility.isUndefinedOrNull(this.publisherTopics[key]) && !disablePublishersOnSet) {
843
+ for (let i = 0, len = this.publisherTopics[key].length; i < len; ++i) {
844
+ publisherSubscriber.publish<'core/formElement/somePropertyChanged'>(
845
+ this.publisherTopics[key][i] as 'core/formElement/somePropertyChanged',
846
+ [key, undefined, oldValue, this.objectData.__identifierPath]
847
+ );
848
+ }
849
+ }
850
+ }
851
+
852
+ /**
853
+ * @throws 1475361757
854
+ * @throws 1475361758
855
+ */
856
+ public on(key: string, topicName: string): void {
857
+ assert(utility.isNonEmptyString(key), 'Invalid parameter "key"', 1475361757);
858
+ assert(utility.isNonEmptyString(topicName), 'Invalid parameter "topicName"', 1475361758);
859
+
860
+ if ('array' !== $.type(this.publisherTopics[key])) {
861
+ this.publisherTopics[key] = [];
862
+ }
863
+ if (this.publisherTopics[key].indexOf(topicName) === -1) {
864
+ this.publisherTopics[key].push(topicName);
865
+ }
866
+ }
867
+
868
+ /**
869
+ * @throws 1475361759
870
+ * @throws 1475361760
871
+ */
872
+ public off(key: string, topicName: string): void {
873
+ assert(utility.isNonEmptyString(key), 'Invalid parameter "key"', 1475361759);
874
+ assert(utility.isNonEmptyString(topicName), 'Invalid parameter "topicName"', 1475361760);
875
+
876
+ if ('array' === $.type(this.publisherTopics[key])) {
877
+ this.publisherTopics[key] = this.publisherTopics[key].filter(
878
+ (currentTopicName) => topicName !== currentTopicName
879
+ );
880
+ }
881
+ }
882
+
883
+ public getObjectData(): T {
884
+ // Return dereferenced object
885
+ return $.extend(true, {}, this.objectData);
886
+ }
887
+
888
+ public toString(): string {
889
+ const objectData = this.getObjectData();
890
+
891
+ const { renderables, __parentRenderable, ...restObjectData } = objectData;
892
+ const childFormElements = renderables || null;
893
+
894
+ let parentRenderable: string = null;
895
+ if (!utility.isUndefinedOrNull(__parentRenderable)) {
896
+ parentRenderable = __parentRenderable.getObjectData().__identifierPath + ' (filtered)';
897
+ }
898
+
899
+ const myObjectData: Omit<T, 'renderables' | '__parentRenderable'> & { renderables?: object[], __parentRenderable?: string} = restObjectData;
900
+
901
+ if (parentRenderable !== null) {
902
+ myObjectData.__parentRenderable = parentRenderable;
903
+ }
904
+
905
+ if (childFormElements !== null && Array.isArray(childFormElements)) {
906
+ const renderables: object[] = [];
907
+ for (let i = 0, len = childFormElements.length; i < len; ++i) {
908
+ const childFormElement = childFormElements[i];
909
+ renderables.push(JSON.parse(childFormElement.toString()));
910
+ }
911
+ myObjectData.renderables = renderables;
912
+ }
913
+
914
+ return JSON.stringify(myObjectData, null, 2);
915
+ }
916
+
917
+ public clone(): Model<D, T> {
918
+ const objectData = this.getObjectData();
919
+ const childFormElements = objectData.renderables || null;
920
+ delete objectData.renderables;
921
+ delete objectData.__parentRenderable;
922
+ objectData.renderables = (childFormElements) ? true : null;
923
+
924
+ const newModel = new Model<D, T>();
925
+ extendModel(newModel, objectData, '', true);
926
+
927
+ if (null !== childFormElements && Array.isArray(childFormElements)) {
928
+ const newRenderables = [];
929
+ for (let i = 0, len = childFormElements.length; i < len; ++i) {
930
+ let childFormElement = childFormElements[i];
931
+
932
+ childFormElement = childFormElement.clone();
933
+ childFormElement.set('__parentRenderable', newModel, true);
934
+ newRenderables.push(childFormElement);
935
+ }
936
+ newModel.set('renderables', newRenderables, true);
937
+ }
938
+
939
+ return newModel;
940
+ }
941
+ }
942
+
943
+ function createModel<D extends object, T extends ModelData<D>>(modelExtension: T): Model<D, T> {
944
+ modelExtension = modelExtension || <T>{};
945
+
946
+ const newModel = new Model<D, T>();
947
+ extendModel(newModel, modelExtension, '', true);
948
+
949
+ return newModel;
950
+ }
951
+
952
+ export class Repository {
953
+
954
+ public formEditorDefinitions: FormEditorDefinitions;
955
+
956
+ /**
957
+ * @throws 1475364394
958
+ */
959
+ public setFormEditorDefinitions(formEditorDefinitions: FormEditorDefinitions): void {
960
+ assert('object' === $.type(formEditorDefinitions), 'Invalid parameter "formEditorDefinitions"', 1475364394);
961
+
962
+ for (const _key1 of Object.keys(formEditorDefinitions)) {
963
+ const key1 = _key1 as keyof FormEditorDefinitions;
964
+ if (formEditorDefinitions[key1] !== null && typeof formEditorDefinitions[key1] !== 'object') {
965
+ continue;
966
+ }
967
+ for (const key2 of Object.keys(formEditorDefinitions[key1])) {
968
+ if (
969
+ formEditorDefinitions[key1][key2] === null ||
970
+ typeof formEditorDefinitions[key1][key2] !== 'object'
971
+ ) {
972
+ formEditorDefinitions[key1][key2] = {} as (FormElementDefinition | FinisherDefinition | FormElementPropertyValidatorDefinition | ValidatorDefinition);
973
+ }
974
+ }
975
+ }
976
+ this.formEditorDefinitions = formEditorDefinitions;
977
+ }
978
+
979
+ /**
980
+ * @throws 1475364952
981
+ * @throws 1475364953
982
+ */
983
+ public getFormEditorDefinition<D extends keyof FormEditorDefinitions, S extends keyof FormEditorDefinitions[D]>(
984
+ definitionName: D,
985
+ subject: S
986
+ ): FormEditorDefinitions[D][S] {
987
+ assert(utility.isNonEmptyString(definitionName), 'Invalid parameter "definitionName"', 1475364952);
988
+ assert(utility.isNonEmptyString(subject), 'Invalid parameter "subject"', 1475364953);
989
+ // Return dereferenced object
990
+ return $.extend(true, {}, this.formEditorDefinitions[definitionName][subject]);
991
+ }
992
+
993
+ public getRootFormElement(): RootFormElement {
994
+ return getApplicationStateStack().getCurrentState('formDefinition');
995
+ }
996
+
997
+ /**
998
+ * @throws 1475436224
999
+ * @throws 1475364956
1000
+ */
1001
+ public addFormElement(
1002
+ formElement: FormElement,
1003
+ referenceFormElement: FormElement,
1004
+ registerPropertyValidators: boolean,
1005
+ disablePublishersOnSet: boolean
1006
+ ): FormElement {
1007
+ let enclosingCompositeFormElement, parentFormElementsArray, referenceFormElementElements;
1008
+ assert('object' === $.type(formElement), 'Invalid parameter "formElement"', 1475436224);
1009
+ assert('object' === $.type(referenceFormElement), 'Invalid parameter "referenceFormElement"', 1475364956);
1010
+
1011
+ if (utility.isUndefinedOrNull(disablePublishersOnSet)) {
1012
+ disablePublishersOnSet = true;
1013
+ }
1014
+ disablePublishersOnSet = !!disablePublishersOnSet;
1015
+
1016
+ registerPropertyValidators = !!registerPropertyValidators;
1017
+ const formElementTypeDefinition = this.getFormEditorDefinition('formElements', formElement.get('type'));
1018
+ const referenceFormElementTypeDefinition = this.getFormEditorDefinition('formElements', referenceFormElement.get('type'));
1019
+
1020
+ // formElement != Page / SummaryPage && referenceFormElement == Page / Fieldset / GridRow
1021
+ if (!formElementTypeDefinition._isTopLevelFormElement && referenceFormElementTypeDefinition._isCompositeFormElement) {
1022
+ if ('array' !== $.type(referenceFormElement.get('renderables'))) {
1023
+ referenceFormElement.set('renderables', [], disablePublishersOnSet);
1024
+ }
1025
+
1026
+ formElement.set('__parentRenderable', referenceFormElement, disablePublishersOnSet);
1027
+ formElement.set('__identifierPath', referenceFormElement.get('__identifierPath') + '/' + formElement.get('identifier'), disablePublishersOnSet);
1028
+ referenceFormElement.get('renderables').push(formElement);
1029
+ } else {
1030
+ // referenceFormElement == root form element
1031
+ if (referenceFormElement.get('__identifierPath') === getApplicationStateStack().getCurrentState('formDefinition').get('__identifierPath')) {
1032
+ referenceFormElementElements = referenceFormElement.get('renderables');
1033
+ // referenceFormElement = last page
1034
+ referenceFormElement = referenceFormElementElements[referenceFormElementElements.length - 1];
1035
+ // if formElement == Page / SummaryPage && referenceFormElement != Page / SummaryPage
1036
+ } else if (formElementTypeDefinition._isTopLevelFormElement && !referenceFormElementTypeDefinition._isTopLevelFormElement) {
1037
+ // referenceFormElement = parent Page
1038
+ referenceFormElement = this.findEnclosingCompositeFormElementWhichIsOnTopLevel(referenceFormElement);
1039
+ // formElement == Page / SummaryPage / Fieldset / GridRow
1040
+ } else if (formElementTypeDefinition._isCompositeFormElement) {
1041
+ enclosingCompositeFormElement = this.findEnclosingCompositeFormElementWhichIsNotOnTopLevel(referenceFormElement);
1042
+ if (enclosingCompositeFormElement) {
1043
+ // referenceFormElement = parent Fieldset / GridRow
1044
+ referenceFormElement = enclosingCompositeFormElement;
1045
+ }
1046
+ }
1047
+
1048
+ formElement.set('__parentRenderable', referenceFormElement.get('__parentRenderable'), disablePublishersOnSet);
1049
+ formElement.set('__identifierPath', referenceFormElement.get('__parentRenderable').get('__identifierPath') + '/' + formElement.get('identifier'), disablePublishersOnSet);
1050
+ parentFormElementsArray = referenceFormElement.get('__parentRenderable').get('renderables');
1051
+ parentFormElementsArray.splice(parentFormElementsArray.indexOf(referenceFormElement) + 1, 0, formElement);
1052
+ }
1053
+
1054
+ if (registerPropertyValidators) {
1055
+ if ('array' === $.type(formElementTypeDefinition.editors)) {
1056
+ for (let i = 0, len1 = formElementTypeDefinition.editors.length; i < len1; ++i) {
1057
+ if ('array' !== $.type(formElementTypeDefinition.editors[i].propertyValidators)) {
1058
+ continue;
1059
+ }
1060
+
1061
+ const propertyValidatorConfiguration: PropertyValidatorConfiguration = {
1062
+ propertyValidatorsMode: 'AND'
1063
+ };
1064
+ if (
1065
+ !utility.isUndefinedOrNull(formElementTypeDefinition.editors[i].propertyValidatorsMode)
1066
+ && formElementTypeDefinition.editors[i].propertyValidatorsMode === 'OR'
1067
+ ) {
1068
+ propertyValidatorConfiguration.propertyValidatorsMode = 'OR';
1069
+ }
1070
+
1071
+ propertyValidationService.addValidatorIdentifiersToFormElementProperty(
1072
+ formElement,
1073
+ formElementTypeDefinition.editors[i].propertyValidators,
1074
+ formElementTypeDefinition.editors[i].propertyPath,
1075
+ undefined,
1076
+ undefined,
1077
+ propertyValidatorConfiguration
1078
+ );
1079
+ }
1080
+ }
1081
+ }
1082
+
1083
+ return formElement;
1084
+ }
1085
+
1086
+ /**
1087
+ * @throws 1472553024
1088
+ * @throws 1475364957
1089
+ */
1090
+ public removeFormElement(
1091
+ formElement: FormElement,
1092
+ removeRegisteredPropertyValidators: boolean,
1093
+ disablePublishersOnSet?: boolean
1094
+ ): void {
1095
+ if (utility.isUndefinedOrNull(disablePublishersOnSet)) {
1096
+ disablePublishersOnSet = true;
1097
+ }
1098
+ disablePublishersOnSet = !!disablePublishersOnSet;
1099
+ removeRegisteredPropertyValidators = !!removeRegisteredPropertyValidators;
1100
+
1101
+ assert('object' === $.type(formElement), 'Invalid parameter "formElement"', 1475364957);
1102
+ assert('object' === $.type(formElement.get('__parentRenderable')), 'Removing the root element is not allowed', 1472553024);
1103
+
1104
+ const parentFormElementElements = formElement.get('__parentRenderable').get('renderables');
1105
+ parentFormElementElements.splice(parentFormElementElements.indexOf(formElement), 1);
1106
+ formElement.get('__parentRenderable').set('renderables', parentFormElementElements, disablePublishersOnSet);
1107
+
1108
+ if (removeRegisteredPropertyValidators) {
1109
+ propertyValidationService.removeAllValidatorIdentifiersFromFormElement(formElement);
1110
+ }
1111
+ }
1112
+
1113
+ /**
1114
+ * @throws 1475364958
1115
+ * @throws 1475364959
1116
+ * @throws 1475364960
1117
+ * @throws 1475364961
1118
+ * @throws 1475364962
1119
+ * @throws 1476993731
1120
+ * @throws 1476993732
1121
+ */
1122
+ public moveFormElement(
1123
+ formElementToMove: FormElement,
1124
+ position: string,
1125
+ referenceFormElement: FormElement,
1126
+ disablePublishersOnSet: boolean
1127
+ ): FormElement {
1128
+ let referenceFormElementParentElements,
1129
+ referenceFormElementElements, referenceFormElementIndex;
1130
+ assert('object' === $.type(formElementToMove), 'Invalid parameter "formElementToMove"', 1475364958);
1131
+ assert('after' === position || 'before' === position || 'inside' === position, 'Invalid position "' + position + '"', 1475364959);
1132
+ assert('object' === $.type(referenceFormElement), 'Invalid parameter "referenceFormElement"', 1475364960);
1133
+
1134
+ if (utility.isUndefinedOrNull(disablePublishersOnSet)) {
1135
+ disablePublishersOnSet = true;
1136
+ }
1137
+ disablePublishersOnSet = !!disablePublishersOnSet;
1138
+
1139
+ const formElementToMoveTypeDefinition = this.getFormEditorDefinition('formElements', formElementToMove.get('type'));
1140
+ const referenceFormElementTypeDefinition = this.getFormEditorDefinition('formElements', referenceFormElement.get('type'));
1141
+
1142
+ this.removeFormElement(formElementToMove, false);
1143
+ const reSetIdentifierPath = (formElement: FormElement, pathPrefix: string): void => {
1144
+ assert('object' === $.type(formElement), 'Invalid parameter "formElement"', 1475364961);
1145
+ assert(utility.isNonEmptyString(pathPrefix), 'Invalid parameter "pathPrefix"', 1475364962);
1146
+
1147
+ const oldIdentifierPath = formElement.get('__identifierPath');
1148
+ const newIdentifierPath = pathPrefix + '/' + formElement.get('identifier');
1149
+
1150
+ const propertyValidationServiceRegisteredValidators = getApplicationStateStack().getCurrentState('propertyValidationServiceRegisteredValidators');
1151
+ if (!utility.isUndefinedOrNull(propertyValidationServiceRegisteredValidators[oldIdentifierPath])) {
1152
+ propertyValidationServiceRegisteredValidators[newIdentifierPath] = propertyValidationServiceRegisteredValidators[oldIdentifierPath];
1153
+ delete propertyValidationServiceRegisteredValidators[oldIdentifierPath];
1154
+ }
1155
+ getApplicationStateStack().setCurrentState('propertyValidationServiceRegisteredValidators', propertyValidationServiceRegisteredValidators);
1156
+
1157
+ formElement.set('__identifierPath', newIdentifierPath, disablePublishersOnSet);
1158
+ const formElements = formElement.get('renderables');
1159
+ if ('array' === $.type(formElements)) {
1160
+ for (let i = 0, len = formElements.length; i < len; ++i) {
1161
+ reSetIdentifierPath(formElements[i], formElement.get('__identifierPath'));
1162
+ }
1163
+ }
1164
+ };
1165
+
1166
+ /**
1167
+ * This is true on:
1168
+ * * Drag a Element on a Page Element (tree)
1169
+ * * Drag a Element on a Section Element (tree)
1170
+ */
1171
+ if (position === 'inside') {
1172
+ // formElementToMove == Page / SummaryPage
1173
+ assert(!formElementToMoveTypeDefinition._isTopLevelFormElement, 'This move is not allowed', 1476993731);
1174
+ // referenceFormElement != Page / Fieldset / GridRow
1175
+ assert(referenceFormElementTypeDefinition._isCompositeFormElement, 'This move is not allowed', 1476993732);
1176
+
1177
+ formElementToMove.set('__parentRenderable', referenceFormElement, disablePublishersOnSet);
1178
+ reSetIdentifierPath(formElementToMove, referenceFormElement.get('__identifierPath'));
1179
+
1180
+ referenceFormElementElements = referenceFormElement.get('renderables');
1181
+ if (utility.isUndefinedOrNull(referenceFormElementElements)) {
1182
+ referenceFormElementElements = [];
1183
+ }
1184
+ referenceFormElementElements.splice(0, 0, formElementToMove);
1185
+ referenceFormElement.set('renderables', referenceFormElementElements, disablePublishersOnSet);
1186
+ } else {
1187
+ /**
1188
+ * This is true on:
1189
+ * * Drag a Page before another Page (tree)
1190
+ * * Drag a Page after another Page (tree)
1191
+ */
1192
+ if (formElementToMoveTypeDefinition._isTopLevelFormElement && referenceFormElementTypeDefinition._isTopLevelFormElement) {
1193
+ referenceFormElementParentElements = referenceFormElement.get('__parentRenderable').get('renderables');
1194
+ referenceFormElementIndex = referenceFormElementParentElements.indexOf(referenceFormElement);
1195
+
1196
+ if (position === 'after') {
1197
+ referenceFormElementParentElements.splice(referenceFormElementIndex + 1, 0, formElementToMove);
1198
+ } else {
1199
+ referenceFormElementParentElements.splice(referenceFormElementIndex, 0, formElementToMove);
1200
+ }
1201
+
1202
+ referenceFormElement.get('__parentRenderable').set('renderables', referenceFormElementParentElements, disablePublishersOnSet);
1203
+ } else {
1204
+ /**
1205
+ * This is true on:
1206
+ * * Drag a Element before another Element within the same level (tree)
1207
+ * * Drag a Element after another Element within the same level (tree)
1208
+ * * Drag a Element before another Element (stage)
1209
+ * * Drag a Element after another Element (stage)
1210
+ */
1211
+ if (formElementToMove.get('__parentRenderable').get('identifier') === referenceFormElement.get('__parentRenderable').get('identifier')) {
1212
+ referenceFormElementParentElements = referenceFormElement.get('__parentRenderable').get('renderables');
1213
+ referenceFormElementIndex = referenceFormElementParentElements.indexOf(referenceFormElement);
1214
+ } else {
1215
+ /**
1216
+ * This is true on:
1217
+ * * Drag a Element before an Element on another page (tree / stage)
1218
+ * * Drag a Element after an Element on another page (tree / stage)
1219
+ */
1220
+ formElementToMove.set('__parentRenderable', referenceFormElement.get('__parentRenderable'), disablePublishersOnSet);
1221
+ reSetIdentifierPath(formElementToMove, referenceFormElement.get('__parentRenderable').get('__identifierPath'));
1222
+
1223
+ referenceFormElementParentElements = referenceFormElement.get('__parentRenderable').get('renderables');
1224
+ referenceFormElementIndex = referenceFormElementParentElements.indexOf(referenceFormElement);
1225
+ }
1226
+
1227
+ if (position === 'after') {
1228
+ referenceFormElementParentElements.splice(referenceFormElementIndex + 1, 0, formElementToMove);
1229
+ } else {
1230
+ referenceFormElementParentElements.splice(referenceFormElementIndex, 0, formElementToMove);
1231
+ }
1232
+
1233
+ referenceFormElement.get('__parentRenderable').set('renderables', referenceFormElementParentElements, disablePublishersOnSet);
1234
+ }
1235
+ }
1236
+
1237
+ return formElementToMove;
1238
+ }
1239
+
1240
+ /**
1241
+ * @throws 1475364963
1242
+ */
1243
+ public getIndexForEnclosingCompositeFormElementWhichIsOnTopLevelForFormElement(
1244
+ formElement: FormElement
1245
+ ): number {
1246
+ let enclosingCompositeFormElementWhichIsOnTopLevel;
1247
+ assert('object' === $.type(formElement), 'Invalid parameter "formElement"', 1475364963);
1248
+
1249
+ const formElementTypeDefinition = this.getFormEditorDefinition('formElements', formElement.get('type'));
1250
+
1251
+ if (formElementTypeDefinition._isTopLevelFormElement && formElementTypeDefinition._isCompositeFormElement) {
1252
+ enclosingCompositeFormElementWhichIsOnTopLevel = formElement;
1253
+ } else if (formElement.get('__identifierPath') === getApplicationStateStack().getCurrentState('formDefinition').get('__identifierPath')) {
1254
+ enclosingCompositeFormElementWhichIsOnTopLevel = getApplicationStateStack().getCurrentState('formDefinition').get('renderables')[0];
1255
+ } else {
1256
+ enclosingCompositeFormElementWhichIsOnTopLevel = this.findEnclosingCompositeFormElementWhichIsOnTopLevel(formElement);
1257
+ }
1258
+ return enclosingCompositeFormElementWhichIsOnTopLevel.get('__parentRenderable').get('renderables').indexOf(enclosingCompositeFormElementWhichIsOnTopLevel);
1259
+ }
1260
+
1261
+ /**
1262
+ * @throws 1472556223
1263
+ * @throws 1475364964
1264
+ */
1265
+ public findEnclosingCompositeFormElementWhichIsOnTopLevel(
1266
+ formElement: FormElement
1267
+ ): FormElement {
1268
+ let formElementTypeDefinition;
1269
+ assert('object' === $.type(formElement), 'Invalid parameter "formElement"', 1475364964);
1270
+ assert('object' === $.type(formElement.get('__parentRenderable')), 'The root element is never encloused by anything', 1472556223);
1271
+
1272
+ formElementTypeDefinition = this.getFormEditorDefinition('formElements', formElement.get('type'));
1273
+ while (!formElementTypeDefinition._isTopLevelFormElement) {
1274
+ formElement = formElement.get('__parentRenderable');
1275
+ formElementTypeDefinition = this.getFormEditorDefinition('formElements', formElement.get('type'));
1276
+ }
1277
+
1278
+ return formElement;
1279
+ }
1280
+
1281
+ /**
1282
+ * @throws 1490520271
1283
+ */
1284
+ public findEnclosingGridRowFormElement(
1285
+ formElement: FormElement
1286
+ ): FormElement | null {
1287
+ let formElementTypeDefinition;
1288
+ assert('object' === $.type(formElement), 'Invalid parameter "formElement"', 1490520271);
1289
+
1290
+ formElementTypeDefinition = this.getFormEditorDefinition('formElements', formElement.get('type'));
1291
+ while (!formElementTypeDefinition._isGridRowFormElement) {
1292
+ if (formElementTypeDefinition._isTopLevelFormElement) {
1293
+ return null;
1294
+ }
1295
+ formElement = formElement.get('__parentRenderable');
1296
+ formElementTypeDefinition = this.getFormEditorDefinition('formElements', formElement.get('type'));
1297
+ }
1298
+ if (formElementTypeDefinition._isTopLevelFormElement) {
1299
+ return null;
1300
+ }
1301
+ return formElement;
1302
+ }
1303
+
1304
+ /**
1305
+ * @throws 1475364965
1306
+ */
1307
+ public findEnclosingCompositeFormElementWhichIsNotOnTopLevel(
1308
+ formElement: FormElement
1309
+ ): FormElement | null {
1310
+ let formElementTypeDefinition;
1311
+ assert('object' === $.type(formElement), 'Invalid parameter "formElement"', 1475364965);
1312
+
1313
+ formElementTypeDefinition = this.getFormEditorDefinition('formElements', formElement.get('type'));
1314
+ while (!formElementTypeDefinition._isCompositeFormElement) {
1315
+ if (formElementTypeDefinition._isTopLevelFormElement) {
1316
+ return null;
1317
+ }
1318
+ formElement = formElement.get('__parentRenderable');
1319
+ formElementTypeDefinition = this.getFormEditorDefinition('formElements', formElement.get('type'));
1320
+ }
1321
+ if (formElementTypeDefinition._isTopLevelFormElement) {
1322
+ return null;
1323
+ }
1324
+ return formElement;
1325
+ }
1326
+
1327
+ public getNonCompositeNonToplevelFormElements(): FormElement[] {
1328
+ const nonCompositeNonToplevelFormElements: FormElement[] = [];
1329
+ const collect = (formElement: FormElement): void => {
1330
+ assert('object' === $.type(formElement), 'Invalid parameter "formElement"', 1475364961);
1331
+
1332
+ const formElementTypeDefinition = this.getFormEditorDefinition('formElements', formElement.get('type'));
1333
+
1334
+ if (!formElementTypeDefinition._isTopLevelFormElement && !formElementTypeDefinition._isCompositeFormElement) {
1335
+ nonCompositeNonToplevelFormElements.push(formElement);
1336
+ }
1337
+
1338
+ const formElements = formElement.get('renderables');
1339
+ if ('array' === $.type(formElements)) {
1340
+ for (let i = 0, len = formElements.length; i < len; ++i) {
1341
+ collect(formElements[i]);
1342
+ }
1343
+ }
1344
+ };
1345
+
1346
+ collect(this.getRootFormElement());
1347
+ return nonCompositeNonToplevelFormElements;
1348
+ }
1349
+
1350
+ /**
1351
+ * @throws 1475364966
1352
+ */
1353
+ public isFormElementIdentifierUsed(identifier: string): boolean {
1354
+ let identifierFound: boolean;
1355
+ assert(utility.isNonEmptyString(identifier), 'Invalid parameter "identifier"', 1475364966);
1356
+
1357
+ const checkIdentifier = (formElement: FormElement): void => {
1358
+ let formElements;
1359
+
1360
+ if (formElement.get('identifier') === identifier) {
1361
+ identifierFound = true;
1362
+ }
1363
+
1364
+ if (!identifierFound) {
1365
+ formElements = formElement.get('renderables');
1366
+ if ('array' === $.type(formElements)) {
1367
+ for (let i = 0, len = formElements.length; i < len; ++i) {
1368
+ checkIdentifier(formElements[i]);
1369
+ if (identifierFound) {
1370
+ break;
1371
+ }
1372
+ }
1373
+ }
1374
+ }
1375
+ };
1376
+
1377
+ checkIdentifier(getApplicationStateStack().getCurrentState('formDefinition'));
1378
+ return identifierFound;
1379
+ }
1380
+
1381
+ /**
1382
+ * @throws 1475373676
1383
+ */
1384
+ public getNextFreeFormElementIdentifier(formElementType: string): string {
1385
+ let i;
1386
+ assert(utility.isNonEmptyString(formElementType), 'Invalid parameter "formElementType"', 1475373676);
1387
+
1388
+ const prefix = formElementType.toLowerCase().replace(/[^a-z0-9]/g, '-') + '-';
1389
+ i = 1;
1390
+ while (this.isFormElementIdentifierUsed(prefix + i)) {
1391
+ i++;
1392
+ }
1393
+ return prefix + i;
1394
+ }
1395
+
1396
+ /**
1397
+ * @throws 1472424333
1398
+ * @throws 1472424334
1399
+ * @throws 1472424330
1400
+ * @throws 1475373677
1401
+ */
1402
+ public findFormElementByIdentifierPath(identifierPath: string): FormElement {
1403
+ let obj, formElements;
1404
+
1405
+ assert(utility.isNonEmptyString(identifierPath), 'Invalid parameter "identifierPath"', 1475373677);
1406
+
1407
+ let formElement: FormElement = getApplicationStateStack().getCurrentState('formDefinition');
1408
+ const pathParts = identifierPath.split('/');
1409
+ const pathPartsLength = pathParts.length;
1410
+
1411
+ for (let i = 0; i < pathPartsLength; ++i) {
1412
+ const key = pathParts[i];
1413
+ if (i === 0 || i === pathPartsLength) {
1414
+ assert(key === formElement.get('identifier'), '"' + key + '" does not exist in path "' + identifierPath + '"', 1472424333);
1415
+ continue;
1416
+ }
1417
+
1418
+ formElements = formElement.get('renderables');
1419
+ if (Array.isArray(formElements)) {
1420
+ obj = null;
1421
+ for (let j = 0, len = formElements.length; j < len; ++j) {
1422
+ if (key === formElements[j].get('identifier')) {
1423
+ obj = formElements[j];
1424
+ break;
1425
+ }
1426
+ }
1427
+
1428
+ assert('null' !== $.type(obj), 'Could not find form element "' + key + '" in path "' + identifierPath + '"', 1472424334);
1429
+ formElement = obj;
1430
+ } else {
1431
+ assert(false, 'No form elements found', 1472424330);
1432
+ }
1433
+ }
1434
+ return formElement;
1435
+ }
1436
+
1437
+ public findFormElement(formElement: FormElement | string): FormElement {
1438
+ if (typeof formElement === 'object') {
1439
+ formElement = <string>formElement.get('__identifierPath');
1440
+ }
1441
+ return this.findFormElementByIdentifierPath(formElement);
1442
+ }
1443
+
1444
+ /**
1445
+ * @throws 1475375281
1446
+ * @throws 1475375282
1447
+ */
1448
+ public findCollectionElementByIdentifierPath(
1449
+ collectionElementIdentifier: string,
1450
+ collection: Collection
1451
+ ): undefined | CollectionEntry {
1452
+ assert(utility.isNonEmptyString(collectionElementIdentifier), 'Invalid parameter "collectionElementIdentifier"', 1475375281);
1453
+ assert('array' === $.type(collection), 'Invalid parameter "collection"', 1475375282);
1454
+
1455
+ for (let i = 0, len = collection.length; i < len; ++i) {
1456
+ if (collection[i].identifier === collectionElementIdentifier) {
1457
+ return collection[i];
1458
+ }
1459
+ }
1460
+
1461
+ return undefined;
1462
+ }
1463
+
1464
+ /**
1465
+ * @throws 1475375283
1466
+ * @throws 1475375284
1467
+ * @throws 1475375285
1468
+ */
1469
+ public getIndexFromPropertyCollectionElementByIdentifier(
1470
+ collectionElementIdentifier: string,
1471
+ collectionName: string,
1472
+ formElement: FormElement
1473
+ ): number {
1474
+ assert(utility.isNonEmptyString(collectionElementIdentifier), 'Invalid parameter "collectionElementIdentifier"', 1475375283);
1475
+ assert('object' === $.type(formElement), 'Invalid parameter "formElement"', 1475375284);
1476
+ assert(utility.isNonEmptyString(collectionName), 'Invalid parameter "collectionName"', 1475375285);
1477
+
1478
+ const collection = formElement.get(collectionName);
1479
+ if ('array' === $.type(collection)) {
1480
+ for (let i = 0, len = collection.length; i < len; ++i) {
1481
+ if (collection[i].identifier === collectionElementIdentifier) {
1482
+ return i;
1483
+ }
1484
+ }
1485
+ }
1486
+ return -1;
1487
+ }
1488
+
1489
+ /**
1490
+ * @throws 1475375686
1491
+ * @throws 1475375687
1492
+ * @throws 1475375688
1493
+ * @throws 1477413154
1494
+ */
1495
+ public addPropertyCollectionElement(
1496
+ collectionElementToAdd: CollectionEntry,
1497
+ collectionName: string,
1498
+ formElement: FormElement,
1499
+ referenceCollectionElementIdentifier: string,
1500
+ disablePublishersOnSet?: boolean
1501
+ ): FormElement {
1502
+ let collection, newCollectionElementIndex;
1503
+ assert('object' === $.type(collectionElementToAdd), 'Invalid parameter "collectionElementToAdd"', 1475375686);
1504
+ assert('object' === $.type(formElement), 'Invalid parameter "formElement"', 1475375687);
1505
+ assert(utility.isNonEmptyString(collectionName), 'Invalid parameter "collectionName"', 1475375688);
1506
+
1507
+ if (utility.isUndefinedOrNull(disablePublishersOnSet)) {
1508
+ disablePublishersOnSet = true;
1509
+ }
1510
+ disablePublishersOnSet = !!disablePublishersOnSet;
1511
+
1512
+ collection = formElement.get(collectionName);
1513
+ if ('array' !== $.type(collection)) {
1514
+ extendModel(formElement, [], collectionName, true);
1515
+ collection = formElement.get(collectionName);
1516
+ }
1517
+
1518
+ if (utility.isUndefinedOrNull(referenceCollectionElementIdentifier)) {
1519
+ newCollectionElementIndex = 0;
1520
+ } else {
1521
+ newCollectionElementIndex = this.getIndexFromPropertyCollectionElementByIdentifier(referenceCollectionElementIdentifier, collectionName, formElement) + 1;
1522
+ assert(-1 < newCollectionElementIndex, 'Could not find collection element ' + referenceCollectionElementIdentifier + ' within collection ' + collectionName, 1477413154);
1523
+ }
1524
+
1525
+ collection.splice(newCollectionElementIndex, 0, collectionElementToAdd);
1526
+ formElement.set(collectionName, collection, true);
1527
+
1528
+ propertyValidationService.removeValidatorIdentifiersFromFormElementProperty(formElement, collectionName);
1529
+
1530
+ for (let i = 0, len = collection.length; i < len; ++i) {
1531
+ extendModel(formElement, collection[i], collectionName + '.' + i, true);
1532
+ }
1533
+
1534
+ formElement.set(collectionName, collection, true);
1535
+ propertyValidationService.addValidatorIdentifiersFromFormElementPropertyCollections(formElement);
1536
+ formElement.set(collectionName, collection, disablePublishersOnSet);
1537
+
1538
+ return formElement;
1539
+ }
1540
+
1541
+ /**
1542
+ * @throws 1475375689
1543
+ * @throws 1475375690
1544
+ * @throws 1475375691
1545
+ * @throws 1475375692
1546
+ */
1547
+ public removePropertyCollectionElementByIdentifier(
1548
+ formElement: FormElement,
1549
+ collectionElementIdentifier: string,
1550
+ collectionName: string,
1551
+ disablePublishersOnSet?: boolean
1552
+ ): void {
1553
+ assert(utility.isNonEmptyString(collectionElementIdentifier), 'Invalid parameter "collectionElementIdentifier"', 1475375689);
1554
+ assert('object' === $.type(formElement), 'Invalid parameter "formElement"', 1475375690);
1555
+ assert(utility.isNonEmptyString(collectionName), 'Invalid parameter "collectionName"', 1475375691);
1556
+
1557
+ const collection = formElement.get(collectionName);
1558
+ assert('array' === $.type(collection), 'The collection "' + collectionName + '" does not exist', 1475375692);
1559
+
1560
+ if (utility.isUndefinedOrNull(disablePublishersOnSet)) {
1561
+ disablePublishersOnSet = true;
1562
+ }
1563
+ disablePublishersOnSet = !!disablePublishersOnSet;
1564
+
1565
+ propertyValidationService.removeValidatorIdentifiersFromFormElementProperty(formElement, collectionName);
1566
+ const collectionElementIndex = this.getIndexFromPropertyCollectionElementByIdentifier(collectionElementIdentifier, collectionName, formElement);
1567
+ collection.splice(collectionElementIndex, 1);
1568
+ formElement.set(collectionName, collection, disablePublishersOnSet);
1569
+ propertyValidationService.addValidatorIdentifiersFromFormElementPropertyCollections(formElement);
1570
+ }
1571
+
1572
+ /**
1573
+ * @throws 1477404484
1574
+ * @throws 1477404485
1575
+ * @throws 1477404486
1576
+ * @throws 1477404488
1577
+ * @throws 1477404489
1578
+ * @throws 1477404490
1579
+ */
1580
+ public movePropertyCollectionElement(
1581
+ collectionElementToMoveIdentifier: string,
1582
+ position: string,
1583
+ referenceCollectionElementIdentifier: string,
1584
+ collectionName: string,
1585
+ formElement: FormElement,
1586
+ disablePublishersOnSet: boolean
1587
+ ): void {
1588
+ let referenceCollectionElement;
1589
+
1590
+ assert('after' === position || 'before' === position, 'Invalid position "' + position + '"', 1477404485);
1591
+ assert('string' === $.type(referenceCollectionElementIdentifier), 'Invalid parameter "referenceCollectionElementIdentifier"', 1477404486);
1592
+ assert('object' === $.type(formElement), 'Invalid parameter "formElement"', 1477404488);
1593
+
1594
+ const collection = formElement.get(collectionName);
1595
+ assert('array' === $.type(collection), 'The collection "' + collectionName + '" does not exist', 1477404490);
1596
+
1597
+ const collectionElementToMove = this.findCollectionElementByIdentifierPath(collectionElementToMoveIdentifier, collection);
1598
+ assert('object' === $.type(collectionElementToMove), 'Invalid parameter "collectionElementToMove"', 1477404484);
1599
+
1600
+ this.removePropertyCollectionElementByIdentifier(formElement, collectionElementToMoveIdentifier, collectionName);
1601
+
1602
+ const referenceCollectionElementIndex = this.getIndexFromPropertyCollectionElementByIdentifier(referenceCollectionElementIdentifier, collectionName, formElement);
1603
+ assert(-1 < referenceCollectionElementIndex, 'Could not find collection element ' + referenceCollectionElementIdentifier + ' within collection ' + collectionName, 1477404489);
1604
+
1605
+ if ('before' === position) {
1606
+ referenceCollectionElement = collection[referenceCollectionElementIndex - 1];
1607
+ if (utility.isUndefinedOrNull(referenceCollectionElement)) {
1608
+ referenceCollectionElementIdentifier = undefined;
1609
+ } else {
1610
+ referenceCollectionElementIdentifier = referenceCollectionElement.identifier;
1611
+ }
1612
+ }
1613
+
1614
+ this.addPropertyCollectionElement(collectionElementToMove, collectionName, formElement, referenceCollectionElementIdentifier, disablePublishersOnSet);
1615
+ }
1616
+ }
1617
+
1618
+
1619
+ export class Factory {
1620
+
1621
+ /**
1622
+ * @throws 1475375693
1623
+ * @throws 1475436040
1624
+ * @throws 1475604050
1625
+ */
1626
+ public createFormElement(
1627
+ configuration: FormElementDefinition,
1628
+ identifierPathPrefix: string,
1629
+ parentFormElement: FormElement,
1630
+ registerPropertyValidators: boolean,
1631
+ disablePublishersOnSet?: boolean
1632
+ ): FormElement {
1633
+ let currentChildFormElements;
1634
+ assert('object' === $.type(configuration), 'Invalid parameter "configuration"', 1475375693);
1635
+ assert(utility.isNonEmptyString(configuration.identifier), '"identifier" must not be empty', 1475436040);
1636
+ assert(utility.isNonEmptyString(configuration.type), '"type" must not be empty', 1475604050);
1637
+
1638
+ registerPropertyValidators = !!registerPropertyValidators;
1639
+ if (utility.isUndefinedOrNull(disablePublishersOnSet)) {
1640
+ disablePublishersOnSet = true;
1641
+ }
1642
+ disablePublishersOnSet = !!disablePublishersOnSet;
1643
+
1644
+ const formElementTypeDefinition = repository.getFormEditorDefinition('formElements', configuration.type);
1645
+ const rawChildFormElements = configuration.renderables;
1646
+ delete configuration.renderables;
1647
+
1648
+ const collections: Record<string, Record<string, CollectionElementConfiguration>> = {};
1649
+ const predefinedDefaults: Record<string, unknown> = formElementTypeDefinition.predefinedDefaults || {};
1650
+ for (const collectionName of Object.keys(configuration)) {
1651
+ if (utility.isUndefinedOrNull(repository.formEditorDefinitions[collectionName as keyof FormEditorDefinitions])) {
1652
+ continue;
1653
+ }
1654
+
1655
+ predefinedDefaults[collectionName] = predefinedDefaults[collectionName] || {};
1656
+ collections[collectionName] = <Record<string, CollectionElementConfiguration>>$.extend(
1657
+ predefinedDefaults[collectionName] || {},
1658
+ configuration[collectionName as keyof typeof configuration]
1659
+ );
1660
+
1661
+ delete predefinedDefaults[collectionName];
1662
+ delete configuration[collectionName as keyof typeof configuration];
1663
+ }
1664
+
1665
+ identifierPathPrefix = identifierPathPrefix || '';
1666
+ const identifierPath = (identifierPathPrefix === '') ? configuration.identifier : identifierPathPrefix + '/' + configuration.identifier;
1667
+
1668
+ const concreteConfiguration: FormElementModelData = {
1669
+ ...<FormElementDefinition>predefinedDefaults,
1670
+ ...<FormElementDefinition>configuration,
1671
+ ...{
1672
+ renderables: (rawChildFormElements) ? true : null,
1673
+ __parentRenderable: null,
1674
+ __identifierPath: identifierPath
1675
+ }
1676
+ };
1677
+
1678
+ const formElement: FormElement = createModel(concreteConfiguration);
1679
+
1680
+ formElement.set('__parentRenderable', parentFormElement || null, disablePublishersOnSet);
1681
+
1682
+ for (const [collectionName, collectionElementConfigurations] of Object.entries(collections)) {
1683
+ let i = 0;
1684
+ for (const collectionElementConfiguration of Object.values(collectionElementConfigurations)) {
1685
+ let previousCreatePropertyCollectionElementIdentifier;
1686
+ const propertyCollectionElement = this.createPropertyCollectionElement(
1687
+ collectionElementConfiguration.identifier,
1688
+ collectionElementConfiguration,
1689
+ collectionName as keyof FormEditorDefinitions
1690
+ );
1691
+ if (i > 0) {
1692
+ previousCreatePropertyCollectionElementIdentifier = collections[collectionName][i - 1].identifier;
1693
+ }
1694
+ repository.addPropertyCollectionElement(
1695
+ propertyCollectionElement,
1696
+ collectionName,
1697
+ formElement,
1698
+ previousCreatePropertyCollectionElementIdentifier,
1699
+ true
1700
+ );
1701
+ ++i;
1702
+ }
1703
+ }
1704
+
1705
+ // Register property change publishers for properties that have not
1706
+ // been configured yet, but may be added by inspector components.
1707
+ if (Array.isArray(formElementTypeDefinition.editors)) {
1708
+ for (const editorConfig of formElementTypeDefinition.editors) {
1709
+ if (editorConfig.propertyPath) {
1710
+ formElement.on(editorConfig.propertyPath, 'core/formElement/somePropertyChanged');
1711
+ }
1712
+ }
1713
+ }
1714
+
1715
+ if (registerPropertyValidators) {
1716
+ if ('array' === $.type(formElementTypeDefinition.editors)) {
1717
+ for (let i = 0, len1 = formElementTypeDefinition.editors.length; i < len1; ++i) {
1718
+ if ('array' !== $.type(formElementTypeDefinition.editors[i].propertyValidators)) {
1719
+ continue;
1720
+ }
1721
+
1722
+ const propertyValidatorConfiguration: PropertyValidatorConfiguration = {
1723
+ propertyValidatorsMode: 'AND'
1724
+ };
1725
+ if (
1726
+ !utility.isUndefinedOrNull(formElementTypeDefinition.editors[i].propertyValidatorsMode)
1727
+ && formElementTypeDefinition.editors[i].propertyValidatorsMode === 'OR'
1728
+ ) {
1729
+ propertyValidatorConfiguration.propertyValidatorsMode = 'OR';
1730
+ }
1731
+
1732
+ propertyValidationService.addValidatorIdentifiersToFormElementProperty(
1733
+ formElement,
1734
+ formElementTypeDefinition.editors[i].propertyValidators,
1735
+ formElementTypeDefinition.editors[i].propertyPath,
1736
+ undefined,
1737
+ undefined,
1738
+ propertyValidatorConfiguration
1739
+ );
1740
+ }
1741
+ }
1742
+ }
1743
+
1744
+ if ('array' === $.type(rawChildFormElements)) {
1745
+ currentChildFormElements = [];
1746
+ for (let i = 0, len = rawChildFormElements.length; i < len; ++i) {
1747
+ currentChildFormElements.push(this.createFormElement(rawChildFormElements[i], identifierPath, formElement, registerPropertyValidators, disablePublishersOnSet));
1748
+ }
1749
+ formElement.set('renderables', currentChildFormElements, disablePublishersOnSet);
1750
+ }
1751
+ return formElement;
1752
+ }
1753
+
1754
+ /**
1755
+ * @throws 1475377160
1756
+ * @throws 1475377161
1757
+ * @throws 1475377162
1758
+ */
1759
+ public createPropertyCollectionElement(
1760
+ collectionElementIdentifier: string,
1761
+ collectionElementConfiguration: CollectionElementConfiguration,
1762
+ collectionName: keyof FormEditorDefinitions
1763
+ ): PropertyCollectionElement {
1764
+ let collectionElementPresets;
1765
+ assert(utility.isNonEmptyString(collectionElementIdentifier), 'Invalid parameter "collectionElementIdentifier"', 1475377160);
1766
+ assert('object' === $.type(collectionElementConfiguration), 'Invalid parameter "collectionElementConfiguration"', 1475377161);
1767
+ assert(utility.isNonEmptyString(collectionName), 'Invalid parameter "collectionName"', 1475377162);
1768
+
1769
+ collectionElementConfiguration.identifier = collectionElementIdentifier;
1770
+ const collectionDefinition = repository.getFormEditorDefinition(collectionName, collectionElementIdentifier);
1771
+ if ('predefinedDefaults' in collectionDefinition && collectionDefinition.predefinedDefaults) {
1772
+ collectionElementPresets = collectionDefinition.predefinedDefaults;
1773
+ } else {
1774
+ collectionElementPresets = {};
1775
+ }
1776
+
1777
+ return $.extend(collectionElementPresets, collectionElementConfiguration);
1778
+ }
1779
+ }
1780
+
1781
+ export class DataBackend {
1782
+ private endpoints: Endpoints = {};
1783
+ private prototypeName: string = null;
1784
+ private persistenceIdentifier: string = null;
1785
+
1786
+ /**
1787
+ * @throws 1475377488
1788
+ */
1789
+ public setEndpoints(endpoints: Endpoints): void {
1790
+ assert('object' === $.type(endpoints), 'Invalid parameter "endpoints"', 1475377488);
1791
+ this.endpoints = endpoints;
1792
+ }
1793
+
1794
+ /**
1795
+ * @throws 1475377489
1796
+ */
1797
+ public setPrototypeName(prototypeName: string): void {
1798
+ assert(utility.isNonEmptyString(prototypeName), 'Invalid parameter "prototypeName"', 1475928095);
1799
+ this.prototypeName = prototypeName;
1800
+ }
1801
+
1802
+ /**
1803
+ * @throws 1475377489
1804
+ */
1805
+ public setPersistenceIdentifier(persistenceIdentifier: string): void {
1806
+ assert(utility.isNonEmptyString(persistenceIdentifier), 'Invalid parameter "persistenceIdentifier"', 1475377489);
1807
+ this.persistenceIdentifier = persistenceIdentifier;
1808
+ }
1809
+
1810
+ /**
1811
+ * @publish core/ajax/saveFormDefinition/success
1812
+ * @publish core/ajax/error
1813
+ * @throws 1475520918
1814
+ */
1815
+ public saveFormDefinition(): void {
1816
+ assert(utility.isNonEmptyString(this.endpoints.saveForm), 'The endpoint "saveForm" is not configured', 1475520918);
1817
+
1818
+ if (runningAjaxRequests.saveForm) {
1819
+ runningAjaxRequests.saveForm.abort();
1820
+ }
1821
+
1822
+ runningAjaxRequests.saveForm = $.post(this.endpoints.saveForm, {
1823
+ formPersistenceIdentifier: this.persistenceIdentifier,
1824
+ formDefinition: JSON.stringify(utility.convertToSimpleObject(getApplicationStateStack().getCurrentState('formDefinition')))
1825
+ }, (data, textStatus, jqXHR): void => {
1826
+ if (runningAjaxRequests.saveForm !== jqXHR) {
1827
+ return;
1828
+ }
1829
+ runningAjaxRequests.saveForm = null;
1830
+ if (data.status === 'success') {
1831
+ publisherSubscriber.publish('core/ajax/saveFormDefinition/success', [data]);
1832
+ } else {
1833
+ publisherSubscriber.publish('core/ajax/saveFormDefinition/error', [data]);
1834
+ }
1835
+ });
1836
+ runningAjaxRequests.saveForm.fail((jqXHR, textStatus, errorThrown): void => {
1837
+ publisherSubscriber.publish('core/ajax/error', [jqXHR, textStatus, errorThrown]);
1838
+ });
1839
+ }
1840
+
1841
+ /**
1842
+ * @publish core/ajax/renderFormDefinitionPage/success
1843
+ * @publish core/ajax/error
1844
+ * @throws 1473447677
1845
+ * @throws 1475377781
1846
+ * @throws 1475377782
1847
+ */
1848
+ public renderFormDefinitionPage(pageIndex: number): void {
1849
+ assert($.isNumeric(pageIndex), 'Invalid parameter "pageIndex"', 1475377781);
1850
+ assert(utility.isNonEmptyString(this.endpoints.formPageRenderer), 'The endpoint "formPageRenderer" is not configured', 1473447677);
1851
+
1852
+ if (runningAjaxRequests.renderFormDefinitionPage) {
1853
+ runningAjaxRequests.renderFormDefinitionPage.abort();
1854
+ }
1855
+
1856
+ runningAjaxRequests.renderFormDefinitionPage = $.post(this.endpoints.formPageRenderer, {
1857
+ formDefinition: JSON.stringify(utility.convertToSimpleObject(getApplicationStateStack().getCurrentState('formDefinition'))),
1858
+ pageIndex: pageIndex,
1859
+ prototypeName: this.prototypeName
1860
+ }, (data: string, textStatus, jqXHR): void => {
1861
+ if (runningAjaxRequests.renderFormDefinitionPage !== jqXHR) {
1862
+ return;
1863
+ }
1864
+ runningAjaxRequests.renderFormDefinitionPage = null;
1865
+ publisherSubscriber.publish('core/ajax/renderFormDefinitionPage/success', [data, pageIndex]);
1866
+ });
1867
+ runningAjaxRequests.renderFormDefinitionPage.fail((jqXHR, textStatus, errorThrown): void => {
1868
+ publisherSubscriber.publish('core/ajax/error', [jqXHR, textStatus, errorThrown]);
1869
+ });
1870
+ }
1871
+ }
1872
+
1873
+ export class ApplicationStateStack {
1874
+ private stackSize: number = 10;
1875
+ private stackPointer: number = 0;
1876
+ private readonly stack: ApplicationState[] = [];
1877
+
1878
+ /**
1879
+ * @publish core/applicationState/add
1880
+ * @throws 1477847415
1881
+ */
1882
+ public add(
1883
+ applicationState: ApplicationState,
1884
+ disablePublishersOnSet: boolean
1885
+ ): void {
1886
+ assert('object' === $.type(applicationState), 'Invalid parameter "applicationState"', 1477847415);
1887
+ disablePublishersOnSet = !!disablePublishersOnSet;
1888
+
1889
+ $.extend(applicationState, {
1890
+ propertyValidationServiceRegisteredValidators: $.extend(true, {}, this.getCurrentState('propertyValidationServiceRegisteredValidators'))
1891
+ });
1892
+
1893
+ this.stack.splice(0, 0, applicationState);
1894
+ if (this.stack.length > this.stackSize) {
1895
+ this.stack.splice(this.stackSize - 1, (this.stack.length - this.stackSize));
1896
+ }
1897
+
1898
+ if (!disablePublishersOnSet) {
1899
+ publisherSubscriber.publish('core/applicationState/add', [
1900
+ applicationState,
1901
+ this.getCurrentStackPointer(),
1902
+ this.getCurrentStackSize()
1903
+ ]);
1904
+ }
1905
+ }
1906
+
1907
+ /**
1908
+ * @publish core/applicationState/add
1909
+ * @throws 1477872641
1910
+ */
1911
+ public addAndReset(
1912
+ applicationState: ApplicationState,
1913
+ disablePublishersOnSet?: boolean
1914
+ ): void {
1915
+ assert('object' === $.type(applicationState), 'Invalid parameter "applicationState"', 1477872641);
1916
+
1917
+ if (this.stackPointer > 0) {
1918
+ this.stack.splice(0, this.stackPointer);
1919
+ }
1920
+
1921
+ this.stackPointer = 0;
1922
+ this.add(applicationState, true);
1923
+
1924
+ if (!disablePublishersOnSet) {
1925
+ publisherSubscriber.publish(
1926
+ 'core/applicationState/add',
1927
+ [
1928
+ this.getCurrentState<undefined>(),
1929
+ this.getCurrentStackPointer(),
1930
+ this.getCurrentStackSize()
1931
+ ]
1932
+ );
1933
+ }
1934
+ }
1935
+
1936
+ /**
1937
+ * @throws 1477932754
1938
+ */
1939
+ public getCurrentState<T extends ApplicationStateType | undefined, R = T extends ApplicationStateType ? ApplicationState[T] : ApplicationState>(
1940
+ type?: T
1941
+ ): R | undefined {
1942
+ if (type === undefined) {
1943
+ return this.stack[this.stackPointer] as R || undefined;
1944
+ }
1945
+ assert(
1946
+ 'formDefinition' === type
1947
+ || 'currentlySelectedPageIndex' === type
1948
+ || 'currentlySelectedFormElementIdentifierPath' === type
1949
+ || 'propertyValidationServiceRegisteredValidators' === type,
1950
+
1951
+ 'Invalid parameter "type"', 1477932754
1952
+ );
1953
+
1954
+ if ('undefined' === $.type(this.stack[this.stackPointer])) {
1955
+ return undefined;
1956
+ }
1957
+ return (this.stack[this.stackPointer][type]) as R;
1958
+ }
1959
+
1960
+ /**
1961
+ * @throws 1477934111
1962
+ */
1963
+ public setCurrentState<T extends ApplicationStateType>(
1964
+ type: T,
1965
+ value: ApplicationState[T]
1966
+ ): void {
1967
+ assert(
1968
+ 'formDefinition' === type
1969
+ || 'currentlySelectedPageIndex' === type
1970
+ || 'currentlySelectedFormElementIdentifierPath' === type
1971
+ || 'propertyValidationServiceRegisteredValidators' === type,
1972
+
1973
+ 'Invalid parameter "type"', 1477934111
1974
+ );
1975
+ this.stack[this.stackPointer][type] = value;
1976
+ }
1977
+
1978
+ /**
1979
+ * @throws 1477846933
1980
+ */
1981
+ public setMaximalStackSize(stackSize: number): void {
1982
+ assert('number' === $.type(stackSize), 'Invalid parameter "size"', 1477846933);
1983
+ this.stackSize = stackSize;
1984
+ }
1985
+
1986
+ public getMaximalStackSize(): number {
1987
+ return this.stackSize;
1988
+ }
1989
+
1990
+ public getCurrentStackSize(): number {
1991
+ return this.stack.length;
1992
+ }
1993
+
1994
+ public getCurrentStackPointer(): number {
1995
+ return this.stackPointer;
1996
+ }
1997
+
1998
+ /**
1999
+ * @throws 1477852138
2000
+ */
2001
+ public setCurrentStackPointer(stackPointer: number): void {
2002
+ assert('number' === $.type(stackPointer), 'Invalid parameter "size"', 1477852138);
2003
+ if (stackPointer < 0) {
2004
+ this.stackPointer = 0;
2005
+ } else if (stackPointer > this.stack.length - 1) {
2006
+ this.stackPointer = this.stack.length - 1;
2007
+ } else {
2008
+ this.stackPointer = stackPointer;
2009
+ }
2010
+ }
2011
+
2012
+ public decrementCurrentStackPointer(): void {
2013
+ this.setCurrentStackPointer(--this.stackPointer);
2014
+ }
2015
+
2016
+ public incrementCurrentStackPointer(): void {
2017
+ this.setCurrentStackPointer(++this.stackPointer);
2018
+ }
2019
+ }
2020
+
2021
+ /**
2022
+ * @throws 1475358064
2023
+ */
2024
+ export function getRunningAjaxRequest<T extends keyof AjaxRequests>(
2025
+ ajaxRequestIdentifier: keyof AjaxRequests
2026
+ ): AjaxRequests[T] | null {
2027
+ assert(utility.isNonEmptyString(ajaxRequestIdentifier), 'Invalid parameter "ajaxRequestIdentifier"', 1475358064);
2028
+ return runningAjaxRequests[ajaxRequestIdentifier] || null;
2029
+ }
2030
+
2031
+ const utility = new Utility();
2032
+ const dataBackend = new DataBackend();
2033
+ const runningAjaxRequests: AjaxRequests = {};
2034
+ const propertyValidationService = new PropertyValidationService();
2035
+ const applicationStateStack = new ApplicationStateStack();
2036
+ const publisherSubscriber = new PublisherSubscriber();
2037
+ const repository = new Repository();
2038
+ const factory = new Factory();
2039
+
2040
+ export function getUtility(): Utility {
2041
+ return utility;
2042
+ }
2043
+
2044
+ export function getDataBackend(): DataBackend {
2045
+ return dataBackend;
2046
+ }
2047
+
2048
+ export function getPropertyValidationService(): PropertyValidationService {
2049
+ return propertyValidationService;
2050
+ }
2051
+
2052
+ export function getApplicationStateStack(): ApplicationStateStack {
2053
+ return applicationStateStack;
2054
+ }
2055
+
2056
+ export function getPublisherSubscriber(): PublisherSubscriber {
2057
+ return publisherSubscriber;
2058
+ }
2059
+
2060
+ export function getFactory(): Factory {
2061
+ return factory;
2062
+ }
2063
+
2064
+ export function getRepository(): Repository {
2065
+ return repository;
2066
+ }
2067
+
2068
+ declare global {
2069
+ interface PublisherSubscriberTopicArgumentsMap {
2070
+ 'core/applicationState/add': readonly [
2071
+ applicationState: ApplicationState,
2072
+ currentStackPointer: number,
2073
+ currentStackSize: number
2074
+ ];
2075
+ 'core/ajax/error': readonly [
2076
+ jqXHR: JQueryXHR,
2077
+ textStatus: string,
2078
+ errorThrown: string
2079
+ ];
2080
+ 'core/ajax/renderFormDefinitionPage/success': readonly [
2081
+ htmldata: string,
2082
+ pageIndex: number
2083
+ ];
2084
+ 'core/ajax/saveFormDefinition/error': readonly [
2085
+ data: {
2086
+ status: string,
2087
+ message: string,
2088
+ code: number
2089
+ }
2090
+ ];
2091
+ 'core/ajax/saveFormDefinition/success': readonly [
2092
+ data: {
2093
+ status: string,
2094
+ formDefinition: FormElementDefinition,
2095
+ }
2096
+ ],
2097
+ 'core/formElement/somePropertyChanged': readonly [
2098
+ propertyPath: string,
2099
+ value?: unknown | undefined,
2100
+ oldValue?: unknown | undefined,
2101
+ formElementIdentifierPath?: string,
2102
+ ];
2103
+ }
2104
+ }