@openui5/sap.ui.core 1.121.0 → 1.122.0

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 (605) hide show
  1. package/.eslintrc.json +22 -5
  2. package/THIRDPARTY.txt +1 -1
  3. package/package.json +1 -1
  4. package/src/jquery.sap.global.js +1 -1
  5. package/src/jquery.sap.properties.js +1 -1
  6. package/src/jquery.sap.resources.js +1 -1
  7. package/src/jquery.sap.script.js +1 -1
  8. package/src/jquery.sap.sjax.js +6 -5
  9. package/src/jquery.sap.storage.js +3 -3
  10. package/src/sap/base/Event.js +1 -1
  11. package/src/sap/base/Eventing.js +1 -1
  12. package/src/sap/base/config.js +1 -1
  13. package/src/sap/base/i18n/Formatting.js +1 -1
  14. package/src/sap/base/i18n/LanguageTag.js +1 -1
  15. package/src/sap/base/i18n/date/TimezoneUtils.js +1 -1
  16. package/src/sap/base/util/Deferred.js +4 -6
  17. package/src/sap/base/util/restricted/_CancelablePromise.js +1 -1
  18. package/src/sap/base/util/restricted/_castArray.js +1 -1
  19. package/src/sap/base/util/restricted/_compact.js +1 -1
  20. package/src/sap/base/util/restricted/_curry.js +1 -1
  21. package/src/sap/base/util/restricted/_debounce.js +1 -1
  22. package/src/sap/base/util/restricted/_difference.js +1 -1
  23. package/src/sap/base/util/restricted/_differenceBy.js +1 -1
  24. package/src/sap/base/util/restricted/_differenceWith.js +1 -1
  25. package/src/sap/base/util/restricted/_flatMap.js +1 -1
  26. package/src/sap/base/util/restricted/_flatMapDeep.js +1 -1
  27. package/src/sap/base/util/restricted/_flatMapDepth.js +1 -1
  28. package/src/sap/base/util/restricted/_flatten.js +1 -1
  29. package/src/sap/base/util/restricted/_flattenDeep.js +1 -1
  30. package/src/sap/base/util/restricted/_flattenDepth.js +1 -1
  31. package/src/sap/base/util/restricted/_intersection.js +1 -1
  32. package/src/sap/base/util/restricted/_intersectionBy.js +1 -1
  33. package/src/sap/base/util/restricted/_intersectionWith.js +1 -1
  34. package/src/sap/base/util/restricted/_isEqual.js +1 -1
  35. package/src/sap/base/util/restricted/_isEqualWith.js +1 -1
  36. package/src/sap/base/util/restricted/_isNil.js +1 -1
  37. package/src/sap/base/util/restricted/_max.js +1 -1
  38. package/src/sap/base/util/restricted/_merge.js +1 -1
  39. package/src/sap/base/util/restricted/_mergeWith.js +1 -1
  40. package/src/sap/base/util/restricted/_min.js +1 -1
  41. package/src/sap/base/util/restricted/_omit.js +1 -1
  42. package/src/sap/base/util/restricted/_pick.js +1 -1
  43. package/src/sap/base/util/restricted/_pickBy.js +1 -1
  44. package/src/sap/base/util/restricted/_throttle.js +1 -1
  45. package/src/sap/base/util/restricted/_toArray.js +1 -1
  46. package/src/sap/base/util/restricted/_union.js +1 -1
  47. package/src/sap/base/util/restricted/_unionBy.js +1 -1
  48. package/src/sap/base/util/restricted/_unionWith.js +1 -1
  49. package/src/sap/base/util/restricted/_uniq.js +1 -1
  50. package/src/sap/base/util/restricted/_uniqBy.js +1 -1
  51. package/src/sap/base/util/restricted/_uniqWith.js +1 -1
  52. package/src/sap/base/util/restricted/_without.js +1 -1
  53. package/src/sap/base/util/restricted/_xor.js +1 -1
  54. package/src/sap/base/util/restricted/_xorBy.js +1 -1
  55. package/src/sap/base/util/restricted/_xorWith.js +1 -1
  56. package/src/sap/base/util/restricted/_zipObject.js +1 -1
  57. package/src/sap/base/util/restricted/_zipObjectDeep.js +1 -1
  58. package/src/sap/ui/Device.js +3 -3
  59. package/src/sap/ui/Global.js +4 -4
  60. package/src/sap/ui/base/Event.js +1 -1
  61. package/src/sap/ui/base/EventProvider.js +11 -5
  62. package/src/sap/ui/base/Exception.js +1 -1
  63. package/src/sap/ui/base/Interface.js +1 -1
  64. package/src/sap/ui/base/ManagedObject.js +22 -3
  65. package/src/sap/ui/base/ManagedObjectMetadata.js +1 -1
  66. package/src/sap/ui/base/Metadata.js +1 -1
  67. package/src/sap/ui/base/Object.js +1 -1
  68. package/src/sap/ui/base/ObjectPool.js +1 -1
  69. package/src/sap/ui/core/.library +1 -1
  70. package/src/sap/ui/core/BusyIndicator.js +1 -1
  71. package/src/sap/ui/core/Component.js +33 -5
  72. package/src/sap/ui/core/ComponentContainer.js +1 -1
  73. package/src/sap/ui/core/ComponentMetadata.js +1 -1
  74. package/src/sap/ui/core/ComponentSupport.js +1 -1
  75. package/src/sap/ui/core/Configuration.js +1 -1
  76. package/src/sap/ui/core/Control.js +19 -3
  77. package/src/sap/ui/core/Core.js +1 -1
  78. package/src/sap/ui/core/CustomData.js +1 -1
  79. package/src/sap/ui/core/DeclarativeSupport.js +1 -1
  80. package/src/sap/ui/core/Element.js +28 -3
  81. package/src/sap/ui/core/ElementMetadata.js +1 -1
  82. package/src/sap/ui/core/EnabledPropagator.js +1 -1
  83. package/src/sap/ui/core/EventBus.js +1 -1
  84. package/src/sap/ui/core/Fragment.js +1 -1
  85. package/src/sap/ui/core/HTML.js +1 -1
  86. package/src/sap/ui/core/History.js +1 -1
  87. package/src/sap/ui/core/Icon.js +1 -1
  88. package/src/sap/ui/core/IndicationColorSupport.js +1 -1
  89. package/src/sap/ui/core/IntervalTrigger.js +1 -1
  90. package/src/sap/ui/core/InvisibleMessage.js +1 -1
  91. package/src/sap/ui/core/InvisibleRenderer.js +1 -1
  92. package/src/sap/ui/core/InvisibleText.js +1 -1
  93. package/src/sap/ui/core/Item.js +1 -1
  94. package/src/sap/ui/core/LabelEnablement.js +1 -1
  95. package/src/sap/ui/core/LayoutData.js +1 -1
  96. package/src/sap/ui/core/ListItem.js +1 -1
  97. package/src/sap/ui/core/LocalBusyIndicator.js +1 -1
  98. package/src/sap/ui/core/Locale.js +1 -1
  99. package/src/sap/ui/core/LocaleData.js +14 -6
  100. package/src/sap/ui/core/Manifest.js +1 -1
  101. package/src/sap/ui/core/Message.js +1 -1
  102. package/src/sap/ui/core/RenderManager.js +1 -1
  103. package/src/sap/ui/core/Renderer.js +1 -1
  104. package/src/sap/ui/core/ResizeHandler.js +1 -1
  105. package/src/sap/ui/core/ScrollBar.js +1 -1
  106. package/src/sap/ui/core/SeparatorItem.js +1 -1
  107. package/src/sap/ui/core/Title.js +1 -1
  108. package/src/sap/ui/core/TooltipBase.js +1 -1
  109. package/src/sap/ui/core/UIArea.js +1 -1
  110. package/src/sap/ui/core/UIComponent.js +1 -1
  111. package/src/sap/ui/core/UIComponentMetadata.js +1 -1
  112. package/src/sap/ui/core/ValueStateSupport.js +1 -1
  113. package/src/sap/ui/core/VariantLayoutData.js +1 -1
  114. package/src/sap/ui/core/XMLComposite.js +1 -1
  115. package/src/sap/ui/core/XMLCompositeMetadata.js +1 -1
  116. package/src/sap/ui/core/date/UI5Date.js +1 -1
  117. package/src/sap/ui/core/date/UniversalDateUtils.js +52 -52
  118. package/src/sap/ui/core/delegate/ItemNavigation.js +1 -1
  119. package/src/sap/ui/core/delegate/ScrollEnablement.js +4 -4
  120. package/src/sap/ui/core/dnd/DragDropBase.js +1 -1
  121. package/src/sap/ui/core/dnd/DragDropInfo.js +1 -1
  122. package/src/sap/ui/core/dnd/DragInfo.js +1 -1
  123. package/src/sap/ui/core/dnd/DropInfo.js +1 -1
  124. package/src/sap/ui/core/format/DateFormat.js +4 -4
  125. package/src/sap/ui/core/format/FormatUtils.js +1 -1
  126. package/src/sap/ui/core/format/NumberFormat.js +32 -13
  127. package/src/sap/ui/core/format/TimezoneUtil.js +1 -1
  128. package/src/sap/ui/core/getCompatibilityVersion.js +1 -1
  129. package/src/sap/ui/core/hyphenation/Hyphenation.js +1 -1
  130. package/src/sap/ui/core/library.js +3 -3
  131. package/src/sap/ui/core/message/ControlMessageProcessor.js +1 -1
  132. package/src/sap/ui/core/message/Message.js +1 -1
  133. package/src/sap/ui/core/message/MessageManager.js +1 -1
  134. package/src/sap/ui/core/message/MessageParser.js +1 -1
  135. package/src/sap/ui/core/message/MessageProcessor.js +1 -1
  136. package/src/sap/ui/core/messagebundle_ar.properties +1 -1
  137. package/src/sap/ui/core/messagebundle_mk.properties +1 -1
  138. package/src/sap/ui/core/mvc/Controller.js +42 -7
  139. package/src/sap/ui/core/mvc/HTMLView.js +1 -1
  140. package/src/sap/ui/core/mvc/JSONView.js +1 -1
  141. package/src/sap/ui/core/mvc/JSView.js +1 -1
  142. package/src/sap/ui/core/mvc/TemplateView.js +1 -1
  143. package/src/sap/ui/core/mvc/View.js +1 -1
  144. package/src/sap/ui/core/mvc/XMLView.js +1 -1
  145. package/src/sap/ui/core/plugin/DeclarativeSupport.js +1 -1
  146. package/src/sap/ui/core/plugin/LessSupport.js +1 -1
  147. package/src/sap/ui/core/plugin/TemplatingSupport.js +1 -1
  148. package/src/sap/ui/core/postmessage/Bus.js +1 -1
  149. package/src/sap/ui/core/postmessage/confirmationDialog.js +1 -1
  150. package/src/sap/ui/core/routing/Router.js +1 -1
  151. package/src/sap/ui/core/search/OpenSearchProvider.js +1 -1
  152. package/src/sap/ui/core/search/SearchProvider.js +1 -1
  153. package/src/sap/ui/core/service/Service.js +1 -1
  154. package/src/sap/ui/core/service/ServiceFactory.js +1 -1
  155. package/src/sap/ui/core/service/ServiceFactoryRegistry.js +1 -1
  156. package/src/sap/ui/core/support/Plugin.js +1 -1
  157. package/src/sap/ui/core/support/Support.js +1 -1
  158. package/src/sap/ui/core/support/plugins/ControlTree.js +1 -1
  159. package/src/sap/ui/core/support/plugins/Interaction.js +1 -1
  160. package/src/sap/ui/core/support/plugins/LocalStorage.js +1 -1
  161. package/src/sap/ui/core/support/plugins/Performance.js +1 -1
  162. package/src/sap/ui/core/support/plugins/Selector.js +1 -1
  163. package/src/sap/ui/core/support/plugins/TechInfo.js +1 -1
  164. package/src/sap/ui/core/support/plugins/Trace.js +1 -1
  165. package/src/sap/ui/core/support/plugins/ViewInfo.js +1 -1
  166. package/src/sap/ui/core/themes/base/base.less +239 -8
  167. package/src/sap/ui/core/themes/base/global.less +20 -0
  168. package/src/sap/ui/core/themes/sap_hcb/global.less +20 -0
  169. package/src/sap/ui/core/tmpl/DOMAttribute.js +1 -1
  170. package/src/sap/ui/core/tmpl/DOMElement.js +1 -1
  171. package/src/sap/ui/core/tmpl/HandlebarsTemplate.js +1 -1
  172. package/src/sap/ui/core/tmpl/Template.js +1 -1
  173. package/src/sap/ui/core/tmpl/TemplateControl.js +1 -1
  174. package/src/sap/ui/core/util/AsyncHintsHelper.js +1 -1
  175. package/src/sap/ui/core/util/Export.js +1 -1
  176. package/src/sap/ui/core/util/ExportCell.js +1 -1
  177. package/src/sap/ui/core/util/ExportColumn.js +1 -1
  178. package/src/sap/ui/core/util/ExportRow.js +1 -1
  179. package/src/sap/ui/core/util/ExportType.js +1 -1
  180. package/src/sap/ui/core/util/ExportTypeCSV.js +1 -1
  181. package/src/sap/ui/core/util/File.js +1 -1
  182. package/src/sap/ui/core/util/LibraryInfo.js +1 -1
  183. package/src/sap/ui/core/util/MockServer.js +1 -1
  184. package/src/sap/ui/core/util/PasteHelper.js +2 -2
  185. package/src/sap/ui/core/util/ShortcutHelper.js +6 -0
  186. package/src/sap/ui/core/util/XMLPreprocessor.js +112 -94
  187. package/src/sap/ui/core/util/_LocalizationHelper.js +2 -1
  188. package/src/sap/ui/core/util/reflection/BaseTreeModifier.js +0 -29
  189. package/src/sap/ui/core/util/reflection/JsControlTreeModifier.js +0 -26
  190. package/src/sap/ui/core/util/reflection/XmlTreeModifier.js +0 -56
  191. package/src/sap/ui/core/util/serializer/HTMLViewSerializer.js +1 -1
  192. package/src/sap/ui/core/util/serializer/Serializer.js +1 -1
  193. package/src/sap/ui/core/util/serializer/ViewSerializer.js +1 -1
  194. package/src/sap/ui/core/util/serializer/XMLViewSerializer.js +1 -1
  195. package/src/sap/ui/core/util/serializer/delegate/Delegate.js +1 -1
  196. package/src/sap/ui/core/util/serializer/delegate/HTML.js +1 -1
  197. package/src/sap/ui/core/util/serializer/delegate/XML.js +1 -1
  198. package/src/sap/ui/core/webc/WebComponent.js +1 -1
  199. package/src/sap/ui/core/webc/WebComponentMetadata.js +1 -1
  200. package/src/sap/ui/core/ws/ReadyState.js +1 -1
  201. package/src/sap/ui/core/ws/SapPcpWebSocket.js +1 -1
  202. package/src/sap/ui/core/ws/WebSocket.js +1 -1
  203. package/src/sap/ui/debug/ControlTree.js +1 -1
  204. package/src/sap/ui/debug/DebugEnv.js +1 -1
  205. package/src/sap/ui/debug/PropertyList.js +1 -1
  206. package/src/sap/ui/model/ClientListBinding.js +13 -6
  207. package/src/sap/ui/model/ClientModel.js +1 -1
  208. package/src/sap/ui/model/ClientTreeBinding.js +16 -7
  209. package/src/sap/ui/model/CompositeBinding.js +11 -4
  210. package/src/sap/ui/model/CompositeDataState.js +1 -1
  211. package/src/sap/ui/model/CompositeType.js +17 -3
  212. package/src/sap/ui/model/DataState.js +1 -1
  213. package/src/sap/ui/model/ListBinding.js +14 -11
  214. package/src/sap/ui/model/MetaModel.js +1 -1
  215. package/src/sap/ui/model/Model.js +11 -9
  216. package/src/sap/ui/model/PropertyBinding.js +21 -4
  217. package/src/sap/ui/model/SelectionModel.js +1 -1
  218. package/src/sap/ui/model/SimpleType.js +1 -1
  219. package/src/sap/ui/model/TreeAutoExpandMode.js +1 -1
  220. package/src/sap/ui/model/TreeBinding.js +14 -7
  221. package/src/sap/ui/model/Type.js +1 -1
  222. package/src/sap/ui/model/analytics/AnalyticalBinding.js +12 -8
  223. package/src/sap/ui/model/analytics/BatchResponseCollector.js +1 -1
  224. package/src/sap/ui/model/analytics/odata4analytics.js +66 -52
  225. package/src/sap/ui/model/controlhelper/TreeBindingProxy.js +1 -4
  226. package/src/sap/ui/model/json/JSONListBinding.js +5 -2
  227. package/src/sap/ui/model/json/JSONModel.js +7 -5
  228. package/src/sap/ui/model/json/JSONTreeBinding.js +5 -2
  229. package/src/sap/ui/model/message/MessageListBinding.js +5 -2
  230. package/src/sap/ui/model/message/MessageModel.js +1 -1
  231. package/src/sap/ui/model/odata/ODataAnnotations.js +1 -1
  232. package/src/sap/ui/model/odata/ODataMessageParser.js +1 -1
  233. package/src/sap/ui/model/odata/ODataMetaModel.js +8 -9
  234. package/src/sap/ui/model/odata/ODataMetadata.js +1 -1
  235. package/src/sap/ui/model/odata/ODataModel.js +1 -1
  236. package/src/sap/ui/model/odata/ODataUtils.js +1 -1
  237. package/src/sap/ui/model/odata/type/Boolean.js +2 -4
  238. package/src/sap/ui/model/odata/type/Byte.js +1 -1
  239. package/src/sap/ui/model/odata/type/Currency.js +1 -1
  240. package/src/sap/ui/model/odata/type/Date.js +1 -1
  241. package/src/sap/ui/model/odata/type/DateTime.js +1 -1
  242. package/src/sap/ui/model/odata/type/DateTimeBase.js +1 -1
  243. package/src/sap/ui/model/odata/type/DateTimeOffset.js +1 -1
  244. package/src/sap/ui/model/odata/type/DateTimeWithTimezone.js +1 -1
  245. package/src/sap/ui/model/odata/type/Decimal.js +1 -1
  246. package/src/sap/ui/model/odata/type/Double.js +1 -1
  247. package/src/sap/ui/model/odata/type/Guid.js +1 -1
  248. package/src/sap/ui/model/odata/type/Int.js +1 -1
  249. package/src/sap/ui/model/odata/type/Int16.js +1 -1
  250. package/src/sap/ui/model/odata/type/Int32.js +1 -1
  251. package/src/sap/ui/model/odata/type/Int64.js +1 -1
  252. package/src/sap/ui/model/odata/type/ODataType.js +1 -1
  253. package/src/sap/ui/model/odata/type/Raw.js +1 -1
  254. package/src/sap/ui/model/odata/type/SByte.js +1 -1
  255. package/src/sap/ui/model/odata/type/Single.js +1 -1
  256. package/src/sap/ui/model/odata/type/Stream.js +1 -1
  257. package/src/sap/ui/model/odata/type/String.js +1 -1
  258. package/src/sap/ui/model/odata/type/Time.js +1 -1
  259. package/src/sap/ui/model/odata/type/TimeOfDay.js +1 -1
  260. package/src/sap/ui/model/odata/type/Unit.js +1 -1
  261. package/src/sap/ui/model/odata/v2/Context.js +1 -1
  262. package/src/sap/ui/model/odata/v2/ODataAnnotations.js +2 -2
  263. package/src/sap/ui/model/odata/v2/ODataListBinding.js +14 -8
  264. package/src/sap/ui/model/odata/v2/ODataModel.js +25 -28
  265. package/src/sap/ui/model/odata/v2/ODataTreeBinding.js +15 -12
  266. package/src/sap/ui/model/odata/v4/Context.js +111 -30
  267. package/src/sap/ui/model/odata/v4/ODataBinding.js +9 -5
  268. package/src/sap/ui/model/odata/v4/ODataContextBinding.js +1 -1
  269. package/src/sap/ui/model/odata/v4/ODataListBinding.js +14 -9
  270. package/src/sap/ui/model/odata/v4/ODataMetaModel.js +4 -3
  271. package/src/sap/ui/model/odata/v4/ODataModel.js +27 -2
  272. package/src/sap/ui/model/odata/v4/ODataPropertyBinding.js +19 -7
  273. package/src/sap/ui/model/odata/v4/lib/_AggregationCache.js +240 -41
  274. package/src/sap/ui/model/odata/v4/lib/_AggregationHelper.js +88 -0
  275. package/src/sap/ui/model/odata/v4/lib/_Cache.js +13 -4
  276. package/src/sap/ui/model/odata/v4/lib/_Helper.js +15 -0
  277. package/src/sap/ui/model/odata/v4/lib/_TreeState.js +77 -15
  278. package/src/sap/ui/model/resource/ResourceModel.js +1 -1
  279. package/src/sap/ui/model/type/Boolean.js +1 -1
  280. package/src/sap/ui/model/type/Currency.js +1 -1
  281. package/src/sap/ui/model/type/Date.js +1 -1
  282. package/src/sap/ui/model/type/DateInterval.js +1 -1
  283. package/src/sap/ui/model/type/DateTime.js +1 -1
  284. package/src/sap/ui/model/type/DateTimeInterval.js +1 -1
  285. package/src/sap/ui/model/type/FileSize.js +1 -1
  286. package/src/sap/ui/model/type/Float.js +1 -1
  287. package/src/sap/ui/model/type/Integer.js +1 -1
  288. package/src/sap/ui/model/type/String.js +1 -1
  289. package/src/sap/ui/model/type/Time.js +1 -1
  290. package/src/sap/ui/model/type/TimeInterval.js +1 -1
  291. package/src/sap/ui/model/type/Unit.js +38 -1
  292. package/src/sap/ui/model/xml/XMLListBinding.js +5 -2
  293. package/src/sap/ui/model/xml/XMLModel.js +1 -1
  294. package/src/sap/ui/model/xml/XMLTreeBinding.js +5 -1
  295. package/src/sap/ui/qunit/utils/ControlIterator.js +1 -1
  296. package/src/sap/ui/qunit/utils/MemoryLeakCheck.js +1 -1
  297. package/src/sap/ui/test/RecordReplay.js +1 -0
  298. package/src/sap/ui/test/autowaiter/_autoWaiterAsync.js +8 -1
  299. package/src/sap/ui/test/generic/TestBase.js +1 -1
  300. package/src/sap/ui/test/gherkin/opa5TestHarness.js +0 -6
  301. package/src/sap/ui/test/gherkin/qUnitTestHarness.js +0 -6
  302. package/src/sap/ui/test/qunitPause.js +5 -1
  303. package/src/sap/ui/util/Storage.js +1 -1
  304. package/src/sap/ui/util/_enforceNoReturnValue.js +26 -0
  305. package/src/ui5loader.js +25 -2
  306. package/test/sap/ui/core/HyphenationPlayground.html +6 -292
  307. package/test/sap/ui/core/HyphenationPlayground.js +313 -0
  308. package/test/sap/ui/core/demokit/docuindex.json +1 -1
  309. package/test/sap/ui/core/demokit/sample/MessageManager/ODataBackendMessagesComp/ui5.yaml +1 -1
  310. package/test/sap/ui/core/demokit/sample/OpaAutoWaitParams/OpaAutoWaitParams.html +1 -1
  311. package/test/sap/ui/core/demokit/sample/OpaAutoWaitParams/applicationUnderTest/index.html +1 -2
  312. package/test/sap/ui/core/demokit/sample/OpaStartup/iStartMyAppInAFrame/README.js +31 -23
  313. package/test/sap/ui/core/demokit/sample/OpaStartup/iStartMyAppInAFrame/iStartMyAppInAFrame.js +103 -94
  314. package/test/sap/ui/core/demokit/sample/gherkin/GherkinWithOPA5/GherkinTestRunner.html +3 -0
  315. package/test/sap/ui/core/demokit/sample/gherkin/GherkinWithOPA5/GherkinTestRunner.js +1 -5
  316. package/test/sap/ui/core/demokit/sample/gherkin/GherkinWithPageObjects/GherkinTestRunner.html +3 -0
  317. package/test/sap/ui/core/demokit/sample/gherkin/GherkinWithPageObjects/GherkinTestRunner.js +1 -5
  318. package/test/sap/ui/core/demokit/sample/gherkin/GherkinWithQUnit/GherkinTestRunner.html +3 -0
  319. package/test/sap/ui/core/demokit/sample/gherkin/GherkinWithQUnit/GherkinTestRunner.js +1 -5
  320. package/test/sap/ui/core/demokit/sample/gherkin/GherkinWithQUnit/Steps.js +5 -5
  321. package/test/sap/ui/core/demokit/sample/gherkin/GherkinWithUIComponent/GherkinTestRunner.html +3 -0
  322. package/test/sap/ui/core/demokit/sample/gherkin/GherkinWithUIComponent/GherkinTestRunner.js +1 -5
  323. package/test/sap/ui/core/demokit/sample/matcher/BindingPath/ui5.yaml +1 -1
  324. package/test/sap/ui/core/demokit/sample/matcher/Descendant/ui5.yaml +1 -1
  325. package/test/sap/ui/core/demokit/sample/matcher/I18NText/ui5.yaml +1 -1
  326. package/test/sap/ui/core/demokit/sample/matcher/LabelFor/ui5.yaml +1 -1
  327. package/test/sap/ui/core/demokit/sample/odata/v4/MultipleInlineCreationRowsGrid/Main.controller.js +16 -9
  328. package/test/sap/ui/core/demokit/sample/odata/v4/MultipleInlineCreationRowsGrid/Main.view.xml +9 -0
  329. package/test/sap/ui/core/demokit/sample/odata/v4/MultipleInlineCreationRowsGrid/SandboxModel.js +11 -0
  330. package/test/sap/ui/core/demokit/sample/odata/v4/Products/data/UnitsOfMeasure.json +1 -1
  331. package/test/sap/ui/core/demokit/tutorial/databinding/01/manifest.json +2 -1
  332. package/test/sap/ui/core/demokit/tutorial/databinding/01/package.json +4 -1
  333. package/test/sap/ui/core/demokit/tutorial/databinding/01/ui5.yaml +1 -1
  334. package/test/sap/ui/core/demokit/tutorial/databinding/01/webapp/Component.js +12 -0
  335. package/test/sap/ui/core/demokit/tutorial/databinding/01/webapp/index.html +8 -7
  336. package/test/sap/ui/core/demokit/tutorial/databinding/01/webapp/manifest.json +28 -1
  337. package/test/sap/ui/core/demokit/tutorial/databinding/01/webapp/view/App.view.xml +5 -0
  338. package/test/sap/ui/core/demokit/tutorial/databinding/02/manifest.json +3 -1
  339. package/test/sap/ui/core/demokit/tutorial/databinding/02/package.json +4 -1
  340. package/test/sap/ui/core/demokit/tutorial/databinding/02/ui5.yaml +1 -1
  341. package/test/sap/ui/core/demokit/tutorial/databinding/02/webapp/Component.js +12 -0
  342. package/test/sap/ui/core/demokit/tutorial/databinding/02/webapp/index.html +8 -7
  343. package/test/sap/ui/core/demokit/tutorial/databinding/02/webapp/manifest.json +34 -1
  344. package/test/sap/ui/core/demokit/tutorial/databinding/02/webapp/model/data.json +3 -0
  345. package/test/sap/ui/core/demokit/tutorial/databinding/02/webapp/view/App.view.xml +5 -0
  346. package/test/sap/ui/core/demokit/tutorial/databinding/03/manifest.json +3 -1
  347. package/test/sap/ui/core/demokit/tutorial/databinding/03/package.json +4 -1
  348. package/test/sap/ui/core/demokit/tutorial/databinding/03/ui5.yaml +1 -1
  349. package/test/sap/ui/core/demokit/tutorial/databinding/03/webapp/Component.js +12 -0
  350. package/test/sap/ui/core/demokit/tutorial/databinding/03/webapp/index.html +8 -7
  351. package/test/sap/ui/core/demokit/tutorial/databinding/03/webapp/manifest.json +34 -1
  352. package/test/sap/ui/core/demokit/tutorial/databinding/03/webapp/model/data.json +3 -0
  353. package/test/sap/ui/core/demokit/tutorial/databinding/03/webapp/view/App.view.xml +5 -0
  354. package/test/sap/ui/core/demokit/tutorial/databinding/04/manifest.json +3 -2
  355. package/test/sap/ui/core/demokit/tutorial/databinding/04/package.json +4 -1
  356. package/test/sap/ui/core/demokit/tutorial/databinding/04/ui5.yaml +1 -1
  357. package/test/sap/ui/core/demokit/tutorial/databinding/04/webapp/Component.js +12 -0
  358. package/test/sap/ui/core/demokit/tutorial/databinding/04/webapp/index.html +8 -10
  359. package/test/sap/ui/core/demokit/tutorial/databinding/04/webapp/manifest.json +35 -1
  360. package/test/sap/ui/core/demokit/tutorial/databinding/04/webapp/model/data.json +6 -0
  361. package/test/sap/ui/core/demokit/tutorial/databinding/05/manifest.json +3 -2
  362. package/test/sap/ui/core/demokit/tutorial/databinding/05/package.json +4 -1
  363. package/test/sap/ui/core/demokit/tutorial/databinding/05/ui5.yaml +1 -1
  364. package/test/sap/ui/core/demokit/tutorial/databinding/05/webapp/Component.js +20 -0
  365. package/test/sap/ui/core/demokit/tutorial/databinding/05/webapp/index.html +8 -10
  366. package/test/sap/ui/core/demokit/tutorial/databinding/05/webapp/manifest.json +35 -1
  367. package/test/sap/ui/core/demokit/tutorial/databinding/05/webapp/model/data.json +6 -0
  368. package/test/sap/ui/core/demokit/tutorial/databinding/06/manifest.json +4 -3
  369. package/test/sap/ui/core/demokit/tutorial/databinding/06/package.json +4 -1
  370. package/test/sap/ui/core/demokit/tutorial/databinding/06/ui5.yaml +1 -1
  371. package/test/sap/ui/core/demokit/tutorial/databinding/06/webapp/Component.js +12 -0
  372. package/test/sap/ui/core/demokit/tutorial/databinding/06/webapp/index.html +8 -10
  373. package/test/sap/ui/core/demokit/tutorial/databinding/06/webapp/manifest.json +46 -1
  374. package/test/sap/ui/core/demokit/tutorial/databinding/06/webapp/model/data.json +5 -0
  375. package/test/sap/ui/core/demokit/tutorial/databinding/07/manifest.json +4 -3
  376. package/test/sap/ui/core/demokit/tutorial/databinding/07/package.json +3 -0
  377. package/test/sap/ui/core/demokit/tutorial/databinding/07/ui5.yaml +1 -1
  378. package/test/sap/ui/core/demokit/tutorial/databinding/07/webapp/Component.js +12 -0
  379. package/test/sap/ui/core/demokit/tutorial/databinding/07/webapp/index.html +8 -10
  380. package/test/sap/ui/core/demokit/tutorial/databinding/07/webapp/manifest.json +46 -1
  381. package/test/sap/ui/core/demokit/tutorial/databinding/07/webapp/model/data.json +5 -0
  382. package/test/sap/ui/core/demokit/tutorial/databinding/08/manifest.json +4 -3
  383. package/test/sap/ui/core/demokit/tutorial/databinding/08/package.json +3 -0
  384. package/test/sap/ui/core/demokit/tutorial/databinding/08/ui5.yaml +1 -1
  385. package/test/sap/ui/core/demokit/tutorial/databinding/08/webapp/Component.js +12 -0
  386. package/test/sap/ui/core/demokit/tutorial/databinding/08/webapp/index.html +8 -10
  387. package/test/sap/ui/core/demokit/tutorial/databinding/08/webapp/manifest.json +46 -1
  388. package/test/sap/ui/core/demokit/tutorial/databinding/08/webapp/model/data.json +11 -0
  389. package/test/sap/ui/core/demokit/tutorial/databinding/08/webapp/view/App.view.xml +1 -1
  390. package/test/sap/ui/core/demokit/tutorial/databinding/09/manifest.json +4 -3
  391. package/test/sap/ui/core/demokit/tutorial/databinding/09/package.json +3 -0
  392. package/test/sap/ui/core/demokit/tutorial/databinding/09/ui5.yaml +1 -1
  393. package/test/sap/ui/core/demokit/tutorial/databinding/09/webapp/Component.js +12 -0
  394. package/test/sap/ui/core/demokit/tutorial/databinding/09/webapp/controller/App.controller.js +8 -7
  395. package/test/sap/ui/core/demokit/tutorial/databinding/09/webapp/index.html +8 -10
  396. package/test/sap/ui/core/demokit/tutorial/databinding/09/webapp/manifest.json +46 -1
  397. package/test/sap/ui/core/demokit/tutorial/databinding/09/webapp/model/data.json +11 -0
  398. package/test/sap/ui/core/demokit/tutorial/databinding/09/webapp/view/App.view.xml +2 -2
  399. package/test/sap/ui/core/demokit/tutorial/databinding/10/manifest.json +4 -3
  400. package/test/sap/ui/core/demokit/tutorial/databinding/10/package.json +3 -0
  401. package/test/sap/ui/core/demokit/tutorial/databinding/10/ui5.yaml +1 -1
  402. package/test/sap/ui/core/demokit/tutorial/databinding/10/webapp/Component.js +12 -0
  403. package/test/sap/ui/core/demokit/tutorial/databinding/10/webapp/controller/App.controller.js +8 -7
  404. package/test/sap/ui/core/demokit/tutorial/databinding/10/webapp/index.html +8 -10
  405. package/test/sap/ui/core/demokit/tutorial/databinding/10/webapp/manifest.json +46 -1
  406. package/test/sap/ui/core/demokit/tutorial/databinding/10/webapp/model/data.json +13 -0
  407. package/test/sap/ui/core/demokit/tutorial/databinding/10/webapp/view/App.view.xml +3 -3
  408. package/test/sap/ui/core/demokit/tutorial/databinding/11/manifest.json +4 -3
  409. package/test/sap/ui/core/demokit/tutorial/databinding/11/package.json +3 -0
  410. package/test/sap/ui/core/demokit/tutorial/databinding/11/ui5.yaml +1 -1
  411. package/test/sap/ui/core/demokit/tutorial/databinding/11/webapp/Component.js +12 -0
  412. package/test/sap/ui/core/demokit/tutorial/databinding/11/webapp/controller/App.controller.js +8 -7
  413. package/test/sap/ui/core/demokit/tutorial/databinding/11/webapp/index.html +8 -10
  414. package/test/sap/ui/core/demokit/tutorial/databinding/11/webapp/manifest.json +47 -1
  415. package/test/sap/ui/core/demokit/tutorial/databinding/11/webapp/model/data.json +13 -0
  416. package/test/sap/ui/core/demokit/tutorial/databinding/11/webapp/view/App.view.xml +3 -3
  417. package/test/sap/ui/core/demokit/tutorial/databinding/12/manifest.json +4 -3
  418. package/test/sap/ui/core/demokit/tutorial/databinding/12/package.json +3 -0
  419. package/test/sap/ui/core/demokit/tutorial/databinding/12/ui5.yaml +1 -1
  420. package/test/sap/ui/core/demokit/tutorial/databinding/12/webapp/Component.js +12 -0
  421. package/test/sap/ui/core/demokit/tutorial/databinding/12/webapp/controller/App.controller.js +10 -11
  422. package/test/sap/ui/core/demokit/tutorial/databinding/12/webapp/index.html +8 -10
  423. package/test/sap/ui/core/demokit/tutorial/databinding/12/webapp/manifest.json +51 -1
  424. package/test/sap/ui/core/demokit/tutorial/databinding/12/webapp/model/Products.json +64 -57
  425. package/test/sap/ui/core/demokit/tutorial/databinding/12/webapp/model/data.json +13 -0
  426. package/test/sap/ui/core/demokit/tutorial/databinding/12/webapp/view/App.view.xml +3 -3
  427. package/test/sap/ui/core/demokit/tutorial/databinding/13/manifest.json +4 -3
  428. package/test/sap/ui/core/demokit/tutorial/databinding/13/package.json +3 -0
  429. package/test/sap/ui/core/demokit/tutorial/databinding/13/ui5.yaml +1 -1
  430. package/test/sap/ui/core/demokit/tutorial/databinding/13/webapp/Component.js +12 -0
  431. package/test/sap/ui/core/demokit/tutorial/databinding/13/webapp/controller/App.controller.js +16 -16
  432. package/test/sap/ui/core/demokit/tutorial/databinding/13/webapp/index.html +8 -10
  433. package/test/sap/ui/core/demokit/tutorial/databinding/13/webapp/manifest.json +51 -1
  434. package/test/sap/ui/core/demokit/tutorial/databinding/13/webapp/model/Products.json +64 -57
  435. package/test/sap/ui/core/demokit/tutorial/databinding/13/webapp/model/data.json +13 -0
  436. package/test/sap/ui/core/demokit/tutorial/databinding/13/webapp/view/App.view.xml +3 -3
  437. package/test/sap/ui/core/demokit/tutorial/databinding/14/manifest.json +4 -3
  438. package/test/sap/ui/core/demokit/tutorial/databinding/14/package.json +3 -0
  439. package/test/sap/ui/core/demokit/tutorial/databinding/14/ui5.yaml +1 -1
  440. package/test/sap/ui/core/demokit/tutorial/databinding/14/webapp/Component.js +12 -0
  441. package/test/sap/ui/core/demokit/tutorial/databinding/14/webapp/controller/App.controller.js +16 -16
  442. package/test/sap/ui/core/demokit/tutorial/databinding/14/webapp/index.html +8 -10
  443. package/test/sap/ui/core/demokit/tutorial/databinding/14/webapp/manifest.json +51 -1
  444. package/test/sap/ui/core/demokit/tutorial/databinding/14/webapp/model/Products.json +64 -57
  445. package/test/sap/ui/core/demokit/tutorial/databinding/14/webapp/model/data.json +14 -0
  446. package/test/sap/ui/core/demokit/tutorial/databinding/14/webapp/view/App.view.xml +3 -3
  447. package/test/sap/ui/core/demokit/tutorial/databinding/15/manifest.json +4 -3
  448. package/test/sap/ui/core/demokit/tutorial/databinding/15/package.json +3 -0
  449. package/test/sap/ui/core/demokit/tutorial/databinding/15/ui5.yaml +1 -1
  450. package/test/sap/ui/core/demokit/tutorial/databinding/15/webapp/Component.js +12 -0
  451. package/test/sap/ui/core/demokit/tutorial/databinding/15/webapp/controller/App.controller.js +19 -22
  452. package/test/sap/ui/core/demokit/tutorial/databinding/15/webapp/index.html +8 -10
  453. package/test/sap/ui/core/demokit/tutorial/databinding/15/webapp/manifest.json +51 -1
  454. package/test/sap/ui/core/demokit/tutorial/databinding/15/webapp/model/Products.json +64 -57
  455. package/test/sap/ui/core/demokit/tutorial/databinding/15/webapp/model/data.json +14 -0
  456. package/test/sap/ui/core/demokit/tutorial/databinding/15/webapp/view/App.view.xml +5 -5
  457. package/test/sap/ui/core/demokit/tutorial/mockserver/01/ui5.yaml +1 -1
  458. package/test/sap/ui/core/demokit/tutorial/mockserver/02/ui5.yaml +1 -1
  459. package/test/sap/ui/core/demokit/tutorial/mockserver/03/ui5.yaml +1 -1
  460. package/test/sap/ui/core/demokit/tutorial/mockserver/04/ui5.yaml +1 -1
  461. package/test/sap/ui/core/demokit/tutorial/navigation/01/ui5.yaml +1 -1
  462. package/test/sap/ui/core/demokit/tutorial/navigation/02/ui5.yaml +1 -1
  463. package/test/sap/ui/core/demokit/tutorial/navigation/03/ui5.yaml +1 -1
  464. package/test/sap/ui/core/demokit/tutorial/navigation/04/ui5.yaml +1 -1
  465. package/test/sap/ui/core/demokit/tutorial/navigation/05/ui5.yaml +1 -1
  466. package/test/sap/ui/core/demokit/tutorial/navigation/06/ui5.yaml +1 -1
  467. package/test/sap/ui/core/demokit/tutorial/navigation/07/ui5.yaml +1 -1
  468. package/test/sap/ui/core/demokit/tutorial/navigation/08/ui5.yaml +1 -1
  469. package/test/sap/ui/core/demokit/tutorial/navigation/09/ui5.yaml +1 -1
  470. package/test/sap/ui/core/demokit/tutorial/navigation/10/ui5.yaml +1 -1
  471. package/test/sap/ui/core/demokit/tutorial/navigation/11/ui5.yaml +1 -1
  472. package/test/sap/ui/core/demokit/tutorial/navigation/12/ui5.yaml +1 -1
  473. package/test/sap/ui/core/demokit/tutorial/navigation/13/ui5.yaml +1 -1
  474. package/test/sap/ui/core/demokit/tutorial/navigation/14/ui5.yaml +1 -1
  475. package/test/sap/ui/core/demokit/tutorial/navigation/15/ui5.yaml +1 -1
  476. package/test/sap/ui/core/demokit/tutorial/navigation/16/ui5.yaml +1 -1
  477. package/test/sap/ui/core/demokit/tutorial/navigation/17/ui5.yaml +1 -1
  478. package/test/sap/ui/core/demokit/tutorial/odatav4/01/ui5.yaml +1 -1
  479. package/test/sap/ui/core/demokit/tutorial/odatav4/02/ui5.yaml +1 -1
  480. package/test/sap/ui/core/demokit/tutorial/odatav4/03/ui5.yaml +1 -1
  481. package/test/sap/ui/core/demokit/tutorial/odatav4/04/ui5.yaml +1 -1
  482. package/test/sap/ui/core/demokit/tutorial/odatav4/05/ui5.yaml +1 -1
  483. package/test/sap/ui/core/demokit/tutorial/odatav4/06/ui5.yaml +1 -1
  484. package/test/sap/ui/core/demokit/tutorial/odatav4/07/ui5.yaml +1 -1
  485. package/test/sap/ui/core/demokit/tutorial/odatav4/08/ui5.yaml +1 -1
  486. package/test/sap/ui/core/demokit/tutorial/odatav4/09/ui5.yaml +1 -1
  487. package/test/sap/ui/core/demokit/tutorial/odatav4/10/ui5.yaml +1 -1
  488. package/test/sap/ui/core/demokit/tutorial/odatav4/11/ui5.yaml +1 -1
  489. package/test/sap/ui/core/demokit/tutorial/troubleshooting/01/ui5.yaml +1 -1
  490. package/test/sap/ui/core/qunit/CompositeBinding.qunit.js +67 -0
  491. package/test/sap/ui/core/qunit/EventProvider.qunit.js +30 -2
  492. package/test/sap/ui/core/qunit/{Core_libraryPreloadFiles.qunit.html → Lib_preloadFiles.qunit.html} +1 -1
  493. package/test/sap/ui/core/qunit/{Core_libraryPreloadFiles.qunit.js → Lib_preloadFiles.qunit.js} +5 -10
  494. package/test/sap/ui/core/qunit/ThemeHelper.qunit.js +1 -1
  495. package/test/sap/ui/core/qunit/ThemeParameters.qunit.js +4 -4
  496. package/test/sap/ui/core/qunit/ThemeParameters_legacyAPIs.qunit.js +12 -12
  497. package/test/sap/ui/core/qunit/analytics/odata4analytics.qunit.js +262 -12
  498. package/test/sap/ui/core/qunit/app/DesignMode_suppressedDeactivation.qunit.js +8 -4
  499. package/test/sap/ui/core/qunit/app/_createDesignModeTests_legacyAPIs.qunit.js +8 -4
  500. package/test/sap/ui/core/qunit/app/fixture/designmode/test01.controller.js +4 -4
  501. package/test/sap/ui/core/qunit/app/testsuite.app.qunit.js +3 -3
  502. package/test/sap/ui/core/qunit/base/Config_cascade.qunit.js +11 -0
  503. package/test/sap/ui/core/qunit/component/Component_keepAlive.qunit.js +30 -2
  504. package/test/sap/ui/core/qunit/component/UIComponent.qunit.js +82 -19
  505. package/test/sap/ui/core/qunit/component/testdata/keepAlive/child3/App.view.xml +3 -0
  506. package/test/sap/ui/core/qunit/component/testdata/keepAlive/child3/Component.js +20 -0
  507. package/test/sap/ui/core/qunit/component/testdata/keepAlive/child3/Home.view.xml +5 -0
  508. package/test/sap/ui/core/qunit/component/testdata/keepAlive/child3/Other.view.xml +5 -0
  509. package/test/sap/ui/core/qunit/component/testdata/keepAlive/child3/manifest.json +54 -0
  510. package/test/sap/ui/core/qunit/gherkin/fixture/testHarnessAmbiguous.html +4 -0
  511. package/test/sap/ui/core/qunit/gherkin/fixture/testHarnessDuplicate.html +4 -0
  512. package/test/sap/ui/core/qunit/gherkin/fixture/testHarnessFailing.html +4 -0
  513. package/test/sap/ui/core/qunit/gherkin/opa5TestHarness.qunit.html +4 -0
  514. package/test/sap/ui/core/qunit/gherkin/opa5TestHarness.qunit.js +1 -1
  515. package/test/sap/ui/core/qunit/gherkin/qUnitTestHarness.qunit.html +4 -0
  516. package/test/sap/ui/core/qunit/gherkin/qUnitTestHarness.qunit.js +1 -1
  517. package/test/sap/ui/core/qunit/internal/1RingModels.qunit.html +1 -1
  518. package/test/sap/ui/core/qunit/internal/1RingModels.qunit.js +5 -6
  519. package/test/sap/ui/core/qunit/internal/testsuite.models.qunit.js +43 -16
  520. package/test/sap/ui/core/qunit/messages/messagesGeneral.qunit.js +194 -180
  521. package/test/sap/ui/core/qunit/messages/messagesUsage.qunit.js +15 -33
  522. package/test/sap/ui/core/qunit/mockserver/MockServer.qunit.js +936 -1014
  523. package/test/sap/ui/core/qunit/mockserver/testsuite.mockserver.qunit.js +2 -4
  524. package/test/sap/ui/core/qunit/model/FAR_CUSTOMER_LINE_ITEMS.metadata.xml +2 -0
  525. package/test/sap/ui/core/qunit/model/PropertyBinding.qunit.js +50 -1
  526. package/test/sap/ui/core/qunit/model/controlhelper/TreeBindingProxy.qunit.js +18 -8
  527. package/test/sap/ui/core/qunit/mvc/Controller.qunit.js +107 -49
  528. package/test/sap/ui/core/qunit/mvc/testdata/asyncHooks.view.xml +7 -0
  529. package/test/sap/ui/core/qunit/odata/ODataMetaModel.qunit.js +0 -3
  530. package/test/sap/ui/core/qunit/odata/v2/ODataModel.integration.qunit.js +143 -2
  531. package/test/sap/ui/core/qunit/odata/v2/ODataModelNoFakeService.qunit.js +34 -0
  532. package/test/sap/ui/core/qunit/odata/v4/Context.qunit.js +230 -39
  533. package/test/sap/ui/core/qunit/odata/v4/ODataBinding.qunit.js +57 -18
  534. package/test/sap/ui/core/qunit/odata/v4/ODataListBinding.qunit.js +40 -6
  535. package/test/sap/ui/core/qunit/odata/v4/ODataMetaModel.qunit.js +3 -0
  536. package/test/sap/ui/core/qunit/odata/v4/ODataModel.integration.qunit.js +1715 -106
  537. package/test/sap/ui/core/qunit/odata/v4/ODataModel.qunit.js +39 -0
  538. package/test/sap/ui/core/qunit/odata/v4/ODataPropertyBinding.qunit.js +88 -18
  539. package/test/sap/ui/core/qunit/odata/v4/lib/_AggregationCache.qunit.js +544 -50
  540. package/test/sap/ui/core/qunit/odata/v4/lib/_AggregationHelper.qunit.js +175 -0
  541. package/test/sap/ui/core/qunit/odata/v4/lib/_Cache.qunit.js +50 -9
  542. package/test/sap/ui/core/qunit/odata/v4/lib/_Helper.qunit.js +17 -0
  543. package/test/sap/ui/core/qunit/odata/v4/lib/_TreeState.qunit.js +140 -27
  544. package/test/sap/ui/core/qunit/opa/RecordReplay.qunit.js +12 -3
  545. package/test/sap/ui/core/qunit/resource/ResourceModel.qunit.js +1 -2
  546. package/test/sap/ui/core/qunit/routing/fixture/placeholder/component/NavContainerOptOut/Component.js +1 -0
  547. package/test/sap/ui/core/qunit/rule/model/bindingPathSyntaxValidation.qunit.js +37 -0
  548. package/test/sap/ui/core/qunit/rule/model/{modelSupport.qunit.js → selectUsedInBoundAggregation.qunit.js} +86 -154
  549. package/test/sap/ui/core/qunit/rule/testsuite.rule.qunit.js +5 -2
  550. package/test/sap/ui/core/qunit/testdata/libraries/themeParameters/lib12/themes/{sap_hcb → sap_horizon_hcb}/library.css +1 -1
  551. package/test/sap/ui/core/qunit/testsuite.core.framework.qunit.js +18 -18
  552. package/test/sap/ui/core/qunit/testsuites/testsuite.base.configuration.qunit.js +1 -1
  553. package/test/sap/ui/core/qunit/testsuites/testsuite.controls.qunit.js +2 -1
  554. package/test/sap/ui/core/qunit/testsuites/testsuite.theming.qunit.js +3 -3
  555. package/test/sap/ui/core/qunit/types/CompositeType.qunit.js +6 -0
  556. package/test/sap/ui/core/qunit/types/DateFormat.qunit.js +3 -6
  557. package/test/sap/ui/core/qunit/types/NumberFormat.qunit.js +1370 -1242
  558. package/test/sap/ui/core/qunit/types/Types.qunit.js +65 -0
  559. package/test/sap/ui/core/qunit/types/testsuite.types.qunit.js +0 -3
  560. package/test/sap/ui/core/qunit/ui5classes/ManagedObject.qunit.js +68 -3
  561. package/test/sap/ui/core/qunit/util/XMLPreprocessor.qunit.js +2757 -1920
  562. package/test/sap/ui/core/qunit/util/reflection/JsControlTreeModifier.qunit.js +0 -102
  563. package/test/sap/ui/core/qunit/util/reflection/XmlTreeModifier.qunit.js +0 -165
  564. package/test/sap/ui/core/relnotes/changes-1.121.json +0 -15
  565. package/test/sap/ui/core/relnotes/changes-1.122.json +80 -0
  566. package/test/sap/ui/core/visual/HyphenationPlayground.spec.js +5 -2
  567. package/test/sap/ui/core/demokit/tutorial/databinding/01/webapp/index.js +0 -15
  568. package/test/sap/ui/core/demokit/tutorial/databinding/02/webapp/index.js +0 -21
  569. package/test/sap/ui/core/demokit/tutorial/databinding/03/webapp/index.js +0 -21
  570. package/test/sap/ui/core/demokit/tutorial/databinding/04/webapp/index.js +0 -25
  571. package/test/sap/ui/core/demokit/tutorial/databinding/05/webapp/index.js +0 -29
  572. package/test/sap/ui/core/demokit/tutorial/databinding/06/webapp/index.js +0 -42
  573. package/test/sap/ui/core/demokit/tutorial/databinding/07/webapp/index.js +0 -44
  574. package/test/sap/ui/core/demokit/tutorial/databinding/08/webapp/index.js +0 -39
  575. package/test/sap/ui/core/demokit/tutorial/databinding/09/webapp/index.js +0 -39
  576. package/test/sap/ui/core/demokit/tutorial/databinding/10/webapp/index.js +0 -41
  577. package/test/sap/ui/core/demokit/tutorial/databinding/11/webapp/index.js +0 -48
  578. package/test/sap/ui/core/demokit/tutorial/databinding/12/webapp/index.js +0 -52
  579. package/test/sap/ui/core/demokit/tutorial/databinding/13/webapp/index.js +0 -52
  580. package/test/sap/ui/core/demokit/tutorial/databinding/14/webapp/index.js +0 -54
  581. package/test/sap/ui/core/demokit/tutorial/databinding/15/webapp/index.js +0 -54
  582. /package/test/sap/ui/core/qunit/testdata/legacy-uilib_legacyAPIs/themes/{sap_hcb → sap_horizon_hcb}/library-parameters.json +0 -0
  583. /package/test/sap/ui/core/qunit/testdata/legacy-uilib_legacyAPIs/themes/{sap_hcb → sap_horizon_hcb}/library.css +0 -0
  584. /package/test/sap/ui/core/qunit/testdata/legacy-uilib_legacyAPIs/themes/{sap_hcb → sap_horizon_hcb}/library[legacy].css +0 -0
  585. /package/test/sap/ui/core/qunit/testdata/libraries/themeParameters/lib1/themes/{sap_hcb → sap_horizon_hcb}/library-parameters.json +0 -0
  586. /package/test/sap/ui/core/qunit/testdata/libraries/themeParameters/lib1/themes/{sap_hcb → sap_horizon_hcb}/library.css +0 -0
  587. /package/test/sap/ui/core/qunit/testdata/libraries/themeParameters/lib10/themes/{sap_hcb → sap_horizon_hcb}/library.css +0 -0
  588. /package/test/sap/ui/core/qunit/testdata/libraries/themeParameters/lib11/themes/{sap_hcb → sap_horizon_hcb}/library.css +0 -0
  589. /package/test/sap/ui/core/qunit/testdata/libraries/themeParameters/lib13/themes/{sap_hcb → sap_horizon_hcb}/library.css +0 -0
  590. /package/test/sap/ui/core/qunit/testdata/libraries/themeParameters/lib14/themes/{sap_hcb → sap_horizon_hcb}/library.css +0 -0
  591. /package/test/sap/ui/core/qunit/testdata/libraries/themeParameters/lib15/themes/{sap_hcb → sap_horizon_hcb}/library-parameters.json +0 -0
  592. /package/test/sap/ui/core/qunit/testdata/libraries/themeParameters/lib15/themes/{sap_hcb → sap_horizon_hcb}/library.css +0 -0
  593. /package/test/sap/ui/core/qunit/testdata/libraries/themeParameters/lib16/themes/{sap_hcb → sap_horizon_hcb}/library-parameters.json +0 -0
  594. /package/test/sap/ui/core/qunit/testdata/libraries/themeParameters/lib16/themes/{sap_hcb → sap_horizon_hcb}/library.css +0 -0
  595. /package/test/sap/ui/core/qunit/testdata/libraries/themeParameters/lib17/themes/{sap_hcb → sap_horizon_hcb}/library.css +0 -0
  596. /package/test/sap/ui/core/qunit/testdata/libraries/themeParameters/lib2/themes/{sap_hcb → sap_horizon_hcb}/library-parameters.json +0 -0
  597. /package/test/sap/ui/core/qunit/testdata/libraries/themeParameters/lib2/themes/{sap_hcb → sap_horizon_hcb}/library.css +0 -0
  598. /package/test/sap/ui/core/qunit/testdata/libraries/themeParameters/lib3/themes/{sap_hcb → sap_horizon_hcb}/library-parameters.json +0 -0
  599. /package/test/sap/ui/core/qunit/testdata/libraries/themeParameters/lib3/themes/{sap_hcb → sap_horizon_hcb}/library.css +0 -0
  600. /package/test/sap/ui/core/qunit/testdata/libraries/themeParameters/lib4/themes/{sap_hcb → sap_horizon_hcb}/library-parameters.json +0 -0
  601. /package/test/sap/ui/core/qunit/testdata/libraries/themeParameters/lib5/themes/{sap_hcb → sap_horizon_hcb}/library.css +0 -0
  602. /package/test/sap/ui/core/qunit/testdata/libraries/themeParameters/lib6/themes/{sap_hcb → sap_horizon_hcb}/library.css +0 -0
  603. /package/test/sap/ui/core/qunit/testdata/libraries/themeParameters/lib7/themes/{sap_hcb → sap_horizon_hcb}/library.css +0 -0
  604. /package/test/sap/ui/core/qunit/testdata/libraries/themeParameters/lib8/themes/{sap_hcb → sap_horizon_hcb}/library.css +0 -0
  605. /package/test/sap/ui/core/qunit/testdata/libraries/themeParameters/lib9/themes/{sap_hcb → sap_horizon_hcb}/library.css +0 -0
@@ -26,6 +26,7 @@ sap.ui.define([
26
26
  "sap/ui/model/FilterType",
27
27
  "sap/ui/model/Sorter",
28
28
  "sap/ui/model/odata/OperationMode",
29
+ "sap/ui/model/odata/type/Decimal",
29
30
  "sap/ui/model/odata/v4/AnnotationHelper",
30
31
  "sap/ui/model/odata/v4/ODataListBinding",
31
32
  "sap/ui/model/odata/v4/ODataMetaModel",
@@ -41,8 +42,8 @@ sap.ui.define([
41
42
  ], function (Log, Localization, uid, ColumnListItem, CustomListItem, FlexBox, _MessageStrip,
42
43
  Text, Device, EventProvider, SyncPromise, Messaging, Rendering, Supportability, Message,
43
44
  Controller, View, ChangeReason, Filter, FilterOperator, FilterType, Sorter, OperationMode,
44
- AnnotationHelper, ODataListBinding, ODataMetaModel, ODataModel, ODataPropertyBinding,
45
- ValueListType, _Helper, Security, TestUtils, XMLHelper) {
45
+ Decimal, AnnotationHelper, ODataListBinding, ODataMetaModel, ODataModel,
46
+ ODataPropertyBinding, ValueListType, _Helper, Security, TestUtils, XMLHelper) {
46
47
  /*eslint no-sparse-arrays: 0, "max-len": ["error", {"code": 100,
47
48
  "ignorePattern": "/sap/opu/odata4/|\" :$|\" : \\{$|\\{meta>"}], */
48
49
  "use strict";
@@ -265,6 +266,26 @@ sap.ui.define([
265
266
  }
266
267
  }
267
268
 
269
+ /**
270
+ * Checks the selection state of the given context.
271
+ *
272
+ * @param {object} assert - The QUnit assert object
273
+ * @param {sap.ui.model.odata.v4.Context} oContext - A context
274
+ * @param {boolean} bSelected - The expected value for the "selected" property,
275
+ * <code>undefined</code> is a valid value for the annotation.
276
+ * @param {string} [sText] - A message for the assertion
277
+ */
278
+ function checkSelected(assert, oContext, bSelected, sText) {
279
+ if (bSelected && oContext.isDeleted()) {
280
+ assert.strictEqual(oContext.isSelected(), false, "selection hidden while deleted");
281
+ } else {
282
+ assert.strictEqual(oContext.isSelected(), !!bSelected,
283
+ sText || "JIRA: CPOUI5ODATAV4-1943");
284
+ }
285
+ assert.strictEqual(oContext.getProperty("@$ui5.context.isSelected"), bSelected,
286
+ sText || "JIRA: CPOUI5ODATAV4-1944");
287
+ }
288
+
268
289
  /**
269
290
  * Checks that the given table has the expected state w.r.t. contexts and content.
270
291
  *
@@ -452,6 +473,22 @@ sap.ui.define([
452
473
  });
453
474
  }
454
475
 
476
+ /**
477
+ * Sets the "selected" property for the given context.
478
+ *
479
+ * @param {boolean} bUseAnnotation - If <code>true</code>, setProperty with the client-side
480
+ * annotation is used for selection; otherwise, the context's setSelected method is used.
481
+ * @param {sap.ui.model.odata.v4.Context} oContext - A context
482
+ * @param {boolean} bSelected - The new "selected" state
483
+ */
484
+ function setSelected(bUseAnnotation, oContext, bSelected) {
485
+ if (bUseAnnotation) {
486
+ oContext.setProperty("@$ui5.context.isSelected", bSelected);
487
+ } else {
488
+ oContext.setSelected(bSelected);
489
+ }
490
+ }
491
+
455
492
  /**
456
493
  * Creates a test with the given title and executes viewStart with the given parameters.
457
494
  *
@@ -5029,6 +5066,8 @@ sap.ui.define([
5029
5066
  // No request is added to the queue and ODataModel#hasPendingChanges and
5030
5067
  // ODataListBinding#hasPendingChanges work as expected.
5031
5068
  // JIRA: CPOUI5ODATAV4-36
5069
+ //
5070
+ // Selecting a context does not interfere with reset (JIRA: CPOUI5ODATAV4-1944).
5032
5071
  QUnit.test("create an entity and immediately reset changes (no UI) V4-36", function (assert) {
5033
5072
  var // use autoExpandSelect so that the cache is created asynchronously
5034
5073
  oModel = this.createSalesOrdersModel({autoExpandSelect : true}),
@@ -5036,7 +5075,10 @@ sap.ui.define([
5036
5075
 
5037
5076
  return this.createView(assert, "", oModel).then(function () {
5038
5077
  var oListBindingWithoutUI = oModel.bindList("/SalesOrderList"),
5039
- oCreatedPromise = oListBindingWithoutUI.create({}, true).created();
5078
+ oContext = oListBindingWithoutUI.create({}, true),
5079
+ oCreatedPromise = oContext.created();
5080
+
5081
+ oContext.setSelected(true);
5040
5082
 
5041
5083
  // This error is unavoidable as #fetchValue runs right after creating the context, but
5042
5084
  // fails as the context is deleted already.
@@ -5205,8 +5247,10 @@ sap.ui.define([
5205
5247
  // JIRA: CPOUI5ODATAV4-12
5206
5248
  //
5207
5249
  // "Select all" is reset by #filter (JIRA: CPOUI5ODATAV4-1943).
5250
+ // Data binding for selection (JIRA: CPOUI5ODATAV4-1944).
5208
5251
  QUnit.test("Relative ODLB inherits parent ODCB's query options on filter", function (assert) {
5209
5252
  var oBinding,
5253
+ oHeaderContext,
5210
5254
  oModel,
5211
5255
  sView = '\
5212
5256
  <FlexBox binding="{path : \'/EMPLOYEES(\\\'42\\\')\',\
@@ -5247,7 +5291,20 @@ sap.ui.define([
5247
5291
  var sResourceUrl = "EMPLOYEES('42')/EMPLOYEE_2_EQUIPMENTS?$orderby=ID&$select=Name&c1=a"
5248
5292
  + "&c2=b&$filter=EQUIPMENT_2_PRODUCT/SupplierIdentifier%20eq%202";
5249
5293
 
5250
- oBinding.getHeaderContext().setSelected(true); // "select all"
5294
+ oHeaderContext = oBinding.getHeaderContext();
5295
+ assert.deepEqual(oHeaderContext.getObject(), {
5296
+ "@$ui5.context.isSelected" : false,
5297
+ $count : 3
5298
+ }, "JIRA: CPOUI5ODATAV4-1944");
5299
+ checkSelected(assert, oHeaderContext, false);
5300
+
5301
+ oHeaderContext.setSelected(true); // "select all"
5302
+
5303
+ assert.deepEqual(oHeaderContext.getObject(), {
5304
+ "@$ui5.context.isSelected" : true,
5305
+ $count : 3
5306
+ }, "JIRA: CPOUI5ODATAV4-1944");
5307
+ checkSelected(assert, oHeaderContext, true);
5251
5308
 
5252
5309
  that.expectRequest(sResourceUrl + "&$skip=0&$top=100", {
5253
5310
  value : [
@@ -5261,11 +5318,11 @@ sap.ui.define([
5261
5318
  oBinding.filter(
5262
5319
  new Filter("EQUIPMENT_2_PRODUCT/SupplierIdentifier", FilterOperator.EQ, 2));
5263
5320
 
5264
- assert.notOk(oBinding.getHeaderContext().isSelected(), "JIRA: CPOUI5ODATAV4-1943");
5265
-
5321
+ checkSelected(assert, oHeaderContext, false);
5266
5322
  assert.throws(function () {
5267
5323
  oBinding.getDownloadUrl();
5268
5324
  }, new Error("Result pending"));
5325
+
5269
5326
  return Promise.all([
5270
5327
  oBinding.requestDownloadUrl().then(function (sDownloadUrl) {
5271
5328
  assert.strictEqual(sDownloadUrl, sTeaBusi + sResourceUrl);
@@ -5273,6 +5330,11 @@ sap.ui.define([
5273
5330
  }),
5274
5331
  that.waitForChanges(assert)
5275
5332
  ]);
5333
+ }).then(function () {
5334
+ assert.deepEqual(oHeaderContext.getObject(""), {
5335
+ "@$ui5.context.isSelected" : false,
5336
+ $count : 2
5337
+ }, "JIRA: CPOUI5ODATAV4-1944");
5276
5338
  });
5277
5339
  });
5278
5340
 
@@ -6901,6 +6963,7 @@ sap.ui.define([
6901
6963
  //
6902
6964
  // Test oHeaderContext.getObject() and oHeaderContext.setProperty("$count")
6903
6965
  // JIRA: CPOUI5ODATAV4-1404
6966
+ // Data binding for selection (JIRA: CPOUI5ODATAV4-1944).
6904
6967
  QUnit.test("ODLB: $count and filter()", function (assert) {
6905
6968
  var oHeaderContext,
6906
6969
  oTable,
@@ -6928,8 +6991,10 @@ sap.ui.define([
6928
6991
 
6929
6992
  // JIRA: CPOUI5ODATAV4-1404
6930
6993
  assert.strictEqual(oHeaderContext.getProperty("$count"), 2);
6931
- assert.deepEqual(oHeaderContext.getObject(), {$count : 2});
6932
- assert.deepEqual(oHeaderContext.getObject(""), {$count : 2});
6994
+ assert.deepEqual(oHeaderContext.getObject(),
6995
+ {"@$ui5.context.isSelected" : false, $count : 2}, "JIRA: CPOUI5ODATAV4-1944");
6996
+ assert.deepEqual(oHeaderContext.getObject(""),
6997
+ {"@$ui5.context.isSelected" : false, $count : 2}, "JIRA: CPOUI5ODATAV4-1944");
6933
6998
 
6934
6999
  that.expectChange("count", "2");
6935
7000
  assert.strictEqual(oTableBinding.getCount(), 2);
@@ -6970,7 +7035,7 @@ sap.ui.define([
6970
7035
  return Promise.all([
6971
7036
  // code under test - request the header data while filter is still running
6972
7037
  oHeaderContext.requestObject().then(function (oResult) {
6973
- assert.deepEqual(oResult, {$count : 1});
7038
+ assert.deepEqual(oResult, {"@$ui5.context.isSelected" : false, $count : 1});
6974
7039
  }),
6975
7040
  that.waitForChanges(assert)
6976
7041
  ]);
@@ -7103,6 +7168,7 @@ sap.ui.define([
7103
7168
  // JIRA: CPOUI5ODATAV4-1098
7104
7169
  //
7105
7170
  // "Select all" is reset by #changeParameters (JIRA: CPOUI5ODATAV4-1943).
7171
+ // Data binding for selection (JIRA: CPOUI5ODATAV4-1944).
7106
7172
  QUnit.test("ODLB: $count and changeParameters()", function (assert) {
7107
7173
  var oModel = this.createSalesOrdersModel({autoExpandSelect : true}),
7108
7174
  oTable,
@@ -7135,7 +7201,8 @@ sap.ui.define([
7135
7201
 
7136
7202
  return that.waitForChanges(assert);
7137
7203
  }).then(function () {
7138
- oTableBinding.getHeaderContext().setSelected(true); // "select all"
7204
+ const oHeaderContext = oTableBinding.getHeaderContext();
7205
+ oHeaderContext.setSelected(true); // "select all"
7139
7206
 
7140
7207
  that.expectRequest("SalesOrderList?$expand=SO_2_BP&$select=SalesOrderID"
7141
7208
  + "&$filter=SalesOrderID gt '0500000001'&$skip=0&$top=100",
@@ -7151,7 +7218,7 @@ sap.ui.define([
7151
7218
  $select : "SalesOrderID"
7152
7219
  });
7153
7220
 
7154
- assert.notOk(oTableBinding.getHeaderContext().isSelected(), "JIRA: CPOUI5ODATAV4-1943");
7221
+ checkSelected(assert, oHeaderContext, false);
7155
7222
 
7156
7223
  return that.waitForChanges(assert);
7157
7224
  });
@@ -7362,7 +7429,8 @@ sap.ui.define([
7362
7429
  var fnResolve,
7363
7430
  oRowContext = that.oView.byId("list").getItems()[1].getBindingContext();
7364
7431
 
7365
- oTable.getBinding("items").getHeaderContext().setSelected(true);
7432
+ const oHeaderContext = oTable.getBinding("items").getHeaderContext();
7433
+ oHeaderContext.setSelected(true);
7366
7434
 
7367
7435
  that.expectRequest("SalesOrderList('2')/SO_2_SOITEM"
7368
7436
  + "?$select=ItemPosition,Note,SalesOrderID&$skip=0&$top=20",
@@ -7390,8 +7458,7 @@ sap.ui.define([
7390
7458
  return Promise.all([
7391
7459
  oTable.setBindingContext(oRowContext),
7392
7460
  resolveLater(function () {
7393
- assert.notOk(oTable.getBinding("items").getHeaderContext().isSelected(),
7394
- "JIRA: CPOUI5ODATAV4-1943");
7461
+ checkSelected(assert, oHeaderContext, false);
7395
7462
 
7396
7463
  resolveLater(fnResolve); // must not respond before requestSideEffects
7397
7464
  return oRowContext.requestSideEffects(["SO_2_SOITEM"]);
@@ -19322,6 +19389,7 @@ sap.ui.define([
19322
19389
  //
19323
19390
  // Selection on contexts which are deleted and restored (JIRA: CPOUI5ODATAV4-1943).
19324
19391
  // Selection is cleared on successful deletion (JIRA: CPOUI5ODATAV4-2053).
19392
+ // Data binding for selection (JIRA: CPOUI5ODATAV4-1944).
19325
19393
  [
19326
19394
  {desc : "submit", success : true},
19327
19395
  {desc : "reset via model", resetViaModel : true},
@@ -19434,17 +19502,20 @@ sap.ui.define([
19434
19502
  oContext4.setSelected(true);
19435
19503
 
19436
19504
  assert.strictEqual(oContext2.toString(), "/SalesOrderList('2')[1;selected]");
19505
+ checkSelected(assert, oContext2, true);
19437
19506
 
19438
19507
  oPromise2 = oContext2.delete();
19439
19508
  oPromise4 = oContext4.delete();
19440
19509
 
19510
+ checkSelected(assert, oContext2, true); // selection hidden while deleted
19511
+
19441
19512
  assert.throws(function () {
19442
19513
  // code under test (JIRA: CPOUI5ODATAV4-1943)
19443
19514
  oContext2.setSelected(true);
19444
19515
  }, new Error("Must not select a deleted entity: /SalesOrderList('2');deleted"));
19445
19516
  // code under test (JIRA: CPOUI5ODATAV4-1943)
19446
19517
  oContext2.setSelected(false);
19447
- assert.notOk(oContext2.isSelected(), "JIRA: CPOUI5ODATAV4-1943");
19518
+ checkSelected(assert, oContext2, false);
19448
19519
 
19449
19520
  assert.ok(oBinding.hasPendingChanges());
19450
19521
  assert.ok(oModel.hasPendingChanges());
@@ -19561,13 +19632,13 @@ sap.ui.define([
19561
19632
  oPromise4.then(function () {
19562
19633
  assert.ok(oFixture.success);
19563
19634
  assert.ok(oContext4.isDeleted());
19564
- assert.notOk(oContext4.isSelected(), "JIRA: CPOUI5ODATAV4-2053");
19635
+ checkSelected(assert, oContext4, undefined, "JIRA: CPOUI5ODATAV4-2053");
19565
19636
  }, function (oError) {
19566
19637
  assert.notOk(oFixture.success);
19567
19638
  assert.ok(oError.canceled);
19568
19639
  assert.notOk(oContext4.hasPendingChanges());
19569
19640
  assert.notOk(oContext4.isDeleted());
19570
- assert.ok(oContext4.isSelected(), "JIRA: CPOUI5ODATAV4-1943");
19641
+ checkSelected(assert, oContext4, true);
19571
19642
  assert.strictEqual(oContext4.getProperty("SalesOrderID"), "4");
19572
19643
  }),
19573
19644
  oModel.submitBatch("update"),
@@ -20073,6 +20144,7 @@ sap.ui.define([
20073
20144
  // JIRA: CPOUI5ODATAV4-1638
20074
20145
  //
20075
20146
  // Selection is hidden, but kept while deleted (JIRA: CPOUI5ODATAV4-2053).
20147
+ // Data binding for selection (JIRA: CPOUI5ODATAV4-1944).
20076
20148
  QUnit.test("CPOUI5ODATAV4-1638: ODLB: deferred delete w/ isKeepAlive fails", function (assert) {
20077
20149
  var oBinding,
20078
20150
  oKeptContext1,
@@ -20140,7 +20212,7 @@ sap.ui.define([
20140
20212
  oRowContext = oBinding.getCurrentContexts()[0];
20141
20213
  oRowContext.setSelected(true);
20142
20214
  oRowPromise = oRowContext.delete("doNotSubmit");
20143
- assert.notOk(oRowContext.isSelected(), "selection hidden while deleted");
20215
+ checkSelected(assert, oRowContext, true); // selection hidden while deleted
20144
20216
 
20145
20217
  // code under test (JIRA: CPOUI5ODATAV4-2053)
20146
20218
  assert.notOk(oBinding.getAllCurrentContexts().includes(oRowContext),
@@ -20223,10 +20295,8 @@ sap.ui.define([
20223
20295
  }).then(function () {
20224
20296
  assertIDs(["3", "1", "4", "5"]);
20225
20297
  that.checkMoreButton(assert, "[4/7]");
20226
- assert.deepEqual(oKeptContext1.getObject(),
20227
- {GrossAmount : "3", SalesOrderID : "1"});
20228
- assert.deepEqual(oKeptContext2.getObject(),
20229
- {GrossAmount : "6", SalesOrderID : "6"});
20298
+ assert.deepEqual(oKeptContext1.getObject(), {GrossAmount : "3", SalesOrderID : "1"});
20299
+ assert.deepEqual(oKeptContext2.getObject(), {GrossAmount : "6", SalesOrderID : "6"});
20230
20300
 
20231
20301
  that.expectRequest("SalesOrderList?$count=true&$filter=LifecycleStatus eq 'N'"
20232
20302
  + "&$select=GrossAmount,SalesOrderID&$orderby=GrossAmount&$skip=0&$top=4", {
@@ -20244,7 +20314,7 @@ sap.ui.define([
20244
20314
  oBinding.resetChanges();
20245
20315
  assert.notOk(oRowContext.hasPendingChanges());
20246
20316
  assert.notOk(oRowContext.isDeleted());
20247
- assert.ok(oRowContext.isSelected(), "selection hidden, but kept while deleted");
20317
+ checkSelected(assert, oRowContext, true, "selection hidden, but kept while deleted");
20248
20318
 
20249
20319
  return Promise.all([
20250
20320
  checkCanceled(assert, oRowPromise),
@@ -20254,11 +20324,9 @@ sap.ui.define([
20254
20324
  assertIDs(["2", "3", "1", "4"]);
20255
20325
  that.checkMoreButton(assert, "[4/8]");
20256
20326
  assert.deepEqual(oRowContext.getObject(),
20257
- {GrossAmount : "1", SalesOrderID : "2"});
20258
- assert.deepEqual(oKeptContext1.getObject(),
20259
- {GrossAmount : "3", SalesOrderID : "1"});
20260
- assert.deepEqual(oKeptContext2.getObject(),
20261
- {GrossAmount : "6", SalesOrderID : "6"});
20327
+ {"@$ui5.context.isSelected" : true, GrossAmount : "1", SalesOrderID : "2"});
20328
+ assert.deepEqual(oKeptContext1.getObject(), {GrossAmount : "3", SalesOrderID : "1"});
20329
+ assert.deepEqual(oKeptContext2.getObject(), {GrossAmount : "6", SalesOrderID : "6"});
20262
20330
  });
20263
20331
  });
20264
20332
 
@@ -21056,11 +21124,11 @@ sap.ui.define([
21056
21124
  // without children. Hence the binding doesn't trigger a request, but its lock must be released.
21057
21125
  QUnit.test("ODCB: delayed refresh", function (assert) {
21058
21126
  var oModel = this.createSalesOrdersModel({autoExpandSelect : true}),
21059
- sView = '\
21060
- <FlexBox binding="{/BusinessPartnerList(\'0100000000\')}">\
21061
- <Text id="company" text="{CompanyName}"/>\
21062
- </FlexBox>\
21063
- <FlexBox binding="{/SalesOrderList}"/>',
21127
+ sView = `
21128
+ <FlexBox binding="{/BusinessPartnerList('0100000000')}">
21129
+ <Text id="company" text="{CompanyName}"/>
21130
+ </FlexBox>
21131
+ <FlexBox binding="{/SalesOrderList('1')}"/>`,
21064
21132
  that = this;
21065
21133
 
21066
21134
  this.expectRequest("BusinessPartnerList('0100000000')"
@@ -25192,6 +25260,8 @@ sap.ui.define([
25192
25260
  // JIRA: CPOUI5ODATAV4-1849
25193
25261
  //
25194
25262
  // Selection on header and root context (JIRA: CPOUI5ODATAV4-1943).
25263
+ // Data binding for selection (JIRA: CPOUI5ODATAV4-1944).
25264
+ //
25195
25265
  // Use $count (JIRA: CPOUI5ODATAV4-1855).
25196
25266
  // Old vs. new format of RecursiveHierarchy annotation (JIRA: CPOUI5ODATAV4-2401).
25197
25267
  //
@@ -25234,6 +25304,7 @@ sap.ui.define([
25234
25304
  },
25235
25305
  $count : true
25236
25306
  }}" threshold="0" visibleRowCount="3">
25307
+ <Text text="{= %{@$ui5.context.isSelected} }"/>
25237
25308
  <Text text="{= %{@$ui5.node.isExpanded} }"/>
25238
25309
  <Text text="{= %{@$ui5.node.level} }"/>
25239
25310
  <Text text="{BestFriend/Name}"/>
@@ -25314,9 +25385,7 @@ sap.ui.define([
25314
25385
  checkTable("root is leaf", assert, oTable, [
25315
25386
  "/Artists(ArtistID='0',IsActiveEntity=true)"
25316
25387
  ], [
25317
- [undefined, 1, "Friend #01"],
25318
- ["", "", ""],
25319
- ["", "", ""]
25388
+ ["", undefined, 1, "Friend #01"]
25320
25389
  ]);
25321
25390
  assert.strictEqual(oListBinding.getCount(), 1, "count of nodes"); // code under test
25322
25391
  assert.deepEqual(oRoot.getObject(), {
@@ -25335,18 +25404,19 @@ sap.ui.define([
25335
25404
  }, "technical properties have been removed");
25336
25405
 
25337
25406
  // code under test
25338
- assert.notOk(oRoot.isSelected(), "JIRA: CPOUI5ODATAV4-1943");
25339
- assert.notOk(oHeaderContext.isSelected());
25407
+ checkSelected(assert, oRoot, undefined);
25408
+ checkSelected(assert, oHeaderContext, false);
25340
25409
 
25341
25410
  // code under test
25342
25411
  oRoot.setSelected(true);
25343
- assert.ok(oRoot.isSelected());
25412
+ checkSelected(assert, oRoot, true);
25413
+
25344
25414
  assert.strictEqual(oRoot.toString(),
25345
25415
  "/Artists(ArtistID='0',IsActiveEntity=true)[0;selected]");
25346
25416
 
25347
25417
  // code under test
25348
25418
  oHeaderContext.setSelected(true);
25349
- assert.ok(oHeaderContext.isSelected());
25419
+ checkSelected(assert, oHeaderContext, true);
25350
25420
 
25351
25421
  that.expectChange("count", "1");
25352
25422
 
@@ -25355,6 +25425,12 @@ sap.ui.define([
25355
25425
 
25356
25426
  return that.waitForChanges(assert, "$count");
25357
25427
  }).then(function () {
25428
+ checkTable("selected root", assert, oTable, [
25429
+ "/Artists(ArtistID='0',IsActiveEntity=true)"
25430
+ ], [
25431
+ [true, undefined, 1, "Friend #01"]
25432
+ ]);
25433
+
25358
25434
  assert.strictEqual(oListBinding.getCount(), 1, "count of nodes"); // code under test
25359
25435
 
25360
25436
  that.expectRequest("Artists(ArtistID='0',IsActiveEntity=true)?$select=defaultChannel", {
@@ -25448,9 +25524,7 @@ sap.ui.define([
25448
25524
  checkTable("side effect: BestFriend/Name for all rows", assert, oTable, [
25449
25525
  "/Artists(ArtistID='0',IsActiveEntity=true)"
25450
25526
  ], [
25451
- [undefined, 1, "Friend #01 (updated)"],
25452
- ["", "", ""],
25453
- ["", "", ""]
25527
+ [true, undefined, 1, "Friend #01 (updated)"]
25454
25528
  ]);
25455
25529
  assert.strictEqual(oListBinding.getCount(), 1, "count of nodes"); // code under test
25456
25530
 
@@ -25495,9 +25569,7 @@ sap.ui.define([
25495
25569
  checkTable("after side effect", assert, oTable, [
25496
25570
  "/Artists(ArtistID='0',IsActiveEntity=true)"
25497
25571
  ], [
25498
- [undefined, 1, "Friend #01 (updated)"],
25499
- ["", "", ""],
25500
- ["", "", ""]
25572
+ [true, undefined, 1, "Friend #01 (updated)"]
25501
25573
  ]);
25502
25574
  assert.strictEqual(oListBinding.getCount(), 1, "count of nodes"); // code under test
25503
25575
  assert.strictEqual(oRoot.getProperty("defaultChannel"), "260", "360 has been ignored");
@@ -25577,14 +25649,13 @@ sap.ui.define([
25577
25649
  "/Artists(ArtistID='1',IsActiveEntity=true)",
25578
25650
  "/Artists(ArtistID='0',IsActiveEntity=true)"
25579
25651
  ], [
25580
- [false, 1, ""],
25581
- ["", "", ""],
25582
- ["", "", ""]
25652
+ ["", false, 1, ""]
25583
25653
  ], 1);
25584
25654
  assert.strictEqual(oListBinding.getCount(), 3, "count of nodes"); // code under test
25585
25655
  assert.strictEqual(oListBinding.getAllCurrentContexts()[1], oKeptAliveNode,
25586
25656
  "still kept alive");
25587
25657
  assert.deepEqual(oKeptAliveNode.getObject(), {
25658
+ "@$ui5.context.isSelected" : true,
25588
25659
  "@odata.etag" : "etag0.4",
25589
25660
  ArtistID : "0",
25590
25661
  BestFriend : {
@@ -25639,9 +25710,7 @@ sap.ui.define([
25639
25710
  "/Artists(ArtistID='1',IsActiveEntity=true)",
25640
25711
  "/Artists(ArtistID='0',IsActiveEntity=true)"
25641
25712
  ], [
25642
- [false, 1, ""],
25643
- ["", "", ""],
25644
- ["", "", ""]
25713
+ ["", false, 1, ""]
25645
25714
  ], 1);
25646
25715
  assert.strictEqual(oListBinding.getCount(), 3, "count of nodes"); // code under test
25647
25716
  assert.strictEqual(oListBinding.getAllCurrentContexts()[1], oKeptAliveNode,
@@ -25678,13 +25747,14 @@ sap.ui.define([
25678
25747
  "/Artists(ArtistID='1',IsActiveEntity=true)",
25679
25748
  "/Artists(ArtistID='0',IsActiveEntity=true)"
25680
25749
  ], [
25681
- [true, 1, ""],
25682
- [false, 2, "Friend #01 (updated once more)"],
25683
- ["", "", ""]
25750
+ ["", true, 1, ""],
25751
+ [true, false, 2, "Friend #01 (updated once more)"],
25752
+ ["", "", "", ""]
25684
25753
  ]);
25685
25754
  assert.strictEqual(oListBinding.getAllCurrentContexts()[1], oKeptAliveNode,
25686
25755
  "still kept alive");
25687
25756
  assert.deepEqual(oKeptAliveNode.getObject(), {
25757
+ "@$ui5.context.isSelected" : true,
25688
25758
  "@$ui5.node.isExpanded" : false,
25689
25759
  "@$ui5.node.level" : 2,
25690
25760
  "@odata.etag" : "etag0.4",
@@ -25770,14 +25840,16 @@ sap.ui.define([
25770
25840
  "/Artists(ArtistID='0',IsActiveEntity=true)",
25771
25841
  "/Artists(ArtistID='2',IsActiveEntity=true)"
25772
25842
  ], [
25773
- [true, 1, "Friend #01 (no more)"],
25774
- [true, 2, ""],
25775
- [undefined, 3, ""]
25843
+ ["", true, 1, "Friend #01 (no more)"],
25844
+ [true, true, 2, ""],
25845
+ ["", undefined, 3, ""]
25776
25846
  ]);
25777
25847
  assert.strictEqual(oListBinding.getCount(), 3, "count of nodes"); // code under test
25778
25848
  assert.strictEqual(oListBinding.getAllCurrentContexts()[1], oKeptAliveNode,
25779
25849
  "still kept alive");
25850
+ checkSelected(assert, oKeptAliveNode, true);
25780
25851
  assert.deepEqual(oKeptAliveNode.getObject(), {
25852
+ "@$ui5.context.isSelected" : true,
25781
25853
  "@$ui5.node.isExpanded" : true,
25782
25854
  "@$ui5.node.level" : 2,
25783
25855
  "@odata.etag" : "etag0.4",
@@ -25790,7 +25862,6 @@ sap.ui.define([
25790
25862
  },
25791
25863
  defaultChannel : "460"
25792
25864
  }, "after expandTo");
25793
- assert.ok(oKeptAliveNode.isSelected());
25794
25865
 
25795
25866
  // no additional request for same aggregation data
25796
25867
  // code under test (BCP: 2370045709)
@@ -29832,6 +29903,8 @@ sap.ui.define([
29832
29903
  // "Refresh single" for stale elements; keep same context instance for created nodes throughout
29833
29904
  // collapse and side effects.
29834
29905
  // JIRA: CPOUI5ODATAV4-2374
29906
+ //
29907
+ // Selection survives a move (JIRA: CPOUI5ODATAV4-1944)
29835
29908
  QUnit.test("Recursive Hierarchy: create new children, move 'em", function (assert) {
29836
29909
  var oBeta, oBetaCreated, oGamma, oGammaCreated, oListBinding, oNewRoot, fnRespond, oRoot,
29837
29910
  oTable;
@@ -30019,6 +30092,7 @@ sap.ui.define([
30019
30092
  Name : "Gamma"
30020
30093
  }, /*bSkipRefresh*/true);
30021
30094
  oGammaCreated = oGamma.created();
30095
+ oGamma.setSelected(true);
30022
30096
 
30023
30097
  assert.strictEqual(oGamma.getIndex(), 1);
30024
30098
 
@@ -30086,7 +30160,9 @@ sap.ui.define([
30086
30160
  checkCreatedPersisted(assert, oBeta, oBetaCreated);
30087
30161
 
30088
30162
  assert.strictEqual(oGamma.getIndex(), 2);
30163
+ checkSelected(assert, oGamma, true);
30089
30164
  assert.deepEqual(oGamma.getObject(), {
30165
+ "@$ui5.context.isSelected" : true,
30090
30166
  "@$ui5.context.isTransient" : false,
30091
30167
  "@$ui5.node.level" : 3,
30092
30168
  "@odata.etag" : "etag2.1", // updated
@@ -30137,6 +30213,7 @@ sap.ui.define([
30137
30213
 
30138
30214
  assert.strictEqual(oGamma.getIndex(), 1);
30139
30215
  assert.deepEqual(oGamma.getObject(), {
30216
+ "@$ui5.context.isSelected" : true,
30140
30217
  "@$ui5.context.isTransient" : false,
30141
30218
  "@$ui5.node.level" : 2,
30142
30219
  "@odata.etag" : "etag2.2", // updated
@@ -30238,6 +30315,7 @@ sap.ui.define([
30238
30315
 
30239
30316
  assert.strictEqual(oGamma.getIndex(), 1);
30240
30317
  assert.deepEqual(oGamma.getObject(), {
30318
+ "@$ui5.context.isSelected" : true,
30241
30319
  "@$ui5.context.isTransient" : false,
30242
30320
  "@$ui5.node.level" : 2,
30243
30321
  "@odata.etag" : "etag2.3",
@@ -30305,6 +30383,7 @@ sap.ui.define([
30305
30383
 
30306
30384
  assert.strictEqual(oGamma.getIndex(), 1);
30307
30385
  assert.deepEqual(oGamma.getObject(), {
30386
+ "@$ui5.context.isSelected" : true,
30308
30387
  "@$ui5.context.isTransient" : false,
30309
30388
  "@$ui5.node.isExpanded" : true,
30310
30389
  "@$ui5.node.level" : 2,
@@ -32172,6 +32251,811 @@ make root = ${bMakeRoot}`;
32172
32251
  ], 4);
32173
32252
  });
32174
32253
 
32254
+ //*********************************************************************************************
32255
+ // Scenario: A hierarchy has an initial expandTo=1 and three visible rows.
32256
+ // (1) Expand Alpha
32257
+ // (2) Create New1, New2, New3 below Alpha; create New4 below Beta; create New5 below Gamma;
32258
+ // create New6 below New3
32259
+ // (3) Side-effects refresh (-> unified cache; New2 is already read in-place, it is shifted when
32260
+ // moving New1 to its out-of-place position; Beta is already read in-place, but shifted
32261
+ // when moving New1 and New3; Gamma is only placeholder when moving New5)
32262
+ // (4) Check all contexts
32263
+ // (5) Refresh the binding (out of place is no longer kept, tree is collapsed again to 1 level)
32264
+ // JIRA: CPOUI5ODATAV4-2454
32265
+ QUnit.test("Recursive Hierarchy: out of place", async function (assert) {
32266
+ const oModel = this.createSpecialCasesModel({autoExpandSelect : true});
32267
+ const sFriend = "/Artists(ArtistID='99',IsActiveEntity=false)/_Friend";
32268
+ const sFilterSearchPrefix = "ancestors("
32269
+ + "$root" + sFriend + ",OrgChart,_/NodeID,"
32270
+ + "filter(IsActiveEntity eq false)/search(covfefe),keep start)/";
32271
+ const baseUrl = (sExpandLevels) => sFriend.slice(1)
32272
+ + "?custom=foo&$apply=" + sFilterSearchPrefix + "orderby(defaultChannel)"
32273
+ + "/com.sap.vocabularies.Hierarchy.v1.TopLevels(HierarchyNodes=$root" + sFriend
32274
+ + ",HierarchyQualifier='OrgChart',NodeProperty='_/NodeID',Levels=1"
32275
+ + (sExpandLevels ? ",ExpandLevels=" + sExpandLevels : "") + ")";
32276
+ const sCountUrl = sFriend.slice(1) + "/$count?$filter=IsActiveEntity eq false&custom=foo"
32277
+ + "&$search=covfefe";
32278
+ const sExpandLevels = JSON.stringify([
32279
+ {NodeID : "1,false", Levels : 1},
32280
+ {NodeID : "2,false", Levels : 1},
32281
+ {NodeID : "3,false", Levels : 1},
32282
+ {NodeID : "13,false", Levels : 1}
32283
+ ]);
32284
+ const sView = `
32285
+ <t:Table id="table" rows="{path : '/Artists(ArtistID=\\'99\\',IsActiveEntity=false)/_Friend',
32286
+ parameters : {
32287
+ $$aggregation : {
32288
+ hierarchyQualifier : 'OrgChart',
32289
+ search : 'covfefe'
32290
+ },
32291
+ $count : true,
32292
+ $filter : 'IsActiveEntity eq false',
32293
+ $orderby : 'defaultChannel',
32294
+ custom : 'foo'
32295
+ }}" threshold="0" visibleRowCount="3">
32296
+ <Text text="{= %{@$ui5.node.isExpanded} }"/>
32297
+ <Text text="{= %{@$ui5.node.level} }"/>
32298
+ <Text text="{ArtistID}"/>
32299
+ <Text text="{Name}"/>
32300
+ </t:Table>`;
32301
+
32302
+ // Server: UI:
32303
+ // 1 Alpha 1 Alpha
32304
+ // 12 New2 (created) 13 New3 (created)
32305
+ // 2 Beta 16 New6 (created)
32306
+ // 14 New4 (created) 12 New2 (created)
32307
+ // 11 New1 (created) 11 New1 (created)
32308
+ // 13 New3 (created) 2 Beta
32309
+ // 16 New6 (created) 14 New4 (created)
32310
+ // 3 Gamma 3 Gamma
32311
+ // 15 New5 (created) 15 New5 (created)
32312
+ // 4 Delta 4 Delta
32313
+ this.expectRequest(sCountUrl, 4)
32314
+ .expectRequest(baseUrl()
32315
+ + "&$select=ArtistID,IsActiveEntity,Name,_/DrillState,_/NodeID"
32316
+ + "&$count=true&$skip=0&$top=3", {
32317
+ "@odata.count" : "3",
32318
+ value : [{
32319
+ ArtistID : "1",
32320
+ IsActiveEntity : false,
32321
+ Name : "Alpha",
32322
+ _ : {
32323
+ DrillState : "collapsed",
32324
+ NodeID : "1,false"
32325
+ }
32326
+ }, {
32327
+ ArtistID : "3",
32328
+ IsActiveEntity : false,
32329
+ Name : "Gamma",
32330
+ _ : {
32331
+ DrillState : "leaf",
32332
+ NodeID : "3,false"
32333
+ }
32334
+ }, {
32335
+ ArtistID : "4",
32336
+ IsActiveEntity : false,
32337
+ Name : "Delta",
32338
+ _ : {
32339
+ DrillState : "leaf",
32340
+ NodeID : "4,false"
32341
+ }
32342
+ }]
32343
+ });
32344
+
32345
+ await this.createView(assert, sView, oModel);
32346
+
32347
+ const oTable = this.oView.byId("table");
32348
+ const oBinding = oTable.getBinding("rows");
32349
+ checkTable("initial page", assert, oTable, [
32350
+ sFriend + "(ArtistID='1',IsActiveEntity=false)",
32351
+ sFriend + "(ArtistID='3',IsActiveEntity=false)",
32352
+ sFriend + "(ArtistID='4',IsActiveEntity=false)"
32353
+ ], [
32354
+ [false, 1, "1", "Alpha"],
32355
+ [undefined, 1, "3", "Gamma"],
32356
+ [undefined, 1, "4", "Delta"]
32357
+ ]);
32358
+ const oAlpha = oTable.getRows()[0].getBindingContext();
32359
+ const oGamma = oTable.getRows()[1].getBindingContext();
32360
+
32361
+ this.expectRequest(sFriend.slice(1) + "?custom=foo&$apply=" + sFilterSearchPrefix
32362
+ + "descendants($root/" + sFriend.slice(1)
32363
+ + ",OrgChart,_/NodeID,filter(ArtistID eq '1' and IsActiveEntity eq false),1)"
32364
+ + "/orderby(defaultChannel)"
32365
+ + "&$select=ArtistID,IsActiveEntity,Name,_/DrillState,_/NodeID"
32366
+ + "&$count=true&$skip=0&$top=3", {
32367
+ "@odata.count" : "1",
32368
+ value : [{
32369
+ ArtistID : "2",
32370
+ IsActiveEntity : false,
32371
+ Name : "Beta",
32372
+ _ : {
32373
+ DrillState : "leaf",
32374
+ NodeID : "2,false"
32375
+ }
32376
+ }]
32377
+ });
32378
+
32379
+ oAlpha.expand();
32380
+
32381
+ await this.waitForChanges(assert, "(1) expand Alpha");
32382
+
32383
+ checkTable("after (1)", assert, oTable, [
32384
+ sFriend + "(ArtistID='1',IsActiveEntity=false)",
32385
+ sFriend + "(ArtistID='2',IsActiveEntity=false)",
32386
+ sFriend + "(ArtistID='3',IsActiveEntity=false)",
32387
+ sFriend + "(ArtistID='4',IsActiveEntity=false)"
32388
+ ], [
32389
+ [true, 1, "1", "Alpha"],
32390
+ [undefined, 2, "2", "Beta"],
32391
+ [undefined, 1, "3", "Gamma"]
32392
+ ]);
32393
+ const oBeta = oTable.getRows()[1].getBindingContext();
32394
+
32395
+ const create = async (sId, sName, oParent) => {
32396
+ const sParentId = oParent.getProperty("ArtistID");
32397
+ this.expectRequest({
32398
+ method : "POST",
32399
+ url : sFriend.slice(1) + "?custom=foo",
32400
+ payload : {
32401
+ "BestFriend@odata.bind" :
32402
+ `../Artists(ArtistID='${sParentId}',IsActiveEntity=false)`,
32403
+ Name : sName
32404
+ }
32405
+ }, {
32406
+ ArtistID : sId,
32407
+ IsActiveEntity : false,
32408
+ Name : sName,
32409
+ _ : null // not available w/ RAP for a non-hierarchical request
32410
+ })
32411
+ .expectRequest(sFriend.slice(1) + "?$apply=" + sFilterSearchPrefix
32412
+ + "descendants($root/" + sFriend.slice(1)
32413
+ + ",OrgChart,_/NodeID,filter(ArtistID eq '" + sParentId
32414
+ + "' and IsActiveEntity eq false),1)"
32415
+ + "/orderby(defaultChannel)"
32416
+ + "&$filter=ArtistID eq '" + sId
32417
+ + "' and IsActiveEntity eq false&$select=_/NodeID", {
32418
+ value : [{
32419
+ _ : {
32420
+ NodeID : `${sId},false`
32421
+ }
32422
+ }]
32423
+ });
32424
+
32425
+ const oContext = oBinding.create({
32426
+ "@$ui5.node.parent" : oParent,
32427
+ Name : sName
32428
+ }, /*bSkipRefresh*/true);
32429
+
32430
+ await oContext.created();
32431
+
32432
+ return oContext;
32433
+ };
32434
+
32435
+ await create("11", "New1", oAlpha);
32436
+ await create("12", "New2", oAlpha);
32437
+ const oNew3 = await create("13", "New3", oAlpha);
32438
+ await create("14", "New4", oBeta);
32439
+ await create("15", "New5", oGamma);
32440
+
32441
+ await this.waitForChanges(assert, "(2a) create nodes");
32442
+
32443
+ const oNew6 = await create("16", "New6", oNew3);
32444
+
32445
+ await this.waitForChanges(assert, "(2b) create nested node");
32446
+
32447
+ checkTable("after (2)", assert, oTable, [
32448
+ sFriend + "(ArtistID='1',IsActiveEntity=false)",
32449
+ sFriend + "(ArtistID='13',IsActiveEntity=false)",
32450
+ sFriend + "(ArtistID='16',IsActiveEntity=false)",
32451
+ sFriend + "(ArtistID='12',IsActiveEntity=false)",
32452
+ sFriend + "(ArtistID='11',IsActiveEntity=false)",
32453
+ sFriend + "(ArtistID='2',IsActiveEntity=false)",
32454
+ sFriend + "(ArtistID='14',IsActiveEntity=false)",
32455
+ sFriend + "(ArtistID='3',IsActiveEntity=false)",
32456
+ sFriend + "(ArtistID='15',IsActiveEntity=false)",
32457
+ sFriend + "(ArtistID='4',IsActiveEntity=false)"
32458
+ ], [
32459
+ [true, 1, "1", "Alpha"],
32460
+ [true, 2, "13", "New3"],
32461
+ [undefined, 3, "16", "New6"]
32462
+ ]);
32463
+
32464
+ this.expectRequest(sCountUrl, 10)
32465
+ .expectRequest({
32466
+ batchNo : 15,
32467
+ url : baseUrl(sExpandLevels)
32468
+ + "&$select=ArtistID,IsActiveEntity,Name,_/DescendantCount,_/DistanceFromRoot"
32469
+ + ",_/DrillState,_/NodeID"
32470
+ + "&$count=true&$skip=0&$top=3"
32471
+ }, {
32472
+ "@odata.count" : "10",
32473
+ value : [{
32474
+ ArtistID : "1",
32475
+ IsActiveEntity : false,
32476
+ Name : "Alpha*",
32477
+ _ : {
32478
+ DescendantCount : "6",
32479
+ DistanceFromRoot : "0",
32480
+ DrillState : "expanded",
32481
+ NodeID : "1,false"
32482
+ }
32483
+ }, {
32484
+ ArtistID : "12",
32485
+ IsActiveEntity : false,
32486
+ Name : "New2*",
32487
+ _ : {
32488
+ DescendantCount : "0",
32489
+ DistanceFromRoot : "1",
32490
+ DrillState : "leaf",
32491
+ NodeID : "12,false"
32492
+ }
32493
+ }, {
32494
+ ArtistID : "2",
32495
+ IsActiveEntity : false,
32496
+ Name : "Beta*",
32497
+ _ : {
32498
+ DescendantCount : "1",
32499
+ DistanceFromRoot : "1",
32500
+ DrillState : "expanded",
32501
+ NodeID : "2,false"
32502
+ }
32503
+ }]
32504
+ })
32505
+ .expectRequest({
32506
+ batchNo : 15,
32507
+ url : baseUrl(sExpandLevels)
32508
+ + "&$select=ArtistID,IsActiveEntity,_/DescendantCount,_/DistanceFromRoot"
32509
+ + ",_/DrillState,_/Limited_Rank"
32510
+ + "&$filter=ArtistID eq '1' and IsActiveEntity eq false"
32511
+ + " or ArtistID eq '11' and IsActiveEntity eq false"
32512
+ + " or ArtistID eq '12' and IsActiveEntity eq false"
32513
+ + " or ArtistID eq '13' and IsActiveEntity eq false"
32514
+ + " or ArtistID eq '14' and IsActiveEntity eq false"
32515
+ + " or ArtistID eq '15' and IsActiveEntity eq false"
32516
+ + " or ArtistID eq '16' and IsActiveEntity eq false"
32517
+ + " or ArtistID eq '2' and IsActiveEntity eq false"
32518
+ + " or ArtistID eq '3' and IsActiveEntity eq false"
32519
+ + "&$top=9"
32520
+ }, {
32521
+ value : [{
32522
+ ArtistID : "1",
32523
+ IsActiveEntity : false,
32524
+ _ : {
32525
+ DescendantCount : "6",
32526
+ DistanceFromRoot : "n/a", // parent's DistanceFromRoot is not yet relevant
32527
+ DrillState : "expanded",
32528
+ Limited_Rank : "0"
32529
+ }
32530
+ }, {
32531
+ ArtistID : "12",
32532
+ IsActiveEntity : false,
32533
+ _ : {
32534
+ DescendantCount : "0",
32535
+ DistanceFromRoot : "1",
32536
+ DrillState : "leaf",
32537
+ Limited_Rank : "1"
32538
+ }
32539
+ }, {
32540
+ ArtistID : "2",
32541
+ IsActiveEntity : false,
32542
+ _ : {
32543
+ DescendantCount : "1",
32544
+ DistanceFromRoot : "n/a", // parent's DistanceFromRoot is not yet relevant
32545
+ DrillState : "expanded",
32546
+ Limited_Rank : "2"
32547
+ }
32548
+ }, {
32549
+ ArtistID : "14",
32550
+ IsActiveEntity : false,
32551
+ _ : {
32552
+ DescendantCount : "0",
32553
+ DistanceFromRoot : "2",
32554
+ DrillState : "leaf",
32555
+ Limited_Rank : "3"
32556
+ }
32557
+ }, {
32558
+ ArtistID : "11",
32559
+ IsActiveEntity : false,
32560
+ _ : {
32561
+ DescendantCount : "0",
32562
+ DistanceFromRoot : "1",
32563
+ DrillState : "leaf",
32564
+ Limited_Rank : "4"
32565
+ }
32566
+ }, {
32567
+ ArtistID : "13",
32568
+ IsActiveEntity : false,
32569
+ _ : {
32570
+ DescendantCount : "1",
32571
+ DistanceFromRoot : "1",
32572
+ DrillState : "expanded",
32573
+ Limited_Rank : "5"
32574
+ }
32575
+ }, {
32576
+ ArtistID : "16",
32577
+ IsActiveEntity : false,
32578
+ _ : {
32579
+ DescendantCount : "0",
32580
+ DistanceFromRoot : "2",
32581
+ DrillState : "leaf",
32582
+ Limited_Rank : "6"
32583
+ }
32584
+ }, {
32585
+ ArtistID : "3",
32586
+ IsActiveEntity : false,
32587
+ _ : {
32588
+ DescendantCount : "1",
32589
+ DistanceFromRoot : "n/a", // parent's DistanceFromRoot is not yet relevant
32590
+ DrillState : "expanded",
32591
+ Limited_Rank : "7"
32592
+ }
32593
+ }, {
32594
+ ArtistID : "15",
32595
+ IsActiveEntity : false,
32596
+ _ : {
32597
+ DescendantCount : "0",
32598
+ DistanceFromRoot : "1",
32599
+ DrillState : "leaf",
32600
+ Limited_Rank : "8"
32601
+ }
32602
+ }]
32603
+ })
32604
+ .expectRequest({
32605
+ batchNo : 15,
32606
+ url : sFriend.slice(1) + "?custom=foo&$apply=descendants($root/" + sFriend.slice(1)
32607
+ + ",OrgChart,_/NodeID,filter(ArtistID eq '1' and IsActiveEntity eq false),1)"
32608
+ + "&$select=ArtistID,IsActiveEntity,Name,_/NodeID"
32609
+ + "&$filter=ArtistID eq '11' and IsActiveEntity eq false"
32610
+ + " or ArtistID eq '12' and IsActiveEntity eq false"
32611
+ + " or ArtistID eq '13' and IsActiveEntity eq false"
32612
+ + "&$top=3"
32613
+ }, {
32614
+ value : [{
32615
+ ArtistID : "11",
32616
+ IsActiveEntity : false,
32617
+ Name : "New1*",
32618
+ _ : {
32619
+ NodeID : "11,false"
32620
+ }
32621
+ }, {
32622
+ ArtistID : "12",
32623
+ IsActiveEntity : false,
32624
+ Name : "New2*",
32625
+ _ : {
32626
+ NodeID : "12,false"
32627
+ }
32628
+ }, {
32629
+ ArtistID : "13",
32630
+ IsActiveEntity : false,
32631
+ Name : "New3*",
32632
+ _ : {
32633
+ NodeID : "13,false"
32634
+ }
32635
+ }]
32636
+ })
32637
+ .expectRequest({
32638
+ batchNo : 15,
32639
+ url : sFriend.slice(1) + "?custom=foo&$apply=descendants($root/" + sFriend.slice(1)
32640
+ + ",OrgChart,_/NodeID,filter(ArtistID eq '2' and IsActiveEntity eq false),1)"
32641
+ + "&$select=ArtistID,IsActiveEntity,Name,_/NodeID"
32642
+ + "&$filter=ArtistID eq '14' and IsActiveEntity eq false"
32643
+ + "&$top=1"
32644
+ }, {
32645
+ value : [{
32646
+ ArtistID : "14",
32647
+ IsActiveEntity : false,
32648
+ Name : "New4*",
32649
+ _ : {
32650
+ NodeID : "14,false"
32651
+ }
32652
+ }]
32653
+ })
32654
+ .expectRequest({
32655
+ batchNo : 15,
32656
+ url : sFriend.slice(1) + "?custom=foo&$apply=descendants($root/" + sFriend.slice(1)
32657
+ + ",OrgChart,_/NodeID,filter(ArtistID eq '3' and IsActiveEntity eq false),1)"
32658
+ + "&$select=ArtistID,IsActiveEntity,Name,_/NodeID"
32659
+ + "&$filter=ArtistID eq '15' and IsActiveEntity eq false"
32660
+ + "&$top=1"
32661
+ }, {
32662
+ value : [{
32663
+ ArtistID : "15",
32664
+ IsActiveEntity : false,
32665
+ Name : "New5*",
32666
+ _ : {
32667
+ NodeID : "15,false"
32668
+ }
32669
+ }]
32670
+ })
32671
+ .expectRequest({
32672
+ batchNo : 15,
32673
+ url : sFriend.slice(1) + "?custom=foo&$apply=descendants($root/" + sFriend.slice(1)
32674
+ + ",OrgChart,_/NodeID,filter(ArtistID eq '13' and IsActiveEntity eq false),1)"
32675
+ + "&$select=ArtistID,IsActiveEntity,Name,_/NodeID"
32676
+ + "&$filter=ArtistID eq '16' and IsActiveEntity eq false"
32677
+ + "&$top=1"
32678
+ }, {
32679
+ value : [{
32680
+ ArtistID : "16",
32681
+ IsActiveEntity : false,
32682
+ Name : "New6*",
32683
+ _ : {
32684
+ NodeID : "16,false"
32685
+ }
32686
+ }]
32687
+ });
32688
+
32689
+ await Promise.all([
32690
+ // code under test
32691
+ oBinding.getHeaderContext().requestSideEffects([""]),
32692
+ this.waitForChanges(assert, "(3) side-effects refresh")
32693
+ ]);
32694
+
32695
+ checkTable("after (3)", assert, oTable, [
32696
+ sFriend + "(ArtistID='1',IsActiveEntity=false)",
32697
+ sFriend + "(ArtistID='13',IsActiveEntity=false)",
32698
+ sFriend + "(ArtistID='16',IsActiveEntity=false)",
32699
+ sFriend + "(ArtistID='12',IsActiveEntity=false)",
32700
+ sFriend + "(ArtistID='11',IsActiveEntity=false)",
32701
+ sFriend + "(ArtistID='2',IsActiveEntity=false)",
32702
+ sFriend + "(ArtistID='14',IsActiveEntity=false)",
32703
+ sFriend + "(ArtistID='15',IsActiveEntity=false)"
32704
+ ], [
32705
+ [true, 1, "1", "Alpha*"],
32706
+ [true, 2, "13", "New3*"],
32707
+ [undefined, 3, "16", "New6*"]
32708
+ ], 10);
32709
+ assert.strictEqual(oBinding.getCurrentContexts()[1], oNew3);
32710
+ assert.strictEqual(oBinding.getCurrentContexts()[2], oNew6);
32711
+
32712
+ this.expectRequest(baseUrl(sExpandLevels)
32713
+ + "&$select=ArtistID,IsActiveEntity,Name,_/DescendantCount,_/DistanceFromRoot"
32714
+ + ",_/DrillState,_/NodeID"
32715
+ + "&$skip=7&$top=1", {
32716
+ value : [{
32717
+ ArtistID : "3",
32718
+ IsActiveEntity : false,
32719
+ Name : "Gamma*",
32720
+ _ : {
32721
+ DescendantCount : "1",
32722
+ DistanceFromRoot : "0",
32723
+ DrillState : "expanded",
32724
+ NodeID : "3,false"
32725
+ }
32726
+ }]
32727
+ })
32728
+ .expectRequest(
32729
+ baseUrl(sExpandLevels)
32730
+ + "&$select=ArtistID,IsActiveEntity,Name,_/DescendantCount,_/DistanceFromRoot"
32731
+ + ",_/DrillState,_/NodeID"
32732
+ + "&$skip=9&$top=1", {
32733
+ value : [{
32734
+ ArtistID : "4",
32735
+ IsActiveEntity : false,
32736
+ Name : "Delta*",
32737
+ _ : {
32738
+ DescendantCount : "0",
32739
+ DistanceFromRoot : "0",
32740
+ DrillState : "leaf",
32741
+ NodeID : "4,false"
32742
+ }
32743
+ }]
32744
+ });
32745
+
32746
+ await this.checkAllContexts("(4) check all contexts", assert, oBinding,
32747
+ ["@$ui5.node.isExpanded", "@$ui5.node.level", "ArtistID", "Name"], [
32748
+ [true, 1, "1", "Alpha*"],
32749
+ [true, 2, "13", "New3*"],
32750
+ [undefined, 3, "16", "New6*"],
32751
+ [undefined, 2, "12", "New2*"],
32752
+ [undefined, 2, "11", "New1*"],
32753
+ [true, 2, "2", "Beta*"],
32754
+ [undefined, 3, "14", "New4*"],
32755
+ [true, 1, "3", "Gamma*"],
32756
+ [undefined, 2, "15", "New5*"],
32757
+ [undefined, 1, "4", "Delta*"]
32758
+ ]);
32759
+
32760
+ this.expectRequest(sCountUrl, 10)
32761
+ .expectRequest(baseUrl()
32762
+ + "&$select=ArtistID,IsActiveEntity,Name,_/DrillState,_/NodeID"
32763
+ + "&$count=true&$skip=0&$top=3", {
32764
+ "@odata.count" : "3",
32765
+ value : [{
32766
+ ArtistID : "1",
32767
+ IsActiveEntity : false,
32768
+ Name : "Alpha**",
32769
+ _ : {
32770
+ DrillState : "collapsed",
32771
+ NodeID : "1,false"
32772
+ }
32773
+ }, {
32774
+ ArtistID : "3",
32775
+ IsActiveEntity : false,
32776
+ Name : "Gamma**",
32777
+ _ : {
32778
+ DrillState : "collapsed",
32779
+ NodeID : "3,false"
32780
+ }
32781
+ }, {
32782
+ ArtistID : "4",
32783
+ IsActiveEntity : false,
32784
+ Name : "Delta**",
32785
+ _ : {
32786
+ DrillState : "leaf",
32787
+ NodeID : "4,false"
32788
+ }
32789
+ }]
32790
+ });
32791
+
32792
+ oBinding.refresh();
32793
+
32794
+ await this.waitForChanges(assert, "(5) refresh the binding");
32795
+
32796
+ checkTable("after (5)", assert, oTable, [
32797
+ sFriend + "(ArtistID='1',IsActiveEntity=false)",
32798
+ sFriend + "(ArtistID='3',IsActiveEntity=false)",
32799
+ sFriend + "(ArtistID='4',IsActiveEntity=false)"
32800
+ ], [
32801
+ [false, 1, "1", "Alpha**"],
32802
+ [false, 1, "3", "Gamma**"],
32803
+ [undefined, 1, "4", "Delta**"]
32804
+ ]);
32805
+ });
32806
+
32807
+ //*********************************************************************************************
32808
+ // Scenario: A hierarchy has two visible rows, expandTo 2, and first visible row 2.
32809
+ // (1) Collapse Gamma
32810
+ // (2) Create two root nodes Zeta and Eta which the server puts at the end
32811
+ // (3) Side-effects refresh (-> unified cache; after having read the in-place data, the created
32812
+ // nodes are moved to the front and the in-place range is shifted)
32813
+ // (4) Check all contexts
32814
+ // JIRA: CPOUI5ODATAV4-2454
32815
+ QUnit.test("Recursive Hierarchy: out of place, root nodes", async function (assert) {
32816
+ const oModel = this.createTeaBusiModel({autoExpandSelect : true});
32817
+ const sCountUrl = "EMPLOYEES/$count?$filter=AGE gt 20&custom=foo&$search=covfefe";
32818
+ const sFilterSearchPrefix = "ancestors($root/EMPLOYEES,OrgChart,ID,filter(AGE gt 20)"
32819
+ + "/search(covfefe),keep start)/";
32820
+ const sUrl = "EMPLOYEES"
32821
+ + "?custom=foo&$apply=" + sFilterSearchPrefix + "orderby(ENTRYDATE)"
32822
+ + "/com.sap.vocabularies.Hierarchy.v1.TopLevels(HierarchyNodes=$root/EMPLOYEES"
32823
+ + ",HierarchyQualifier='OrgChart',NodeProperty='ID',Levels=2)";
32824
+ const sUrlWithExpandLevels = sUrl.slice(0, -1)
32825
+ + ",ExpandLevels=" + JSON.stringify([{NodeID : "3", Levels : 0}]) + ")";
32826
+ const sView = `
32827
+ <t:Table id="table" firstVisibleRow="2" rows="{path : '/EMPLOYEES',
32828
+ parameters : {
32829
+ $$aggregation : {
32830
+ expandTo : 2,
32831
+ hierarchyQualifier : 'OrgChart',
32832
+ search : 'covfefe'
32833
+ },
32834
+ $count : true,
32835
+ $filter : 'AGE gt 20',
32836
+ $orderby : 'ENTRYDATE',
32837
+ custom : 'foo'
32838
+ }}" threshold="0" visibleRowCount="2">
32839
+ <Text text="{= %{@$ui5.node.isExpanded} }"/>
32840
+ <Text text="{= %{@$ui5.node.level} }"/>
32841
+ <Text text="{Name}"/>
32842
+ </t:Table>`;
32843
+
32844
+ // 1 Alpha
32845
+ // 2 Beta
32846
+ // 3 Gamma (first visible row)
32847
+ // 4 Delta
32848
+ // 5 Epsilon (w/o this, the first visible row would be decreased)
32849
+ // 6 Zeta (created)
32850
+ // 7 Eta (created)
32851
+ this.expectRequest(sCountUrl, 5)
32852
+ .expectRequest(sUrl + "&$select=DescendantCount,DistanceFromRoot,DrillState,ID,Name"
32853
+ + "&$count=true&$skip=2&$top=2", {
32854
+ "@odata.count" : "5",
32855
+ value : [{
32856
+ DescendantCount : "1",
32857
+ DistanceFromRoot : "0",
32858
+ DrillState : "expanded",
32859
+ ID : "3",
32860
+ Name : "Gamma"
32861
+ }, {
32862
+ DescendantCount : "0",
32863
+ DistanceFromRoot : "1",
32864
+ DrillState : "leaf",
32865
+ ID : "4",
32866
+ Name : "Delta"
32867
+ }]
32868
+ });
32869
+
32870
+ await this.createView(assert, sView, oModel);
32871
+
32872
+ const oTable = this.oView.byId("table");
32873
+ const oBinding = oTable.getBinding("rows");
32874
+ const oGamma = oTable.getRows()[0].getBindingContext();
32875
+ checkTable("initial page", assert, oTable, [
32876
+ "/EMPLOYEES('3')",
32877
+ "/EMPLOYEES('4')"
32878
+ ], [
32879
+ [true, 1, "Gamma"],
32880
+ [undefined, 2, "Delta"]
32881
+ ], 5);
32882
+
32883
+ this.expectRequest(sUrl
32884
+ + "&$select=DescendantCount,DistanceFromRoot,DrillState,ID,Name&$skip=4&$top=1", {
32885
+ value : [{
32886
+ DescendantCount : "0",
32887
+ DistanceFromRoot : "0",
32888
+ DrillState : "leaf",
32889
+ ID : "5",
32890
+ Name : "Epsilon"
32891
+ }]
32892
+ });
32893
+
32894
+ oGamma.collapse();
32895
+
32896
+ await this.waitForChanges(assert, "(1) collapse Gamma");
32897
+
32898
+ checkTable("after (1)", assert, oTable, [
32899
+ "/EMPLOYEES('3')",
32900
+ "/EMPLOYEES('5')"
32901
+ ], [
32902
+ [false, 1, "Gamma"],
32903
+ [undefined, 1, "Epsilon"]
32904
+ ], 4);
32905
+
32906
+ this.expectRequest(
32907
+ {method : "POST", url : "EMPLOYEES?custom=foo", payload : {Name : "Zeta"}},
32908
+ {ID : "6", Name : "Zeta"})
32909
+ // Beta becomes visible, but oFirstLevel reads more due to the transient element Zeta
32910
+ .expectRequest(sUrl
32911
+ + "&$select=DescendantCount,DistanceFromRoot,DrillState,ID,Name&$skip=0&$top=2", {
32912
+ value : [{
32913
+ DescendantCount : "0",
32914
+ DistanceFromRoot : "0",
32915
+ DrillState : "leaf",
32916
+ ID : "1",
32917
+ Name : "Alpha"
32918
+ }, {
32919
+ DescendantCount : "0",
32920
+ DistanceFromRoot : "0",
32921
+ DrillState : "leaf",
32922
+ ID : "2",
32923
+ Name : "Beta"
32924
+ }]
32925
+ })
32926
+ .expectRequest(sUrl.replace("custom=foo&", "")
32927
+ + "&$filter=ID eq '6'&$select=LimitedRank",
32928
+ {value : [{LimitedRank : "5"}]});
32929
+
32930
+ const oZeta = oBinding.create({Name : "Zeta"}, /*bSkipRefresh*/true);
32931
+
32932
+ await Promise.all([
32933
+ oZeta.created(), // must not interleave two creates
32934
+ this.waitForChanges(assert, "(2a) create Zeta")
32935
+ ]);
32936
+
32937
+ this.expectRequest(
32938
+ {method : "POST", url : "EMPLOYEES?custom=foo", payload : {Name : "Eta"}},
32939
+ {ID : "7", Name : "Eta"})
32940
+ .expectRequest(sUrl.replace("custom=foo&", "")
32941
+ + "&$filter=ID eq '7'&$select=LimitedRank",
32942
+ {value : [{LimitedRank : "6"}]});
32943
+
32944
+ const oEta = oBinding.create({Name : "Eta"}, /*bSkipRefresh*/true);
32945
+
32946
+ await Promise.all([
32947
+ oEta.created(),
32948
+ this.waitForChanges(assert, "(2b) create Eta")
32949
+ ]);
32950
+
32951
+ checkTable("after (2)", assert, oTable, [
32952
+ "/EMPLOYEES('7')",
32953
+ "/EMPLOYEES('6')",
32954
+ "/EMPLOYEES('1')",
32955
+ "/EMPLOYEES('2')",
32956
+ "/EMPLOYEES('3')",
32957
+ "/EMPLOYEES('5')"
32958
+ ], [
32959
+ [undefined, 1, "Alpha"],
32960
+ [undefined, 1, "Beta"]
32961
+ ]);
32962
+
32963
+ this.expectRequest(sCountUrl, 7)
32964
+ .expectRequest({
32965
+ batchNo : 7,
32966
+ url : sUrlWithExpandLevels
32967
+ + "&$select=DescendantCount,DistanceFromRoot,DrillState,ID,Name"
32968
+ + "&$count=true&$skip=0&$top=4"
32969
+ }, {
32970
+ "@odata.count" : "6",
32971
+ value : [{
32972
+ DescendantCount : "0",
32973
+ DistanceFromRoot : "0",
32974
+ DrillState : "leaf",
32975
+ ID : "1",
32976
+ Name : "Alpha*"
32977
+ }, {
32978
+ DescendantCount : "0",
32979
+ DistanceFromRoot : "0",
32980
+ DrillState : "leaf",
32981
+ ID : "2",
32982
+ Name : "Beta*"
32983
+ }, {
32984
+ DescendantCount : "0",
32985
+ DistanceFromRoot : "0",
32986
+ DrillState : "collapsed",
32987
+ ID : "3",
32988
+ Name : "Gamma*"
32989
+ }, {
32990
+ DescendantCount : "0",
32991
+ DistanceFromRoot : "0",
32992
+ DrillState : "leaf",
32993
+ ID : "5",
32994
+ Name : "Epsilon*"
32995
+ }]
32996
+ })
32997
+ .expectRequest({
32998
+ batchNo : 7,
32999
+ url : sUrlWithExpandLevels
33000
+ + "&$select=DescendantCount,DistanceFromRoot,DrillState,ID,LimitedRank"
33001
+ + "&$filter=ID eq '6' or ID eq '7'&$top=2"
33002
+ }, {
33003
+ value : [{
33004
+ DescendantCount : "0",
33005
+ DistanceFromRoot : "0",
33006
+ DrillState : "leaf",
33007
+ ID : "6",
33008
+ LimitedRank : "4"
33009
+ }, {
33010
+ DescendantCount : "0",
33011
+ DistanceFromRoot : "0",
33012
+ DrillState : "leaf",
33013
+ ID : "7",
33014
+ LimitedRank : "5"
33015
+ }]
33016
+ })
33017
+ .expectRequest({
33018
+ batchNo : 7,
33019
+ url : "EMPLOYEES?custom=foo&$apply=com.sap.vocabularies.Hierarchy.v1.TopLevels"
33020
+ + "(HierarchyNodes=$root/EMPLOYEES,HierarchyQualifier='OrgChart'"
33021
+ + ",NodeProperty='ID',Levels=1)"
33022
+ + "&$select=ID,Name"
33023
+ + "&$filter=ID eq '6' or ID eq '7'&$top=2"
33024
+ }, {
33025
+ value : [
33026
+ {ID : "6", Name : "Zeta*"},
33027
+ {ID : "7", Name : "Eta*"}
33028
+ ]
33029
+ });
33030
+
33031
+ await Promise.all([
33032
+ oBinding.getHeaderContext().requestSideEffects([""]),
33033
+ this.waitForChanges(assert, "(3) side-effects refresh")
33034
+ ]);
33035
+
33036
+ checkTable("after (3)", assert, oTable, [
33037
+ "/EMPLOYEES('7')",
33038
+ "/EMPLOYEES('6')",
33039
+ "/EMPLOYEES('1')",
33040
+ "/EMPLOYEES('2')",
33041
+ "/EMPLOYEES('3')",
33042
+ "/EMPLOYEES('5')"
33043
+ ], [
33044
+ [undefined, 1, "Alpha*"],
33045
+ [undefined, 1, "Beta*"]
33046
+ ]);
33047
+
33048
+ await this.checkAllContexts("(4) check all contexts", assert, oBinding,
33049
+ ["@$ui5.node.isExpanded", "@$ui5.node.level", "Name"], [
33050
+ [undefined, 1, "Eta*"],
33051
+ [undefined, 1, "Zeta*"],
33052
+ [undefined, 1, "Alpha*"],
33053
+ [undefined, 1, "Beta*"],
33054
+ [false, 1, "Gamma*"],
33055
+ [undefined, 1, "Epsilon*"]
33056
+ ]);
33057
+ });
33058
+
32175
33059
  //*********************************************************************************************
32176
33060
  // Scenario: Expand all levels of a recursive hierarchy and move a node with descendants (not
32177
33061
  // yet fully loaded) to another parent. Although it is shown as the new parent's first child on
@@ -33080,6 +33964,426 @@ make root = ${bMakeRoot}`;
33080
33964
  ], 6);
33081
33965
  });
33082
33966
 
33967
+ //*********************************************************************************************
33968
+ // Scenario: Show the top pyramid of a recursive hierarchy, expanded to level 2. First visible
33969
+ // row starts at 2 (Gamma). Scroll to "Zeta". Determine the parent node of "Delta" and "Eta"
33970
+ // with #requestParent. A side effect for a structural property does not lead to trouble, same
33971
+ // for a side-effects refresh.
33972
+ // JIRA: CPOUI5ODATAV4-2467
33973
+ QUnit.test("Recursive Hierarchy: #requestParent for non-adjacent children",
33974
+ async function (assert) {
33975
+ const oModel = this.createTeaBusiModel({autoExpandSelect : true});
33976
+ const sUrl = "EMPLOYEES?$apply=com.sap.vocabularies.Hierarchy.v1.TopLevels("
33977
+ + "HierarchyNodes=$root/EMPLOYEES,HierarchyQualifier='OrgChart'"
33978
+ + ",NodeProperty='ID',Levels=2)";
33979
+ const sView = `
33980
+ <t:Table id="table" rows="{path : '/EMPLOYEES',
33981
+ parameters : {
33982
+ $$aggregation : {expandTo : 2, hierarchyQualifier : 'OrgChart'}
33983
+ }}" firstVisibleRow="2" threshold="0" visibleRowCount="2">
33984
+ <Text text="{= %{@$ui5.node.isExpanded} }"/>
33985
+ <Text text="{= %{@$ui5.node.level} }"/>
33986
+ <Text id="id" text="{ID}"/>
33987
+ <Text text="{Name}"/>
33988
+ </t:Table>`;
33989
+
33990
+ // 0 Alpha // not loaded
33991
+ // 1 Beta // not loaded
33992
+ // 2 Gamma
33993
+ // 3 Delta
33994
+ // 4 Epsilon // not loaded
33995
+ // 5 Zeta
33996
+ // 6 Eta
33997
+ this.expectRequest(sUrl + "&$select=DescendantCount,DistanceFromRoot,DrillState,ID,Name"
33998
+ + "&$count=true&$skip=2&$top=2", {
33999
+ "@odata.count" : "7",
34000
+ value : [{
34001
+ DescendantCount : 0,
34002
+ DistanceFromRoot : 1,
34003
+ DrillState : "leaf",
34004
+ ID : "2",
34005
+ Name : "Gamma"
34006
+ }, {
34007
+ DescendantCount : 0,
34008
+ DistanceFromRoot : 1,
34009
+ DrillState : "leaf",
34010
+ ID : "3",
34011
+ Name : "Delta"
34012
+ }]
34013
+ })
34014
+ .expectChange("id", [,, "2", "3"]);
34015
+
34016
+ await this.createView(assert, sView, oModel);
34017
+
34018
+ const oTable = this.oView.byId("table");
34019
+ checkTable("initial page", assert, oTable, [
34020
+ "/EMPLOYEES('2')",
34021
+ "/EMPLOYEES('3')"
34022
+ ], [
34023
+ [undefined, 2, "2", "Gamma"],
34024
+ [undefined, 2, "3", "Delta"]
34025
+ ], 7);
34026
+ const oDelta = oTable.getRows()[1].getBindingContext();
34027
+
34028
+ this.expectRequest(sUrl + "&$select=DescendantCount,DistanceFromRoot,DrillState,ID,Name"
34029
+ + "&$skip=5&$top=2", {
34030
+ value : [{
34031
+ DescendantCount : 0,
34032
+ DistanceFromRoot : 1,
34033
+ DrillState : "leaf",
34034
+ ID : "5",
34035
+ Name : "Zeta"
34036
+ }, {
34037
+ DescendantCount : 0,
34038
+ DistanceFromRoot : 1,
34039
+ DrillState : "leaf",
34040
+ ID : "6",
34041
+ Name : "Eta"
34042
+ }]
34043
+ })
34044
+ .expectChange("id", [,,,,, "5", "6"]);
34045
+
34046
+ oTable.setFirstVisibleRow(5);
34047
+
34048
+ await this.waitForChanges(assert, "scroll to 5 (Zeta)");
34049
+
34050
+ checkTable("after scroll to 5 (Zeta)", assert, oTable, [
34051
+ "/EMPLOYEES('2')",
34052
+ "/EMPLOYEES('3')",
34053
+ "/EMPLOYEES('5')",
34054
+ "/EMPLOYEES('6')"
34055
+ ], [
34056
+ [undefined, 2, "5", "Zeta"],
34057
+ [undefined, 2, "6", "Eta"]
34058
+ ], 7);
34059
+ const oZeta = oTable.getRows()[0].getBindingContext();
34060
+ const oEta = oTable.getRows()[1].getBindingContext();
34061
+
34062
+ this.expectRequest({
34063
+ batchNo : 3,
34064
+ url : "EMPLOYEES?$apply=ancestors($root/EMPLOYEES,OrgChart,ID,filter(ID eq '2'),1)"
34065
+ + "&$select=ID,Name"
34066
+ }, {
34067
+ value : [{
34068
+ ID : "0",
34069
+ Name : "Alpha"
34070
+ }]
34071
+ })
34072
+ .expectRequest({
34073
+ batchNo : 3,
34074
+ url : "EMPLOYEES?$apply=ancestors($root/EMPLOYEES,OrgChart,ID,filter(ID eq '5'),1)"
34075
+ + "&$select=ID,Name"
34076
+ }, {
34077
+ value : [{
34078
+ ID : "0",
34079
+ Name : "Alpha"
34080
+ }]
34081
+ })
34082
+ .expectRequest({
34083
+ batchNo : 4,
34084
+ url : sUrl + "&$filter=ID eq '0'"
34085
+ + "&$select=DescendantCount,DistanceFromRoot,DrillState,LimitedRank"
34086
+ }, {
34087
+ value : [{
34088
+ DescendantCount : "6",
34089
+ DistanceFromRoot : "0",
34090
+ DrillState : "expanded",
34091
+ LimitedRank : "0"
34092
+ }]
34093
+ });
34094
+
34095
+ // code under test
34096
+ const [oAlpha, oAlpha0] = await Promise.all([
34097
+ oDelta.requestParent(),
34098
+ oEta.requestParent(),
34099
+ this.waitForChanges(assert, "request parent of 3 (Delta) and 6 (Eta)")
34100
+ ]);
34101
+
34102
+ assert.strictEqual(oAlpha, oAlpha0, "same context");
34103
+ assert.strictEqual(oAlpha.getPath(), "/EMPLOYEES('0')");
34104
+ assert.strictEqual(oAlpha.iIndex, 0);
34105
+ assert.deepEqual(oAlpha.getObject(), {
34106
+ "@$ui5.node.isExpanded" : true,
34107
+ "@$ui5.node.level" : 1,
34108
+ ID : "0",
34109
+ Name : "Alpha"
34110
+ });
34111
+
34112
+ assert.strictEqual(oZeta.getParent(), oAlpha);
34113
+ assert.strictEqual(oEta.getParent(), oAlpha);
34114
+ assert.strictEqual(oDelta.getParent(), oAlpha);
34115
+
34116
+ this.expectRequest("EMPLOYEES?$select=ID,Name&$filter=ID eq '5' or ID eq '6'&$top=2", {
34117
+ value : [{
34118
+ DrillState : "leaf",
34119
+ ID : "5",
34120
+ Name : "Zeta"
34121
+ }, {
34122
+ DrillState : "leaf",
34123
+ ID : "6",
34124
+ Name : "Eta"
34125
+ }]
34126
+ });
34127
+
34128
+ await Promise.all([
34129
+ oEta.getBinding().getHeaderContext().requestSideEffects(["Name"]),
34130
+ this.waitForChanges(assert, "request side effects for name")
34131
+ ]);
34132
+
34133
+ checkTable("after requestSideEffects", assert, oTable, [
34134
+ "/EMPLOYEES('5')",
34135
+ "/EMPLOYEES('6')"
34136
+ ], [
34137
+ [undefined, 2, "5", "Zeta"],
34138
+ [undefined, 2, "6", "Eta"]
34139
+ ], 7);
34140
+
34141
+ // code under test
34142
+ assert.strictEqual(oEta.getParent(), undefined);
34143
+
34144
+ this.expectRequest(sUrl + "&$select=DescendantCount,DistanceFromRoot,DrillState,ID,Name"
34145
+ + "&$skip=0&$top=1", {
34146
+ value : [{
34147
+ DescendantCount : "6",
34148
+ DistanceFromRoot : "0",
34149
+ DrillState : "expanded",
34150
+ ID : "0",
34151
+ Name : "Alpha"
34152
+ }]
34153
+ });
34154
+
34155
+ // code under test
34156
+ const [oResult] = await Promise.all([
34157
+ oEta.requestParent(),
34158
+ this.waitForChanges(assert, "request parent of 6 (Eta)")
34159
+ ]);
34160
+
34161
+ assert.notStrictEqual(oResult, oAlpha, "Alpha was destroyed by side effect");
34162
+ assert.strictEqual(oResult.getPath(), "/EMPLOYEES('0')");
34163
+ assert.strictEqual(oResult.iIndex, 0);
34164
+
34165
+ this.expectRequest(sUrl + "&$select=DescendantCount,DistanceFromRoot,DrillState,ID,Name"
34166
+ + "&$count=true&$skip=5&$top=2", {
34167
+ "@odata.count" : "7",
34168
+ value : [{
34169
+ DescendantCount : 0,
34170
+ DistanceFromRoot : 1,
34171
+ DrillState : "leaf",
34172
+ ID : "5",
34173
+ Name : "Zeta"
34174
+ }, {
34175
+ DescendantCount : 0,
34176
+ DistanceFromRoot : 1,
34177
+ DrillState : "leaf",
34178
+ ID : "6",
34179
+ Name : "Eta"
34180
+ }]
34181
+ });
34182
+
34183
+ await Promise.all([
34184
+ oEta.getBinding().getHeaderContext().requestSideEffects([""]),
34185
+ this.waitForChanges(assert, "request side effects refresh")
34186
+ ]);
34187
+
34188
+ this.expectRequest({
34189
+ url : "EMPLOYEES?$apply=ancestors($root/EMPLOYEES,OrgChart,ID,filter(ID eq '5'),1)"
34190
+ + "&$select=ID,Name"
34191
+ }, {
34192
+ value : [{
34193
+ ID : "1",
34194
+ Name : "Beta"
34195
+ }]
34196
+ })
34197
+ .expectRequest({
34198
+ url : sUrl + "&$filter=ID eq '1'"
34199
+ + "&$select=DescendantCount,DistanceFromRoot,DrillState,LimitedRank"
34200
+ }, {
34201
+ value : [{
34202
+ DescendantCount : "0",
34203
+ DistanceFromRoot : "1",
34204
+ DrillState : "leaf",
34205
+ LimitedRank : "1"
34206
+ }]
34207
+ });
34208
+
34209
+ // code under test
34210
+ const [oBeta] = await Promise.all([
34211
+ oEta.requestParent(),
34212
+ this.waitForChanges(assert, "request parent of 6 (Eta)")
34213
+ ]);
34214
+
34215
+ assert.strictEqual(oBeta.getPath(), "/EMPLOYEES('1')");
34216
+ assert.strictEqual(oBeta.iIndex, 1);
34217
+ assert.deepEqual(oBeta.getObject(), {
34218
+ "@$ui5.node.level" : 2,
34219
+ ID : "1",
34220
+ Name : "Beta"
34221
+ });
34222
+ });
34223
+
34224
+ //*********************************************************************************************
34225
+ // Scenario: Show the top pyramid of a recursive hierarchy, expanded to level 2. First visible
34226
+ // row starts at 2 (Gamma). Request "Beta" as a keep alive context. Scroll to "Zeta". Determine
34227
+ // the parent node of "Delta" and "Eta" in an interleaved fashion and see that it is "Beta".
34228
+ // JIRA: CPOUI5ODATAV4-2467
34229
+ QUnit.test("Recursive Hierarchy: #requestParent interleaved", async function (assert) {
34230
+ const oModel = this.createTeaBusiModel({autoExpandSelect : true});
34231
+ const sUrl = "EMPLOYEES?$apply=com.sap.vocabularies.Hierarchy.v1.TopLevels("
34232
+ + "HierarchyNodes=$root/EMPLOYEES,HierarchyQualifier='OrgChart'"
34233
+ + ",NodeProperty='ID',Levels=2)";
34234
+ const sView = `
34235
+ <t:Table id="table" rows="{path : '/EMPLOYEES',
34236
+ parameters : {
34237
+ $$aggregation : {expandTo : 2, hierarchyQualifier : 'OrgChart'}
34238
+ }}" firstVisibleRow="2" threshold="0" visibleRowCount="2">
34239
+ <Text text="{= %{@$ui5.node.isExpanded} }"/>
34240
+ <Text text="{= %{@$ui5.node.level} }"/>
34241
+ <Text id="id" text="{ID}"/>
34242
+ <Text text="{Name}"/>
34243
+ </t:Table>`;
34244
+
34245
+ // 0 Alpha // not loaded
34246
+ // 1 Beta // not loaded
34247
+ // 2 Gamma
34248
+ // 3 Delta
34249
+ // 4 Epsilon // not loaded
34250
+ // 5 Zeta
34251
+ // 6 Eta
34252
+ this.expectRequest(sUrl + "&$select=DescendantCount,DistanceFromRoot,DrillState,ID,Name"
34253
+ + "&$count=true&$skip=2&$top=2", {
34254
+ "@odata.count" : "7",
34255
+ value : [{
34256
+ DescendantCount : 0,
34257
+ DistanceFromRoot : 1,
34258
+ DrillState : "leaf",
34259
+ ID : "2",
34260
+ Name : "Gamma"
34261
+ }, {
34262
+ DescendantCount : 0,
34263
+ DistanceFromRoot : 1,
34264
+ DrillState : "leaf",
34265
+ ID : "3",
34266
+ Name : "Delta"
34267
+ }]
34268
+ })
34269
+ .expectChange("id", [,, "2", "3"]);
34270
+
34271
+ await this.createView(assert, sView, oModel);
34272
+
34273
+ const oTable = this.oView.byId("table");
34274
+ checkTable("initial page", assert, oTable, [
34275
+ "/EMPLOYEES('2')",
34276
+ "/EMPLOYEES('3')"
34277
+ ], [
34278
+ [undefined, 2, "2", "Gamma"],
34279
+ [undefined, 2, "3", "Delta"]
34280
+ ], 7);
34281
+ const oDelta = oTable.getRows()[1].getBindingContext();
34282
+
34283
+ this.expectRequest("EMPLOYEES('1')?$select=ID", {ID : "1"});
34284
+
34285
+ const oBeta = oDelta.getBinding().getKeepAliveContext("/EMPLOYEES('1')");
34286
+
34287
+ await this.waitForChanges(assert, "keep alive 1 (Beta)");
34288
+
34289
+ this.expectRequest(sUrl + "&$select=DescendantCount,DistanceFromRoot,DrillState,ID,Name"
34290
+ + "&$skip=5&$top=2", {
34291
+ value : [{
34292
+ DescendantCount : 0,
34293
+ DistanceFromRoot : 1,
34294
+ DrillState : "leaf",
34295
+ ID : "5",
34296
+ Name : "Zeta"
34297
+ }, {
34298
+ DescendantCount : 0,
34299
+ DistanceFromRoot : 1,
34300
+ DrillState : "leaf",
34301
+ ID : "6",
34302
+ Name : "Eta"
34303
+ }]
34304
+ })
34305
+ .expectChange("id", [,,,,, "5", "6"]);
34306
+
34307
+ oTable.setFirstVisibleRow(5);
34308
+
34309
+ await this.waitForChanges(assert, "scroll to 5 (Zeta)");
34310
+
34311
+ checkTable("after scroll to 5 (Zeta)", assert, oTable, [
34312
+ "/EMPLOYEES('2')",
34313
+ "/EMPLOYEES('3')",
34314
+ "/EMPLOYEES('5')",
34315
+ "/EMPLOYEES('6')",
34316
+ "/EMPLOYEES('1')"
34317
+ ], [
34318
+ [undefined, 2, "5", "Zeta"],
34319
+ [undefined, 2, "6", "Eta"]
34320
+ ], 7);
34321
+ const oEta = oTable.getRows()[1].getBindingContext();
34322
+ assert.strictEqual(oBeta.iIndex, undefined, "still unknown");
34323
+
34324
+ let fnResolve;
34325
+ this.expectRequest({
34326
+ url : "EMPLOYEES?$apply=ancestors($root/EMPLOYEES,OrgChart,ID,filter(ID eq '2'),1)"
34327
+ + "&$select=ID,Name"
34328
+ }, new Promise(function (resolve) {
34329
+ fnResolve = resolve.bind(null, {
34330
+ value : [{
34331
+ ID : "1",
34332
+ Name : "Beta"
34333
+ }]
34334
+ });
34335
+ }));
34336
+
34337
+ // code under test
34338
+ const oBetaPromise = oDelta.requestParent();
34339
+
34340
+ await this.waitForChanges(assert, "request parent of 3 (Delta)");
34341
+
34342
+ this.expectRequest({
34343
+ url : "EMPLOYEES?$apply=ancestors($root/EMPLOYEES,OrgChart,ID,filter(ID eq '5'),1)"
34344
+ + "&$select=ID,Name"
34345
+ }, {
34346
+ value : [{
34347
+ ID : "1",
34348
+ Name : "Beta"
34349
+ }]
34350
+ })
34351
+ .expectRequest({
34352
+ url : sUrl + "&$filter=ID eq '1'"
34353
+ + "&$select=DescendantCount,DistanceFromRoot,DrillState,LimitedRank"
34354
+ }, {
34355
+ value : [{
34356
+ DescendantCount : "5",
34357
+ DistanceFromRoot : "0",
34358
+ DrillState : "expanded",
34359
+ LimitedRank : "1"
34360
+ }]
34361
+ });
34362
+
34363
+ const [oBeta0] = await Promise.all([
34364
+ // code under test
34365
+ oEta.requestParent(),
34366
+ this.waitForChanges(assert, "request parent of 6 (Eta)")
34367
+ ]);
34368
+
34369
+ assert.strictEqual(oBeta0, oBeta, "keep alive context reused");
34370
+ assert.strictEqual(oBeta.getPath(), "/EMPLOYEES('1')");
34371
+ assert.strictEqual(oBeta.iIndex, 1);
34372
+ assert.deepEqual(oBeta.getObject(), {
34373
+ "@$ui5.node.isExpanded" : true,
34374
+ "@$ui5.node.level" : 1,
34375
+ ID : "1",
34376
+ Name : "Beta"
34377
+ });
34378
+
34379
+ fnResolve();
34380
+
34381
+ assert.strictEqual(await oBetaPromise, oBeta, "same context");
34382
+
34383
+ assert.strictEqual(oDelta.getParent(), oBeta);
34384
+ assert.strictEqual(oEta.getParent(), oBeta);
34385
+ });
34386
+
33083
34387
  //*********************************************************************************************
33084
34388
  // Scenario: Show the top pyramid of a recursive hierarchy, expanded to level 3. Create a new
33085
34389
  // child ("Iota") inserted below "Beta"; create a new child node ("Rho") inserted below "Alpha"
@@ -33091,6 +34395,9 @@ make root = ${bMakeRoot}`;
33091
34395
  // node ("Omicron") where the parent ("Xi") is not yet loaded and request this parent.
33092
34396
  // Scroll to "Xi" and see that it is inserted on the right position.
33093
34397
  // JIRA: CPOUI5ODATAV4-2378
34398
+ //
34399
+ // Second #requestParent on the same node returns the same context (JIRA: CPOUI5ODATAV4-2467).
34400
+ // #requestParent on adjacent children returns the same context (JIRA: CPOUI5ODATAV4-2467).
33094
34401
  QUnit.test("Recursive Hierarchy: getParent/requestParent with expandTo > 1",
33095
34402
  async function (assert) {
33096
34403
  const sUrl = "Artists?$apply=com.sap.vocabularies.Hierarchy.v1.TopLevels("
@@ -33468,9 +34775,11 @@ make root = ${bMakeRoot}`;
33468
34775
  [undefined, 3, "4.2", "Pi"]
33469
34776
  ], 15);
33470
34777
  const oOmicron = oTable.getRows()[0].getBindingContext();
34778
+ const oPi = oTable.getRows()[1].getBindingContext();
33471
34779
 
33472
34780
  // code under test
33473
34781
  assert.strictEqual(oOmicron.getParent(), undefined);
34782
+ assert.strictEqual(oPi.getParent(), undefined);
33474
34783
 
33475
34784
  this.expectRequest({
33476
34785
  batchNo : 11,
@@ -33503,8 +34812,17 @@ make root = ${bMakeRoot}`;
33503
34812
  });
33504
34813
 
33505
34814
  // code under test
33506
- const oXi = await oOmicron.requestParent();
34815
+ const [oXi, oXi0, oXi1] = await Promise.all([
34816
+ oPi.requestParent(),
34817
+ oOmicron.requestParent(),
34818
+ oOmicron.requestParent(),
34819
+ this.waitForChanges(assert, "request parent of 4.1 (Omicron) and 4.2 (Pi)")
34820
+ ]);
33507
34821
 
34822
+ assert.strictEqual(oXi0, oXi,
34823
+ "CPOUI5ODATAV4-2467: request parent of 4.2 (Pi) returns the same context");
34824
+ assert.strictEqual(oXi0, oXi1,
34825
+ "CPOUI5ODATAV4-2467: second request returns the same context");
33508
34826
  assert.strictEqual(oXi.getIndex(), 12);
33509
34827
  assert.strictEqual(oXi.getPath(), "/Artists(ArtistID='4',IsActiveEntity=false)");
33510
34828
  assert.deepEqual(oXi.getObject(), {
@@ -33978,7 +35296,7 @@ make root = ${bMakeRoot}`;
33978
35296
  + ",NodeProperty='ID',Levels=1)&$select=DrillState,ID"
33979
35297
  : "$count=true&$select=ID";
33980
35298
  const sView = `
33981
- <t:Table id="table" rows="{path : '/EMPLOYEES', parameters : ${sParameters}}"
35299
+ <t:Table firstVisibleRow="30" id="table" rows="{path : '/EMPLOYEES', parameters : ${sParameters}}"
33982
35300
  threshold="5" visibleRowCount="3">
33983
35301
  <Text id="id" text="{ID}"/>
33984
35302
  </t:Table>`;
@@ -34032,12 +35350,12 @@ make root = ${bMakeRoot}`;
34032
35350
  }
34033
35351
  };
34034
35352
 
34035
- expect(0, 0, 8); // 3 visible, 5 after
35353
+ expect(30, 25, 13); // 5 before, 3 visible, 5 after
34036
35354
 
34037
35355
  await this.createView(assert, sView, oModel);
34038
35356
 
34039
35357
  oTable = this.oView.byId("table");
34040
- await scroll(30, 25, 13); // 5 before, 3 visible, 5 after
35358
+
34041
35359
  // forward
34042
35360
  await scroll(31);
34043
35361
  await scroll(32);
@@ -38895,6 +40213,8 @@ make root = ${bMakeRoot}`;
38895
40213
  // Scenario: Modify a property within a list binding with $$patchWithoutSideEffects, then modify
38896
40214
  // in a context binding that inherits the parameter
38897
40215
  // CPOUI5UISERVICESV3-1684
40216
+ //
40217
+ // Refresh of a relative context binding w/ $$ownRequest (JIRA: CPOUI5ODATAV4-2500)
38898
40218
  QUnit.test("$$patchWithoutSideEffects in list binding and inherited", function (assert) {
38899
40219
  var oModel = this.createSalesOrdersModel({autoExpandSelect : true}),
38900
40220
  oTable,
@@ -38957,6 +40277,19 @@ make root = ${bMakeRoot}`;
38957
40277
  that.oView.byId("formNote").getBinding("value").setValue("Note (entered)");
38958
40278
 
38959
40279
  return that.waitForChanges(assert);
40280
+ }).then(function () {
40281
+ that.expectRequest("SalesOrderList('42')?$select=Note,SalesOrderID", {
40282
+ "@odata.etag" : "ETag2",
40283
+ Note : "Note (refreshed)",
40284
+ SalesOrderID : "42"
40285
+ })
40286
+ .expectChange("formNote", "Note (refreshed)");
40287
+
40288
+ return Promise.all([
40289
+ // code under test
40290
+ that.oView.byId("form").getObjectBinding().requestRefresh(),
40291
+ that.waitForChanges(assert)
40292
+ ]);
38960
40293
  });
38961
40294
  });
38962
40295
 
@@ -39286,6 +40619,82 @@ make root = ${bMakeRoot}`;
39286
40619
  });
39287
40620
  });
39288
40621
 
40622
+ //*********************************************************************************************
40623
+ // Scenario: Modifying a property of a kept-alive element in a list with
40624
+ // $$patchWithoutSideEffects, triggers a side-effects refresh. The PATCH request does change the
40625
+ // ETag of the kept-alive element. The list refresh request does only add unknown properties
40626
+ // to the kept-alive element, but does not take over changed properties. The refresh for the
40627
+ // kept-alive element must do this.
40628
+ // SNOW: DINC0072978
40629
+ QUnit.test("requestSideEffects with modified keep alive element", async function (assert) {
40630
+ const oModel = this.createTeaBusiModel({autoExpandSelect : true});
40631
+ const sView = `
40632
+ <Table id="table" items="{path : '/TEAMS', parameters : {$$patchWithoutSideEffects : true}}">
40633
+ <Input id="name" value="{Name}"/>
40634
+ <Text id="budget" text="{Budget}"/>
40635
+ </Table>`;
40636
+
40637
+ this.expectRequest("TEAMS?$select=Budget,Name,Team_Id&$skip=0&$top=100", {
40638
+ value : [{
40639
+ "@odata.etag" : "etag1.0",
40640
+ Team_Id : "TEAM_01",
40641
+ Name : "Team 01",
40642
+ Budget : "0"
40643
+ }]
40644
+ })
40645
+ .expectChange("name", ["Team 01"])
40646
+ .expectChange("budget", ["0"]);
40647
+
40648
+ await this.createView(assert, sView, oModel);
40649
+
40650
+ const oBinding = this.oView.byId("table").getBinding("items");
40651
+ const oKeptContext = oBinding.getCurrentContexts()[0];
40652
+ oKeptContext.setKeepAlive(true);
40653
+
40654
+ this.expectChange("name", ["New Team"])
40655
+ .expectRequest({
40656
+ batchNo : 2,
40657
+ headers : {
40658
+ "If-Match" : "etag1.0",
40659
+ Prefer : "return=minimal"
40660
+ },
40661
+ method : "PATCH",
40662
+ url : "TEAMS('TEAM_01')",
40663
+ payload : {Name : "New Team"}
40664
+ }, null, {ETag : "etag1.1"}) // no response required
40665
+ .expectRequest({
40666
+ batchNo : 2,
40667
+ url : "TEAMS?$select=Budget,Name,Team_Id&$filter=Team_Id eq 'TEAM_01'"
40668
+ }, {
40669
+ value : [{
40670
+ "@odata.etag" : "etag1.1",
40671
+ Budget : "42",
40672
+ Name : "New Team",
40673
+ Team_Id : "TEAM_01"
40674
+ }]
40675
+ })
40676
+ .expectRequest({
40677
+ batchNo : 2,
40678
+ url : "TEAMS?$select=Budget,Name,Team_Id&$skip=0&$top=100"
40679
+ }, {
40680
+ value : [{
40681
+ "@odata.etag" : "etag1.1",
40682
+ Budget : "n/a",
40683
+ Name : "n/a",
40684
+ Team_Id : "TEAM_01"
40685
+ }]
40686
+ })
40687
+ .expectChange("budget", ["42"]); // "side effect"
40688
+
40689
+ const aTableRows = this.oView.byId("table").getItems();
40690
+ aTableRows[0].getCells()[0].getBinding("value").setValue("New Team");
40691
+
40692
+ return Promise.all([
40693
+ oBinding.getHeaderContext().requestSideEffects([""]),
40694
+ this.waitForChanges(assert)
40695
+ ]);
40696
+ });
40697
+
39289
40698
  //*********************************************************************************************
39290
40699
  // Scenario: read side effects which affect dependent bindings; add some unnecessary context
39291
40700
  // bindings
@@ -41982,6 +43391,9 @@ make root = ${bMakeRoot}`;
41982
43391
  // No own test as unit value list is cached in a private cache
41983
43392
  // JIRA: CPOUI5MODELS-302
41984
43393
  // Transport sap-language (BCP: 2270119565)
43394
+ // Show that the amount scale is used instead of the unit decimal places. Change the type of the
43395
+ // binding part for the amount to see that this is also considered in the output format.
43396
+ // JIRA: CPOUI5MODELS-1606
41985
43397
  QUnit.test("OData Unit type considering unit customizing", function (assert) {
41986
43398
  var oControl,
41987
43399
  oModel = this.createModel(sSalesOrderService + "?sap-client=123", {
@@ -42038,9 +43450,9 @@ make root = ${bMakeRoot}`;
42038
43450
  }]
42039
43451
  })
42040
43452
  .expectChange("weightMeasure", "12.340") // Scale=3 in property metadata => 3 decimals
42041
- .expectChange("weight", "12.34000 KG")
42042
- .expectChange("weight0", "12.34000")
42043
- .expectChange("weight1", "12.34000");
43453
+ .expectChange("weight", "12.340 KG")
43454
+ .expectChange("weight0", "12.340")
43455
+ .expectChange("weight1", "12.340");
42044
43456
 
42045
43457
  return this.createView(assert, sView, oModel).then(function () {
42046
43458
  that.expectMessages([{
@@ -42075,9 +43487,11 @@ make root = ${bMakeRoot}`;
42075
43487
  // remove model messages again
42076
43488
  oModel.reportStateMessages("ProductList", {});
42077
43489
  }).then(function () {
42078
- that.expectChange("weight", "23.40000 KG")
42079
- .expectChange("weight0", "23.40000")
42080
- .expectChange("weight1", "23.40000")
43490
+ oControl = that.oView.byId("weight");
43491
+
43492
+ that.expectChange("weight", "23.400 KG")
43493
+ .expectChange("weight0", "23.400")
43494
+ .expectChange("weight1", "23.400")
42081
43495
  .expectChange("weightMeasure", "23.400")
42082
43496
  .expectRequest({
42083
43497
  method : "PATCH",
@@ -42086,13 +43500,42 @@ make root = ${bMakeRoot}`;
42086
43500
  payload : {WeightMeasure : "23.4", WeightUnit : "KG"}
42087
43501
  });
42088
43502
 
42089
- that.oView.byId("weight").getBinding("value").setRawValue(["23.4", "KG"]);
43503
+ oControl.getBinding("value").setRawValue(["23.4", "KG"]);
42090
43504
 
42091
43505
  return that.waitForChanges(assert);
43506
+ }).then(function () {
43507
+ // this change happens twice because PropertyBinding#setType fires change via
43508
+ // fnTypeChangedCallback and v4.ODataPropertyBinding#setType itself fires changes also.
43509
+ // This is ok because the usecase for changing a binding part's type of a composite
43510
+ // binding is very rare.
43511
+ that.expectChange("weight", "23.40 KG")
43512
+ .expectChange("weight", "23.40 KG");
43513
+
43514
+ // code under test: change scale of amount part from 3 to 2
43515
+ oControl.getBinding("value").getBindings()[0].setType(
43516
+ new Decimal(undefined, {precision : 13, scale : 2}));
43517
+
43518
+ return that.waitForChanges(assert, "JIRA: CPOUI5MODELS-1606");
43519
+ }).then(function () {
43520
+ that.expectChange("weight", "34.51 KG")
43521
+ .expectChange("weightMeasure", "34.510")
43522
+ .expectChange("weight0", "34.510")
43523
+ .expectChange("weight1", "34.510")
43524
+ .expectRequest({
43525
+ method : "PATCH",
43526
+ url : "ProductList('HT-1000')?sap-client=123",
43527
+ headers : {"If-Match" : "ETag"},
43528
+ payload : {WeightMeasure : "34.51", WeightUnit : "KG"}
43529
+ });
43530
+
43531
+ // code under test: for amount change the event for "weight" happens only once
43532
+ oControl.getBinding("value").setRawValue(["34.51", "KG"]);
43533
+
43534
+ return that.waitForChanges(assert, "JIRA: CPOUI5MODELS-1606");
42092
43535
  }).then(function () {
42093
43536
  that.expectChange("weightMeasure", "0.000")
42094
- .expectChange("weight0", "0.00000")
42095
- .expectChange("weight1", "0.00000")
43537
+ .expectChange("weight0", "0.000")
43538
+ .expectChange("weight1", "0.000")
42096
43539
  .expectRequest({
42097
43540
  method : "PATCH",
42098
43541
  url : "ProductList('HT-1000')?sap-client=123",
@@ -42100,7 +43543,6 @@ make root = ${bMakeRoot}`;
42100
43543
  payload : {WeightMeasure : "0", WeightUnit : "KG"}
42101
43544
  });
42102
43545
 
42103
- oControl = that.oView.byId("weight");
42104
43546
  // remove the formatter so that we can call setValue at the control
42105
43547
  oControl.getBinding("value").setFormatter(null);
42106
43548
 
@@ -42110,7 +43552,7 @@ make root = ${bMakeRoot}`;
42110
43552
  return that.waitForChanges(assert);
42111
43553
  }).then(function () {
42112
43554
  // Check that the previous setValue led to the correct result
42113
- assert.strictEqual(oControl.getValue(), "0.00000 KG");
43555
+ assert.strictEqual(oControl.getValue(), "0.00 KG");
42114
43556
 
42115
43557
  that.expectMessages([{
42116
43558
  message : "EnterNumberFraction 5",
@@ -47728,6 +49170,8 @@ make root = ${bMakeRoot}`;
47728
49170
 
47729
49171
  return this.createView(assert, sView, oModel).then(function () {
47730
49172
  that.expectRequest({
49173
+ batchNo : 2,
49174
+ changeSetNo : 1,
47731
49175
  headers : {
47732
49176
  Prefer : "handling=strict"
47733
49177
  },
@@ -47738,6 +49182,8 @@ make root = ${bMakeRoot}`;
47738
49182
  "Preference-Applied" : "handling=strict"
47739
49183
  })
47740
49184
  .expectRequest({
49185
+ batchNo : 2,
49186
+ changeSetNo : 1,
47741
49187
  headers : {
47742
49188
  Prefer : "handling=strict"
47743
49189
  },
@@ -47746,6 +49192,8 @@ make root = ${bMakeRoot}`;
47746
49192
  payload : {}
47747
49193
  }/*response does not matter*/)
47748
49194
  .expectRequest({
49195
+ batchNo : 2,
49196
+ changeSetNo : 1,
47749
49197
  headers : {
47750
49198
  Prefer : "handling=strict"
47751
49199
  },
@@ -47769,6 +49217,8 @@ make root = ${bMakeRoot}`;
47769
49217
  }).then(function () {
47770
49218
  if (bConfirm) {
47771
49219
  that.expectRequest({
49220
+ batchNo : 3,
49221
+ changeSetNo : 1,
47772
49222
  method : "POST",
47773
49223
  url : "SalesOrderList('0')/" + sAction,
47774
49224
  payload : {}
@@ -47777,6 +49227,8 @@ make root = ${bMakeRoot}`;
47777
49227
  SalesOrderID : "0"
47778
49228
  })
47779
49229
  .expectRequest({
49230
+ batchNo : 3,
49231
+ changeSetNo : 1,
47780
49232
  method : "POST",
47781
49233
  url : "SalesOrderList('1')/" + sAction,
47782
49234
  payload : {}
@@ -47785,6 +49237,8 @@ make root = ${bMakeRoot}`;
47785
49237
  SalesOrderID : "1"
47786
49238
  })
47787
49239
  .expectRequest({
49240
+ batchNo : 3,
49241
+ changeSetNo : 1,
47788
49242
  method : "POST",
47789
49243
  url : "SalesOrderList('2')/" + sAction,
47790
49244
  payload : {}
@@ -49253,7 +50707,7 @@ make root = ${bMakeRoot}`;
49253
50707
  assert.strictEqual(normalizeUID(oContext2.toString()),
49254
50708
  "/SalesOrderList('42')/SO_2_SOITEM($uid=...)[-9007199254740991;deleted]",
49255
50709
  "Context#toString: deleted");
49256
- assert.notOk(oContext2.isSelected(), "JIRA: CPOUI5ODATAV4-2053");
50710
+ checkSelected(assert, oContext2, undefined, "JIRA: CPOUI5ODATAV4-2053");
49257
50711
 
49258
50712
  return Promise.all([
49259
50713
  checkCanceled(assert, oContext2.created()),
@@ -49267,6 +50721,10 @@ make root = ${bMakeRoot}`;
49267
50721
  "/SalesOrderList('42')/SO_2_SOITEM($uid=...)[-9007199254740991;destroyed]",
49268
50722
  "Context#toString: destroyed");
49269
50723
  assert.notOk(oContext2.isSelected(), "JIRA: CPOUI5ODATAV4-1943");
50724
+ assert.throws(() => {
50725
+ oContext2.getProperty("@$ui5.context.isSelected");
50726
+ // TypeError("Cannot read properties of undefined (reading 'checkSuspended')")
50727
+ }, "Binding already gone (JIRA: CPOUI5ODATAV4-1944)");
49270
50728
 
49271
50729
  that.expectChange("count", "3")
49272
50730
  .expectChange("note", [,, "Note 3"])
@@ -50910,11 +52368,14 @@ make root = ${bMakeRoot}`;
50910
52368
  // Refresh a kept-alive context that is not part of the collection (B1). After refresh this
50911
52369
  // context is not in the collection and has new data (A1).
50912
52370
  // JIRA: CPOUI5ODATAV4-366
52371
+ //
52372
+ // Selection and data binding for selection (JIRA: CPOUI5ODATAV4-1943, CPOUI5ODATAV4-1944).
50913
52373
  QUnit.test("CPOUI5ODATAV4-366: Context#refresh on a context that is not in the collection"
50914
52374
  + "; after refresh that context is not in the collection", function (assert) {
50915
- var that = this;
52375
+ var oKeptContext,
52376
+ that = this;
50916
52377
 
50917
- return this.createKeepAliveScenario(assert, true).then(function (oKeptContext) {
52378
+ return this.createKeepAliveScenario(assert, true).then(function (oKeptContext0) {
50918
52379
  that.expectRequest("SalesOrderList?$filter=SalesOrderID eq '1'"
50919
52380
  + "&$select=GrossAmount,Note,SalesOrderID", {
50920
52381
  value : [{GrossAmount : "199", Note : "After refresh", SalesOrderID : "1"}]
@@ -50926,10 +52387,18 @@ make root = ${bMakeRoot}`;
50926
52387
  value : [/*does not matter*/]
50927
52388
  });
50928
52389
 
52390
+ oKeptContext = oKeptContext0;
52391
+
52392
+ // code under test
52393
+ oKeptContext.setSelected(true);
52394
+
50929
52395
  // code under test
50930
52396
  oKeptContext.refresh(undefined, true);
50931
52397
 
50932
52398
  return that.waitForChanges(assert, "(3)");
52399
+ }).then(function () {
52400
+ // code under test
52401
+ checkSelected(assert, oKeptContext, true);
50933
52402
  });
50934
52403
  });
50935
52404
 
@@ -51485,9 +52954,11 @@ make root = ${bMakeRoot}`;
51485
52954
  // requested.
51486
52955
  //
51487
52956
  // Do likewise for selection which implicitly keeps alive (JIRA: CPOUI5ODATAV4-2053).
52957
+ // Select via setSelected and setting the client-side annotation (JIRA: CPOUI5ODATAV4-1944).
51488
52958
  [false, true].forEach(function (bImplicitly) {
51489
- var sTitle = "CPOUI5ODATAV4-488: Refresh w/" + (bImplicitly ? " implicitly" : "")
51490
- + " kept-alive context";
52959
+ [false, true].forEach(function (bUseAnnotation) {
52960
+ var sTitle = "CPOUI5ODATAV4-488: Refresh w/" + (bImplicitly ? " implicitly" : "")
52961
+ + " kept-alive context, selection via annotation= " + bUseAnnotation;
51491
52962
 
51492
52963
  QUnit.test(sTitle, function (assert) {
51493
52964
  var oKeptContext,
@@ -51505,9 +52976,11 @@ make root = ${bMakeRoot}`;
51505
52976
  // 2nd kept-alive context (CPOUI5ODATAV4-579)
51506
52977
  oKeptContext2 = oTable.getItems()[0].getBindingContext();
51507
52978
  if (bImplicitly) {
51508
- oKeptContext.setSelected(true);
52979
+ setSelected(bUseAnnotation, oKeptContext, true);
51509
52980
  oKeptContext.setKeepAlive(false);
51510
- oKeptContext2.setSelected(true);
52981
+ setSelected(bUseAnnotation, oKeptContext2, true);
52982
+ checkSelected(assert, oKeptContext, true);
52983
+ checkSelected(assert, oKeptContext2, true);
51511
52984
  } else {
51512
52985
  oKeptContext2.setKeepAlive(true);
51513
52986
  }
@@ -51564,7 +53037,8 @@ make root = ${bMakeRoot}`;
51564
53037
  var oKeptContext3 = oTable.getItems()[1].getBindingContext();
51565
53038
 
51566
53039
  if (bImplicitly) {
51567
- oKeptContext3.setSelected(true);
53040
+ setSelected(bUseAnnotation, oKeptContext3, true);
53041
+ checkSelected(assert, oKeptContext3, true);
51568
53042
  } else {
51569
53043
  // 3rd kept-alive ontext (CPOUI5ODATAV4-579)
51570
53044
  oKeptContext3.setKeepAlive(true, fnOnBeforeDestroy);
@@ -51663,7 +53137,10 @@ make root = ${bMakeRoot}`;
51663
53137
 
51664
53138
  that.oView.byId("objectPage").setBindingContext(null);
51665
53139
  oKeptContext.setKeepAlive(false);
51666
- oKeptContext.setSelected(false);
53140
+ setSelected(bUseAnnotation, oKeptContext, false);
53141
+ // in case of !bImplicitly and !bUseAnnotation oKeptContext was never selected.
53142
+ // the annotation stays undefined if it is set (repeatedly) to false then.
53143
+ checkSelected(assert, oKeptContext, bImplicitly || bUseAnnotation ? false : undefined);
51667
53144
 
51668
53145
  return Promise.all([
51669
53146
  // code under test
@@ -51699,6 +53176,7 @@ make root = ${bMakeRoot}`;
51699
53176
  assert.strictEqual(oKeptContext2.getProperty("GrossAmount"), "149.5");
51700
53177
  });
51701
53178
  });
53179
+ });
51702
53180
  });
51703
53181
 
51704
53182
  //*********************************************************************************************
@@ -53423,6 +54901,8 @@ make root = ${bMakeRoot}`;
53423
54901
  // code under test (& clean up)
53424
54902
  oModel.resetChanges("doNotSubmit");
53425
54903
  assert.notOk(oCreationRowContext.isSelected(), "already destroyed");
54904
+ // binding is already destroyed
54905
+ // assert.notOk(oCreationRowContext.getProperty("@$ui5.context.isSelected"));
53426
54906
  assert.strictEqual(oCreationRowContext.created(), undefined, "already destroyed");
53427
54907
 
53428
54908
  return Promise.all([
@@ -55059,6 +56539,7 @@ make root = ${bMakeRoot}`;
55059
56539
  // JIRA: CPOUI5ODATAV4-1409
55060
56540
  //
55061
56541
  // Add refresh (JIRA: CPOUI5ODATAV4-1382) and side-effects refresh (JIRA: CPOUI5ODATAV4-1384)
56542
+ // and a refresh of a relative binding w/ $$ownRequest (JIRA: CPOUI5ODATAV4-2500)
55062
56543
  //
55063
56544
  // Show that a created persisted can stay kept-alive during refresh (JIRA: CPOUI5ODATAV4-1386)
55064
56545
  [
@@ -55180,14 +56661,6 @@ make root = ${bMakeRoot}`;
55180
56661
  break;
55181
56662
 
55182
56663
  case "refresh":
55183
- if (bRelative) {
55184
- assert.throws(function () {
55185
- // code under test
55186
- oBinding.refresh();
55187
- }, new Error("Refresh on this binding is not supported"));
55188
- }
55189
-
55190
- // Note: expect no request for "objectPage" as there's no ODPrB there!
55191
56664
  that.expectRequest(sTeams + "?$select=Name,Team_Id&$filter=Team_Id eq 'TEAM_A'",
55192
56665
  oResultA)
55193
56666
  // Note: GET not yet processed, binding still "empty"
@@ -55195,10 +56668,7 @@ make root = ${bMakeRoot}`;
55195
56668
  .expectRequest(sTeams + "?$select=Name,Team_Id&$skip=0&$top=2", oResult);
55196
56669
 
55197
56670
  // code under test
55198
- oPromise = (bRelative
55199
- ? that.oView.byId("objectPage").getObjectBinding()
55200
- : oBinding
55201
- ).requestRefresh();
56671
+ oPromise = oBinding.requestRefresh();
55202
56672
  break;
55203
56673
 
55204
56674
  case "resume":
@@ -55298,6 +56768,8 @@ make root = ${bMakeRoot}`;
55298
56768
  // context outside the collection. Refresh a single selected context inside the collection with
55299
56769
  // removal from the collection, but still implicitly kept alive.
55300
56770
  // JIRA: CPOUI5ODATAV4-2053
56771
+ //
56772
+ // Data binding for selection (JIRA: CPOUI5ODATAV4-1944).
55301
56773
  [
55302
56774
  "changeParameters", "filter", "refresh", "resume", "sideEffectsRefresh", "sort"
55303
56775
  ].forEach(function (sMethod) {
@@ -55307,6 +56779,7 @@ make root = ${bMakeRoot}`;
55307
56779
  oContext_01,
55308
56780
  oContext_03,
55309
56781
  oExpectedNewObject = {
56782
+ "@$ui5.context.isSelected" : true,
55310
56783
  "@$ui5.context.isTransient" : false,
55311
56784
  MEMBER_COUNT : 0,
55312
56785
  Team_Id : "NEW"
@@ -55468,13 +56941,14 @@ make root = ${bMakeRoot}`;
55468
56941
  assert.strictEqual(aAllContexts[0], oContext_03, "still the same");
55469
56942
  assert.strictEqual(aAllContexts[1], oContext_01, "implicitly kept alive");
55470
56943
  assert.strictEqual(aAllContexts[2], oCreatedContext, "implicitly kept alive");
55471
- assert.ok(oContext_01.isSelected());
56944
+ checkSelected(assert, oContext_01, true);
55472
56945
  assert.deepEqual(oContext_01.getObject(), {
56946
+ "@$ui5.context.isSelected" : true,
55473
56947
  MEMBER_COUNT : 9,
55474
56948
  Name : "Team #1",
55475
56949
  Team_Id : "TEAM_01"
55476
56950
  });
55477
- assert.ok(oCreatedContext.isSelected());
56951
+ checkSelected(assert, oCreatedContext, true);
55478
56952
  assert.deepEqual(oCreatedContext.getObject(), oExpectedNewObject);
55479
56953
 
55480
56954
  that.expectChange("name", "pending");
@@ -55518,16 +56992,18 @@ make root = ${bMakeRoot}`;
55518
56992
  assert.strictEqual(aAllContexts[0], oCreatedContext);
55519
56993
  assert.strictEqual(aAllContexts[1], oContext_01);
55520
56994
  assert.strictEqual(aAllContexts[2], oContext_03);
55521
- assert.ok(oCreatedContext.isSelected());
56995
+ checkSelected(assert, oCreatedContext, true);
55522
56996
  assert.deepEqual(oCreatedContext.getObject(), oExpectedNewObject);
55523
- assert.ok(oContext_01.isSelected());
56997
+ checkSelected(assert, oContext_01, true);
55524
56998
  assert.deepEqual(oContext_01.getObject(), {
56999
+ "@$ui5.context.isSelected" : true,
55525
57000
  MEMBER_COUNT : 9,
55526
57001
  Name : "pending",
55527
57002
  Team_Id : "TEAM_01"
55528
57003
  });
55529
- assert.ok(oContext_03.isSelected());
57004
+ checkSelected(assert, oContext_03, true);
55530
57005
  assert.deepEqual(oContext_03.getObject(), {
57006
+ "@$ui5.context.isSelected" : true,
55531
57007
  MEMBER_COUNT : 11,
55532
57008
  Team_Id : "TEAM_03"
55533
57009
  });
@@ -55625,7 +57101,7 @@ make root = ${bMakeRoot}`;
55625
57101
  assert.strictEqual(aAllContexts.length, 2);
55626
57102
  assert.strictEqual(aAllContexts[0], oContext_01);
55627
57103
  assert.strictEqual(aAllContexts[1], oCreatedContext, "implicitly kept alive");
55628
- assert.ok(oCreatedContext.isSelected());
57104
+ checkSelected(assert, oCreatedContext, true);
55629
57105
  assert.strictEqual(oCreatedContext.isTransient(), false, "created");
55630
57106
  delete oExpectedNewObject["@$ui5.context.isTransient"]; //TODO bug?!
55631
57107
  assert.deepEqual(oCreatedContext.getObject(), oExpectedNewObject);
@@ -55702,6 +57178,8 @@ make root = ${bMakeRoot}`;
55702
57178
  }).then(function () {
55703
57179
  if (bCancelCreation) { // creation already canceled
55704
57180
  assert.notOk(oCreatedContext.isSelected(), "destroyed");
57181
+ // binding is already destroyed
57182
+ // assert.notOk(oCreatedContext.getProperty("@$ui5.context.isSelected"));
55705
57183
  assert.strictEqual(oCreatedContext.getModel(), undefined, "destroyed");
55706
57184
 
55707
57185
  return;
@@ -55744,6 +57222,8 @@ make root = ${bMakeRoot}`;
55744
57222
  return that.waitForChanges(assert, "ODLB#destroyPreviousContextsLater");
55745
57223
  }).then(function () {
55746
57224
  assert.notOk(oCreatedContext.isSelected(), "destroyed");
57225
+ // binding is already destroyed
57226
+ // assert.notOk(oCreatedContext.getProperty("@$ui5.context.isSelected"));
55747
57227
  assert.strictEqual(oCreatedContext.getModel(), undefined, "destroyed");
55748
57228
  });
55749
57229
  });
@@ -55753,8 +57233,12 @@ make root = ${bMakeRoot}`;
55753
57233
  // Scenario: Create a new context, save and select it. Have it drop out of the collection via a
55754
57234
  // refresh of the single context or the whole binding. See that it is not destroyed.
55755
57235
  // JIRA: CPOUI5ODATAV4-2053
57236
+ //
57237
+ // Data binding for selection (JIRA: CPOUI5ODATAV4-1944).
55756
57238
  [false, true].forEach(function (bSingle) {
55757
- var sTitle = "CPOUI5ODATAV4-2053: removeCreated, w/o UI on top; bSingle=" + bSingle;
57239
+ [false, true].forEach(function (bUseAnnotation) {
57240
+ var sTitle = "CPOUI5ODATAV4-2053: removeCreated, w/o UI on top; bSingle=" + bSingle
57241
+ + ", selection via annotation=" + bUseAnnotation;
55758
57242
 
55759
57243
  QUnit.test(sTitle, function (assert) {
55760
57244
  var oBinding,
@@ -55781,13 +57265,23 @@ make root = ${bMakeRoot}`;
55781
57265
  oCreatedContext = oBinding.create({MEMBER_COUNT : 0, Team_Id : "NEW"}, true);
55782
57266
 
55783
57267
  // code under test
55784
- oCreatedContext.setSelected(true);
57268
+ setSelected(bUseAnnotation, oCreatedContext, true);
57269
+
57270
+ assert.ok(oCreatedContext.isSelected());
55785
57271
 
55786
57272
  return Promise.all([
55787
57273
  oCreatedContext.created(),
55788
57274
  that.waitForChanges(assert, "create")
55789
57275
  ]);
55790
57276
  }).then(function () {
57277
+ assert.deepEqual(oCreatedContext.getObject(), {
57278
+ "@$ui5.context.isSelected" : true,
57279
+ "@$ui5.context.isTransient" : false,
57280
+ MEMBER_COUNT : 1,
57281
+ Team_Id : "NEW"
57282
+ });
57283
+ checkSelected(assert, oCreatedContext, true);
57284
+
55791
57285
  that.expectRequest("TEAMS?$filter=Team_Id eq 'NEW'", {
55792
57286
  value : [{MEMBER_COUNT : 2, Team_Id : "NEW"}]
55793
57287
  });
@@ -55811,19 +57305,22 @@ make root = ${bMakeRoot}`;
55811
57305
 
55812
57306
  assert.strictEqual(aAllContexts.length, 1);
55813
57307
  assert.strictEqual(aAllContexts[0], oCreatedContext, "implicitly kept alive");
55814
- assert.ok(oCreatedContext.isSelected());
57308
+ checkSelected(assert, oCreatedContext, true);
55815
57309
  assert.strictEqual(oCreatedContext.isTransient(), false, "created");
55816
57310
  assert.deepEqual(oCreatedContext.getObject(), bSingle ? {
55817
57311
  //TODO "@$ui5.context.isTransient" : false,
57312
+ "@$ui5.context.isSelected" : true,
55818
57313
  MEMBER_COUNT : 2,
55819
57314
  Team_Id : "NEW"
55820
57315
  } : {
57316
+ "@$ui5.context.isSelected" : true,
55821
57317
  "@$ui5.context.isTransient" : false,
55822
57318
  MEMBER_COUNT : 2,
55823
57319
  Team_Id : "NEW"
55824
57320
  });
55825
57321
  });
55826
57322
  });
57323
+ });
55827
57324
  });
55828
57325
 
55829
57326
  //*********************************************************************************************
@@ -60914,13 +62411,15 @@ make root = ${bMakeRoot}`;
60914
62411
  method : "POST",
60915
62412
  payload : {},
60916
62413
  url : "SalesOrderList('1')/" + sAction
60917
- }).expectRequest({
62414
+ })
62415
+ .expectRequest({
60918
62416
  method : "POST",
60919
62417
  batchNo : 3,
60920
62418
  groupId : "$single",
60921
62419
  payload : {},
60922
62420
  url : "SalesOrderList('2')/" + sAction
60923
- }).expectRequest({
62421
+ })
62422
+ .expectRequest({
60924
62423
  batchNo : -4,
60925
62424
  method : "POST",
60926
62425
  payload : {},
@@ -61003,6 +62502,116 @@ make root = ${bMakeRoot}`;
61003
62502
  ]);
61004
62503
  });
61005
62504
 
62505
+ //*********************************************************************************************
62506
+ // Scenario: Set a context to selected using a property binding to the client-side annotation
62507
+ // "@$ui5.context.isSelected".
62508
+ // JIRA: CPOUI5ODATAV4-1944
62509
+ //
62510
+ // Select a header context via all three possible ways: setSelected and write to the annotation
62511
+ // via context or property binding. Swap the context of the "selectAll" property binding and
62512
+ // check if change listeners are correctly removed.
62513
+ // JIRA: CPOUI5ODATAV4-2493
62514
+ QUnit.test("Selection on header context and row context", async function (assert) {
62515
+ const oModel = this.createSalesOrdersModel({autoExpandSelect : true});
62516
+ const sView = `
62517
+ <Input id="selectAll" value="{path: '@$ui5.context.isSelected', targetType: 'any'}"/>
62518
+ <Table id="table" items="{/SalesOrderList}">
62519
+ <Text id="id" text="{SalesOrderID}"/>
62520
+ <Input id="selected" value="{path : '@$ui5.context.isSelected', targetType: 'any'}"/>
62521
+ </Table>`;
62522
+
62523
+ this.expectRequest("SalesOrderList?$select=SalesOrderID&$skip=0&$top=100", {
62524
+ value : [
62525
+ {SalesOrderID : "1"}
62526
+ ]
62527
+ })
62528
+ .expectChange("selectAll")
62529
+ .expectChange("id", ["1"])
62530
+ .expectChange("selected", [undefined]);
62531
+
62532
+ await this.createView(assert, sView, oModel);
62533
+
62534
+ const oPropertyBinding = this.oView.byId("table").getItems()[0].getCells()[1]
62535
+ .getBinding("value");
62536
+ const oContext = oPropertyBinding.getContext();
62537
+
62538
+ this.expectChange("selected", [true]);
62539
+
62540
+ // code under test
62541
+ oPropertyBinding.setValue(true);
62542
+
62543
+ checkSelected(assert, oContext, true);
62544
+ await this.waitForChanges(assert);
62545
+
62546
+ this.expectChange("selected", [false]);
62547
+
62548
+ // code under test
62549
+ oPropertyBinding.setValue(false);
62550
+
62551
+ checkSelected(assert, oContext, false);
62552
+ await this.waitForChanges(assert);
62553
+
62554
+ const oHeaderContext = this.oView.byId("table").getBinding("items").getHeaderContext();
62555
+ const oSelectAllInput = this.oView.byId("selectAll");
62556
+ oSelectAllInput.setBindingContext(oHeaderContext);
62557
+ const oSelectAllBinding = oSelectAllInput.getBinding("value");
62558
+
62559
+ this.expectChange("selectAll", true);
62560
+
62561
+ // code under test
62562
+ oSelectAllBinding.setValue(true);
62563
+
62564
+ checkSelected(assert, oHeaderContext, true);
62565
+ await this.waitForChanges(assert);
62566
+
62567
+ this.expectChange("selectAll", false);
62568
+
62569
+ // code under test
62570
+ oSelectAllBinding.setValue(false);
62571
+
62572
+ checkSelected(assert, oHeaderContext, false);
62573
+ await this.waitForChanges(assert);
62574
+
62575
+ this.expectChange("selectAll", true);
62576
+
62577
+ // code under test
62578
+ oHeaderContext.setProperty("@$ui5.context.isSelected", true);
62579
+
62580
+ checkSelected(assert, oHeaderContext, true);
62581
+ await this.waitForChanges(assert);
62582
+
62583
+ this.expectChange("selectAll", false);
62584
+
62585
+ // code under test
62586
+ oHeaderContext.setProperty("@$ui5.context.isSelected", false);
62587
+
62588
+ checkSelected(assert, oHeaderContext, false);
62589
+ await this.waitForChanges(assert);
62590
+
62591
+ this.expectChange("selectAll", true);
62592
+
62593
+ // code under test
62594
+ oHeaderContext.setSelected(true);
62595
+
62596
+ checkSelected(assert, oHeaderContext, true);
62597
+ await this.waitForChanges(assert);
62598
+
62599
+ this.expectChange("selectAll", false);
62600
+
62601
+ // code under test
62602
+ oHeaderContext.setSelected(false);
62603
+
62604
+ checkSelected(assert, oHeaderContext, false);
62605
+ await this.waitForChanges(assert);
62606
+
62607
+ oSelectAllInput.setBindingContext(oContext);
62608
+
62609
+ // code under test - change listener is deregistered, no change expected
62610
+ oHeaderContext.setSelected(true);
62611
+
62612
+ await this.waitForChanges(assert);
62613
+ });
62614
+
61006
62615
  //*********************************************************************************************
61007
62616
  // Scenario: Dependent ContextBinding below a dependent ListBinding, below of an absolute
61008
62617
  // ListBinding, all w/ own cache. Set a row context of the absolute ListBinding as parent