@openui5/sap.ui.core 1.127.1 → 1.129.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 (285) hide show
  1. package/.eslintrc.json +3 -1
  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.storage.js +3 -3
  9. package/src/sap/base/Event.js +1 -1
  10. package/src/sap/base/Eventing.js +1 -1
  11. package/src/sap/base/config.js +1 -1
  12. package/src/sap/base/i18n/LanguageTag.js +1 -1
  13. package/src/sap/base/i18n/date/TimezoneUtils.js +1 -1
  14. package/src/sap/base/util/restricted/_CancelablePromise.js +1 -1
  15. package/src/sap/base/util/restricted/_castArray.js +1 -1
  16. package/src/sap/base/util/restricted/_compact.js +1 -1
  17. package/src/sap/base/util/restricted/_curry.js +1 -1
  18. package/src/sap/base/util/restricted/_debounce.js +1 -1
  19. package/src/sap/base/util/restricted/_difference.js +1 -1
  20. package/src/sap/base/util/restricted/_differenceBy.js +1 -1
  21. package/src/sap/base/util/restricted/_differenceWith.js +1 -1
  22. package/src/sap/base/util/restricted/_flatMap.js +1 -1
  23. package/src/sap/base/util/restricted/_flatMapDeep.js +1 -1
  24. package/src/sap/base/util/restricted/_flatMapDepth.js +1 -1
  25. package/src/sap/base/util/restricted/_flatten.js +1 -1
  26. package/src/sap/base/util/restricted/_flattenDeep.js +1 -1
  27. package/src/sap/base/util/restricted/_flattenDepth.js +1 -1
  28. package/src/sap/base/util/restricted/_intersection.js +1 -1
  29. package/src/sap/base/util/restricted/_intersectionBy.js +1 -1
  30. package/src/sap/base/util/restricted/_intersectionWith.js +1 -1
  31. package/src/sap/base/util/restricted/_isEqual.js +1 -1
  32. package/src/sap/base/util/restricted/_isEqualWith.js +1 -1
  33. package/src/sap/base/util/restricted/_isNil.js +1 -1
  34. package/src/sap/base/util/restricted/_max.js +1 -1
  35. package/src/sap/base/util/restricted/_merge.js +1 -1
  36. package/src/sap/base/util/restricted/_mergeWith.js +1 -1
  37. package/src/sap/base/util/restricted/_min.js +1 -1
  38. package/src/sap/base/util/restricted/_omit.js +1 -1
  39. package/src/sap/base/util/restricted/_pick.js +1 -1
  40. package/src/sap/base/util/restricted/_pickBy.js +1 -1
  41. package/src/sap/base/util/restricted/_throttle.js +1 -1
  42. package/src/sap/base/util/restricted/_toArray.js +1 -1
  43. package/src/sap/base/util/restricted/_union.js +1 -1
  44. package/src/sap/base/util/restricted/_unionBy.js +1 -1
  45. package/src/sap/base/util/restricted/_unionWith.js +1 -1
  46. package/src/sap/base/util/restricted/_uniq.js +1 -1
  47. package/src/sap/base/util/restricted/_uniqBy.js +1 -1
  48. package/src/sap/base/util/restricted/_uniqWith.js +1 -1
  49. package/src/sap/base/util/restricted/_without.js +1 -1
  50. package/src/sap/base/util/restricted/_xor.js +1 -1
  51. package/src/sap/base/util/restricted/_xorBy.js +1 -1
  52. package/src/sap/base/util/restricted/_xorWith.js +1 -1
  53. package/src/sap/base/util/restricted/_zipObject.js +1 -1
  54. package/src/sap/base/util/restricted/_zipObjectDeep.js +1 -1
  55. package/src/sap/ui/Device.js +3 -3
  56. package/src/sap/ui/Global.js +3 -3
  57. package/src/sap/ui/base/BindingParser.js +38 -4
  58. package/src/sap/ui/base/Event.js +1 -1
  59. package/src/sap/ui/base/EventProvider.js +1 -1
  60. package/src/sap/ui/base/Interface.js +1 -1
  61. package/src/sap/ui/base/ManagedObject.js +1 -1
  62. package/src/sap/ui/base/ManagedObjectMetadata.js +1 -1
  63. package/src/sap/ui/base/Metadata.js +1 -1
  64. package/src/sap/ui/base/Object.js +1 -1
  65. package/src/sap/ui/base/ObjectPool.js +1 -1
  66. package/src/sap/ui/core/.library +1 -1
  67. package/src/sap/ui/core/BusyIndicator.js +1 -1
  68. package/src/sap/ui/core/Component.js +28 -6
  69. package/src/sap/ui/core/ComponentContainer.js +1 -1
  70. package/src/sap/ui/core/ComponentMetadata.js +1 -1
  71. package/src/sap/ui/core/ComponentSupport.js +1 -1
  72. package/src/sap/ui/core/Configuration.js +1 -1
  73. package/src/sap/ui/core/Control.js +1 -1
  74. package/src/sap/ui/core/Core.js +28 -15
  75. package/src/sap/ui/core/CustomData.js +1 -1
  76. package/src/sap/ui/core/DeclarativeSupport.js +1 -1
  77. package/src/sap/ui/core/Element.js +1 -1
  78. package/src/sap/ui/core/ElementMetadata.js +1 -1
  79. package/src/sap/ui/core/EnabledPropagator.js +1 -1
  80. package/src/sap/ui/core/EventBus.js +1 -1
  81. package/src/sap/ui/core/Fragment.js +1 -1
  82. package/src/sap/ui/core/HTML.js +1 -1
  83. package/src/sap/ui/core/History.js +1 -1
  84. package/src/sap/ui/core/Icon.js +2 -2
  85. package/src/sap/ui/core/IndicationColorSupport.js +1 -1
  86. package/src/sap/ui/core/IntervalTrigger.js +1 -1
  87. package/src/sap/ui/core/InvisibleMessage.js +1 -1
  88. package/src/sap/ui/core/InvisibleRenderer.js +1 -1
  89. package/src/sap/ui/core/InvisibleText.js +1 -1
  90. package/src/sap/ui/core/Item.js +1 -1
  91. package/src/sap/ui/core/LabelEnablement.js +1 -1
  92. package/src/sap/ui/core/LayoutData.js +1 -1
  93. package/src/sap/ui/core/Lib.js +1 -0
  94. package/src/sap/ui/core/ListItem.js +1 -1
  95. package/src/sap/ui/core/LocalBusyIndicator.js +1 -1
  96. package/src/sap/ui/core/Locale.js +1 -1
  97. package/src/sap/ui/core/LocaleData.js +1 -1
  98. package/src/sap/ui/core/Manifest.js +1 -1
  99. package/src/sap/ui/core/Message.js +1 -1
  100. package/src/sap/ui/core/RenderManager.js +1 -1
  101. package/src/sap/ui/core/Renderer.js +1 -1
  102. package/src/sap/ui/core/ResizeHandler.js +1 -1
  103. package/src/sap/ui/core/ScrollBar.js +1 -1
  104. package/src/sap/ui/core/SeparatorItem.js +1 -1
  105. package/src/sap/ui/core/Title.js +1 -1
  106. package/src/sap/ui/core/TooltipBase.js +1 -1
  107. package/src/sap/ui/core/UIArea.js +1 -1
  108. package/src/sap/ui/core/UIComponent.js +1 -1
  109. package/src/sap/ui/core/UIComponentMetadata.js +1 -1
  110. package/src/sap/ui/core/ValueStateSupport.js +1 -1
  111. package/src/sap/ui/core/VariantLayoutData.js +1 -1
  112. package/src/sap/ui/core/XMLComposite.js +1 -1
  113. package/src/sap/ui/core/XMLCompositeMetadata.js +4 -4
  114. package/src/sap/ui/core/XMLTemplateProcessor.js +55 -33
  115. package/src/sap/ui/core/boot/FieldHelpEndpoint.js +70 -0
  116. package/src/sap/ui/core/date/UI5Date.js +1 -1
  117. package/src/sap/ui/core/delegate/ItemNavigation.js +1 -1
  118. package/src/sap/ui/core/delegate/ScrollEnablement.js +3 -2
  119. package/src/sap/ui/core/dnd/DragDropBase.js +1 -1
  120. package/src/sap/ui/core/dnd/DragDropInfo.js +1 -1
  121. package/src/sap/ui/core/dnd/DragInfo.js +1 -1
  122. package/src/sap/ui/core/dnd/DropInfo.js +1 -1
  123. package/src/sap/ui/core/fieldhelp/FieldHelp.js +3 -3
  124. package/src/sap/ui/core/format/FormatUtils.js +1 -1
  125. package/src/sap/ui/core/format/NumberFormat.js +6 -2
  126. package/src/sap/ui/core/format/TimezoneUtil.js +1 -1
  127. package/src/sap/ui/core/getCompatibilityVersion.js +1 -1
  128. package/src/sap/ui/core/hyphenation/Hyphenation.js +1 -1
  129. package/src/sap/ui/core/library.js +4 -4
  130. package/src/sap/ui/core/message/ControlMessageProcessor.js +1 -1
  131. package/src/sap/ui/core/message/Message.js +1 -1
  132. package/src/sap/ui/core/message/MessageManager.js +1 -1
  133. package/src/sap/ui/core/message/MessageParser.js +1 -1
  134. package/src/sap/ui/core/message/MessageProcessor.js +1 -1
  135. package/src/sap/ui/core/mvc/HTMLView.js +1 -1
  136. package/src/sap/ui/core/mvc/JSONView.js +1 -1
  137. package/src/sap/ui/core/mvc/JSView.js +1 -1
  138. package/src/sap/ui/core/mvc/TemplateView.js +1 -1
  139. package/src/sap/ui/core/mvc/View.js +1 -1
  140. package/src/sap/ui/core/mvc/XMLView.js +1 -1
  141. package/src/sap/ui/core/plugin/DeclarativeSupport.js +1 -1
  142. package/src/sap/ui/core/plugin/LessSupport.js +1 -1
  143. package/src/sap/ui/core/plugin/TemplatingSupport.js +1 -1
  144. package/src/sap/ui/core/postmessage/Bus.js +1 -1
  145. package/src/sap/ui/core/postmessage/confirmationDialog.js +1 -1
  146. package/src/sap/ui/core/search/OpenSearchProvider.js +1 -1
  147. package/src/sap/ui/core/search/SearchProvider.js +1 -1
  148. package/src/sap/ui/core/service/Service.js +1 -1
  149. package/src/sap/ui/core/service/ServiceFactory.js +1 -1
  150. package/src/sap/ui/core/service/ServiceFactoryRegistry.js +1 -1
  151. package/src/sap/ui/core/support/Plugin.js +1 -1
  152. package/src/sap/ui/core/support/Support.js +1 -1
  153. package/src/sap/ui/core/support/ToolsAPI.js +4 -2
  154. package/src/sap/ui/core/support/plugins/ControlTree.js +1 -1
  155. package/src/sap/ui/core/support/plugins/Interaction.js +1 -1
  156. package/src/sap/ui/core/support/plugins/LocalStorage.js +1 -1
  157. package/src/sap/ui/core/support/plugins/Performance.js +1 -1
  158. package/src/sap/ui/core/support/plugins/Selector.js +1 -1
  159. package/src/sap/ui/core/support/plugins/TechInfo.js +1 -1
  160. package/src/sap/ui/core/support/plugins/Trace.js +1 -1
  161. package/src/sap/ui/core/support/plugins/ViewInfo.js +1 -1
  162. package/src/sap/ui/core/themes/base/base.less +4238 -122
  163. package/src/sap/ui/core/themes/base/global.less +460 -7
  164. package/src/sap/ui/core/themes/base/skeleton.less +454 -3
  165. package/src/sap/ui/core/themes/sap_hcb/global.less +493 -40
  166. package/src/sap/ui/core/theming/Parameters.js +3 -3
  167. package/src/sap/ui/core/tmpl/DOMAttribute.js +1 -1
  168. package/src/sap/ui/core/tmpl/DOMElement.js +1 -1
  169. package/src/sap/ui/core/tmpl/HandlebarsTemplate.js +1 -1
  170. package/src/sap/ui/core/tmpl/Template.js +1 -1
  171. package/src/sap/ui/core/tmpl/TemplateControl.js +1 -1
  172. package/src/sap/ui/core/util/AsyncHintsHelper.js +1 -1
  173. package/src/sap/ui/core/util/Export.js +1 -1
  174. package/src/sap/ui/core/util/ExportCell.js +1 -1
  175. package/src/sap/ui/core/util/ExportColumn.js +1 -1
  176. package/src/sap/ui/core/util/ExportRow.js +1 -1
  177. package/src/sap/ui/core/util/ExportType.js +1 -1
  178. package/src/sap/ui/core/util/ExportTypeCSV.js +1 -1
  179. package/src/sap/ui/core/util/File.js +1 -1
  180. package/src/sap/ui/core/util/LibraryInfo.js +1 -1
  181. package/src/sap/ui/core/util/MockServer.js +1 -1
  182. package/src/sap/ui/core/util/PasteHelper.js +1 -1
  183. package/src/sap/ui/core/util/reflection/BaseTreeModifier.js +134 -148
  184. package/src/sap/ui/core/util/reflection/JsControlTreeModifier.js +165 -202
  185. package/src/sap/ui/core/util/reflection/XmlTreeModifier.js +365 -468
  186. package/src/sap/ui/core/util/serializer/HTMLViewSerializer.js +1 -1
  187. package/src/sap/ui/core/util/serializer/Serializer.js +1 -1
  188. package/src/sap/ui/core/util/serializer/ViewSerializer.js +1 -1
  189. package/src/sap/ui/core/util/serializer/XMLViewSerializer.js +1 -1
  190. package/src/sap/ui/core/util/serializer/delegate/Delegate.js +1 -1
  191. package/src/sap/ui/core/util/serializer/delegate/HTML.js +1 -1
  192. package/src/sap/ui/core/util/serializer/delegate/XML.js +1 -1
  193. package/src/sap/ui/core/webc/WebComponent.js +1 -1
  194. package/src/sap/ui/core/webc/WebComponentMetadata.js +1 -1
  195. package/src/sap/ui/core/webc/WebComponentRenderer.js +7 -2
  196. package/src/sap/ui/core/ws/ReadyState.js +1 -1
  197. package/src/sap/ui/core/ws/SapPcpWebSocket.js +1 -1
  198. package/src/sap/ui/core/ws/WebSocket.js +1 -1
  199. package/src/sap/ui/debug/ControlTree.js +1 -1
  200. package/src/sap/ui/debug/DebugEnv.js +1 -1
  201. package/src/sap/ui/debug/PropertyList.js +1 -1
  202. package/src/sap/ui/dom/findTabbable.js +3 -5
  203. package/src/sap/ui/model/ClientModel.js +1 -1
  204. package/src/sap/ui/model/CompositeDataState.js +11 -12
  205. package/src/sap/ui/model/CompositeType.js +1 -1
  206. package/src/sap/ui/model/DataState.js +33 -5
  207. package/src/sap/ui/model/MetaModel.js +1 -1
  208. package/src/sap/ui/model/Model.js +1 -1
  209. package/src/sap/ui/model/SelectionModel.js +1 -1
  210. package/src/sap/ui/model/SimpleType.js +1 -1
  211. package/src/sap/ui/model/TreeAutoExpandMode.js +1 -1
  212. package/src/sap/ui/model/Type.js +1 -1
  213. package/src/sap/ui/model/_Helper.js +3 -1
  214. package/src/sap/ui/model/json/JSONModel.js +1 -1
  215. package/src/sap/ui/model/message/MessageModel.js +1 -1
  216. package/src/sap/ui/model/odata/ODataAnnotations.js +1 -1
  217. package/src/sap/ui/model/odata/ODataMessageParser.js +1 -1
  218. package/src/sap/ui/model/odata/ODataMetaModel.js +116 -35
  219. package/src/sap/ui/model/odata/ODataMetadata.js +1 -1
  220. package/src/sap/ui/model/odata/ODataModel.js +1 -1
  221. package/src/sap/ui/model/odata/type/Boolean.js +1 -1
  222. package/src/sap/ui/model/odata/type/Byte.js +1 -1
  223. package/src/sap/ui/model/odata/type/Currency.js +1 -1
  224. package/src/sap/ui/model/odata/type/Date.js +1 -1
  225. package/src/sap/ui/model/odata/type/DateTime.js +1 -1
  226. package/src/sap/ui/model/odata/type/DateTimeBase.js +1 -1
  227. package/src/sap/ui/model/odata/type/DateTimeOffset.js +1 -1
  228. package/src/sap/ui/model/odata/type/DateTimeWithTimezone.js +1 -1
  229. package/src/sap/ui/model/odata/type/Decimal.js +1 -1
  230. package/src/sap/ui/model/odata/type/Double.js +1 -1
  231. package/src/sap/ui/model/odata/type/Guid.js +1 -1
  232. package/src/sap/ui/model/odata/type/Int.js +1 -1
  233. package/src/sap/ui/model/odata/type/Int16.js +1 -1
  234. package/src/sap/ui/model/odata/type/Int32.js +1 -1
  235. package/src/sap/ui/model/odata/type/Int64.js +1 -1
  236. package/src/sap/ui/model/odata/type/ODataType.js +1 -1
  237. package/src/sap/ui/model/odata/type/Raw.js +1 -1
  238. package/src/sap/ui/model/odata/type/SByte.js +1 -1
  239. package/src/sap/ui/model/odata/type/Single.js +1 -1
  240. package/src/sap/ui/model/odata/type/Stream.js +1 -1
  241. package/src/sap/ui/model/odata/type/String.js +1 -1
  242. package/src/sap/ui/model/odata/type/Time.js +1 -1
  243. package/src/sap/ui/model/odata/type/TimeOfDay.js +1 -1
  244. package/src/sap/ui/model/odata/type/Unit.js +1 -1
  245. package/src/sap/ui/model/odata/type/UnitMixin.js +14 -9
  246. package/src/sap/ui/model/odata/v2/Context.js +1 -1
  247. package/src/sap/ui/model/odata/v2/ODataAnnotations.js +1 -1
  248. package/src/sap/ui/model/odata/v2/ODataModel.js +185 -54
  249. package/src/sap/ui/model/odata/v2/ODataTreeBinding.js +29 -10
  250. package/src/sap/ui/model/odata/v4/Context.js +65 -16
  251. package/src/sap/ui/model/odata/v4/ODataBinding.js +6 -0
  252. package/src/sap/ui/model/odata/v4/ODataContextBinding.js +1 -1
  253. package/src/sap/ui/model/odata/v4/ODataListBinding.js +113 -41
  254. package/src/sap/ui/model/odata/v4/ODataMetaModel.js +1 -1
  255. package/src/sap/ui/model/odata/v4/ODataModel.js +42 -6
  256. package/src/sap/ui/model/odata/v4/ODataPropertyBinding.js +1 -1
  257. package/src/sap/ui/model/odata/v4/_AnnotationHelperExpression.js +1 -1
  258. package/src/sap/ui/model/odata/v4/lib/_AggregationCache.js +112 -55
  259. package/src/sap/ui/model/odata/v4/lib/_AggregationHelper.js +40 -15
  260. package/src/sap/ui/model/odata/v4/lib/_Cache.js +118 -80
  261. package/src/sap/ui/model/odata/v4/lib/_Helper.js +10 -7
  262. package/src/sap/ui/model/odata/v4/lib/_Requestor.js +29 -4
  263. package/src/sap/ui/model/odata/v4/lib/_TreeState.js +64 -14
  264. package/src/sap/ui/model/resource/ResourceModel.js +1 -1
  265. package/src/sap/ui/model/type/Boolean.js +1 -1
  266. package/src/sap/ui/model/type/Currency.js +1 -1
  267. package/src/sap/ui/model/type/Date.js +1 -1
  268. package/src/sap/ui/model/type/DateInterval.js +1 -1
  269. package/src/sap/ui/model/type/DateTime.js +1 -1
  270. package/src/sap/ui/model/type/DateTimeInterval.js +1 -1
  271. package/src/sap/ui/model/type/FileSize.js +1 -1
  272. package/src/sap/ui/model/type/Float.js +1 -1
  273. package/src/sap/ui/model/type/Integer.js +1 -1
  274. package/src/sap/ui/model/type/String.js +1 -1
  275. package/src/sap/ui/model/type/Time.js +1 -1
  276. package/src/sap/ui/model/type/TimeInterval.js +1 -1
  277. package/src/sap/ui/model/type/Unit.js +1 -1
  278. package/src/sap/ui/model/xml/XMLModel.js +1 -1
  279. package/src/sap/ui/qunit/utils/ControlIterator.js +1 -1
  280. package/src/sap/ui/qunit/utils/MemoryLeakCheck.js +1 -1
  281. package/src/sap/ui/test/Opa5.js +2 -1
  282. package/src/sap/ui/test/TestUtils.js +107 -43
  283. package/src/sap/ui/test/generic/TestBase.js +1 -1
  284. package/src/sap/ui/util/Storage.js +1 -1
  285. package/src/ui5loader.js +38 -13
@@ -1128,32 +1128,6 @@ sap.ui.define([
1128
1128
  * @public
1129
1129
  */
1130
1130
 
1131
- /**
1132
- * Returns an array containing all current elements of a collection or single cache for the
1133
- * given relative path; the array is annotated with the collection's $count. If there are
1134
- * pending requests, the corresponding promises will be ignored and set to
1135
- * <code>undefined</code>.
1136
- *
1137
- * @param {string} [sPath]
1138
- * Relative path to drill-down into, may be empty (only for collection cache)
1139
- * @returns {object[]} The cache elements
1140
- *
1141
- * @public
1142
- */
1143
- _Cache.prototype.getAllElements = function (sPath) {
1144
- var aAllElements;
1145
-
1146
- if (sPath) {
1147
- return this.getValue(sPath);
1148
- }
1149
- aAllElements = this.aElements.map(function (oElement) {
1150
- return oElement instanceof SyncPromise ? undefined : oElement;
1151
- });
1152
- aAllElements.$count = this.aElements.$count;
1153
-
1154
- return aAllElements;
1155
- };
1156
-
1157
1131
  /**
1158
1132
  * Returns the collection at the given path and removes it from the cache if it is marked as
1159
1133
  * transferable.
@@ -1242,6 +1216,34 @@ sap.ui.define([
1242
1216
  this.getDownloadQueryOptions(mQueryOptions), false, true);
1243
1217
  };
1244
1218
 
1219
+ /**
1220
+ * Returns an array containing elements of a collection or single cache for the given relative
1221
+ * path; the array is annotated with the collection's $count. If no range is given, all elements
1222
+ * are returned. If there are pending requests, the corresponding promises will be ignored and
1223
+ * set to <code>undefined</code>.
1224
+ *
1225
+ * @param {string} [sPath]
1226
+ * Relative path to drill-down into, may be empty (only for collection cache)
1227
+ * @param {number} [iStart]
1228
+ * The start index of the range (inclusive)
1229
+ * @param {number} [iEnd]
1230
+ * The end index of the range (exclusive)
1231
+ * @returns {object[]|undefined} The cache elements
1232
+ *
1233
+ * @public
1234
+ */
1235
+ _Cache.prototype.getElements = function (sPath, iStart, iEnd) {
1236
+ const aElements = this.getValue(sPath);
1237
+ if (!aElements) {
1238
+ return undefined;
1239
+ }
1240
+ const aFilteredElements = aElements.slice(iStart, iEnd)
1241
+ .map((oElement) => (oElement instanceof SyncPromise ? undefined : oElement));
1242
+ aFilteredElements.$count = aElements.$count;
1243
+
1244
+ return aFilteredElements;
1245
+ };
1246
+
1245
1247
  /**
1246
1248
  * Returns the query options for late properties.
1247
1249
  *
@@ -1617,7 +1619,11 @@ sap.ui.define([
1617
1619
  .reportStateMessages(that.sResourcePath, {}, [sPath + sPredicate]);
1618
1620
  fnOnRemove(false);
1619
1621
  } else if (bRemoveFromCollection) {
1620
- _Helper.copySelected(aElements.$byPredicate[sPredicate], aReadResult[0]);
1622
+ const oOldElement = aElements.$byPredicate[sPredicate];
1623
+ _Helper.copySelected(oOldElement, aReadResult[0]);
1624
+ if ("@$ui5.context.isTransient" in oOldElement) {
1625
+ aReadResult[0]["@$ui5.context.isTransient"] = false;
1626
+ }
1621
1627
  that.removeElement(iIndex, sPredicate, aElements, sPath);
1622
1628
  // element no longer in cache -> re-insert via replaceElement
1623
1629
  that.replaceElement(aElements, undefined, sPredicate, aReadResult[0],
@@ -2545,12 +2551,14 @@ sap.ui.define([
2545
2551
  * The deep resource path to be used to build the target path for bound messages
2546
2552
  * @param {boolean} [bSharedRequest]
2547
2553
  * If this parameter is set, the cache is read-only and modifying calls lead to an error.
2554
+ * @param {string[]} [aSeparateProperties]
2555
+ * An array of properties which are requested separately
2548
2556
  *
2549
2557
  * @alias sap.ui.model.odata.v4.lib._CollectionCache
2550
2558
  * @constructor
2551
2559
  */
2552
2560
  function _CollectionCache(oRequestor, sResourcePath, mQueryOptions, bSortExpandSelect,
2553
- sDeepResourcePath, bSharedRequest) {
2561
+ sDeepResourcePath, bSharedRequest, aSeparateProperties) {
2554
2562
  _Cache.call(this, oRequestor, sResourcePath, mQueryOptions, bSortExpandSelect,
2555
2563
  sDeepResourcePath, bSharedRequest);
2556
2564
 
@@ -2563,6 +2571,8 @@ sap.ui.define([
2563
2571
  // number of all (client-side) created elements (active or inactive)
2564
2572
  this.aElements.$created = 0;
2565
2573
  // this.aElements.$deleted = []; // only created on demand
2574
+ // "select all", only created on demand
2575
+ // this.aElements["@$ui5.context.isSelected"] = false;
2566
2576
  this.aElements.$tail = undefined; // promise for a read w/o $top
2567
2577
  // upper limit for @odata.count, maybe sharp; assumes #getQueryString can $filter out all
2568
2578
  // created elements
@@ -2572,6 +2582,7 @@ sap.ui.define([
2572
2582
  // - iStart: the start (inclusive)
2573
2583
  // - iEnd: the end (exclusive)
2574
2584
  this.aReadRequests = [];
2585
+ this.aSeparateProperties = aSeparateProperties ?? []; // properties to be loaded separately
2575
2586
  this.bServerDrivenPaging = false;
2576
2587
  this.oSyncPromiseAll = undefined;
2577
2588
  }
@@ -2712,6 +2723,8 @@ sap.ui.define([
2712
2723
  that = this;
2713
2724
 
2714
2725
  oGroupLock.unlock();
2726
+ that.registerChangeListener(sPath, oListener);
2727
+
2715
2728
  if (this.aElements.$byPredicate[sFirstSegment]) {
2716
2729
  oSyncPromise = SyncPromise.resolve(); // sync access possible
2717
2730
  } else if ((oGroupLock === _GroupLock.$cached || sFirstSegment !== "$count")
@@ -2731,17 +2744,14 @@ sap.ui.define([
2731
2744
  }
2732
2745
 
2733
2746
  return oSyncPromise.then(function () {
2734
- // register afterwards to avoid that updateExisting fires updates before the first
2735
- // response
2736
- that.registerChangeListener(sPath, oListener);
2737
2747
  return that.drillDown(that.aElements, sPath, oGroupLock, bCreateOnDemand);
2738
2748
  });
2739
2749
  };
2740
2750
 
2741
2751
  /**
2742
- * Fills the given range of currently available elements with the given promise. If it is not
2743
- * an option to enlarge the array to accommodate <code>iEnd - 1</code>, the promise is also
2744
- * stored in <code>aElements.$tail</code>.
2752
+ * Fills the given range of currently available elements with the given promise. If the
2753
+ * collection count is unknown and it is not an option to enlarge the array to accommodate
2754
+ * <code>iEnd - 1</code>, the promise is stored in <code>aElements.$tail</code>.
2745
2755
  *
2746
2756
  * @param {sap.ui.base.SyncPromise} oPromise
2747
2757
  * The promise
@@ -2749,13 +2759,19 @@ sap.ui.define([
2749
2759
  * The start index
2750
2760
  * @param {number} iEnd
2751
2761
  * The end index (will not be filled)
2762
+ * @throws {Error}
2763
+ * If the array cannot be filled and the promise was stored in <code>aElements.$tail</code> in
2764
+ * a previous call already
2752
2765
  *
2753
2766
  * @private
2754
2767
  */
2755
2768
  _CollectionCache.prototype.fill = function (oPromise, iStart, iEnd) {
2756
2769
  var i;
2757
2770
 
2758
- if (iEnd > this.aElements.length && iEnd - iStart > 1024) {
2771
+ // iEnd = Infinity is not an issue here. If $count is known, it is taken care of that iEnd
2772
+ // is never higher than $count (using iLimit) @see #read, @see ODataUtils#_getReadIntervals.
2773
+ // If not, iEnd is reduced to this.aElements.length here.
2774
+ if (!this.aElements.$count && iEnd > this.aElements.length && iEnd - iStart > 1024) {
2759
2775
  if (this.aElements.$tail && oPromise) {
2760
2776
  throw new Error("Cannot fill from " + iStart + " to " + iEnd
2761
2777
  + ", $tail already in use, # of elements is " + this.aElements.length);
@@ -2822,6 +2838,18 @@ sap.ui.define([
2822
2838
  sFilterOptions = mQueryOptions.$filter,
2823
2839
  sQueryString = this.sQueryString;
2824
2840
 
2841
+ if (this.aSeparateProperties.length) {
2842
+ mQueryOptions.$expand = {...mQueryOptions.$expand};
2843
+ this.aSeparateProperties.forEach((sProperty) => {
2844
+ delete mQueryOptions.$expand[sProperty];
2845
+ });
2846
+ if (_Helper.isEmptyObject(mQueryOptions.$expand)) {
2847
+ delete mQueryOptions.$expand;
2848
+ }
2849
+ sQueryString = this.oRequestor.buildQueryString(this.sMetaPath, mQueryOptions, false,
2850
+ this.bSortExpandSelect, true);
2851
+ }
2852
+
2825
2853
  if (sExclusiveFilter) {
2826
2854
  if (sFilterOptions) {
2827
2855
  mQueryOptions.$filter = "(" + sFilterOptions + ") and " + sExclusiveFilter;
@@ -3520,6 +3548,26 @@ sap.ui.define([
3520
3548
  mTypeForMetaPath = this.getTypes(),
3521
3549
  that = this;
3522
3550
 
3551
+ /*
3552
+ * Handles the response for a single element.
3553
+ *
3554
+ * @param {object} oElement - The response for a single element
3555
+ * @param {string} [sPredicate] - The element's key predicate
3556
+ */
3557
+ function handle(oElement,
3558
+ sPredicate = _Helper.getPrivateAnnotation(oElement, "predicate")) {
3559
+ that.beforeUpdateSelected?.(sPredicate, oElement);
3560
+ _Helper.updateSelected(that.mChangeListeners, sPredicate,
3561
+ that.aElements.$byPredicate[sPredicate], oElement, aPaths,
3562
+ function preventKeyPredicateChange(sPath) {
3563
+ sPath = sPath.slice(sPredicate.length + 1); // strip sPredicate
3564
+ // not (below) a $NavigationPropertyPath?
3565
+ return !aPaths.some(function (sSideEffectPath) {
3566
+ return _Helper.getRelativePath(sPath, sSideEffectPath) !== undefined;
3567
+ });
3568
+ });
3569
+ }
3570
+
3523
3571
  this.checkSharedRequest();
3524
3572
 
3525
3573
  mQueryOptions = _Helper.intersectQueryOptions(
@@ -3528,31 +3576,29 @@ sap.ui.define([
3528
3576
  if (!mQueryOptions) {
3529
3577
  return SyncPromise.resolve(); // micro optimization: use *sync.* promise which is cached
3530
3578
  }
3531
- if (this.beforeRequestSideEffects) {
3532
- this.beforeRequestSideEffects(mQueryOptions);
3533
- }
3579
+ this.beforeRequestSideEffects?.(mQueryOptions);
3534
3580
 
3581
+ delete mQueryOptions.$count;
3582
+ delete mQueryOptions.$orderby;
3583
+ delete mQueryOptions.$search;
3535
3584
  if (bSingle) {
3536
- aElements = [this.aElements.$byPredicate[aPredicates[0]]];
3585
+ delete mQueryOptions.$filter;
3537
3586
  } else {
3538
3587
  aElements = this.keepOnlyGivenElements(aPredicates);
3539
3588
  if (!aElements.length) {
3540
3589
  return SyncPromise.resolve(); // micro optimization: use cached *sync.* promise
3541
3590
  }
3591
+ mQueryOptions.$filter = aElements.map(function (oElement) {
3592
+ // all elements have a key predicate, so we will get a key filter
3593
+ return _Helper.getKeyFilter(oElement, that.sMetaPath, mTypeForMetaPath);
3594
+ }).sort().join(" or ");
3595
+ if (aElements.length > 1) { // avoid small default page size for server-driven paging
3596
+ mQueryOptions.$top = aElements.length;
3597
+ }
3598
+ _Helper.selectKeyProperties(mQueryOptions, mTypeForMetaPath[this.sMetaPath]);
3542
3599
  }
3543
- mQueryOptions.$filter = aElements.map(function (oElement) {
3544
- // all elements have a key predicate, so we will get a key filter
3545
- return _Helper.getKeyFilter(oElement, that.sMetaPath, mTypeForMetaPath);
3546
- }).sort().join(" or ");
3547
- if (aElements.length > 1) { // avoid small default page size for server-driven paging
3548
- mQueryOptions.$top = aElements.length;
3549
- }
3550
- _Helper.selectKeyProperties(mQueryOptions, mTypeForMetaPath[this.sMetaPath]);
3551
- delete mQueryOptions.$count;
3552
- delete mQueryOptions.$orderby;
3553
- delete mQueryOptions.$search;
3554
3600
  mMergeableQueryOptions = _Helper.extractMergeableQueryOptions(mQueryOptions);
3555
- sResourcePath = this.sResourcePath
3601
+ sResourcePath = this.sResourcePath + (bSingle ? aPredicates[0] : "")
3556
3602
  + this.oRequestor.buildQueryString(this.sMetaPath, mQueryOptions, false, true);
3557
3603
 
3558
3604
  return this.oRequestor.request("GET", sResourcePath, oGroupLock, undefined, undefined,
@@ -3565,36 +3611,25 @@ sap.ui.define([
3565
3611
  return aPaths;
3566
3612
  }
3567
3613
  }).then(function (oResult) {
3568
- var oElement, sPredicate, i, n;
3569
-
3570
- function preventKeyPredicateChange(sPath) {
3571
- sPath = sPath.slice(sPredicate.length + 1); // strip sPredicate
3572
- // not (below) a $NavigationPropertyPath?
3573
- return !aPaths.some(function (sSideEffectPath) {
3574
- return _Helper.getRelativePath(sPath, sSideEffectPath) !== undefined;
3575
- });
3576
- }
3577
-
3578
3614
  if (bSkip) {
3579
3615
  return;
3580
3616
  }
3581
3617
 
3582
- if (oResult.value.length !== aElements.length) {
3583
- throw new Error("Expected " + aElements.length + " row(s), but instead saw "
3584
- + oResult.value.length);
3585
- }
3586
- // Note: iStart makes no sense here (use NaN instead), but is not needed because
3587
- // we know we have key predicates
3588
- that.visitResponse(oResult, mTypeForMetaPath, undefined, "", NaN, true);
3589
- for (i = 0, n = oResult.value.length; i < n; i += 1) {
3590
- oElement = oResult.value[i];
3591
- sPredicate = _Helper.getPrivateAnnotation(oElement, "predicate");
3592
- if (that.beforeUpdateSelected) {
3593
- that.beforeUpdateSelected(sPredicate, oElement);
3618
+ if (bSingle) {
3619
+ that.visitResponse(oResult, mTypeForMetaPath, undefined, aPredicates[0],
3620
+ undefined, true);
3621
+ handle(oResult, aPredicates[0]);
3622
+ } else {
3623
+ if (oResult.value.length !== aElements.length) {
3624
+ throw new Error("Expected " + aElements.length + " row(s), but instead saw "
3625
+ + oResult.value.length);
3626
+ }
3627
+ // Note: iStart makes no sense here (use NaN instead), but is not needed because
3628
+ // we know we have key predicates
3629
+ that.visitResponse(oResult, mTypeForMetaPath, undefined, "", NaN, true);
3630
+ for (let i = 0, n = oResult.value.length; i < n; i += 1) {
3631
+ handle(oResult.value[i]);
3594
3632
  }
3595
- _Helper.updateSelected(that.mChangeListeners, sPredicate,
3596
- that.aElements.$byPredicate[sPredicate], oElement, aPaths,
3597
- preventKeyPredicateChange);
3598
3633
  }
3599
3634
  });
3600
3635
  };
@@ -3862,8 +3897,9 @@ sap.ui.define([
3862
3897
  this.sResourcePath + this.sQueryString, oGroupLock, undefined, undefined,
3863
3898
  fnDataRequested, undefined, this.sMetaPath));
3864
3899
  }
3900
+ that.registerChangeListener("", oListener);
3901
+
3865
3902
  return this.oPromise.then(function (oResult) {
3866
- that.registerChangeListener("", oListener);
3867
3903
  // Note: For a null value, null is returned due to "204 No Content". For $count,
3868
3904
  // "a simple primitive integer value with media type text/plain" is returned.
3869
3905
  return oResult && typeof oResult === "object" ? oResult.value : oResult;
@@ -3991,6 +4027,7 @@ sap.ui.define([
3991
4027
  var sResourcePath = this.sResourcePath + this.sQueryString,
3992
4028
  that = this;
3993
4029
 
4030
+ this.registerChangeListener(sPath, oListener);
3994
4031
  if (this.oPromise) {
3995
4032
  oGroupLock.unlock();
3996
4033
  } else {
@@ -4013,7 +4050,6 @@ sap.ui.define([
4013
4050
  if (oResult && oResult["$ui5.deleted"]) {
4014
4051
  throw new Error("Cannot read a deleted entity");
4015
4052
  }
4016
- that.registerChangeListener(sPath, oListener);
4017
4053
  return that.drillDown(oResult, sPath, oGroupLock, bCreateOnDemand);
4018
4054
  });
4019
4055
  };
@@ -4407,13 +4443,15 @@ sap.ui.define([
4407
4443
  * If this parameter is set, multiple requests for a cache using the same resource path will
4408
4444
  * always return the same, shared cache. This cache is read-only, modifying calls lead to an
4409
4445
  * error.
4446
+ * @param {string[]} [aSeparateProperties]
4447
+ * An array of properties which are requested separately
4410
4448
  * @returns {sap.ui.model.odata.v4.lib._Cache}
4411
4449
  * The cache
4412
4450
  *
4413
4451
  * @public
4414
4452
  */
4415
4453
  _Cache.create = function (oRequestor, sResourcePath, mQueryOptions, bSortExpandSelect,
4416
- sDeepResourcePath, bSharedRequest) {
4454
+ sDeepResourcePath, bSharedRequest, aSeparateProperties) {
4417
4455
  var iCount, aKeys, sPath, oSharedCollectionCache, mSharedCollectionCacheByPath;
4418
4456
 
4419
4457
  if (bSharedRequest) {
@@ -4450,7 +4488,7 @@ sap.ui.define([
4450
4488
  }
4451
4489
 
4452
4490
  return new _CollectionCache(oRequestor, sResourcePath, mQueryOptions, bSortExpandSelect,
4453
- sDeepResourcePath);
4491
+ sDeepResourcePath, bSharedRequest, aSeparateProperties);
4454
4492
  };
4455
4493
 
4456
4494
  /**
@@ -2230,9 +2230,11 @@ sap.ui.define([
2230
2230
  * @param {string} [sOrderby]
2231
2231
  * The new value for the query option "$orderby"
2232
2232
  * @param {string[]} [aFilters]
2233
- * An array that consists of two filters, the first one ("$filter") has to be be applied
2234
- * after and the second one ("$$filterBeforeAggregate") has to be applied before
2235
- * aggregating the data. Both can be <code>undefined</code>.
2233
+ * An array that consists of three filters where each can be <code>undefined</code>. The
2234
+ * first one ("$filter") has to be applied after data aggregation. The second one
2235
+ * ("$$filterBeforeAggregate") can be applied before data aggregation. The third one
2236
+ * ("$$filterOnAggregate") has to be applied before data aggregation and already contains
2237
+ * the special syntax "$these/aggregate(...)" because it relates to aggregates.
2236
2238
  * @returns {object}
2237
2239
  * The merged map of query options
2238
2240
  *
@@ -2242,8 +2244,8 @@ sap.ui.define([
2242
2244
  var mResult;
2243
2245
 
2244
2246
  function set(sProperty, sValue) {
2245
- if (sValue && (!mQueryOptions || mQueryOptions[sProperty] !== sValue)) {
2246
- mResult ??= mQueryOptions ? _Helper.clone(mQueryOptions) : {};
2247
+ if (sValue && mQueryOptions?.[sProperty] !== sValue) {
2248
+ mResult ??= {...mQueryOptions};
2247
2249
  mResult[sProperty] = sValue;
2248
2250
  }
2249
2251
  }
@@ -2252,6 +2254,7 @@ sap.ui.define([
2252
2254
  if (aFilters) {
2253
2255
  set("$filter", aFilters[0]);
2254
2256
  set("$$filterBeforeAggregate", aFilters[1]);
2257
+ set("$$filterOnAggregate", aFilters[2]);
2255
2258
  }
2256
2259
  return mResult || mQueryOptions;
2257
2260
  },
@@ -2498,9 +2501,9 @@ sap.ui.define([
2498
2501
  * Searches all properties in oOld annotated with "@$ui5.updating" and restores the property
2499
2502
  * value in oNew.
2500
2503
  *
2501
- * @param {object} oOld
2504
+ * @param {object} [oOld]
2502
2505
  * The old element
2503
- * @param {object} oNew
2506
+ * @param {object} [oNew]
2504
2507
  * The new element
2505
2508
  * @returns {object}
2506
2509
  * The new element with the restored properties
@@ -91,6 +91,7 @@ sap.ui.define([
91
91
  this.oModelInterface = oModelInterface;
92
92
  this.oOptimisticBatch = null; // optimistic batch processing off
93
93
  this.sQueryParams = _Helper.buildQuery(mQueryParams); // Used for $batch and CSRF token only
94
+ this.oRetryAfterPromise = null;
94
95
  this.mRunningChangeRequests = {}; // map from group ID to a SyncPromise[]
95
96
  this.iSessionTimer = 0;
96
97
  this.iSerialNumber = 0;
@@ -1396,7 +1397,7 @@ sap.ui.define([
1396
1397
  // methods it must be possible to insert the ETag from the header
1397
1398
  oResponse = vRequest.method === "GET" ? null : {};
1398
1399
  }
1399
- that.reportHeaderMessages(vRequest.url,
1400
+ that.reportHeaderMessages(vRequest.$resourcePath,
1400
1401
  getResponseHeader.call(vResponse, "sap-messages"));
1401
1402
  sETag = getResponseHeader.call(vResponse, "ETag");
1402
1403
  if (sETag) {
@@ -1425,6 +1426,7 @@ sap.ui.define([
1425
1426
  "HTTP request was not processed because $batch failed");
1426
1427
 
1427
1428
  oRequestError.cause = oError;
1429
+ oRequestError.$reported = oError.$reported;
1428
1430
  reject(oRequestError, aRequests);
1429
1431
  throw oError;
1430
1432
  }).finally(function () {
@@ -1891,7 +1893,9 @@ sap.ui.define([
1891
1893
  aRequests[iChangeSetNo].push(oRequest);
1892
1894
  }
1893
1895
  if (sGroupId === "$single") {
1894
- that.submitBatch("$single");
1896
+ that.submitBatch("$single").catch(() => {
1897
+ // nothing to do, see "HTTP request was not processed because $batch failed"
1898
+ });
1895
1899
  }
1896
1900
  });
1897
1901
  oRequest.$promise = oPromise;
@@ -1913,7 +1917,7 @@ sap.ui.define([
1913
1917
  sMethod === "GET" ? {"sap-cancel-on-close" : "true"} : undefined),
1914
1918
  JSON.stringify(oPayload), sOriginalResourcePath
1915
1919
  ).then(function (oResponse) {
1916
- that.reportHeaderMessages(oResponse.resourcePath, oResponse.messages);
1920
+ that.reportHeaderMessages(sOriginalResourcePath, oResponse.messages);
1917
1921
  return that.doConvertResponse(
1918
1922
  // Note: "text/plain" used for $count
1919
1923
  typeof oResponse.body === "string" ? JSON.parse(oResponse.body) : oResponse.body,
@@ -2072,6 +2076,22 @@ sap.ui.define([
2072
2076
  that.refreshSecurityToken(sOldCsrfToken).then(function () {
2073
2077
  send(true);
2074
2078
  }, fnReject);
2079
+ } else if (jqXHR.status === 503 && jqXHR.getResponseHeader("Retry-After")
2080
+ && (that.oRetryAfterPromise
2081
+ || that.oModelInterface.getRetryAfterHandler())) {
2082
+ if (!that.oRetryAfterPromise) {
2083
+ const oRetryAfterError = _Helper.createError(jqXHR, "");
2084
+ that.oRetryAfterPromise = that.oModelInterface.getRetryAfterHandler()(
2085
+ oRetryAfterError);
2086
+ that.oRetryAfterPromise.finally(() => {
2087
+ that.oRetryAfterPromise = null;
2088
+ }).catch(() => { /* catch is only needed due to finally */ });
2089
+ that.oRetryAfterPromise.catch((oError) => {
2090
+ // own error reason is not reported to the message model
2091
+ oError.$reported = oError !== oRetryAfterError;
2092
+ });
2093
+ }
2094
+ that.oRetryAfterPromise.then(send, fnReject);
2075
2095
  } else {
2076
2096
  sMessage = "Communication error";
2077
2097
  if (sContextId) {
@@ -2091,7 +2111,9 @@ sap.ui.define([
2091
2111
  });
2092
2112
  }
2093
2113
 
2094
- if (that.oSecurityTokenPromise && sMethod !== "GET") {
2114
+ if (that.oRetryAfterPromise) {
2115
+ that.oRetryAfterPromise.then(send, fnReject);
2116
+ } else if (that.oSecurityTokenPromise && sMethod !== "GET") {
2095
2117
  that.oSecurityTokenPromise.then(send);
2096
2118
  } else {
2097
2119
  send();
@@ -2309,6 +2331,9 @@ sap.ui.define([
2309
2331
  * A catch handler function expecting an <code>Error</code> instance. This function will call
2310
2332
  * {@link sap.ui.model.odata.v4.ODataModel#reportError} if the error has not been reported
2311
2333
  * yet
2334
+ * @param {function} oModelInterface.getRetryAfterHandler
2335
+ * A function that returns the "Retry-After" handler,
2336
+ * see also {@link sap.ui.model.odata.v4.ODataModel#setRetryAfterHandler}
2312
2337
  * @param {function():boolean} oModelInterface.isIgnoreETag
2313
2338
  * Tells whether an entity's ETag should be actively ignored (If-Match:*) for PATCH requests.
2314
2339
  * @param {function} oModelInterface.onCreateGroup
@@ -47,22 +47,29 @@ sap.ui.define([
47
47
  * Collapse a node.
48
48
  *
49
49
  * @param {object} oNode - The node
50
- *
50
+ * @param {boolean} bAll
51
+ * Whether collapsing completely
52
+ * @param {boolean} [bNested]
53
+ * Whether the "collapse all" was performed at an ancestor
51
54
  * @public
52
55
  */
53
- collapse(oNode) {
56
+ collapse(oNode, bAll, bNested) {
54
57
  if (!this.sNodeProperty) {
55
58
  return;
56
59
  }
57
60
 
58
61
  const sPredicate = _Helper.getPrivateAnnotation(oNode, "predicate");
59
62
  const oExpandLevel = this.mPredicate2ExpandLevels[sPredicate];
60
- if (oExpandLevel && oExpandLevel.Levels !== 0) {
63
+ if (bNested || oExpandLevel && oExpandLevel.levels !== 0) {
61
64
  delete this.mPredicate2ExpandLevels[sPredicate];
62
65
  } else {
63
- // must have NodeId as the node may be missing when calling #getExpandLevels
66
+ // must determine node ID now; the node may be missing when calling #getExpandLevels
64
67
  const sNodeId = _Helper.drillDown(oNode, this.sNodeProperty);
65
- this.mPredicate2ExpandLevels[sPredicate] = {NodeID : sNodeId, Levels : 0};
68
+ this.mPredicate2ExpandLevels[sPredicate] = {
69
+ collapseAll : bAll,
70
+ levels : 0,
71
+ nodeId : sNodeId
72
+ };
66
73
  }
67
74
  }
68
75
 
@@ -87,6 +94,20 @@ sap.ui.define([
87
94
  });
88
95
  }
89
96
 
97
+ /**
98
+ * Deletes the expand levels for the given node and all its descendants.
99
+ *
100
+ * @param {object} oNode - The node
101
+ *
102
+ * @private
103
+ */
104
+ deleteExpandLevels(oNode) {
105
+ delete this.mPredicate2ExpandLevels[_Helper.getPrivateAnnotation(oNode, "predicate")];
106
+ _Helper.getPrivateAnnotation(oNode, "spliced", []).forEach((oChild) => {
107
+ this.deleteExpandLevels(oChild);
108
+ });
109
+ }
110
+
90
111
  /**
91
112
  * Deletes a node and all its descendants from the out-of-place list (making them in-place).
92
113
  *
@@ -108,6 +129,7 @@ sap.ui.define([
108
129
  sPredicate = sParentPredicate;
109
130
  }
110
131
  }
132
+ this.mPredicate2OutOfPlace[sPredicate].context.setOutOfPlace(false);
111
133
  delete this.mPredicate2OutOfPlace[sPredicate];
112
134
  Object.values(this.mPredicate2OutOfPlace).forEach((oOutOfPlace) => {
113
135
  if (oOutOfPlace.parentPredicate === sPredicate) {
@@ -131,17 +153,18 @@ sap.ui.define([
131
153
  return;
132
154
  }
133
155
 
156
+ if (iLevels >= Number.MAX_SAFE_INTEGER) {
157
+ iLevels = null;
158
+ this.deleteExpandLevels(oNode);
159
+ }
134
160
  const sPredicate = _Helper.getPrivateAnnotation(oNode, "predicate");
135
161
  const oExpandLevel = this.mPredicate2ExpandLevels[sPredicate];
136
- if (oExpandLevel && !oExpandLevel.Levels) {
162
+ if (oExpandLevel && !oExpandLevel.levels && !oExpandLevel.collapseAll) {
137
163
  delete this.mPredicate2ExpandLevels[sPredicate];
138
164
  } else {
139
- // must have NodeId as the node may be missing when calling #getExpandLevels
165
+ // must determine node ID now; the node may be missing when calling #getExpandLevels
140
166
  const sNodeId = _Helper.drillDown(oNode, this.sNodeProperty);
141
- if (iLevels >= Number.MAX_SAFE_INTEGER) {
142
- iLevels = null;
143
- }
144
- this.mPredicate2ExpandLevels[sPredicate] = {NodeID : sNodeId, Levels : iLevels};
167
+ this.mPredicate2ExpandLevels[sPredicate] = {levels : iLevels, nodeId : sNodeId};
145
168
  }
146
169
  }
147
170
 
@@ -155,7 +178,12 @@ sap.ui.define([
155
178
  */
156
179
  getExpandLevels() {
157
180
  const aExpandLevels = Object.values(this.mPredicate2ExpandLevels);
158
- return aExpandLevels.length ? JSON.stringify(aExpandLevels) : undefined;
181
+ return aExpandLevels.length
182
+ ? JSON.stringify(aExpandLevels.map((oExpandLevel) => {
183
+ // build the server representation
184
+ return {NodeID : oExpandLevel.nodeId, Levels : oExpandLevel.levels};
185
+ }))
186
+ : undefined;
159
187
  }
160
188
 
161
189
  /**
@@ -247,28 +275,50 @@ sap.ui.define([
247
275
  * @public
248
276
  */
249
277
  resetOutOfPlace() {
250
- this.mPredicate2OutOfPlace = {};
278
+ this.getOutOfPlacePredicates()
279
+ .forEach((sPredicate) => this.deleteOutOfPlace(sPredicate));
251
280
  }
252
281
 
253
282
  /**
254
- * Makes the node out of place.
283
+ * Makes the ("created persisted"!) node out of place.
255
284
  *
256
285
  * @param {object} oNode - The node
257
286
  * @param {object} [oParent] - The parent, unless the node is a root
287
+ * @throws {Error} If the node is not 'created persisted'
258
288
  *
259
289
  * @public
260
290
  */
261
291
  setOutOfPlace(oNode, oParent) {
292
+ if (oNode["@$ui5.context.isTransient"] !== false) {
293
+ throw new Error("Not 'created persisted'");
294
+ }
262
295
  const oOutOfPlace = {
296
+ context : _Helper.getPrivateAnnotation(oNode, "context"),
263
297
  nodeFilter : this.fnGetKeyFilter(oNode),
264
298
  nodePredicate : _Helper.getPrivateAnnotation(oNode, "predicate")
265
299
  };
300
+ oOutOfPlace.context.setOutOfPlace(true);
266
301
  if (oParent) {
267
302
  oOutOfPlace.parentFilter = this.fnGetKeyFilter(oParent);
268
303
  oOutOfPlace.parentPredicate = _Helper.getPrivateAnnotation(oParent, "predicate");
269
304
  }
270
305
  this.mPredicate2OutOfPlace[oOutOfPlace.nodePredicate] = oOutOfPlace;
271
306
  }
307
+
308
+ /**
309
+ * The given node is still out of place and thus must keep a client-side annotation
310
+ * <code>"@$ui5.context.isTransient"</code> as well as a private annotation "context".
311
+ *
312
+ * @param {object} oNode - The node
313
+ * @param {string} sPredicate - The node's key predicate
314
+ *
315
+ * @public
316
+ */
317
+ stillOutOfPlace(oNode, sPredicate) {
318
+ oNode["@$ui5.context.isTransient"] = false;
319
+ _Helper.setPrivateAnnotation(oNode, "context",
320
+ this.mPredicate2OutOfPlace[sPredicate].context);
321
+ }
272
322
  }
273
323
 
274
324
  return _TreeState;
@@ -227,7 +227,7 @@ sap.ui.define([
227
227
  *
228
228
  * @extends sap.ui.model.Model
229
229
  * @public
230
- * @version 1.127.1
230
+ * @version 1.129.0
231
231
  */
232
232
  var ResourceModel = Model.extend("sap.ui.model.resource.ResourceModel", /** @lends sap.ui.model.resource.ResourceModel.prototype */ {
233
233
 
@@ -19,7 +19,7 @@ sap.ui.define(["sap/ui/core/Lib", 'sap/ui/model/SimpleType', 'sap/ui/model/Forma
19
19
  * @extends sap.ui.model.SimpleType
20
20
  *
21
21
  * @author SAP SE
22
- * @version 1.127.1
22
+ * @version 1.129.0
23
23
  *
24
24
  * @public
25
25
  * @param {object} [oFormatOptions]
@@ -34,7 +34,7 @@ sap.ui.define([
34
34
  * @extends sap.ui.model.CompositeType
35
35
  *
36
36
  * @author SAP SE
37
- * @version 1.127.1
37
+ * @version 1.129.0
38
38
  *
39
39
  * @public
40
40
  * @param {object} [oFormatOptions]