@openui5/sap.ui.core 1.107.0 → 1.108.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 (287) hide show
  1. package/.dtsgenrc +63 -0
  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/i18n/ResourceBundle.js +10 -0
  10. package/src/sap/base/security/URLListValidator.js +36 -3
  11. package/src/sap/base/util/restricted/_CancelablePromise.js +1 -1
  12. package/src/sap/base/util/restricted/_castArray.js +1 -1
  13. package/src/sap/base/util/restricted/_compact.js +1 -1
  14. package/src/sap/base/util/restricted/_curry.js +1 -1
  15. package/src/sap/base/util/restricted/_debounce.js +1 -1
  16. package/src/sap/base/util/restricted/_difference.js +1 -1
  17. package/src/sap/base/util/restricted/_differenceBy.js +1 -1
  18. package/src/sap/base/util/restricted/_differenceWith.js +1 -1
  19. package/src/sap/base/util/restricted/_flatMap.js +1 -1
  20. package/src/sap/base/util/restricted/_flatMapDeep.js +1 -1
  21. package/src/sap/base/util/restricted/_flatMapDepth.js +1 -1
  22. package/src/sap/base/util/restricted/_flatten.js +1 -1
  23. package/src/sap/base/util/restricted/_flattenDeep.js +1 -1
  24. package/src/sap/base/util/restricted/_flattenDepth.js +1 -1
  25. package/src/sap/base/util/restricted/_intersection.js +1 -1
  26. package/src/sap/base/util/restricted/_intersectionBy.js +1 -1
  27. package/src/sap/base/util/restricted/_intersectionWith.js +1 -1
  28. package/src/sap/base/util/restricted/_isEqual.js +1 -1
  29. package/src/sap/base/util/restricted/_isEqualWith.js +1 -1
  30. package/src/sap/base/util/restricted/_isNil.js +1 -1
  31. package/src/sap/base/util/restricted/_max.js +1 -1
  32. package/src/sap/base/util/restricted/_merge.js +1 -1
  33. package/src/sap/base/util/restricted/_mergeWith.js +1 -1
  34. package/src/sap/base/util/restricted/_min.js +1 -1
  35. package/src/sap/base/util/restricted/_omit.js +1 -1
  36. package/src/sap/base/util/restricted/_pick.js +1 -1
  37. package/src/sap/base/util/restricted/_pickBy.js +1 -1
  38. package/src/sap/base/util/restricted/_throttle.js +1 -1
  39. package/src/sap/base/util/restricted/_toArray.js +1 -1
  40. package/src/sap/base/util/restricted/_union.js +1 -1
  41. package/src/sap/base/util/restricted/_unionBy.js +1 -1
  42. package/src/sap/base/util/restricted/_unionWith.js +1 -1
  43. package/src/sap/base/util/restricted/_uniq.js +1 -1
  44. package/src/sap/base/util/restricted/_uniqBy.js +1 -1
  45. package/src/sap/base/util/restricted/_uniqWith.js +1 -1
  46. package/src/sap/base/util/restricted/_without.js +1 -1
  47. package/src/sap/base/util/restricted/_xor.js +1 -1
  48. package/src/sap/base/util/restricted/_xorBy.js +1 -1
  49. package/src/sap/base/util/restricted/_xorWith.js +1 -1
  50. package/src/sap/base/util/restricted/_zipObject.js +1 -1
  51. package/src/sap/base/util/restricted/_zipObjectDeep.js +1 -1
  52. package/src/sap/ui/Device.js +3 -3
  53. package/src/sap/ui/Global.js +4 -4
  54. package/src/sap/ui/base/Event.js +1 -1
  55. package/src/sap/ui/base/EventProvider.js +1 -1
  56. package/src/sap/ui/base/Interface.js +1 -1
  57. package/src/sap/ui/base/ManagedObject.js +2 -2
  58. package/src/sap/ui/base/ManagedObjectMetadata.js +1 -1
  59. package/src/sap/ui/base/Metadata.js +1 -1
  60. package/src/sap/ui/base/Object.js +1 -1
  61. package/src/sap/ui/base/ObjectPool.js +1 -1
  62. package/src/sap/ui/core/.library +50 -50
  63. package/src/sap/ui/core/BusyIndicator.js +1 -1
  64. package/src/sap/ui/core/BusyIndicatorUtils.js +22 -8
  65. package/src/sap/ui/core/Component.js +21 -4
  66. package/src/sap/ui/core/ComponentContainer.js +5 -1
  67. package/src/sap/ui/core/ComponentMetadata.js +1 -1
  68. package/src/sap/ui/core/ComponentSupport.js +1 -1
  69. package/src/sap/ui/core/Configuration.js +2 -15
  70. package/src/sap/ui/core/Control.js +20 -2
  71. package/src/sap/ui/core/Core.js +311 -413
  72. package/src/sap/ui/core/CustomData.js +1 -1
  73. package/src/sap/ui/core/DeclarativeSupport.js +1 -1
  74. package/src/sap/ui/core/Element.js +1 -1
  75. package/src/sap/ui/core/ElementMetadata.js +1 -1
  76. package/src/sap/ui/core/EnabledPropagator.js +1 -1
  77. package/src/sap/ui/core/EventBus.js +1 -1
  78. package/src/sap/ui/core/FocusHandler.js +12 -14
  79. package/src/sap/ui/core/Fragment.js +5 -2
  80. package/src/sap/ui/core/HTML.js +1 -1
  81. package/src/sap/ui/core/History.js +1 -1
  82. package/src/sap/ui/core/Icon.js +1 -1
  83. package/src/sap/ui/core/IconPool.js +7 -1
  84. package/src/sap/ui/core/IndicationColorSupport.js +1 -1
  85. package/src/sap/ui/core/IntervalTrigger.js +1 -1
  86. package/src/sap/ui/core/InvisibleMessage.js +1 -1
  87. package/src/sap/ui/core/InvisibleRenderer.js +1 -1
  88. package/src/sap/ui/core/InvisibleText.js +1 -1
  89. package/src/sap/ui/core/Item.js +1 -1
  90. package/src/sap/ui/core/LabelEnablement.js +1 -1
  91. package/src/sap/ui/core/LayoutData.js +1 -1
  92. package/src/sap/ui/core/ListItem.js +1 -1
  93. package/src/sap/ui/core/LocalBusyIndicator.js +1 -1
  94. package/src/sap/ui/core/Locale.js +1 -1
  95. package/src/sap/ui/core/LocaleData.js +1 -1
  96. package/src/sap/ui/core/Manifest.js +16 -83
  97. package/src/sap/ui/core/Message.js +1 -1
  98. package/src/sap/ui/core/Popup.js +14 -4
  99. package/src/sap/ui/core/RenderManager.js +111 -109
  100. package/src/sap/ui/core/Renderer.js +1 -1
  101. package/src/sap/ui/core/ResizeHandler.js +1 -1
  102. package/src/sap/ui/core/ScrollBar.js +1 -1
  103. package/src/sap/ui/core/SeparatorItem.js +1 -1
  104. package/src/sap/ui/core/ShortcutHintsMixin.js +20 -0
  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 +4 -2
  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 +1 -1
  114. package/src/sap/ui/core/_IconRegistry.js +11 -7
  115. package/src/sap/ui/core/_UrlResolver.js +139 -0
  116. package/src/sap/ui/core/date/CalendarUtils.js +87 -0
  117. package/src/sap/ui/core/date/CalendarWeekNumbering.js +73 -0
  118. package/src/sap/ui/core/date/UniversalDate.js +198 -74
  119. package/src/sap/ui/core/delegate/ItemNavigation.js +1 -1
  120. package/src/sap/ui/core/delegate/ScrollEnablement.js +1 -1
  121. package/src/sap/ui/core/dnd/DragDropBase.js +1 -1
  122. package/src/sap/ui/core/dnd/DragDropInfo.js +1 -1
  123. package/src/sap/ui/core/dnd/DragInfo.js +1 -1
  124. package/src/sap/ui/core/dnd/DropInfo.js +1 -1
  125. package/src/sap/ui/core/format/DateFormat.js +187 -57
  126. package/src/sap/ui/core/format/NumberFormat.js +64 -23
  127. package/src/sap/ui/core/format/TimezoneUtil.js +3 -1
  128. package/src/sap/ui/core/hyphenation/Hyphenation.js +1 -1
  129. package/src/sap/ui/core/library.js +19 -10
  130. package/src/sap/ui/core/message/ControlMessageProcessor.js +1 -1
  131. package/src/sap/ui/core/message/Message.js +5 -3
  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/messagebundle_fr.properties +1 -1
  136. package/src/sap/ui/core/mvc/HTMLView.js +10 -2
  137. package/src/sap/ui/core/mvc/JSONView.js +1 -1
  138. package/src/sap/ui/core/mvc/JSView.js +1 -1
  139. package/src/sap/ui/core/mvc/TemplateView.js +1 -1
  140. package/src/sap/ui/core/mvc/View.js +1 -1
  141. package/src/sap/ui/core/mvc/XMLView.js +1 -1
  142. package/src/sap/ui/core/plugin/DeclarativeSupport.js +1 -1
  143. package/src/sap/ui/core/plugin/LessSupport.js +21 -20
  144. package/src/sap/ui/core/plugin/TemplatingSupport.js +1 -1
  145. package/src/sap/ui/core/postmessage/Bus.js +1 -1
  146. package/src/sap/ui/core/postmessage/confirmationDialog.js +1 -1
  147. package/src/sap/ui/core/search/OpenSearchProvider.js +1 -1
  148. package/src/sap/ui/core/search/SearchProvider.js +1 -1
  149. package/src/sap/ui/core/service/Service.js +1 -1
  150. package/src/sap/ui/core/service/ServiceFactory.js +1 -1
  151. package/src/sap/ui/core/service/ServiceFactoryRegistry.js +1 -1
  152. package/src/sap/ui/core/support/Plugin.js +1 -1
  153. package/src/sap/ui/core/support/Support.js +1 -1
  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/LocalBusyIndicator.less +3 -3
  163. package/src/sap/ui/core/themes/base/fonts/SAP-icons.woff2 +0 -0
  164. package/src/sap/ui/core/theming/Parameters.js +31 -12
  165. package/src/sap/ui/core/theming/ThemeHelper.js +56 -1
  166. package/src/sap/ui/core/theming/ThemeManager.js +817 -0
  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/serializer/HTMLViewSerializer.js +2 -1
  184. package/src/sap/ui/core/util/serializer/Serializer.js +1 -1
  185. package/src/sap/ui/core/util/serializer/ViewSerializer.js +1 -1
  186. package/src/sap/ui/core/util/serializer/XMLViewSerializer.js +1 -1
  187. package/src/sap/ui/core/util/serializer/delegate/Delegate.js +1 -1
  188. package/src/sap/ui/core/util/serializer/delegate/HTML.js +1 -1
  189. package/src/sap/ui/core/util/serializer/delegate/XML.js +1 -1
  190. package/src/sap/ui/core/ws/ReadyState.js +1 -1
  191. package/src/sap/ui/core/ws/SapPcpWebSocket.js +1 -1
  192. package/src/sap/ui/core/ws/WebSocket.js +1 -1
  193. package/src/sap/ui/debug/ControlTree.js +1 -1
  194. package/src/sap/ui/debug/DebugEnv.js +1 -1
  195. package/src/sap/ui/debug/PropertyList.js +1 -1
  196. package/src/sap/ui/dom/getFirstEditableInput.js +25 -6
  197. package/src/sap/ui/dom/includeStylesheet.js +2 -2
  198. package/src/sap/ui/model/ClientListBinding.js +11 -4
  199. package/src/sap/ui/model/ClientModel.js +1 -1
  200. package/src/sap/ui/model/ClientTreeBinding.js +60 -5
  201. package/src/sap/ui/model/CompositeDataState.js +1 -1
  202. package/src/sap/ui/model/CompositeType.js +1 -1
  203. package/src/sap/ui/model/DataState.js +1 -1
  204. package/src/sap/ui/model/Filter.js +6 -6
  205. package/src/sap/ui/model/MetaModel.js +1 -1
  206. package/src/sap/ui/model/Model.js +1 -1
  207. package/src/sap/ui/model/SelectionModel.js +1 -1
  208. package/src/sap/ui/model/SimpleType.js +1 -1
  209. package/src/sap/ui/model/Sorter.js +6 -4
  210. package/src/sap/ui/model/TreeAutoExpandMode.js +1 -1
  211. package/src/sap/ui/model/TreeBinding.js +18 -0
  212. package/src/sap/ui/model/TreeBindingCompatibilityAdapter.js +1 -1
  213. package/src/sap/ui/model/Type.js +1 -1
  214. package/src/sap/ui/model/analytics/AnalyticalTreeBindingAdapter.js +28 -34
  215. package/src/sap/ui/model/controlhelper/TreeBindingProxy.js +590 -0
  216. package/src/sap/ui/model/json/JSONModel.js +1 -1
  217. package/src/sap/ui/model/message/MessageModel.js +1 -1
  218. package/src/sap/ui/model/odata/ODataAnnotations.js +1 -1
  219. package/src/sap/ui/model/odata/ODataMessageParser.js +1 -1
  220. package/src/sap/ui/model/odata/ODataMetaModel.js +1 -1
  221. package/src/sap/ui/model/odata/ODataMetadata.js +1 -1
  222. package/src/sap/ui/model/odata/ODataModel.js +1 -1
  223. package/src/sap/ui/model/odata/type/Boolean.js +1 -1
  224. package/src/sap/ui/model/odata/type/Byte.js +1 -1
  225. package/src/sap/ui/model/odata/type/Currency.js +1 -1
  226. package/src/sap/ui/model/odata/type/Date.js +1 -1
  227. package/src/sap/ui/model/odata/type/DateTime.js +1 -1
  228. package/src/sap/ui/model/odata/type/DateTimeBase.js +1 -1
  229. package/src/sap/ui/model/odata/type/DateTimeOffset.js +1 -1
  230. package/src/sap/ui/model/odata/type/DateTimeWithTimezone.js +1 -1
  231. package/src/sap/ui/model/odata/type/Decimal.js +1 -1
  232. package/src/sap/ui/model/odata/type/Double.js +1 -1
  233. package/src/sap/ui/model/odata/type/Guid.js +1 -1
  234. package/src/sap/ui/model/odata/type/Int.js +1 -1
  235. package/src/sap/ui/model/odata/type/Int16.js +1 -1
  236. package/src/sap/ui/model/odata/type/Int32.js +1 -1
  237. package/src/sap/ui/model/odata/type/Int64.js +1 -1
  238. package/src/sap/ui/model/odata/type/ODataType.js +1 -1
  239. package/src/sap/ui/model/odata/type/Raw.js +1 -1
  240. package/src/sap/ui/model/odata/type/SByte.js +1 -1
  241. package/src/sap/ui/model/odata/type/Single.js +1 -1
  242. package/src/sap/ui/model/odata/type/Stream.js +1 -1
  243. package/src/sap/ui/model/odata/type/String.js +1 -1
  244. package/src/sap/ui/model/odata/type/Time.js +1 -1
  245. package/src/sap/ui/model/odata/type/TimeOfDay.js +1 -1
  246. package/src/sap/ui/model/odata/type/Unit.js +1 -1
  247. package/src/sap/ui/model/odata/v2/BatchMode.js +2 -2
  248. package/src/sap/ui/model/odata/v2/Context.js +169 -4
  249. package/src/sap/ui/model/odata/v2/ODataAnnotations.js +1 -1
  250. package/src/sap/ui/model/odata/v2/ODataListBinding.js +39 -17
  251. package/src/sap/ui/model/odata/v2/ODataModel.js +219 -82
  252. package/src/sap/ui/model/odata/v2/ODataTreeBinding.js +1 -1
  253. package/src/sap/ui/model/odata/v4/Context.js +35 -22
  254. package/src/sap/ui/model/odata/v4/ODataBinding.js +28 -22
  255. package/src/sap/ui/model/odata/v4/ODataContextBinding.js +6 -6
  256. package/src/sap/ui/model/odata/v4/ODataListBinding.js +111 -89
  257. package/src/sap/ui/model/odata/v4/ODataMetaModel.js +5 -4
  258. package/src/sap/ui/model/odata/v4/ODataModel.js +84 -46
  259. package/src/sap/ui/model/odata/v4/ODataParentBinding.js +19 -20
  260. package/src/sap/ui/model/odata/v4/ODataPropertyBinding.js +3 -3
  261. package/src/sap/ui/model/odata/v4/_AnnotationHelperExpression.js +1 -1
  262. package/src/sap/ui/model/odata/v4/lib/_AggregationCache.js +12 -5
  263. package/src/sap/ui/model/odata/v4/lib/_Cache.js +130 -64
  264. package/src/sap/ui/model/odata/v4/lib/_Helper.js +1 -1
  265. package/src/sap/ui/model/odata/v4/lib/_Requestor.js +56 -15
  266. package/src/sap/ui/model/resource/ResourceModel.js +1 -1
  267. package/src/sap/ui/model/type/Boolean.js +1 -1
  268. package/src/sap/ui/model/type/Currency.js +1 -1
  269. package/src/sap/ui/model/type/Date.js +1 -1
  270. package/src/sap/ui/model/type/DateInterval.js +1 -1
  271. package/src/sap/ui/model/type/DateTime.js +1 -1
  272. package/src/sap/ui/model/type/DateTimeInterval.js +1 -1
  273. package/src/sap/ui/model/type/FileSize.js +1 -1
  274. package/src/sap/ui/model/type/Float.js +1 -1
  275. package/src/sap/ui/model/type/Integer.js +1 -1
  276. package/src/sap/ui/model/type/String.js +1 -1
  277. package/src/sap/ui/model/type/Time.js +1 -1
  278. package/src/sap/ui/model/type/TimeInterval.js +1 -1
  279. package/src/sap/ui/model/type/Unit.js +1 -1
  280. package/src/sap/ui/model/xml/XMLModel.js +1 -1
  281. package/src/sap/ui/qunit/utils/ControlIterator.js +1 -1
  282. package/src/sap/ui/qunit/utils/MemoryLeakCheck.js +1 -1
  283. package/src/sap/ui/test/TestUtils.js +20 -0
  284. package/src/sap/ui/test/generic/TestBase.js +1 -1
  285. package/src/sap/ui/thirdparty/mobify-carousel.js +0 -4
  286. package/src/sap/ui/util/Storage.js +1 -1
  287. package/src/sap/ui/core/ThemeCheck.js +0 -389
@@ -15,6 +15,7 @@ sap.ui.define([
15
15
  "sap/ui/model/odata/ODataUtils"
16
16
  ], function (_GroupLock, _Helper, _Requestor, Log, isEmptyObject, SyncPromise, ODataUtils) {
17
17
  "use strict";
18
+ /*eslint max-nested-callbacks: 0 */
18
19
 
19
20
  var sClassName = "sap.ui.model.odata.v4.lib._Cache",
20
21
  // Matches if ending with a transient key predicate:
@@ -24,9 +25,9 @@ sap.ui.define([
24
25
  rInactive = /^\$inactive\./,
25
26
  sMessagesAnnotation = "@com.sap.vocabularies.Common.v1.Messages",
26
27
  rNumber = /^-?\d+$/,
27
- // Matches two cases: segment with predicate or simply predicate:
28
+ // Matches two cases: segment with predicate or simply predicate:
28
29
  // EMPLOYEE(ID='42') -> aMatches[1] === "EMPLOYEE", aMatches[2] === "(ID='42')"
29
- // (ID='42') -> aMatches[1] === "", aMatches[2] === "(ID='42')"
30
+ // (ID='42') -> aMatches[1] === "", aMatches[2] === "(ID='42')"
30
31
  rSegmentWithPredicate = /^([^(]*)(\(.*\))$/;
31
32
 
32
33
  /**
@@ -136,7 +137,7 @@ sap.ui.define([
136
137
  * A lock for the group ID to be used for the DELETE request; w/o a lock, no DELETE is sent.
137
138
  * For a transient entity, the lock is ignored (use NULL)!
138
139
  * @param {string} sEditUrl
139
- * The entity's edit URL to be used for the DELETE request; w/o a lock, this is mostly
140
+ * The entity's edit URL to be used for the DELETE request; w/o a lock, this is mostly
140
141
  * ignored.
141
142
  * @param {string} sPath
142
143
  * The entity's path within the cache (as used by change listeners)
@@ -144,10 +145,6 @@ sap.ui.define([
144
145
  * An entity with the ETag of the binding for which the deletion was requested. This is
145
146
  * provided if the deletion is delegated from a context binding with empty path to a list
146
147
  * binding. W/o a lock, this is ignored.
147
- * @param {boolean} [bDoNotRequestCount]
148
- * Whether not to request the new count from the server; useful in case of
149
- * {@link sap.ui.model.odata.v4.Context#replaceWith} where it is known that the count remains
150
- * unchanged; only used when deleting from an entity collection
151
148
  * @param {function} [fnCallback]
152
149
  * A function which is called immediately when an entity has been deleted from the cache, or
153
150
  * when it was re-inserted due to an error; only used when deleting from an entity collection,
@@ -160,8 +157,7 @@ sap.ui.define([
160
157
  *
161
158
  * @public
162
159
  */
163
- _Cache.prototype._delete = function (oGroupLock, sEditUrl, sPath, oETagEntity,
164
- bDoNotRequestCount, fnCallback) {
160
+ _Cache.prototype._delete = function (oGroupLock, sEditUrl, sPath, oETagEntity, fnCallback) {
165
161
  var aSegments = sPath.split("/"),
166
162
  vDeleteProperty = aSegments.pop(),
167
163
  sParentPath = aSegments.join("/"),
@@ -200,14 +196,7 @@ sap.ui.define([
200
196
  aMessages = oModelInterface.getMessagesByPath(
201
197
  _Helper.buildPath("/", that.sResourcePath, sEntityPath), true);
202
198
 
203
- if (aMessages.length) {
204
- aMessages = aMessages.filter(function (oMessage) {
205
- return !oMessage.persistent;
206
- });
207
- _Helper.setPrivateAnnotation(oEntity, "messages", aMessages);
208
- }
209
-
210
- oModelInterface.reportStateMessages(that.sResourcePath, {}, [sEntityPath]);
199
+ oModelInterface.fireMessageChange({oldMessages : aMessages});
211
200
 
212
201
  oEntity["@$ui5.context.isDeleted"] = true;
213
202
  if (Array.isArray(vCacheData)) {
@@ -220,23 +209,16 @@ sap.ui.define([
220
209
  sEditUrl += that.oRequestor.buildQueryString(that.sMetaPath, that.mQueryOptions, true);
221
210
  // the existence of an onCancel callback causes a pending change in the requestor
222
211
  oRequestPromise = oGroupLock
223
- ? that.oRequestor.request("DELETE", sEditUrl, oGroupLock.getUnlockedCopy(),
224
- mHeaders, undefined, undefined, /*onCancel*/function () {}, undefined,
212
+ ? that.oRequestor.request("DELETE", sEditUrl, oGroupLock, mHeaders, undefined,
213
+ undefined, /*onCancel*/function () {}, undefined,
225
214
  _Helper.buildPath(that.getOriginalResourcePath(oEntity), sEntityPath))
226
215
  : SyncPromise.resolve();
227
216
  _Helper.addByPath(that.mChangeRequests, sEntityPath, oRequestPromise);
228
- return SyncPromise.all([
229
- oRequestPromise.catch(function (oError) {
230
- if (oError.status !== 404) {
231
- throw oError;
232
- } // else: map 404 to 200
233
- }),
234
- iIndex === undefined // single element or kept-alive not in list
235
- && !bDoNotRequestCount
236
- && that.requestCount(oGroupLock || that.oRequestor.lockGroup("$auto", that)),
237
- oGroupLock && oGroupLock.unlock() // unlock when all requests have been queued
238
- ]).then(function () {
239
- _Helper.deletePrivateAnnotation(oEntity, "messages");
217
+ return oRequestPromise.catch(function (oError) {
218
+ if (oError.status !== 404) {
219
+ throw oError;
220
+ } // else: map 404 to 200
221
+ }).then(function () {
240
222
  if (Array.isArray(vCacheData)) {
241
223
  vCacheData.$deleted.splice(vCacheData.$deleted.indexOf(oDeleted), 1);
242
224
  delete vCacheData.$byPredicate[sKeyPredicate];
@@ -249,13 +231,16 @@ sap.ui.define([
249
231
  oEntity["$ui5.deleted"] = true;
250
232
  }
251
233
  }, function (oError) {
252
- var iDeletedIndex,
253
- aMessages = _Helper.getPrivateAnnotation(oEntity, "messages");
234
+ var iDeletedIndex;
254
235
 
255
- if (aMessages) {
236
+ if (aMessages.length) {
237
+ if (!oError.canceled) {
238
+ aMessages = aMessages.filter(function (oMessage) {
239
+ return !oMessage.persistent;
240
+ });
241
+ }
256
242
  oModelInterface.fireMessageChange({newMessages : aMessages});
257
243
  }
258
- _Helper.deletePrivateAnnotation(oEntity, "messages");
259
244
 
260
245
  delete oEntity["@$ui5.context.isDeleted"];
261
246
  if (Array.isArray(vCacheData)) {
@@ -271,7 +256,14 @@ sap.ui.define([
271
256
  that.iActiveElements += 1;
272
257
  }
273
258
  }
274
- fnCallback(iIndex, 1);
259
+ if (that.iActiveUsages) {
260
+ fnCallback(iIndex, 1);
261
+ } else if (iIndex === undefined) {
262
+ // an active cache must let the binding reset to be told about kept-alive
263
+ // elements, an inactive cache however has no binding and no kept-alive
264
+ // elements
265
+ that.reset([]);
266
+ }
275
267
  }
276
268
  throw oError;
277
269
  }).finally(function () {
@@ -282,11 +274,12 @@ sap.ui.define([
282
274
 
283
275
  /**
284
276
  * Adds an entry about a deleted entity to <code>aElements.$deleted</code>. Ensures that the
285
- * entries are ordered by entity index and deletion order (if two entities were deleted on the
286
- * same index, the second one must be behind).
277
+ * entries are ordered ascending by entity index and deletion order (if two entities were
278
+ * deleted on the same index, the second one must be behind). Entities w/o index are placed at
279
+ * the start.
287
280
  *
288
281
  * @param {object[]} aElements - The elements collection
289
- * @param {number} iIndex - The entity's index
282
+ * @param {number} [iIndex] - The entity's index, undefined if it was not in the collection
290
283
  * @param {string} sPredicate - The entity's key predicate
291
284
  * @param {sap.ui.model.odata.v4.lib._GroupLock|undefined} oGroupLock - The deletion group lock
292
285
  * @param {boolean} bCreated - Whether the entity was created
@@ -304,12 +297,16 @@ sap.ui.define([
304
297
  i;
305
298
 
306
299
  aElements.$deleted = aElements.$deleted || [];
307
- for (i = 0; i < aElements.$deleted.length; i += 1) {
308
- if (iIndex < aElements.$deleted[i].index) {
309
- break;
300
+ if (iIndex === undefined) {
301
+ aElements.$deleted.unshift(oDeleted);
302
+ } else {
303
+ for (i = 0; i < aElements.$deleted.length; i += 1) {
304
+ if (iIndex < aElements.$deleted[i].index) {
305
+ break;
306
+ }
310
307
  }
308
+ aElements.$deleted.splice(i, 0, oDeleted);
311
309
  }
312
- aElements.$deleted.splice(i, 0, oDeleted);
313
310
  return oDeleted;
314
311
  };
315
312
 
@@ -336,7 +333,8 @@ sap.ui.define([
336
333
  *
337
334
  * @param {string} sPath The path of the collection in the cache
338
335
  * @param {object[]} aElements The collection
339
- * @param {number} iIndex The index at which the element has been inserted or removed
336
+ * @param {number} [iIndex]
337
+ * The index at which the element has been inserted or removed; undefined if not in the list
340
338
  * @param {number} iOffset The offset (1 = insert, -1 = remove)
341
339
  * @param {number} iDeletedIndex The element's index in $deleted (only for re-insertion)
342
340
  * @param {boolean} bCreate Whether the insert is a create (and not reverting a delete)
@@ -345,6 +343,9 @@ sap.ui.define([
345
343
  */
346
344
  _Cache.prototype.adjustIndexes = function (sPath, aElements, iIndex, iOffset, iDeletedIndex,
347
345
  bCreate) {
346
+ if (iIndex === undefined) {
347
+ return; // not in the list -> nothing to adjust
348
+ }
348
349
  if (!sPath) {
349
350
  // If the path is empty, we are in a _CollectionCache and aReadRequest exists
350
351
  this.aReadRequests.forEach(function (oReadRequest) {
@@ -835,7 +836,7 @@ sap.ui.define([
835
836
 
836
837
  function onSubmit() {
837
838
  bDataRequested = true;
838
- that.oRequestor.getModelInterface().fireDataRequested();
839
+ that.oRequestor.getModelInterface().fireDataRequested("/" + sFullResourcePath);
839
840
  }
840
841
 
841
842
  /*
@@ -942,11 +943,13 @@ sap.ui.define([
942
943
  aUpdateProperties);
943
944
  if (bDataRequested) {
944
945
  bDataRequested = false;
945
- that.oRequestor.getModelInterface().fireDataReceived();
946
+ that.oRequestor.getModelInterface()
947
+ .fireDataReceived(undefined, "/" + sFullResourcePath);
946
948
  }
947
949
  }).catch(function (oError) {
948
950
  if (bDataRequested) {
949
- that.oRequestor.getModelInterface().fireDataReceived(oError);
951
+ that.oRequestor
952
+ .getModelInterface().fireDataReceived(oError, "/" + sFullResourcePath);
950
953
  }
951
954
  throw oError;
952
955
  }).finally(function () { // clean up only after updateSelected!
@@ -1199,7 +1202,7 @@ sap.ui.define([
1199
1202
  * The relative path of a binding; must not end with '/'
1200
1203
  * @param {boolean} [bIgnoreKeptAlive]
1201
1204
  * Whether to ignore changes which will not be lost by APIs like sort or filter because they
1202
- * relate to a context which is kept alive
1205
+ * relate to a deleted context or a context which is kept alive
1203
1206
  * @param {boolean} [bIgnoreTransient]
1204
1207
  * Whether to ignore transient elements on top level which will not be lost by APIs like sort
1205
1208
  * or filter
@@ -1216,8 +1219,9 @@ sap.ui.define([
1216
1219
  return Object.keys(this.mChangeRequests).some(function (sRequestPath) {
1217
1220
  return _Helper.hasPathPrefix(sRequestPath, sPath)
1218
1221
  && !(bIgnoreKeptAlive
1219
- && that.mChangeRequests[sRequestPath].every(function (oPatchPromise) {
1220
- return oPatchPromise.$isKeepAlive();
1222
+ && that.mChangeRequests[sRequestPath].every(function (oChangePromise) {
1223
+ // w/o $isKeepAlive it is a DELETE
1224
+ return !oChangePromise.$isKeepAlive || oChangePromise.$isKeepAlive();
1221
1225
  }));
1222
1226
  }) || Object.keys(this.mPostRequests).some(function (sRequestPath) {
1223
1227
  return bIgnoreTransient && !sRequestPath
@@ -1249,7 +1253,7 @@ sap.ui.define([
1249
1253
  * A promise to be resolved with the patched data
1250
1254
  * @throws {Error} If the cache is shared
1251
1255
  *
1252
- * @private
1256
+ * @public
1253
1257
  */
1254
1258
  _Cache.prototype.patch = function (sPath, oData) {
1255
1259
  var that = this;
@@ -1280,7 +1284,8 @@ sap.ui.define([
1280
1284
  * The function is called just before the back-end request is sent.
1281
1285
  * If no back-end request is needed, the function is not called.
1282
1286
  * @returns {sap.ui.base.SyncPromise}
1283
- * A promise which resolves without a defined result when it is updated in the cache.
1287
+ * A promise which resolves without a defined result when it is updated in the cache; it
1288
+ * rejects with an error when no key predicate is known.
1284
1289
  * @throws {Error} If the cache is shared
1285
1290
  *
1286
1291
  * @public
@@ -1298,6 +1303,9 @@ sap.ui.define([
1298
1303
  if (iIndex !== undefined) {
1299
1304
  sPredicate = _Helper.getPrivateAnnotation(aElements[iIndex], "predicate");
1300
1305
  }
1306
+ if (!sPredicate) { // Note: no need to give path here, error is wrapped by ODLB!
1307
+ throw new Error("No key predicate known");
1308
+ }
1301
1309
  sReadUrl = _Helper.buildPath(that.sResourcePath, sPath, sPredicate);
1302
1310
  if (bKeepAlive && that.mLateQueryOptions) {
1303
1311
  // bKeepAlive === true -> own cache of the list binding -> sPath === ''
@@ -1354,7 +1362,7 @@ sap.ui.define([
1354
1362
  * <code>false</code>
1355
1363
  * @returns {sap.ui.base.SyncPromise}
1356
1364
  * A promise which resolves with <code>undefined</code> when the entity is updated in
1357
- * the cache.
1365
+ * the cache; it rejects with an error when no key predicate is known.
1358
1366
  * @throws {Error} If the cache is shared
1359
1367
  *
1360
1368
  * @private
@@ -1384,6 +1392,9 @@ sap.ui.define([
1384
1392
  if (iIndex !== undefined) {
1385
1393
  oEntity = aElements[iIndex];
1386
1394
  sPredicate = _Helper.getPrivateAnnotation(oEntity, "predicate");
1395
+ if (!sPredicate) { // Note: no need to give path here, error is wrapped by ODLB!
1396
+ throw new Error("No key predicate known");
1397
+ }
1387
1398
  } else {
1388
1399
  oEntity = aElements.$byPredicate[sPredicate];
1389
1400
  }
@@ -1536,7 +1547,7 @@ sap.ui.define([
1536
1547
  * @public
1537
1548
  */
1538
1549
  _Cache.prototype.removeMessages = function () {
1539
- if (this.sReportedMessagesPath) {
1550
+ if (this.sReportedMessagesPath) { // Note: never set if the cache shares requests
1540
1551
  this.oRequestor.getModelInterface().reportStateMessages(this.sReportedMessagesPath, {});
1541
1552
  this.sReportedMessagesPath = undefined;
1542
1553
  }
@@ -1602,7 +1613,7 @@ sap.ui.define([
1602
1613
  }
1603
1614
  _Helper.restoreUpdatingProperties(oOldElement, oElement);
1604
1615
 
1605
- // Note: iStart is not needed here because we know we have key predicates
1616
+ // Note: iStart is not needed here because we know we have a key predicate
1606
1617
  this.visitResponse(oElement, mTypeForMetaPath,
1607
1618
  _Helper.getMetaPath(_Helper.buildPath(this.sMetaPath, sPath)), sPath + sPredicate);
1608
1619
  };
@@ -1612,11 +1623,10 @@ sap.ui.define([
1612
1623
  *
1613
1624
  * @param {sap.ui.model.odata.v4.lib._GroupLock} oGroupLock
1614
1625
  * A lock for the group ID
1615
- * @returns {Promise|undefined}
1616
- * A promise that resolves if the count has been determined or <code>undefined</code> if no
1617
- * request needed
1626
+ * @returns {Promise<number>}
1627
+ * A promise that resolves with the count regardless whether a request was needed
1618
1628
  *
1619
- * @private
1629
+ * @public
1620
1630
  */
1621
1631
  _Cache.prototype.requestCount = function (oGroupLock) {
1622
1632
  var sExclusiveFilter, mQueryOptions, sReadUrl,
@@ -1651,8 +1661,11 @@ sap.ui.define([
1651
1661
 
1652
1662
  setCount(that.mChangeListeners, "", that.aElements, iCount);
1653
1663
  that.iLimit = iCount;
1664
+ return iCount;
1654
1665
  });
1655
1666
  }
1667
+
1668
+ return Promise.resolve(that.iLimit);
1656
1669
  };
1657
1670
 
1658
1671
  /**
@@ -1662,13 +1675,15 @@ sap.ui.define([
1662
1675
  * The path
1663
1676
  * @throws {Error}
1664
1677
  * If there is a change which has been sent to the server and for which there is no response
1665
- * yet.
1678
+ * yet, or if the cache is shared
1666
1679
  *
1667
1680
  * @public
1668
1681
  */
1669
1682
  _Cache.prototype.resetChangesForPath = function (sPath) {
1670
1683
  var that = this;
1671
1684
 
1685
+ this.checkSharedRequest();
1686
+
1672
1687
  Object.keys(this.mChangeRequests).reverse().forEach(function (sRequestPath) {
1673
1688
  var aPromises, i;
1674
1689
 
@@ -1732,6 +1747,7 @@ sap.ui.define([
1732
1747
  * @see #hasSentRequest
1733
1748
  */
1734
1749
  _Cache.prototype.setLateQueryOptions = function (mQueryOptions) {
1750
+ // this.checkSharedRequest(); // don't do that here! it might work well enough
1735
1751
  if (mQueryOptions) {
1736
1752
  this.mLateQueryOptions = {
1737
1753
  // must contain both properties for requestSideEffects
@@ -1855,7 +1871,8 @@ sap.ui.define([
1855
1871
  * @param {string} [sEntityPath]
1856
1872
  * Path of the entity, relative to the cache (as used by change listeners)
1857
1873
  * @param {string} [sUnitOrCurrencyPath]
1858
- * Path of the unit or currency for the property, relative to the entity
1874
+ * Path of the unit or currency for the property, relative to the (entity or complex) type
1875
+ * which contains the property to update
1859
1876
  * @param {boolean} [bPatchWithoutSideEffects]
1860
1877
  * Whether the PATCH response is ignored, except for a new ETag
1861
1878
  * @param {function} fnPatchSent
@@ -2073,6 +2090,8 @@ sap.ui.define([
2073
2090
  // write the changed value into the cache
2074
2091
  _Helper.updateAll(that.mChangeListeners, sEntityPath, oEntity, oUpdateData);
2075
2092
  if (sUnitOrCurrencyPath) {
2093
+ sUnitOrCurrencyPath
2094
+ = _Helper.buildPath(aPropertyPath.slice(0, -1).join("/"), sUnitOrCurrencyPath);
2076
2095
  aUnitOrCurrencyPath = sUnitOrCurrencyPath.split("/");
2077
2096
  sUnitOrCurrencyPath = _Helper.buildPath(sEntityPath, sUnitOrCurrencyPath);
2078
2097
  sUnitOrCurrencyValue = that.getValue(sUnitOrCurrencyPath);
@@ -2121,6 +2140,8 @@ sap.ui.define([
2121
2140
  * @param {number} [iStart]
2122
2141
  * The index in the collection where "oRoot.value" needs to be inserted or undefined if
2123
2142
  * "oRoot" references a single entity
2143
+ * @throws {Error}
2144
+ * If the cache is shared and OData messages would be reported
2124
2145
  *
2125
2146
  * @private
2126
2147
  */
@@ -2141,6 +2162,7 @@ sap.ui.define([
2141
2162
  function addMessages(aMessages, sInstancePath, sContextUrl) {
2142
2163
  bHasMessages = true;
2143
2164
  if (aMessages && aMessages.length) {
2165
+ that.checkSharedRequest();
2144
2166
  mPathToODataMessages[sInstancePath] = aMessages;
2145
2167
  aMessages.forEach(function (oMessage) {
2146
2168
  if (oMessage.longtextUrl) {
@@ -2280,7 +2302,7 @@ sap.ui.define([
2280
2302
  } else if (oRoot && typeof oRoot === "object") {
2281
2303
  visitInstance(oRoot, sRootMetaPath || this.sMetaPath, sRootPath || "", sRequestUrl);
2282
2304
  }
2283
- if (bHasMessages) {
2305
+ if (bHasMessages && !this.bSharedRequest) {
2284
2306
  this.sReportedMessagesPath = this.getOriginalResourcePath(oRoot);
2285
2307
  this.oRequestor.getModelInterface().reportStateMessages(this.sReportedMessagesPath,
2286
2308
  mPathToODataMessages, aCachePaths);
@@ -2345,10 +2367,13 @@ sap.ui.define([
2345
2367
  * Adds the element to $byPredicate of the cache's element list.
2346
2368
  *
2347
2369
  * @param {object} oElement - The element
2370
+ * @throws {Error}
2371
+ * If the cache is shared
2348
2372
  *
2349
2373
  * @public
2350
2374
  */
2351
2375
  _CollectionCache.prototype.addKeptElement = function (oElement) {
2376
+ this.checkSharedRequest();
2352
2377
  this.aElements.$byPredicate[_Helper.getPrivateAnnotation(oElement, "predicate")] = oElement;
2353
2378
  };
2354
2379
 
@@ -2386,12 +2411,15 @@ sap.ui.define([
2386
2411
  *
2387
2412
  * @param {string} sPredicate - The predicate
2388
2413
  * @returns {object} The empty element
2414
+ * @throws {Error}
2415
+ * If the cache is shared
2389
2416
  *
2390
2417
  * @public
2391
2418
  */
2392
2419
  _CollectionCache.prototype.createEmptyElement = function (sPredicate) {
2393
2420
  var oElement = {};
2394
2421
 
2422
+ this.checkSharedRequest();
2395
2423
  _Helper.setPrivateAnnotation(oElement, "predicate", sPredicate);
2396
2424
  this.aElements.$byPredicate[sPredicate] = oElement;
2397
2425
 
@@ -2403,12 +2431,15 @@ sap.ui.define([
2403
2431
  *
2404
2432
  * @param {number} iIndex - The index
2405
2433
  * @param {object} oElement - The new element
2434
+ * @throws {Error}
2435
+ * If the cache is shared
2406
2436
  *
2407
2437
  * @public
2408
2438
  */
2409
2439
  _CollectionCache.prototype.doReplaceWith = function (iIndex, oElement) {
2410
2440
  var oOldElement = this.aElements[iIndex];
2411
2441
 
2442
+ this.checkSharedRequest();
2412
2443
  if (oOldElement && _Helper.hasPrivateAnnotation(oOldElement, "transientPredicate")
2413
2444
  && !_Helper.hasPrivateAnnotation(oElement, "transientPredicate")) {
2414
2445
  // when replacing a created element (w/ transientPredicate), make sure the replacement
@@ -2767,6 +2798,20 @@ sap.ui.define([
2767
2798
  return iOffset;
2768
2799
  };
2769
2800
 
2801
+ /**
2802
+ * Returns whether there are pending deletions in any group but the given one.
2803
+ *
2804
+ * @param {string} sGroupId - The ID of the allowed group
2805
+ * @returns {boolean} Whether there are such pending deletions
2806
+ *
2807
+ * @public
2808
+ */
2809
+ _CollectionCache.prototype.isDeletingInOtherGroup = function (sGroupId) {
2810
+ return Object.values(this.aElements.$deleted || {}).some(function (oDeleted) {
2811
+ return oDeleted.sGroupId !== sGroupId;
2812
+ });
2813
+ };
2814
+
2770
2815
  /**
2771
2816
  * Returns a promise to be resolved with an OData object for a range of the requested data.
2772
2817
  * Calculates the key predicates for all entities in the result before the promise is resolved.
@@ -2893,6 +2938,8 @@ sap.ui.define([
2893
2938
  * @returns {sap.ui.base.SyncPromise|undefined}
2894
2939
  * A promise resolving without a defined result, or rejecting with an error if the refresh
2895
2940
  * fails, or <code>undefined</code> if there are no kept-alive elements.
2941
+ * @throws {Error}
2942
+ * If the cache is shared
2896
2943
  *
2897
2944
  * @public
2898
2945
  */
@@ -2948,6 +2995,7 @@ sap.ui.define([
2948
2995
  && !that.hasPendingChangesForPath(sPredicate);
2949
2996
  }
2950
2997
 
2998
+ this.checkSharedRequest();
2951
2999
  if (aPredicates.length === 0) {
2952
3000
  return undefined;
2953
3001
  }
@@ -2970,7 +3018,7 @@ sap.ui.define([
2970
3018
  mStillAliveElements[sPredicate]);
2971
3019
  } else {
2972
3020
  oElement = that.aElements.$byPredicate[sPredicate];
2973
- if (_Helper.getPrivateAnnotation(oElement, "transientPredicate")) {
3021
+ if (_Helper.hasPrivateAnnotation(oElement, "transientPredicate")) {
2974
3022
  iIndex = that.removeElement(that.aElements, -1, sPredicate, "");
2975
3023
  } else {
2976
3024
  delete that.aElements.$byPredicate[sPredicate];
@@ -3195,7 +3243,7 @@ sap.ui.define([
3195
3243
  /**
3196
3244
  * Resets this cache to its initial state, but keeps certain elements and their change listeners
3197
3245
  * alive: all kept-alive elements identified by the given key predicates as well as all
3198
- * transient elements on top level.
3246
+ * transient and deleted elements on top level.
3199
3247
  *
3200
3248
  * @param {string[]} aKeptElementPredicates
3201
3249
  * The key predicates for all kept-alive elements
@@ -3203,6 +3251,8 @@ sap.ui.define([
3203
3251
  * The group ID used for a side-effects refresh; if given, only inline creation
3204
3252
  * rows and transient elements with a different batch group shall be kept in place and a
3205
3253
  * backup shall be remembered for a later {@link #restore}
3254
+ * @throws {Error}
3255
+ * If a cache is shared and a group ID is given
3206
3256
  *
3207
3257
  * @public
3208
3258
  * @see _Cache#hasPendingChangesForPath
@@ -3217,6 +3267,7 @@ sap.ui.define([
3217
3267
  that = this;
3218
3268
 
3219
3269
  if (sGroupId) {
3270
+ this.checkSharedRequest();
3220
3271
  this.oBackup = {
3221
3272
  iActiveElements : this.iActiveElements,
3222
3273
  mChangeListeners : this.mChangeListeners,
@@ -3244,6 +3295,11 @@ sap.ui.define([
3244
3295
  this.iActiveElements -= 1;
3245
3296
  }
3246
3297
  }
3298
+ Object.keys(mByPredicate).forEach(function (sPredicate) {
3299
+ if ("@$ui5.context.isDeleted" in mByPredicate[sPredicate]) {
3300
+ aKeptElementPredicates.push(sPredicate);
3301
+ }
3302
+ });
3247
3303
  this.mChangeListeners = {};
3248
3304
  this.sContext = undefined;
3249
3305
  this.aElements.length = this.aElements.$created = iCreated;
@@ -3263,6 +3319,9 @@ sap.ui.define([
3263
3319
  this.mChangeListeners[""] = mChangeListeners[""];
3264
3320
  _Helper.fireChange(this.mChangeListeners, "");
3265
3321
  }
3322
+ Object.values(this.aElements.$deleted || {}).forEach(function (oDeleted) {
3323
+ oDeleted.index = undefined;
3324
+ });
3266
3325
  };
3267
3326
 
3268
3327
  /**
@@ -3270,11 +3329,14 @@ sap.ui.define([
3270
3329
  * really do so; drops the backup in any case to free memory.
3271
3330
  *
3272
3331
  * @param {boolean} bReally - Whether to really restore, not just drop the backup
3332
+ * @throws {Error}
3333
+ * If a shared cache is told to really restore
3273
3334
  *
3274
3335
  * @public
3275
3336
  */
3276
3337
  _CollectionCache.prototype.restore = function (bReally) {
3277
3338
  if (bReally) {
3339
+ this.checkSharedRequest();
3278
3340
  this.iActiveElements = this.oBackup.iActiveElements;
3279
3341
  this.mChangeListeners = this.oBackup.mChangeListeners;
3280
3342
  this.sContext = this.oBackup.sContext;
@@ -3725,6 +3787,8 @@ sap.ui.define([
3725
3787
  * order to allow that it may change.
3726
3788
  *
3727
3789
  * @param {string} sPath - The path to the property within the cache
3790
+ *
3791
+ * @private
3728
3792
  */
3729
3793
  _SingleCache.prototype.resetProperty = function (sPath) {
3730
3794
  var oData = this.oPromise.getResult();
@@ -3840,6 +3904,8 @@ sap.ui.define([
3840
3904
  * Resets the property for its own relative path within the singleton's single cache. This means
3841
3905
  * that the next #fetchValue will request the property again via #fetchLateProperty. Deletes
3842
3906
  * also the entity's ETag within the cache in order to allow that it may change.
3907
+ *
3908
+ * @public
3843
3909
  */
3844
3910
  _SingletonPropertyCache.prototype.reset = function () {
3845
3911
  this.oSingleton.resetProperty(this.sRelativePath);
@@ -1511,7 +1511,7 @@ sap.ui.define([
1511
1511
  *
1512
1512
  * Note: In case the meta path <code>sRootMetaPath</code> points to a single-valued
1513
1513
  * navigation property, for example "/SalesOrderList/SO_2_BP", this methods adds the key
1514
- * properties of the related entity type to the "$select" query options. Although this
1514
+ * properties of the related entity type to the "$select" query options. Although this is
1515
1515
  * not needed in order to obtain the correct nested entity it enables
1516
1516
  * {@link sap.ui.model.odata.v4.Context#requestSideEffects}) to check the consistency of the
1517
1517
  * key predicates.
@@ -454,7 +454,7 @@ sap.ui.define([
454
454
  }
455
455
 
456
456
  function isUsingStrictHandling(oRequest) {
457
- return oRequest.headers["Prefer"] === "handling=strict";
457
+ return oRequest.headers.Prefer === "handling=strict";
458
458
  }
459
459
 
460
460
  // do not look past aRequests.iChangeSet because these cannot be change sets
@@ -1043,6 +1043,32 @@ sap.ui.define([
1043
1043
  return this.lockGroup("$auto", oGroupLock.getOwner());
1044
1044
  };
1045
1045
 
1046
+ /**
1047
+ * Tells whether there are only PATCH requests with the "Prefer" header set to "return=minimal"
1048
+ * (results from using $$patchWithoutSideEffects=true) enqueued in the batch queue with the
1049
+ * given group ID.
1050
+ *
1051
+ * @param {string} sGroupId
1052
+ * The group ID
1053
+ * @returns {boolean}
1054
+ * Returns <code>true</code> if only PATCHes are enqueued in the batch queue with the given
1055
+ * group ID
1056
+ *
1057
+ * @private
1058
+ */
1059
+ _Requestor.prototype.hasOnlyPatchesWithoutSideEffects = function (sGroupId) {
1060
+ return this.getGroupSubmitMode(sGroupId) === "Auto"
1061
+ && !!this.mBatchQueue[sGroupId]
1062
+ && this.mBatchQueue[sGroupId].every(function (vChangeSetOrRequest) {
1063
+ // PATCH requests must be in a change set which is modeled as an array
1064
+ return Array.isArray(vChangeSetOrRequest)
1065
+ && vChangeSetOrRequest.every(function (oRequest) {
1066
+ return oRequest.method === "PATCH"
1067
+ && oRequest.headers.Prefer === "return=minimal";
1068
+ });
1069
+ });
1070
+ };
1071
+
1046
1072
  /**
1047
1073
  * Tells whether there are changes (that is, updates via PATCH or bound actions via POST) for
1048
1074
  * the given group ID and given entity.
@@ -1383,13 +1409,13 @@ sap.ui.define([
1383
1409
 
1384
1410
  /**
1385
1411
  * This function has two tasks:
1386
- * <ul>
1387
- * <li>We are in the 1st app start, no optimistic batch payload stored so far. If optimistic
1388
- * batch handling is enabled via
1389
- * {@link sap.ui.model.odata.v4.ODataModel#setOptimisticBatchEnabler}, this function
1390
- * stores the current batch requests in cache.
1391
- * <li>If an optimistic batch was already sent, it returns its result promise.
1392
- * </ul>
1412
+ * <ul>
1413
+ * <li> We are in the 1st app start, no optimistic batch payload stored so far. If optimistic
1414
+ * batch handling is enabled via
1415
+ * {@link sap.ui.model.odata.v4.ODataModel#setOptimisticBatchEnabler}, this function stores
1416
+ * the current batch requests in cache.
1417
+ * <li> If an optimistic batch was already sent, it returns its result promise.
1418
+ * </ul>
1393
1419
  *
1394
1420
  * @param {object[]} aRequests The requests of the current batch
1395
1421
  * @param {string} sGroupId The group ID
@@ -1397,12 +1423,12 @@ sap.ui.define([
1397
1423
  * The optimistic batch result or <code>undefined</code> if the batch should be sent
1398
1424
  * normally. <code>undefined</code> can have the following reasons:
1399
1425
  * <ul>
1400
- * <li>We are in the 1st app start, no optimistic batch payload stored so far, or
1401
- * <li>the optimistic batch was sent, but its payload did not match to the current one, or
1402
- * <li>we are not in the first #sendBatch call within the _Requestors lifecycle, or
1403
- * <li>#sendBatch was called before first batch payload could be read via CacheManager or
1404
- * <li>we are in the first #sendBatch but the batch is modifying, means contains others than
1405
- * GET requests.
1426
+ * <li> We are in the 1st app start, no optimistic batch payload stored so far, or
1427
+ * <li> the optimistic batch was sent, but its payload did not match to the current one, or
1428
+ * <li> we are not in the first #sendBatch call within the _Requestors lifecycle, or
1429
+ * <li> #sendBatch was called before first batch payload could be read via CacheManager or
1430
+ * <li> we are in the first #sendBatch but the batch is modifying, means contains others
1431
+ * than GET requests.
1406
1432
  * </ul>
1407
1433
  *
1408
1434
  * @private
@@ -2040,7 +2066,10 @@ sap.ui.define([
2040
2066
 
2041
2067
  /**
2042
2068
  * Waits until all group locks for the given group ID have been unlocked and submits the
2043
- * requests associated with this group ID in one batch request.
2069
+ * requests associated with this group ID in one batch request. If only PATCH requests are
2070
+ * enqueued (see {@link #hasOnlyPatchesWithoutSideEffects}), this will delay the execution to
2071
+ * wait for potential side effect requests triggered by
2072
+ * {@link sap.ui.core.Control#event:validateFieldGroup}.
2044
2073
  *
2045
2074
  * @param {string} sGroupId
2046
2075
  * The group ID
@@ -2064,7 +2093,19 @@ sap.ui.define([
2064
2093
  if (bBlocked) {
2065
2094
  Log.info("submitBatch('" + sGroupId + "') is waiting for locks", null, sClassName);
2066
2095
  }
2096
+
2067
2097
  return oPromise.then(function () {
2098
+ if (that.hasOnlyPatchesWithoutSideEffects(sGroupId)) {
2099
+ bBlocked = true;
2100
+ Log.info("submitBatch('" + sGroupId
2101
+ + "') is waiting for potential side effect requests", null, sClassName);
2102
+ return new Promise(function (fnResolve) {
2103
+ setTimeout(function () {
2104
+ fnResolve();
2105
+ }, 0);
2106
+ });
2107
+ }
2108
+ }).then(function () {
2068
2109
  if (bBlocked) {
2069
2110
  Log.info("submitBatch('" + sGroupId + "') continues", null, sClassName);
2070
2111
  }