@sapui5/sap.fe.core 1.99.0 → 1.101.1

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 (289) hide show
  1. package/package.json +6 -4
  2. package/src/sap/fe/core/.library +2 -3
  3. package/src/sap/fe/core/AnnotationHelper.js +43 -92
  4. package/src/sap/fe/core/AnnotationHelper.ts +43 -107
  5. package/src/sap/fe/core/AppComponent.js +381 -399
  6. package/src/sap/fe/core/AppComponent.ts +397 -0
  7. package/src/sap/fe/core/AppStateHandler.js +131 -162
  8. package/src/sap/fe/core/AppStateHandler.ts +2 -2
  9. package/src/sap/fe/core/BaseController.js +82 -58
  10. package/src/sap/fe/core/BaseController.ts +67 -0
  11. package/src/sap/fe/core/CommonUtils.js +179 -31
  12. package/src/sap/fe/core/CommonUtils.ts +295 -125
  13. package/src/sap/fe/core/ExtensionAPI.js +279 -274
  14. package/src/sap/fe/core/ExtensionAPI.ts +242 -0
  15. package/src/sap/fe/core/PageController.js +158 -29
  16. package/src/sap/fe/core/PageController.ts +65 -37
  17. package/src/sap/fe/core/RouterProxy.js +700 -750
  18. package/src/sap/fe/core/RouterProxy.ts +47 -31
  19. package/src/sap/fe/core/Synchronization.js +21 -31
  20. package/src/sap/fe/core/TemplateComponent.js +193 -118
  21. package/src/sap/fe/core/TemplateComponent.ts +104 -109
  22. package/src/sap/fe/core/TemplateModel.js +24 -44
  23. package/src/sap/fe/core/TemplateModel.ts +3 -3
  24. package/src/sap/fe/core/TransactionHelper.js +1368 -1369
  25. package/src/sap/fe/core/TransactionHelper.ts +201 -171
  26. package/src/sap/fe/core/actions/collaboration/ActivitySync.js +406 -0
  27. package/src/sap/fe/core/actions/collaboration/ActivitySync.ts +362 -0
  28. package/src/sap/fe/core/actions/collaboration/CollaborationCommon.js +146 -0
  29. package/src/sap/fe/core/actions/collaboration/CollaborationCommon.ts +129 -0
  30. package/src/sap/fe/core/actions/collaboration/Manage.js +264 -0
  31. package/src/sap/fe/core/actions/collaboration/Manage.ts +246 -0
  32. package/src/sap/fe/core/actions/collaboration/ManageDialog.fragment.xml +100 -0
  33. package/src/sap/fe/core/actions/collaboration/UserDetails.fragment.xml +13 -0
  34. package/src/sap/fe/core/actions/draft.js +324 -220
  35. package/src/sap/fe/core/actions/draft.ts +209 -133
  36. package/src/sap/fe/core/actions/messageHandling.js +79 -48
  37. package/src/sap/fe/core/actions/messageHandling.ts +113 -83
  38. package/src/sap/fe/core/actions/operations.js +37 -18
  39. package/src/sap/fe/core/actions/operations.ts +51 -20
  40. package/src/sap/fe/core/actions/sticky.js +17 -4
  41. package/src/sap/fe/core/actions/sticky.ts +21 -4
  42. package/src/sap/fe/core/buildingBlocks/AttributeModel.js +60 -0
  43. package/src/sap/fe/core/buildingBlocks/AttributeModel.ts +37 -0
  44. package/src/sap/fe/core/buildingBlocks/BuildingBlock.js +165 -0
  45. package/src/sap/fe/core/buildingBlocks/BuildingBlock.ts +178 -0
  46. package/src/sap/fe/core/buildingBlocks/BuildingBlockRuntime.js +707 -0
  47. package/src/sap/fe/core/buildingBlocks/BuildingBlockRuntime.ts +628 -0
  48. package/src/sap/fe/core/buildingBlocks/TraceInfo.js +436 -0
  49. package/src/sap/fe/core/buildingBlocks/TraceInfo.ts +431 -0
  50. package/src/sap/fe/core/controllerextensions/EditFlow.js +1854 -1669
  51. package/src/sap/fe/core/controllerextensions/EditFlow.ts +1792 -0
  52. package/src/sap/fe/core/controllerextensions/IntentBasedNavigation.js +79 -54
  53. package/src/sap/fe/core/controllerextensions/IntentBasedNavigation.ts +60 -0
  54. package/src/sap/fe/core/controllerextensions/InternalEditFlow.js +716 -779
  55. package/src/sap/fe/core/controllerextensions/InternalEditFlow.ts +785 -0
  56. package/src/sap/fe/core/controllerextensions/InternalIntentBasedNavigation.js +796 -816
  57. package/src/sap/fe/core/controllerextensions/InternalIntentBasedNavigation.ts +810 -0
  58. package/src/sap/fe/core/controllerextensions/InternalRouting.js +1056 -1005
  59. package/src/sap/fe/core/controllerextensions/InternalRouting.ts +1001 -0
  60. package/src/sap/fe/core/controllerextensions/KPIManagement.js +498 -532
  61. package/src/sap/fe/core/controllerextensions/KPIManagement.ts +13 -12
  62. package/src/sap/fe/core/controllerextensions/MassEdit.js +141 -169
  63. package/src/sap/fe/core/controllerextensions/MassEdit.ts +155 -0
  64. package/src/sap/fe/core/controllerextensions/MessageHandler.js +221 -244
  65. package/src/sap/fe/core/controllerextensions/MessageHandler.ts +215 -0
  66. package/src/sap/fe/core/controllerextensions/PageReady.js +312 -345
  67. package/src/sap/fe/core/controllerextensions/PageReady.ts +57 -53
  68. package/src/sap/fe/core/controllerextensions/Paginator.js +188 -175
  69. package/src/sap/fe/core/controllerextensions/Paginator.ts +169 -0
  70. package/src/sap/fe/core/controllerextensions/Placeholder.js +157 -149
  71. package/src/sap/fe/core/controllerextensions/Placeholder.ts +149 -0
  72. package/src/sap/fe/core/controllerextensions/Routing.js +144 -125
  73. package/src/sap/fe/core/controllerextensions/Routing.ts +131 -0
  74. package/src/sap/fe/core/controllerextensions/RoutingListener.js +7 -6
  75. package/src/sap/fe/core/controllerextensions/RoutingListener.ts +3 -0
  76. package/src/sap/fe/core/controllerextensions/Share.js +230 -268
  77. package/src/sap/fe/core/controllerextensions/Share.ts +231 -0
  78. package/src/sap/fe/core/controllerextensions/SideEffects.js +603 -644
  79. package/src/sap/fe/core/controllerextensions/SideEffects.ts +68 -68
  80. package/src/sap/fe/core/controllerextensions/ViewState.js +774 -806
  81. package/src/sap/fe/core/controllerextensions/ViewState.ts +796 -0
  82. package/src/sap/fe/core/controls/ActionParameterDialog.fragment.xml +2 -2
  83. package/src/sap/fe/core/controls/ActionPartial.fragment.xml +2 -2
  84. package/src/sap/fe/core/controls/Any.js +28 -0
  85. package/src/sap/fe/core/controls/Any.ts +30 -0
  86. package/src/sap/fe/core/controls/CommandExecution.js +92 -68
  87. package/src/sap/fe/core/controls/CommandExecution.ts +72 -0
  88. package/src/sap/fe/core/controls/ConditionalWrapper.js +165 -79
  89. package/src/sap/fe/core/controls/ConditionalWrapper.ts +74 -0
  90. package/src/sap/fe/core/controls/CustomFilterFieldContentWrapper.js +366 -0
  91. package/src/sap/fe/core/controls/CustomFilterFieldContentWrapper.ts +278 -0
  92. package/src/sap/fe/core/controls/CustomQuickViewPage.js +167 -125
  93. package/src/sap/fe/core/controls/CustomQuickViewPage.ts +116 -0
  94. package/src/sap/fe/core/controls/DataLossOrDraftDiscard/DataLossDraft.fragment.xml +44 -5
  95. package/src/sap/fe/core/controls/DataLossOrDraftDiscard/DataLossOrDraftDiscardHandler.js +163 -122
  96. package/src/sap/fe/core/controls/DataLossOrDraftDiscard/DataLossOrDraftDiscardHandler.ts +155 -0
  97. package/src/sap/fe/core/controls/FieldWrapper.js +212 -141
  98. package/src/sap/fe/core/controls/FieldWrapper.ts +104 -0
  99. package/src/sap/fe/core/controls/FileWrapper.js +313 -0
  100. package/src/sap/fe/core/controls/FileWrapper.ts +169 -0
  101. package/src/sap/fe/core/controls/FilterBar.js +197 -159
  102. package/src/sap/fe/core/controls/FilterBar.ts +148 -0
  103. package/src/sap/fe/core/controls/FormElementWrapper.js +100 -39
  104. package/src/sap/fe/core/controls/FormElementWrapper.ts +37 -0
  105. package/src/sap/fe/core/controls/MultiValueParameterDelegate.js +37 -42
  106. package/src/sap/fe/core/controls/MultiValueParameterDelegate.ts +31 -0
  107. package/src/sap/fe/core/controls/filterbar/FilterContainer.js +147 -115
  108. package/src/sap/fe/core/controls/filterbar/FilterContainer.ts +102 -0
  109. package/src/sap/fe/core/controls/filterbar/VisualFilter.js +300 -265
  110. package/src/sap/fe/core/controls/filterbar/VisualFilter.ts +252 -0
  111. package/src/sap/fe/core/controls/filterbar/VisualFilterContainer.js +185 -140
  112. package/src/sap/fe/core/controls/filterbar/VisualFilterContainer.ts +125 -0
  113. package/src/sap/fe/core/controls/filterbar/utils/VisualFilterUtils.js +335 -322
  114. package/src/sap/fe/core/controls/filterbar/utils/VisualFilterUtils.ts +337 -0
  115. package/src/sap/fe/core/controls/massEdit/MassEditDialog.fragment.xml +37 -42
  116. package/src/sap/fe/core/controls/massEdit/MassEditHandlers.js +75 -74
  117. package/src/sap/fe/core/controls/massEdit/MassEditHandlers.ts +71 -0
  118. package/src/sap/fe/core/converters/ConverterContext.js +348 -379
  119. package/src/sap/fe/core/converters/ConverterContext.ts +19 -16
  120. package/src/sap/fe/core/converters/ManifestSettings.js +13 -1
  121. package/src/sap/fe/core/converters/ManifestSettings.ts +17 -2
  122. package/src/sap/fe/core/converters/ManifestWrapper.js +354 -378
  123. package/src/sap/fe/core/converters/ManifestWrapper.ts +10 -0
  124. package/src/sap/fe/core/converters/MetaModelConverter.js +6 -4
  125. package/src/sap/fe/core/converters/MetaModelConverter.ts +5 -2
  126. package/src/sap/fe/core/converters/TemplateConverter.js +1 -1
  127. package/src/sap/fe/core/converters/TemplateConverter.ts +2 -1
  128. package/src/sap/fe/core/converters/annotations/DataField.js +26 -13
  129. package/src/sap/fe/core/converters/annotations/DataField.ts +40 -17
  130. package/src/sap/fe/core/converters/controls/Common/Action.js +10 -10
  131. package/src/sap/fe/core/converters/controls/Common/Action.ts +20 -19
  132. package/src/sap/fe/core/converters/controls/Common/Chart.js +8 -8
  133. package/src/sap/fe/core/converters/controls/Common/Chart.ts +12 -11
  134. package/src/sap/fe/core/converters/controls/Common/Form.js +6 -6
  135. package/src/sap/fe/core/converters/controls/Common/Form.ts +7 -3
  136. package/src/sap/fe/core/converters/controls/Common/KPI.js +1 -1
  137. package/src/sap/fe/core/converters/controls/Common/KPI.ts +2 -2
  138. package/src/sap/fe/core/converters/controls/Common/Table.js +326 -86
  139. package/src/sap/fe/core/converters/controls/Common/Table.ts +384 -167
  140. package/src/sap/fe/core/converters/controls/Common/table/StandardActions.js +120 -55
  141. package/src/sap/fe/core/converters/controls/Common/table/StandardActions.ts +158 -98
  142. package/src/sap/fe/core/converters/controls/ListReport/FilterBar.js +206 -223
  143. package/src/sap/fe/core/converters/controls/ListReport/FilterBar.ts +263 -287
  144. package/src/sap/fe/core/converters/controls/ObjectPage/HeaderFacet.js +6 -6
  145. package/src/sap/fe/core/converters/controls/ObjectPage/HeaderFacet.ts +20 -18
  146. package/src/sap/fe/core/converters/controls/ObjectPage/SubSection.js +5 -2
  147. package/src/sap/fe/core/converters/controls/ObjectPage/SubSection.ts +4 -1
  148. package/src/sap/fe/core/converters/helpers/Aggregation.js +115 -133
  149. package/src/sap/fe/core/converters/helpers/BindingHelper.js +20 -6
  150. package/src/sap/fe/core/converters/helpers/BindingHelper.ts +16 -4
  151. package/src/sap/fe/core/converters/helpers/ConfigurableObject.js +12 -1
  152. package/src/sap/fe/core/converters/helpers/ConfigurableObject.ts +11 -0
  153. package/src/sap/fe/core/converters/helpers/Key.js +42 -57
  154. package/src/sap/fe/core/converters/helpers/Key.ts +1 -1
  155. package/src/sap/fe/core/converters/objectPage/FormMenuActions.js +1 -1
  156. package/src/sap/fe/core/converters/objectPage/FormMenuActions.ts +0 -4
  157. package/src/sap/fe/core/converters/objectPage/HeaderAndFooterAction.js +51 -27
  158. package/src/sap/fe/core/converters/objectPage/HeaderAndFooterAction.ts +69 -43
  159. package/src/sap/fe/core/converters/templates/ListReportConverter.js +42 -25
  160. package/src/sap/fe/core/converters/templates/ListReportConverter.ts +91 -65
  161. package/src/sap/fe/core/converters/templates/ObjectPageConverter.js +11 -9
  162. package/src/sap/fe/core/converters/templates/ObjectPageConverter.ts +8 -8
  163. package/src/sap/fe/core/designtime/AppComponent.designtime.js +92 -98
  164. package/src/sap/fe/core/designtime/AppComponent.designtime.ts +91 -0
  165. package/src/sap/fe/core/formatters/CollaborationFormatter.js +104 -0
  166. package/src/sap/fe/core/formatters/CollaborationFormatter.ts +60 -0
  167. package/src/sap/fe/core/formatters/KPIFormatter.js +3 -12
  168. package/src/sap/fe/core/formatters/KPIFormatter.ts +3 -2
  169. package/src/sap/fe/core/formatters/TableFormatter.js +53 -2
  170. package/src/sap/fe/core/formatters/TableFormatter.ts +51 -0
  171. package/src/sap/fe/core/formatters/ValueFormatter.js +4 -4
  172. package/src/sap/fe/core/formatters/ValueFormatter.ts +4 -7
  173. package/src/sap/fe/core/fpm/Component.js +80 -55
  174. package/src/sap/fe/core/fpm/Component.ts +43 -0
  175. package/src/sap/fe/core/helpers/AppStartupHelper.js +323 -309
  176. package/src/sap/fe/core/helpers/AppStartupHelper.ts +363 -337
  177. package/src/sap/fe/core/helpers/BindingExpression.js +7 -7
  178. package/src/sap/fe/core/helpers/BindingExpression.ts +7 -7
  179. package/src/sap/fe/core/helpers/ClassSupport.js +307 -166
  180. package/src/sap/fe/core/helpers/ClassSupport.ts +348 -155
  181. package/src/sap/fe/core/helpers/DynamicAnnotationPathHelper.js +5 -4
  182. package/src/sap/fe/core/helpers/DynamicAnnotationPathHelper.ts +1 -5
  183. package/src/sap/fe/core/helpers/FPMHelper.js +1 -1
  184. package/src/sap/fe/core/helpers/FPMHelper.ts +1 -1
  185. package/src/sap/fe/core/helpers/MassEditHelper.js +735 -684
  186. package/src/sap/fe/core/helpers/MassEditHelper.ts +803 -0
  187. package/src/sap/fe/core/helpers/ModelHelper.js +53 -1
  188. package/src/sap/fe/core/helpers/ModelHelper.ts +46 -0
  189. package/src/sap/fe/core/helpers/PasteHelper.js +4 -4
  190. package/src/sap/fe/core/helpers/PasteHelper.ts +4 -3
  191. package/src/sap/fe/core/helpers/SemanticDateOperators.js +7 -3
  192. package/src/sap/fe/core/helpers/SemanticDateOperators.ts +7 -1
  193. package/src/sap/fe/core/helpers/SemanticKeyHelper.js +1 -1
  194. package/src/sap/fe/core/helpers/SemanticKeyHelper.ts +1 -1
  195. package/src/sap/fe/core/helpers/StableIdHelper.js +1 -7
  196. package/src/sap/fe/core/helpers/StableIdHelper.ts +0 -4
  197. package/src/sap/fe/core/jsx-runtime/jsx.js +35 -5
  198. package/src/sap/fe/core/jsx-runtime/jsx.ts +22 -8
  199. package/src/sap/fe/core/library.js +425 -451
  200. package/src/sap/fe/core/library.support.js +22 -33
  201. package/src/sap/fe/core/library.support.ts +23 -0
  202. package/src/sap/fe/core/library.ts +420 -0
  203. package/src/sap/fe/core/manifestMerger/ChangePageConfiguration.js +5 -3
  204. package/src/sap/fe/core/manifestMerger/ChangePageConfiguration.ts +4 -4
  205. package/src/sap/fe/core/messagebundle.properties +45 -13
  206. package/src/sap/fe/core/messagebundle_ar.properties +29 -7
  207. package/src/sap/fe/core/messagebundle_bg.properties +29 -7
  208. package/src/sap/fe/core/messagebundle_ca.properties +29 -7
  209. package/src/sap/fe/core/messagebundle_cs.properties +29 -7
  210. package/src/sap/fe/core/messagebundle_cy.properties +29 -7
  211. package/src/sap/fe/core/messagebundle_da.properties +29 -7
  212. package/src/sap/fe/core/messagebundle_de.properties +29 -7
  213. package/src/sap/fe/core/messagebundle_el.properties +29 -7
  214. package/src/sap/fe/core/messagebundle_en.properties +29 -7
  215. package/src/sap/fe/core/messagebundle_en_GB.properties +29 -7
  216. package/src/sap/fe/core/messagebundle_en_US_sappsd.properties +29 -7
  217. package/src/sap/fe/core/messagebundle_en_US_saprigi.properties +29 -7
  218. package/src/sap/fe/core/messagebundle_en_US_saptrc.properties +29 -7
  219. package/src/sap/fe/core/messagebundle_es.properties +29 -7
  220. package/src/sap/fe/core/messagebundle_es_MX.properties +29 -7
  221. package/src/sap/fe/core/messagebundle_et.properties +29 -7
  222. package/src/sap/fe/core/messagebundle_fi.properties +30 -8
  223. package/src/sap/fe/core/messagebundle_fr.properties +31 -9
  224. package/src/sap/fe/core/messagebundle_fr_CA.properties +31 -9
  225. package/src/sap/fe/core/messagebundle_hi.properties +29 -7
  226. package/src/sap/fe/core/messagebundle_hr.properties +29 -7
  227. package/src/sap/fe/core/messagebundle_hu.properties +29 -7
  228. package/src/sap/fe/core/messagebundle_id.properties +29 -7
  229. package/src/sap/fe/core/messagebundle_it.properties +29 -7
  230. package/src/sap/fe/core/messagebundle_iw.properties +29 -7
  231. package/src/sap/fe/core/messagebundle_ja.properties +28 -6
  232. package/src/sap/fe/core/messagebundle_kk.properties +29 -7
  233. package/src/sap/fe/core/messagebundle_ko.properties +29 -7
  234. package/src/sap/fe/core/messagebundle_lt.properties +29 -7
  235. package/src/sap/fe/core/messagebundle_lv.properties +30 -8
  236. package/src/sap/fe/core/messagebundle_ms.properties +29 -7
  237. package/src/sap/fe/core/messagebundle_nl.properties +29 -7
  238. package/src/sap/fe/core/messagebundle_no.properties +29 -7
  239. package/src/sap/fe/core/messagebundle_pl.properties +29 -7
  240. package/src/sap/fe/core/messagebundle_pt.properties +30 -8
  241. package/src/sap/fe/core/messagebundle_pt_PT.properties +29 -7
  242. package/src/sap/fe/core/messagebundle_ro.properties +29 -7
  243. package/src/sap/fe/core/messagebundle_ru.properties +29 -7
  244. package/src/sap/fe/core/messagebundle_sh.properties +29 -7
  245. package/src/sap/fe/core/messagebundle_sk.properties +29 -7
  246. package/src/sap/fe/core/messagebundle_sl.properties +29 -7
  247. package/src/sap/fe/core/messagebundle_sv.properties +30 -8
  248. package/src/sap/fe/core/messagebundle_th.properties +28 -6
  249. package/src/sap/fe/core/messagebundle_tr.properties +32 -10
  250. package/src/sap/fe/core/messagebundle_uk.properties +29 -7
  251. package/src/sap/fe/core/messagebundle_vi.properties +29 -7
  252. package/src/sap/fe/core/messagebundle_zh_CN.properties +29 -7
  253. package/src/sap/fe/core/messagebundle_zh_TW.properties +29 -7
  254. package/src/sap/fe/core/services/AsyncComponentServiceFactory.js +47 -73
  255. package/src/sap/fe/core/services/AsyncComponentServiceFactory.ts +1 -1
  256. package/src/sap/fe/core/services/CacheHandlerServiceFactory.js +158 -196
  257. package/src/sap/fe/core/services/CacheHandlerServiceFactory.ts +5 -6
  258. package/src/sap/fe/core/services/EnvironmentServiceFactory.js +70 -96
  259. package/src/sap/fe/core/services/EnvironmentServiceFactory.ts +7 -6
  260. package/src/sap/fe/core/services/NavigationServiceFactory.js +287 -342
  261. package/src/sap/fe/core/services/NavigationServiceFactory.ts +11 -14
  262. package/src/sap/fe/core/services/ResourceModelServiceFactory.js +70 -105
  263. package/src/sap/fe/core/services/ResourceModelServiceFactory.ts +6 -3
  264. package/src/sap/fe/core/services/RoutingServiceFactory.js +796 -820
  265. package/src/sap/fe/core/services/RoutingServiceFactory.ts +62 -53
  266. package/src/sap/fe/core/services/ShellServicesFactory.js +694 -741
  267. package/src/sap/fe/core/services/ShellServicesFactory.ts +33 -33
  268. package/src/sap/fe/core/services/SideEffectsServiceFactory.js +570 -595
  269. package/src/sap/fe/core/services/SideEffectsServiceFactory.ts +23 -4
  270. package/src/sap/fe/core/services/TemplatedViewServiceFactory.js +357 -389
  271. package/src/sap/fe/core/services/TemplatedViewServiceFactory.ts +25 -29
  272. package/src/sap/fe/core/services/view/TemplatingErrorPage.controller.js +43 -5
  273. package/src/sap/fe/core/services/view/TemplatingErrorPage.controller.ts +7 -4
  274. package/src/sap/fe/core/support/CommonHelper.js +1 -1
  275. package/src/sap/fe/core/support/CommonHelper.ts +1 -4
  276. package/src/sap/fe/core/support/Diagnostics.js +36 -48
  277. package/src/sap/fe/core/templating/DataModelPathHelper.js +91 -90
  278. package/src/sap/fe/core/templating/DataModelPathHelper.ts +126 -123
  279. package/src/sap/fe/core/templating/DisplayModeFormatter.js +23 -3
  280. package/src/sap/fe/core/templating/DisplayModeFormatter.ts +26 -5
  281. package/src/sap/fe/core/templating/FilterHelper.js +25 -32
  282. package/src/sap/fe/core/templating/FilterHelper.ts +36 -35
  283. package/src/sap/fe/core/templating/PropertyHelper.js +16 -2
  284. package/src/sap/fe/core/templating/PropertyHelper.ts +31 -24
  285. package/src/sap/fe/core/templating/UIFormatters.js +150 -44
  286. package/src/sap/fe/core/templating/UIFormatters.ts +165 -67
  287. package/src/sap/fe/core/type/Email.js +26 -8
  288. package/src/sap/fe/core/type/Email.ts +8 -7
  289. package/src/sap/fe/core/controllerextensions/ControllerExtensionMetadata.js +0 -75
@@ -0,0 +1,1001 @@
1
+ import Log from "sap/base/Log";
2
+ import ActivitySync from "sap/fe/core/actions/collaboration/ActivitySync";
3
+ import draft from "sap/fe/core/actions/draft";
4
+ import AppComponent from "sap/fe/core/AppComponent";
5
+ import BusyLocker from "sap/fe/core/BusyLocker";
6
+ import CommonUtils from "sap/fe/core/CommonUtils";
7
+ import {
8
+ defineUI5Class,
9
+ EnhanceWithUI5,
10
+ extensible,
11
+ finalExtension,
12
+ methodOverride,
13
+ publicExtension
14
+ } from "sap/fe/core/helpers/ClassSupport";
15
+ import EditState from "sap/fe/core/helpers/EditState";
16
+ import ModelHelper from "sap/fe/core/helpers/ModelHelper";
17
+ import SemanticKeyHelper from "sap/fe/core/helpers/SemanticKeyHelper";
18
+ import FELibrary from "sap/fe/core/library";
19
+ import PageController from "sap/fe/core/PageController";
20
+ import RouterProxy from "sap/fe/core/RouterProxy";
21
+ import { RoutingService } from "sap/fe/core/services/RoutingServiceFactory";
22
+ import TemplateComponent from "sap/fe/core/TemplateComponent";
23
+ import Event from "sap/ui/base/Event";
24
+ import Component from "sap/ui/core/Component";
25
+ import Core from "sap/ui/core/Core";
26
+ import ControllerExtension from "sap/ui/core/mvc/ControllerExtension";
27
+ import OverrideExecution from "sap/ui/core/mvc/OverrideExecution";
28
+ import View from "sap/ui/core/mvc/View";
29
+ import Router from "sap/ui/core/routing/Router";
30
+ import Filter from "sap/ui/model/Filter";
31
+ import FilterOperator from "sap/ui/model/FilterOperator";
32
+ import JSONModel from "sap/ui/model/json/JSONModel";
33
+ import Context from "sap/ui/model/odata/v4/Context";
34
+ import { CoreEx } from "types/extension_types";
35
+
36
+ /**
37
+ * {@link sap.ui.core.mvc.ControllerExtension Controller extension}
38
+ *
39
+ * @namespace
40
+ * @alias sap.fe.core.controllerextensions.InternalRouting
41
+ *
42
+ * @private
43
+ * @since 1.74.0
44
+ */
45
+ @defineUI5Class("sap.fe.core.controllerextensions.InternalRouting")
46
+ class InternalRouting extends ControllerExtension {
47
+ private base!: PageController;
48
+ private _oView!: View;
49
+ private _oAppComponent!: AppComponent;
50
+ private _oPageComponent!: EnhanceWithUI5<TemplateComponent> | null;
51
+ private _oRouter!: Router;
52
+ private _oRoutingService!: RoutingService;
53
+ private _oRouterProxy!: RouterProxy;
54
+ private _fnRouteMatchedBound!: Function;
55
+ private _oTargetInformation: any;
56
+
57
+ @methodOverride()
58
+ onExit() {
59
+ this._oRoutingService && this._oRoutingService.detachRouteMatched(this._fnRouteMatchedBound);
60
+ }
61
+
62
+ @methodOverride()
63
+ onInit() {
64
+ this._oView = this.base.getView();
65
+ this._oAppComponent = CommonUtils.getAppComponent(this._oView);
66
+ this._oPageComponent = Component.getOwnerComponentFor(this._oView) as EnhanceWithUI5<TemplateComponent>;
67
+ this._oRouter = this._oAppComponent.getRouter();
68
+ this._oRouterProxy = (this._oAppComponent as any).getRouterProxy();
69
+
70
+ if (!this._oAppComponent || !this._oPageComponent) {
71
+ throw new Error("Failed to initialize controler extension 'sap.fe.core.controllerextesions.InternalRouting");
72
+ }
73
+
74
+ // eslint-disable-next-line @typescript-eslint/ban-ts-comment
75
+ // @ts-ignore
76
+ if (this._oAppComponent === this._oPageComponent) {
77
+ // The view isn't hosted in a dedicated UIComponent, but directly in the app
78
+ // --> just keep the view
79
+ this._oPageComponent = null;
80
+ }
81
+
82
+ this._oAppComponent
83
+ .getService("routingService")
84
+ .then((oRoutingService: RoutingService) => {
85
+ this._oRoutingService = oRoutingService;
86
+ this._fnRouteMatchedBound = this._onRouteMatched.bind(this);
87
+ this._oRoutingService.attachRouteMatched(this._fnRouteMatchedBound);
88
+ this._oTargetInformation = oRoutingService.getTargetInformationFor(this._oPageComponent || this._oView);
89
+ })
90
+ .catch(function () {
91
+ throw new Error("This controller extension cannot work without a 'routingService' on the main AppComponent");
92
+ });
93
+ }
94
+
95
+ /**
96
+ * Triggered every time this controller is a navigation target.
97
+ */
98
+ @publicExtension()
99
+ @extensible(OverrideExecution.After)
100
+ onRouteMatched() {
101
+ /**/
102
+ }
103
+
104
+ @publicExtension()
105
+ @extensible(OverrideExecution.After)
106
+ onRouteMatchedFinished() {
107
+ /**/
108
+ }
109
+
110
+ @publicExtension()
111
+ @extensible(OverrideExecution.After)
112
+ onBeforeBinding(oBindingContext: any, mParameters?: any) {
113
+ const oRouting = (this.base.getView().getController() as any).routing;
114
+ if (oRouting && oRouting.onBeforeBinding) {
115
+ oRouting.onBeforeBinding(oBindingContext, mParameters);
116
+ }
117
+ }
118
+
119
+ @publicExtension()
120
+ @extensible(OverrideExecution.After)
121
+ onAfterBinding(oBindingContext: any, mParameters?: any) {
122
+ (this._oAppComponent as any).getRootViewController().onContextBoundToView(oBindingContext);
123
+ const oRouting = (this.base.getView().getController() as any).routing;
124
+ if (oRouting && oRouting.onAfterBinding) {
125
+ oRouting.onAfterBinding(oBindingContext, mParameters);
126
+ }
127
+ }
128
+
129
+ ///////////////////////////////////////////////////////////
130
+ // Methods triggering a navigation after a user action
131
+ // (e.g. click on a table row, button, etc...)
132
+ ///////////////////////////////////////////////////////////
133
+
134
+ /**
135
+ * Navigates to the specified navigation target.
136
+ *
137
+ * @param {sap.ui.model.odata.v4.Context} oContext Context instance
138
+ * @param {string} sNavigationTargetName Navigation target name
139
+ * @param {object} oSemanticObject Semantic object
140
+ * @param {boolean} bPreserveHistory True to force the new URL to be added at the end of the browser history (no replace)
141
+ * @ui5-restricted
142
+ */
143
+ @publicExtension()
144
+ navigateToTarget(oContext: any, sNavigationTargetName: string, oSemanticObject?: object, bPreserveHistory?: boolean) {
145
+ const oNavigationConfiguration =
146
+ this._oPageComponent &&
147
+ this._oPageComponent.getNavigationConfiguration &&
148
+ this._oPageComponent.getNavigationConfiguration(sNavigationTargetName);
149
+ if (oNavigationConfiguration) {
150
+ const oDetailRoute = oNavigationConfiguration.detail;
151
+ const sRouteName = oDetailRoute.route;
152
+ const mParameterMapping = oDetailRoute.parameters;
153
+ this._oRoutingService.navigateTo(oContext, sRouteName, mParameterMapping, bPreserveHistory);
154
+ } else {
155
+ this._oRoutingService.navigateTo(oContext, null, null, bPreserveHistory);
156
+ }
157
+ this._oView.getViewData();
158
+ }
159
+
160
+ /**
161
+ * Navigates to the specified navigation target route.
162
+ *
163
+ * @param {string} sTargetRouteName Name of the target route
164
+ * @param {object} [oParameters] Parameters to be used with route to create the target hash
165
+ * @returns {Promise} Promise that is resolved when the navigation is finalized
166
+ * @ui5-restricted
167
+ */
168
+ @publicExtension()
169
+ navigateToRoute(sTargetRouteName: string, oParameters?: object) {
170
+ return this._oRoutingService.navigateToRoute(sTargetRouteName, oParameters);
171
+ }
172
+
173
+ /**
174
+ * Navigates to a specific context.
175
+ *
176
+ * @param {sap.ui.model.odata.v4.Context} oContext The context to be navigated to
177
+ * @param {object} [mParameters] Optional navigation parameters
178
+ * @returns {Promise} Promise resolved when the navigation has been triggered
179
+ *
180
+ * @ui5-restricted
181
+ */
182
+ @publicExtension()
183
+ @finalExtension()
184
+ navigateToContext(oContext: any, mParameters?: any): Promise<void> {
185
+ const oContextInfo: any = {};
186
+ mParameters = mParameters || {};
187
+
188
+ if (oContext.isA("sap.ui.model.odata.v4.ODataListBinding")) {
189
+ if (mParameters.asyncContext) {
190
+ // the context is either created async (Promise)
191
+ // We need to activate the routeMatchSynchro on the RouterProxy to avoid that
192
+ // the subsequent call to navigateToContext conflicts with the current one
193
+ this._oRouterProxy.activateRouteMatchSynchronization();
194
+
195
+ mParameters.asyncContext
196
+ .then((oContext: any) => {
197
+ // once the context is returned we navigate into it
198
+ this.navigateToContext(oContext, {
199
+ checkNoHashChange: mParameters.checkNoHashChange,
200
+ editable: mParameters.editable,
201
+ bPersistOPScroll: mParameters.bPersistOPScroll,
202
+ updateFCLLevel: mParameters.updateFCLLevel,
203
+ bForceFocus: mParameters.bForceFocus,
204
+ bNavigateToSiblingEntity: mParameters.bNavigateToSiblingEntity
205
+ });
206
+ })
207
+ .catch(function (oError: any) {
208
+ Log.error("Error with the async context", oError);
209
+ });
210
+ } else if (!mParameters.bDeferredContext) {
211
+ // Navigate to a list binding not yet supported
212
+ throw "navigation to a list binding is not yet supported";
213
+ }
214
+ }
215
+
216
+ if (mParameters.callExtension) {
217
+ const oInternalModel = this._oView.getModel("internal") as JSONModel;
218
+ oInternalModel.setProperty("/paginatorCurrentContext", null);
219
+
220
+ oContextInfo.sourceBindingContext = oContext.getObject();
221
+ oContextInfo.bindingContext = oContext;
222
+ if (mParameters.oEvent) {
223
+ oContextInfo.oEvent = mParameters.oEvent;
224
+ }
225
+ // Storing the selected context to use it in internal route navigation if neccessary.
226
+ const bOverrideNav = (this.base.getView().getController() as any).routing.onBeforeNavigation(oContextInfo);
227
+ if (bOverrideNav) {
228
+ oInternalModel.setProperty("/paginatorCurrentContext", oContext);
229
+ return Promise.resolve();
230
+ }
231
+ }
232
+ mParameters.FCLLevel = this._getFCLLevel();
233
+
234
+ return this._oRoutingService.navigateToContext(oContext, mParameters, this._oView.getViewData(), this._oTargetInformation);
235
+ }
236
+
237
+ /**
238
+ * Navigates backwards from a context.
239
+ *
240
+ * @param {sap.ui.model.odata.v4.Context} oContext Context to be navigated from
241
+ * @param {object} [mParameters] Optional navigation parameters
242
+ * @returns {Promise} Promise resolved when the navigation has been triggered
243
+ *
244
+ * @ui5-restricted
245
+ */
246
+ @publicExtension()
247
+ @finalExtension()
248
+ navigateBackFromContext(oContext: any, mParameters?: any) {
249
+ mParameters = mParameters || {};
250
+ mParameters.updateFCLLevel = -1;
251
+
252
+ return this.navigateToContext(oContext, mParameters);
253
+ }
254
+
255
+ /**
256
+ * Navigates forwards to a context.
257
+ *
258
+ * @param {sap.ui.model.odata.v4.Context} oContext Context to be navigated to
259
+ * @param {object} mParameters Optional navigation parameters
260
+ * @returns {Promise} Promise resolved when the navigation has been triggered
261
+ *
262
+ * @ui5-restricted
263
+ */
264
+ @publicExtension()
265
+ @finalExtension()
266
+ navigateForwardToContext(oContext: any, mParameters?: any) {
267
+ if (this._oView.getBindingContext("internal")?.getProperty("messageFooterContainsErrors") === true) {
268
+ return Promise.resolve();
269
+ }
270
+ mParameters = mParameters || {};
271
+ mParameters.updateFCLLevel = 1;
272
+
273
+ return this.navigateToContext(oContext, mParameters);
274
+ }
275
+
276
+ /**
277
+ * Navigates back in history if the current hash corresponds to a transient state.
278
+ */
279
+ @publicExtension()
280
+ @finalExtension()
281
+ navigateBackFromTransientState() {
282
+ const sHash = this._oRouterProxy.getHash();
283
+
284
+ // if triggered while navigating to (...), we need to navigate back
285
+ if (sHash.indexOf("(...)") !== -1) {
286
+ this._oRouterProxy.navBack();
287
+ }
288
+ }
289
+
290
+ @publicExtension()
291
+ @finalExtension()
292
+ navigateToMessagePage(sErrorMessage: any, mParameters: any) {
293
+ mParameters = mParameters || {};
294
+ if (this._oRouterProxy.getHash().indexOf("i-action=create") > -1) {
295
+ return this._oRouterProxy.navToHash(this._oRoutingService.getDefaultCreateHash());
296
+ } else {
297
+ mParameters.FCLLevel = this._getFCLLevel();
298
+
299
+ return (this._oAppComponent as any).getRootViewController().displayMessagePage(sErrorMessage, mParameters);
300
+ }
301
+ }
302
+
303
+ /**
304
+ * Checks if one of the current views on the screen is bound to a given context.
305
+ *
306
+ * @param {sap.ui.model.odata.v4.Context} oContext
307
+ * @returns {boolean}
308
+ *
309
+ * @ui5-restricted
310
+ */
311
+ @publicExtension()
312
+ @finalExtension()
313
+ isCurrentStateImpactedBy(oContext: any) {
314
+ return this._oRoutingService.isCurrentStateImpactedBy(oContext);
315
+ }
316
+
317
+ ///////////////////////////////////////////////////////////
318
+ // Methods to bind the page when a route is matched
319
+ ///////////////////////////////////////////////////////////
320
+
321
+ /**
322
+ * Called when a route is matched.
323
+ * Builds the binding context from the navigation parameters, and bind the page accordingly.
324
+ *
325
+ * @param {object} oEvent
326
+ *
327
+ * @ui5-restricted
328
+ */
329
+ _onRouteMatched(oEvent: Event) {
330
+ // Check if the target for this view is part of the event targets
331
+ const aTargets = oEvent.getParameter("routeInformation") && oEvent.getParameter("routeInformation").targets;
332
+ if (!aTargets || aTargets.indexOf(this._oTargetInformation.targetName) === -1) {
333
+ return;
334
+ }
335
+
336
+ // Retrieve the binding context pattern
337
+ let sTarget;
338
+ if (this._oPageComponent && this._oPageComponent.getBindingContextPattern) {
339
+ sTarget = this._oPageComponent.getBindingContextPattern();
340
+ }
341
+ sTarget = sTarget || this._oTargetInformation.contextPattern;
342
+
343
+ if (sTarget === null || sTarget === undefined) {
344
+ // Don't do this if we already got sTarget == '', which is a valid target pattern
345
+ sTarget = oEvent.getParameter("routePattern");
346
+ }
347
+ sTarget = sTarget.replace(":?query:", "");
348
+
349
+ // Replace the parameters by their values in the binding context pattern
350
+ const mArguments = (oEvent.getParameters() as any).arguments;
351
+ let bDeferred = false;
352
+ const oNavigationParameters = oEvent.getParameter("navigationInfo");
353
+
354
+ for (const sKey in mArguments) {
355
+ const sValue = mArguments[sKey];
356
+ if (sValue === "..." && sTarget.indexOf("{" + sKey + "}") >= 0) {
357
+ bDeferred = true;
358
+ // Sometimes in preferredMode = create, the edit button is shown in background when the
359
+ // action parameter dialog shows up, setting bTargetEditable passes editable as true
360
+ // to onBeforeBinding in _bindTargetPage function
361
+ oNavigationParameters.bTargetEditable = true;
362
+ }
363
+ sTarget = sTarget.replace("{" + sKey + "}", sValue);
364
+ }
365
+ if (mArguments["?query"] && mArguments["?query"].hasOwnProperty("i-action")) {
366
+ oNavigationParameters.bActionCreate = true;
367
+ }
368
+
369
+ // the binding target is always absolute
370
+ if (sTarget && sTarget[0] !== "/") {
371
+ sTarget = "/" + sTarget;
372
+ }
373
+
374
+ this.onRouteMatched();
375
+
376
+ const oModel = this._oView.getModel();
377
+ let oOut;
378
+ if (bDeferred) {
379
+ oOut = this._bindDeferred(sTarget, oNavigationParameters);
380
+ } else {
381
+ oOut = this._bindPage(sTarget, oModel, oNavigationParameters);
382
+ }
383
+ // eslint-disable-next-line promise/catch-or-return
384
+ oOut.finally(() => {
385
+ this.onRouteMatchedFinished();
386
+ });
387
+
388
+ (this._oAppComponent as any).getRootViewController().updateUIStateForView(this._oView, this._getFCLLevel());
389
+ }
390
+
391
+ /**
392
+ * Deferred binding (during object creation).
393
+ *
394
+ * @param {string} sTargetPath The path to the deffered context
395
+ * @param {object} oNavigationParameters Navigation parameters
396
+ * @returns {Promise}
397
+ * @ui5-restricted
398
+ */
399
+ _bindDeferred(sTargetPath: string, oNavigationParameters: any) {
400
+ this.onBeforeBinding(null, { editable: oNavigationParameters.bTargetEditable });
401
+
402
+ if (oNavigationParameters.bDeferredContext || !oNavigationParameters.oAsyncContext) {
403
+ // either the context shall be created in the target page (deferred Context) or it shall
404
+ // be created async but the user refreshed the page / bookmarked this URL
405
+ // TODO: currently the target component creates this document but we shall move this to
406
+ // a central place
407
+ if (this._oPageComponent && this._oPageComponent.createDeferredContext) {
408
+ this._oPageComponent.createDeferredContext(
409
+ sTargetPath,
410
+ oNavigationParameters.useContext,
411
+ oNavigationParameters.bActionCreate
412
+ );
413
+ }
414
+ }
415
+
416
+ if (this._getBindingContext() && this._getBindingContext().hasPendingChanges()) {
417
+ // For now remove the pending changes to avoid the model raises errors and the object page is at least bound
418
+ // Ideally the user should be asked for
419
+ this._getBindingContext().getBinding().resetChanges();
420
+ }
421
+
422
+ // remove the context to avoid showing old data
423
+ this._setBindingContext(null);
424
+
425
+ this.onAfterBinding(null);
426
+ return Promise.resolve();
427
+ }
428
+
429
+ /**
430
+ * Sets the binding context of the page from a path.
431
+ *
432
+ * @param {string} sTargetPath The path to the context
433
+ * @param {sap.ui.model.odata.v4.ODataModel} oModel The OData model
434
+ * @param {object} oNavigationParameters Navigation parameters
435
+ * @returns {Promise}
436
+ * @ui5-restricted
437
+ */
438
+ _bindPage(sTargetPath: string, oModel: any, oNavigationParameters: object) {
439
+ if (sTargetPath === "") {
440
+ return Promise.resolve(this._bindPageToContext(null, oModel, oNavigationParameters));
441
+ } else {
442
+ return this._resolveSemanticPath(sTargetPath, oModel)
443
+ .then((sTechnicalPath: any) => {
444
+ this._bindPageToPath(sTechnicalPath, oModel, oNavigationParameters);
445
+ })
446
+ .catch((oError: any) => {
447
+ // Error handling for erroneous metadata request
448
+ const oResourceBundle = (Core as CoreEx).getLibraryResourceBundle("sap.fe.core");
449
+
450
+ this.navigateToMessagePage(oResourceBundle.getText("C_COMMON_SAPFE_DATA_RECEIVED_ERROR"), {
451
+ title: oResourceBundle.getText("C_COMMON_SAPFE_ERROR"),
452
+ description: oError.message
453
+ });
454
+ });
455
+ }
456
+ }
457
+
458
+ /**
459
+ * Creates the filter to retrieve a context corresponding to a semantic path.
460
+ *
461
+ * @param {string} sSemanticPath The semantic path
462
+ * @param {Array} aSemanticKeys The semantic keys for the path
463
+ * @param {object} oMetaModel The instance of the meta model
464
+ * @returns {sap.ui.model.Filter} The filter
465
+ *
466
+ * @ui5-restricted
467
+ */
468
+ _createFilterFromSemanticPath(sSemanticPath: string, aSemanticKeys: any[], oMetaModel: object) {
469
+ const fnUnquoteAndDecode = function (sValue: any) {
470
+ if (sValue.indexOf("'") === 0 && sValue.lastIndexOf("'") === sValue.length - 1) {
471
+ // Remove the quotes from the value and decode special chars
472
+ sValue = decodeURIComponent(sValue.substring(1, sValue.length - 1));
473
+ }
474
+ return sValue;
475
+ };
476
+ const aKeyValues = sSemanticPath.substring(sSemanticPath.indexOf("(") + 1, sSemanticPath.length - 1).split(",");
477
+ let aFilters: Filter[];
478
+
479
+ if (aSemanticKeys.length != aKeyValues.length) {
480
+ return null;
481
+ }
482
+
483
+ const bFilteringCaseSensitive = ModelHelper.isFilteringCaseSensitive(oMetaModel);
484
+
485
+ if (aSemanticKeys.length === 1) {
486
+ // Take the first key value
487
+ const sKeyValue = fnUnquoteAndDecode(aKeyValues[0]);
488
+ aFilters = [
489
+ new Filter({
490
+ path: aSemanticKeys[0].$PropertyPath,
491
+ operator: FilterOperator.EQ,
492
+ value1: sKeyValue,
493
+ caseSensitive: bFilteringCaseSensitive
494
+ })
495
+ ];
496
+ } else {
497
+ const mKeyValues: any = {};
498
+ // Create a map of all key values
499
+ aKeyValues.forEach(function (sKeyAssignment: string) {
500
+ const aParts = sKeyAssignment.split("="),
501
+ sKeyValue = fnUnquoteAndDecode(aParts[1]);
502
+
503
+ mKeyValues[aParts[0]] = sKeyValue;
504
+ });
505
+
506
+ let bFailed = false;
507
+ aFilters = aSemanticKeys.map(function (oSemanticKey: any) {
508
+ const sKey = oSemanticKey.$PropertyPath,
509
+ sValue = mKeyValues[sKey];
510
+
511
+ if (sValue !== undefined) {
512
+ return new Filter({
513
+ path: sKey,
514
+ operator: FilterOperator.EQ,
515
+ value1: sValue,
516
+ caseSensitive: bFilteringCaseSensitive
517
+ });
518
+ } else {
519
+ bFailed = true;
520
+ return new Filter({
521
+ path: "XX"
522
+ }); // will be ignore anyway since we return after
523
+ }
524
+ });
525
+
526
+ if (bFailed) {
527
+ return null;
528
+ }
529
+ }
530
+
531
+ // Add a draft filter to make sure we take the draft entity if there is one
532
+ // Or the active entity otherwise
533
+ const oDraftFilter = new Filter({
534
+ filters: [new Filter("IsActiveEntity", "EQ", false), new Filter("SiblingEntity/IsActiveEntity", "EQ", null)],
535
+ and: false
536
+ });
537
+ aFilters.push(oDraftFilter);
538
+
539
+ const oCombinedFilter = new Filter(aFilters, true);
540
+ return oCombinedFilter;
541
+ }
542
+
543
+ /**
544
+ * Converts a path with semantic keys to a path with technical keys.
545
+ *
546
+ * @param {string} sSemanticPath The path with semantic keys
547
+ * @param {sap.ui.model.odata.v4.ODataModel} oModel The model for the path
548
+ * @param {Array} aSemanticKeys The semantic keys for the path
549
+ * @returns {Promise} A Promise containing the path with technical keys if sSemanticPath could be interpreted as a semantic path, null otherwise
550
+ *
551
+ * @ui5-restricted
552
+ */
553
+ _getTechnicalPathFromSemanticPath(sSemanticPath: string, oModel: any, aSemanticKeys: any[]) {
554
+ const oMetaModel = oModel.getMetaModel();
555
+ let sEntitySetPath = oMetaModel.getMetaContext(sSemanticPath).getPath();
556
+
557
+ if (!aSemanticKeys || aSemanticKeys.length === 0) {
558
+ // No semantic keys
559
+ return Promise.resolve(null);
560
+ }
561
+
562
+ // Create a set of filters corresponding to all keys
563
+ const oFilter = this._createFilterFromSemanticPath(sSemanticPath, aSemanticKeys, oMetaModel);
564
+ if (oFilter === null) {
565
+ // Couldn't interpret the path as a semantic one
566
+ return Promise.resolve(null);
567
+ }
568
+
569
+ // Load the corresponding object
570
+ if (!sEntitySetPath?.startsWith("/")) {
571
+ sEntitySetPath = "/" + sEntitySetPath;
572
+ }
573
+ const oListBinding = oModel.bindList(sEntitySetPath, undefined, undefined, oFilter, {
574
+ "$$groupId": "$auto.Heroes"
575
+ });
576
+
577
+ return oListBinding.requestContexts(0, 2).then(function (oContexts: any) {
578
+ if (oContexts && oContexts.length) {
579
+ return oContexts[0].getPath();
580
+ } else {
581
+ // No data could be loaded
582
+ return null;
583
+ }
584
+ });
585
+ }
586
+
587
+ /**
588
+ * Checks if a path is eligible for semantic bookmarking.
589
+ *
590
+ * @param {string} sPath The path to test
591
+ * @param {sap.ui.model.odata.v4.ODataMetaModel} oMetaModel The associated metadata model
592
+ * @returns {boolean} `true` if the path is eligible
593
+ *
594
+ * @ui5-restricted
595
+ */
596
+ _checkPathForSemanticBookmarking(sPath: string, oMetaModel: any) {
597
+ // Only path on root objects allow semantic bookmarking, i.e. sPath = xxx(yyy)
598
+ const aMatches = /^[\/]?(\w+)\([^\/]+\)$/.exec(sPath);
599
+ if (!aMatches) {
600
+ return false;
601
+ }
602
+ // Get the entitySet name
603
+ const sEntitySetPath = "/" + aMatches[1];
604
+ // Check the entity set supports draft (otherwise we don't support semantic bookmarking)
605
+ const oDraftRoot = oMetaModel.getObject(sEntitySetPath + "@com.sap.vocabularies.Common.v1.DraftRoot");
606
+ const oDraftNode = oMetaModel.getObject(sEntitySetPath + "@com.sap.vocabularies.Common.v1.DraftNode");
607
+ return oDraftRoot || oDraftNode ? true : false;
608
+ }
609
+
610
+ /**
611
+ * Builds a path with semantic keys from a path with technical keys.
612
+ * @param {string} sPathToResolve The path to be transformed
613
+ * @param oModel
614
+ * @returns {Promise} String promise for the new path. If sPathToResolved couldn't be interpreted as a semantic path, it is returned as is.
615
+ * @ui5-restricted
616
+ */
617
+ _resolveSemanticPath(sPathToResolve: string, oModel: any): Promise<string> {
618
+ const oMetaModel = oModel.getMetaModel();
619
+ const oLastSemanticMapping = this._oRoutingService.getLastSemanticMapping();
620
+ let sCurrentHashNoParams = this._oRouter.getHashChanger().getHash().split("?")[0];
621
+
622
+ if (sCurrentHashNoParams && sCurrentHashNoParams.lastIndexOf("/") === sCurrentHashNoParams.length - 1) {
623
+ // Remove trailing '/'
624
+ sCurrentHashNoParams = sCurrentHashNoParams.substring(0, sCurrentHashNoParams.length - 1);
625
+ }
626
+
627
+ let sRootEntityName = sCurrentHashNoParams && sCurrentHashNoParams.substr(0, sCurrentHashNoParams.indexOf("("));
628
+ if (sRootEntityName.indexOf("/") === 0) {
629
+ sRootEntityName = sRootEntityName.substring(1);
630
+ }
631
+ const bAllowSemanticBookmark = this._checkPathForSemanticBookmarking(sCurrentHashNoParams, oMetaModel),
632
+ aSemanticKeys = bAllowSemanticBookmark && SemanticKeyHelper.getSemanticKeys(oMetaModel, sRootEntityName);
633
+ if (!aSemanticKeys) {
634
+ // No semantic keys available --> use the path as is
635
+ return Promise.resolve(sPathToResolve);
636
+ } else if (oLastSemanticMapping && oLastSemanticMapping.semanticPath === sPathToResolve) {
637
+ // This semantic path has been resolved previously
638
+ return Promise.resolve(oLastSemanticMapping.technicalPath);
639
+ } else {
640
+ // We need resolve the semantic path to get the technical keys
641
+ return this._getTechnicalPathFromSemanticPath(sCurrentHashNoParams, oModel, aSemanticKeys).then((sTechnicalPath: any) => {
642
+ if (sTechnicalPath && sTechnicalPath !== sPathToResolve) {
643
+ // The semantic path was resolved (otherwise keep the original value for target)
644
+ this._oRoutingService.setLastSemanticMapping({
645
+ technicalPath: sTechnicalPath,
646
+ semanticPath: sPathToResolve
647
+ });
648
+ return sTechnicalPath;
649
+ } else {
650
+ return sPathToResolve;
651
+ }
652
+ });
653
+ }
654
+ }
655
+
656
+ /**
657
+ * Sets the binding context of the page from a path.
658
+ *
659
+ * @param {string} sTargetPath The path to build the context. Needs to contain technical keys only.
660
+ * @param {sap.ui.model.odata.v4.ODataModel} oModel The OData model
661
+ * @param {object} oNavigationParameters Navigation parameters
662
+ *
663
+ * @ui5-restricted
664
+ */
665
+ _bindPageToPath(sTargetPath: string, oModel: any, oNavigationParameters: any) {
666
+ const oCurrentContext = this._getBindingContext(),
667
+ sCurrentPath = oCurrentContext && oCurrentContext.getPath(),
668
+ oUseContext = oNavigationParameters.useContext;
669
+
670
+ // We set the binding context only if it's different from the current one
671
+ // or if we have a context already selected
672
+ if (sCurrentPath !== sTargetPath || (oUseContext && oUseContext.getPath() === sTargetPath)) {
673
+ let oTargetContext;
674
+ if (oUseContext && oUseContext.getPath() === sTargetPath) {
675
+ // We already have the context to be used
676
+ oTargetContext = oUseContext;
677
+ } else {
678
+ // Otherwise we need to create it from sTargetPath
679
+ oTargetContext = this._createBindingContext(sTargetPath, oModel, oNavigationParameters.bNavigateToSiblingEntity);
680
+ }
681
+ if (oTargetContext !== oCurrentContext) {
682
+ this._bindPageToContext(oTargetContext, oModel, oNavigationParameters);
683
+ }
684
+ } else if (!oNavigationParameters.bReasonIsIappState && EditState.isEditStateDirty()) {
685
+ this._refreshBindingContext(oCurrentContext);
686
+ }
687
+ }
688
+
689
+ /**
690
+ * Binds the page to a context.
691
+ *
692
+ * @param {sap.ui.model.odata.v4.Context} oContext Context to be bound
693
+ * @param {sap.ui.model.odata.v4.ODataModel} oModel The OData model
694
+ * @param {object} oNavigationParameters Navigation parameters
695
+ *
696
+ * @ui5-restricted
697
+ */
698
+ _bindPageToContext(oContext: any, oModel: any, oNavigationParameters: any) {
699
+ if (!oContext) {
700
+ this.onBeforeBinding(null);
701
+ this.onAfterBinding(null);
702
+ } else {
703
+ const oParentListBinding = oContext.getBinding();
704
+
705
+ if (!oContext.getBinding() || oContext.getBinding().isA("sap.ui.model.odata.v4.ODataListBinding")) {
706
+ // We need to recreate the context otherwise we get errors
707
+ oContext = this._createBindingContext(oContext.getPath(), oModel, oNavigationParameters.bNavigateToSiblingEntity);
708
+ if (EditState.isEditStateDirty()) {
709
+ // TODO: as a workaround we invalidate the model cache while the app is dirty
710
+ // as the manage model sets the parent in an async task and the request side effects
711
+ // relies on the parent relationship we have to set a timeout 0
712
+ setTimeout(() => {
713
+ this._refreshBindingContext(oContext);
714
+ }, 0);
715
+ }
716
+ }
717
+
718
+ // Set the binding context with the proper before/after callbacks
719
+ this.onBeforeBinding(oContext, {
720
+ editable: oNavigationParameters.bTargetEditable,
721
+ listBinding: oParentListBinding,
722
+ bPersistOPScroll: oNavigationParameters.bPersistOPScroll,
723
+ bDraftNavigation: oNavigationParameters.bDraftNavigation,
724
+ showPlaceholder: oNavigationParameters.bShowPlaceholder
725
+ });
726
+
727
+ this._setBindingContext(oContext);
728
+ this.onAfterBinding(oContext);
729
+ }
730
+ }
731
+
732
+ /**
733
+ * Creates a binding context from a path.
734
+ *
735
+ * @param {string} sPath The path
736
+ * @param {sap.ui.model.odata.v4.ODataModel} oModel The OData model
737
+ * @returns {sap.ui.model.odata.v4.Context} Created context
738
+ *
739
+ * @ui5-restricted
740
+ */
741
+ @publicExtension()
742
+ _createBindingContext(sPath: string, oModel: any, navigateToSiblingEntity: boolean = true) {
743
+ const oPageComponent = this._oPageComponent,
744
+ sEntitySet = oPageComponent && oPageComponent.getEntitySet && oPageComponent.getEntitySet(),
745
+ sContextPath =
746
+ (oPageComponent && oPageComponent.getContextPath && oPageComponent.getContextPath()) || (sEntitySet && "/" + sEntitySet),
747
+ oMetaModel = oModel.getMetaModel(),
748
+ mParameters: any = {
749
+ $$patchWithoutSideEffects: true,
750
+ $$groupId: "$auto.Heroes",
751
+ $$updateGroupId: "$auto"
752
+ };
753
+
754
+ if (sEntitySet) {
755
+ const sMessagesPath = oMetaModel.getObject(sContextPath + "/@com.sap.vocabularies.Common.v1.Messages/$Path");
756
+ if (sMessagesPath) {
757
+ mParameters.$select = sMessagesPath;
758
+ }
759
+ }
760
+
761
+ // In case of draft: $select the state flags (HasActiveEntity, HasDraftEntity, and IsActiveEntity)
762
+ const oDraftRoot = oMetaModel.getObject(sContextPath + "@com.sap.vocabularies.Common.v1.DraftRoot");
763
+ const oDraftNode = oMetaModel.getObject(sContextPath + "@com.sap.vocabularies.Common.v1.DraftNode");
764
+ if (oDraftRoot || oDraftNode) {
765
+ if (mParameters.$select === undefined) {
766
+ mParameters.$select = "HasActiveEntity,HasDraftEntity,IsActiveEntity";
767
+ } else {
768
+ mParameters.$select += ",HasActiveEntity,HasDraftEntity,IsActiveEntity";
769
+ }
770
+ }
771
+
772
+ const oHiddenBinding = oModel.bindContext(sPath, undefined, mParameters);
773
+
774
+ oHiddenBinding.attachEventOnce("dataRequested", () => {
775
+ BusyLocker.lock(this._oView);
776
+ });
777
+ oHiddenBinding.attachEventOnce("dataReceived", this._dataReceivedEventHandler.bind(this, navigateToSiblingEntity));
778
+ return oHiddenBinding.getBoundContext();
779
+ }
780
+
781
+ async _dataReceivedEventHandler(navigateToSiblingEntity: boolean, oEvent: Event) {
782
+ const context = oEvent?.getSource && (oEvent?.getSource() as any)?.getBoundContext();
783
+ const ProgrammingModel = FELibrary.ProgrammingModel;
784
+ const programmingModel = (this._oView?.getController() as PageController)?._editFlow?.getProgrammingModel(context);
785
+ const sErrorDescription = oEvent && oEvent.getParameter("error");
786
+ BusyLocker.unlock(this._oView);
787
+ if (
788
+ programmingModel === ProgrammingModel.Draft &&
789
+ ActivitySync.isCollaborationEnabled(this._oView) &&
790
+ navigateToSiblingEntity &&
791
+ context.getProperty("IsActiveEntity") &&
792
+ context.getObject().DraftAdministrativeData
793
+ ) {
794
+ const siblingInfo = await draft.computeSiblingInformation(context, context);
795
+ if (siblingInfo) {
796
+ this.navigateToContext(siblingInfo.targetContext);
797
+ return;
798
+ }
799
+ }
800
+
801
+ if (sErrorDescription) {
802
+ // TODO: in case of 404 the text shall be different
803
+ try {
804
+ const oResourceBundle = await (Core as CoreEx).getLibraryResourceBundle("sap.fe.core", true);
805
+ const messageHandler = this.base.messageHandler;
806
+ let mParams = {};
807
+ if (sErrorDescription && sErrorDescription.status === 503) {
808
+ mParams = {
809
+ isInitialLoad503Error: true,
810
+ shellBack: true
811
+ };
812
+ } else {
813
+ mParams = {
814
+ title: oResourceBundle.getText("SAPFE_ERROR"),
815
+ description: sErrorDescription,
816
+ isDataReceivedError: true,
817
+ shellBack: true
818
+ };
819
+ }
820
+ messageHandler.showMessages(mParams);
821
+ } catch (oError: any) {
822
+ Log.error("Error while getting the core resource bundle", oError);
823
+ }
824
+ }
825
+ }
826
+
827
+ /**
828
+ * Requests side effects on a binding context to "refresh" it.
829
+ * TODO: get rid of this once provided by the model
830
+ * a refresh on the binding context does not work in case a creation row with a transient context is
831
+ * used. also a requestSideEffects with an empty path would fail due to the transient context
832
+ * therefore we get all dependent bindings (via private model method) to determine all paths and then
833
+ * request them.
834
+ *
835
+ * @param {sap.ui.model.odata.v4.Context} oBindingContext Context to be refreshed
836
+ *
837
+ * @ui5-restricted
838
+ */
839
+ _refreshBindingContext(oBindingContext: any) {
840
+ const oPageComponent = this._oPageComponent;
841
+ const oSideEffectsService = this._oAppComponent.getSideEffectsService();
842
+ const sRootContextPath = oBindingContext.getPath();
843
+ const sEntitySet = oPageComponent && oPageComponent.getEntitySet && oPageComponent.getEntitySet();
844
+ const sContextPath =
845
+ (oPageComponent && oPageComponent.getContextPath && oPageComponent.getContextPath()) || (sEntitySet && "/" + sEntitySet);
846
+ const oMetaModel = this._oView.getModel().getMetaModel();
847
+ let sMessagesPath;
848
+ const aNavigationPropertyPaths: any[] = [];
849
+ const aPropertyPaths: any[] = [];
850
+ const oSideEffects: any = {
851
+ TargetProperties: [],
852
+ TargetEntities: []
853
+ };
854
+
855
+ function getBindingPaths(oBinding: any) {
856
+ let aDependentBindings;
857
+ const sRelativePath = ((oBinding.getContext() && oBinding.getContext().getPath()) || "").replace(sRootContextPath, ""); // If no context, this is an absolute binding so no relative path
858
+ const sPath = (sRelativePath ? sRelativePath.slice(1) + "/" : sRelativePath) + oBinding.getPath();
859
+
860
+ if (oBinding.isA("sap.ui.model.odata.v4.ODataContextBinding")) {
861
+ // if (sPath === "") {
862
+ // now get the dependent bindings
863
+ aDependentBindings = oBinding.getDependentBindings();
864
+ if (aDependentBindings) {
865
+ // ask the dependent bindings (and only those with the specified groupId
866
+ //if (aDependentBindings.length > 0) {
867
+ for (let i = 0; i < aDependentBindings.length; i++) {
868
+ getBindingPaths(aDependentBindings[i]);
869
+ }
870
+ } else if (aNavigationPropertyPaths.indexOf(sPath) === -1) {
871
+ aNavigationPropertyPaths.push(sPath);
872
+ }
873
+ } else if (oBinding.isA("sap.ui.model.odata.v4.ODataListBinding")) {
874
+ if (aNavigationPropertyPaths.indexOf(sPath) === -1) {
875
+ aNavigationPropertyPaths.push(sPath);
876
+ }
877
+ } else if (oBinding.isA("sap.ui.model.odata.v4.ODataPropertyBinding")) {
878
+ if (aPropertyPaths.indexOf(sPath) === -1) {
879
+ aPropertyPaths.push(sPath);
880
+ }
881
+ }
882
+ }
883
+
884
+ if (sContextPath) {
885
+ sMessagesPath = oMetaModel.getObject(sContextPath + "/@com.sap.vocabularies.Common.v1.Messages/$Path");
886
+ }
887
+
888
+ // binding of the context must have $$PatchWithoutSideEffects true, this bound context may be needed to be fetched from the dependent binding
889
+ getBindingPaths(oBindingContext.getBinding());
890
+
891
+ let i;
892
+ for (i = 0; i < aNavigationPropertyPaths.length; i++) {
893
+ oSideEffects.TargetEntities.push({
894
+ $NavigationPropertyPath: aNavigationPropertyPaths[i]
895
+ });
896
+ }
897
+ oSideEffects.TargetProperties = aPropertyPaths;
898
+ if (sMessagesPath) {
899
+ oSideEffects.TargetProperties.push({
900
+ $PropertyPath: sMessagesPath
901
+ });
902
+ }
903
+ oSideEffectsService.requestSideEffects(oSideEffects.TargetEntities.concat(oSideEffects.TargetProperties), oBindingContext);
904
+ }
905
+
906
+ /**
907
+ * Gets the binding context of the page or the component.
908
+ *
909
+ * @returns {sap.ui.model.odata.v4.Context} The binding context
910
+ *
911
+ * @ui5-restricted
912
+ */
913
+ _getBindingContext(): Context {
914
+ if (this._oPageComponent) {
915
+ return this._oPageComponent.getBindingContext() as Context;
916
+ } else {
917
+ return this._oView.getBindingContext() as Context;
918
+ }
919
+ }
920
+
921
+ /**
922
+ * Sets the binding context of the page or the component.
923
+ *
924
+ * @param {sap.ui.model.odata.v4.Context} oContext The binding context
925
+ *
926
+ * @ui5-restricted
927
+ */
928
+ _setBindingContext(oContext: any) {
929
+ if (this._oPageComponent) {
930
+ this._oPageComponent.setBindingContext(oContext);
931
+ } else {
932
+ this._oView.setBindingContext(oContext);
933
+ }
934
+ }
935
+
936
+ /**
937
+ * Gets the flexible column layout (FCL) level corresponding to the view (-1 if the app is not FCL).
938
+ *
939
+ * @returns {number} The level
940
+ *
941
+ * @ui5-restricted
942
+ */
943
+ _getFCLLevel() {
944
+ return this._oTargetInformation.FCLLevel;
945
+ }
946
+
947
+ /**
948
+ * Switches between column and full-screen mode when FCL is used.
949
+ *
950
+ * @ui5-restricted
951
+ */
952
+
953
+ @publicExtension()
954
+ @finalExtension()
955
+ switchFullScreen() {
956
+ const oSource = this.base.getView();
957
+ const oFCLHelperModel = oSource.getModel("fclhelper"),
958
+ bIsFullScreen = oFCLHelperModel.getProperty("/actionButtonsInfo/isFullScreen"),
959
+ sNextLayout = oFCLHelperModel.getProperty(
960
+ bIsFullScreen ? "/actionButtonsInfo/exitFullScreen" : "/actionButtonsInfo/fullScreen"
961
+ ),
962
+ oRootViewController = (this._oAppComponent as any).getRootViewController();
963
+
964
+ const oContext = oRootViewController.getRightmostContext ? oRootViewController.getRightmostContext() : oSource.getBindingContext();
965
+
966
+ this.base._routing.navigateToContext(oContext, { sLayout: sNextLayout }).catch(function () {
967
+ Log.warning("cannot switch between column and fullscreen");
968
+ });
969
+ }
970
+
971
+ /**
972
+ * Closes the column for the current view in a FCL.
973
+ *
974
+ * @ui5-restricted
975
+ */
976
+ @publicExtension()
977
+ @extensible(OverrideExecution.Before)
978
+ closeColumn() {
979
+ const oSource = this.base.getView();
980
+ const oViewData = oSource.getViewData() as any;
981
+ const oContext = oSource.getBindingContext() as Context;
982
+ const base = this.base;
983
+ const oMetaModel = oContext.getModel().getMetaModel();
984
+
985
+ if (oViewData && oViewData.viewLevel === 1 && ModelHelper.isDraftSupported(oMetaModel, oContext.getPath())) {
986
+ CommonUtils.fnProcessDataLossOrDraftDiscardConfirmation(
987
+ function () {
988
+ base._routing.navigateBackFromContext(oContext, { noPreservationCache: true });
989
+ },
990
+ Function.prototype,
991
+ oContext,
992
+ oSource.getController(),
993
+ false
994
+ );
995
+ } else {
996
+ base._routing.navigateBackFromContext(oContext, { noPreservationCache: true });
997
+ }
998
+ }
999
+ }
1000
+
1001
+ export default InternalRouting;