@openui5/sap.ui.core 1.142.0 → 1.142.1

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (270) hide show
  1. package/REUSE.toml +1 -1
  2. package/THIRDPARTY.txt +2 -2
  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/Event.js +1 -1
  58. package/src/sap/ui/base/EventProvider.js +1 -1
  59. package/src/sap/ui/base/Interface.js +1 -1
  60. package/src/sap/ui/base/ManagedObject.js +1 -1
  61. package/src/sap/ui/base/ManagedObjectMetadata.js +1 -1
  62. package/src/sap/ui/base/Metadata.js +1 -1
  63. package/src/sap/ui/base/Object.js +1 -1
  64. package/src/sap/ui/base/ObjectPool.js +1 -1
  65. package/src/sap/ui/core/.library +4 -4
  66. package/src/sap/ui/core/BusyIndicator.js +1 -1
  67. package/src/sap/ui/core/Component.js +10 -1
  68. package/src/sap/ui/core/ComponentContainer.js +1 -1
  69. package/src/sap/ui/core/ComponentMetadata.js +1 -1
  70. package/src/sap/ui/core/ComponentSupport.js +1 -1
  71. package/src/sap/ui/core/Configuration.js +1 -1
  72. package/src/sap/ui/core/Control.js +1 -1
  73. package/src/sap/ui/core/Core.js +2 -2
  74. package/src/sap/ui/core/CustomData.js +1 -1
  75. package/src/sap/ui/core/DeclarativeSupport.js +1 -1
  76. package/src/sap/ui/core/Element.js +3 -2
  77. package/src/sap/ui/core/ElementMetadata.js +1 -1
  78. package/src/sap/ui/core/EnabledPropagator.js +1 -1
  79. package/src/sap/ui/core/EventBus.js +1 -1
  80. package/src/sap/ui/core/Fragment.js +1 -1
  81. package/src/sap/ui/core/HTML.js +1 -1
  82. package/src/sap/ui/core/History.js +1 -1
  83. package/src/sap/ui/core/Icon.js +1 -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 +1 -1
  97. package/src/sap/ui/core/Message.js +1 -1
  98. package/src/sap/ui/core/RenderManager.js +13 -2
  99. package/src/sap/ui/core/Renderer.js +1 -1
  100. package/src/sap/ui/core/ResizeHandler.js +1 -1
  101. package/src/sap/ui/core/ScrollBar.js +1 -1
  102. package/src/sap/ui/core/SeparatorItem.js +1 -1
  103. package/src/sap/ui/core/ShortcutHintsMixin.js +13 -1
  104. package/src/sap/ui/core/Title.js +1 -1
  105. package/src/sap/ui/core/TooltipBase.js +1 -1
  106. package/src/sap/ui/core/UIArea.js +1 -1
  107. package/src/sap/ui/core/UIComponent.js +1 -1
  108. package/src/sap/ui/core/UIComponentMetadata.js +1 -1
  109. package/src/sap/ui/core/ValueStateSupport.js +1 -1
  110. package/src/sap/ui/core/VariantLayoutData.js +1 -1
  111. package/src/sap/ui/core/XMLComposite.js +1 -1
  112. package/src/sap/ui/core/XMLCompositeMetadata.js +1 -1
  113. package/src/sap/ui/core/date/UI5Date.js +1 -1
  114. package/src/sap/ui/core/delegate/ItemNavigation.js +1 -1
  115. package/src/sap/ui/core/delegate/ScrollEnablement.js +1 -1
  116. package/src/sap/ui/core/dnd/DragDropBase.js +1 -1
  117. package/src/sap/ui/core/dnd/DragDropInfo.js +1 -1
  118. package/src/sap/ui/core/dnd/DragInfo.js +1 -1
  119. package/src/sap/ui/core/dnd/DropInfo.js +1 -1
  120. package/src/sap/ui/core/format/FormatUtils.js +1 -1
  121. package/src/sap/ui/core/format/TimezoneUtil.js +1 -1
  122. package/src/sap/ui/core/getCompatibilityVersion.js +1 -1
  123. package/src/sap/ui/core/hyphenation/Hyphenation.js +1 -1
  124. package/src/sap/ui/core/library.js +3 -3
  125. package/src/sap/ui/core/message/ControlMessageProcessor.js +1 -1
  126. package/src/sap/ui/core/message/Message.js +1 -1
  127. package/src/sap/ui/core/message/MessageManager.js +1 -1
  128. package/src/sap/ui/core/message/MessageParser.js +1 -1
  129. package/src/sap/ui/core/message/MessageProcessor.js +1 -1
  130. package/src/sap/ui/core/mvc/HTMLView.js +1 -1
  131. package/src/sap/ui/core/mvc/JSONView.js +1 -1
  132. package/src/sap/ui/core/mvc/JSView.js +1 -1
  133. package/src/sap/ui/core/mvc/TemplateView.js +1 -1
  134. package/src/sap/ui/core/mvc/View.js +1 -1
  135. package/src/sap/ui/core/mvc/XMLView.js +1 -1
  136. package/src/sap/ui/core/plugin/DeclarativeSupport.js +1 -1
  137. package/src/sap/ui/core/plugin/TemplatingSupport.js +1 -1
  138. package/src/sap/ui/core/postmessage/Bus.js +1 -1
  139. package/src/sap/ui/core/postmessage/confirmationDialog.js +1 -1
  140. package/src/sap/ui/core/search/OpenSearchProvider.js +1 -1
  141. package/src/sap/ui/core/search/SearchProvider.js +1 -1
  142. package/src/sap/ui/core/service/Service.js +1 -1
  143. package/src/sap/ui/core/service/ServiceFactory.js +1 -1
  144. package/src/sap/ui/core/service/ServiceFactoryRegistry.js +1 -1
  145. package/src/sap/ui/core/support/Plugin.js +1 -1
  146. package/src/sap/ui/core/support/Support.js +1 -1
  147. package/src/sap/ui/core/support/plugins/ControlTree.js +1 -1
  148. package/src/sap/ui/core/support/plugins/Interaction.js +1 -1
  149. package/src/sap/ui/core/support/plugins/LocalStorage.js +1 -1
  150. package/src/sap/ui/core/support/plugins/Performance.js +1 -1
  151. package/src/sap/ui/core/support/plugins/Selector.js +1 -1
  152. package/src/sap/ui/core/support/plugins/TechInfo.js +1 -1
  153. package/src/sap/ui/core/support/plugins/Trace.js +1 -1
  154. package/src/sap/ui/core/support/plugins/ViewInfo.js +1 -1
  155. package/src/sap/ui/core/tmpl/DOMAttribute.js +1 -1
  156. package/src/sap/ui/core/tmpl/DOMElement.js +1 -1
  157. package/src/sap/ui/core/tmpl/HandlebarsTemplate.js +1 -1
  158. package/src/sap/ui/core/tmpl/Template.js +1 -1
  159. package/src/sap/ui/core/tmpl/TemplateControl.js +1 -1
  160. package/src/sap/ui/core/util/AsyncHintsHelper.js +1 -1
  161. package/src/sap/ui/core/util/Export.js +1 -1
  162. package/src/sap/ui/core/util/ExportCell.js +1 -1
  163. package/src/sap/ui/core/util/ExportColumn.js +1 -1
  164. package/src/sap/ui/core/util/ExportRow.js +1 -1
  165. package/src/sap/ui/core/util/ExportType.js +1 -1
  166. package/src/sap/ui/core/util/ExportTypeCSV.js +1 -1
  167. package/src/sap/ui/core/util/File.js +1 -1
  168. package/src/sap/ui/core/util/LibraryInfo.js +1 -1
  169. package/src/sap/ui/core/util/MockServer.js +1 -1
  170. package/src/sap/ui/core/util/PasteHelper.js +1 -1
  171. package/src/sap/ui/core/util/reflection/BaseTreeModifier.js +2 -2
  172. package/src/sap/ui/core/util/reflection/JsControlTreeModifier.js +1 -1
  173. package/src/sap/ui/core/util/reflection/XmlTreeModifier.js +2 -2
  174. package/src/sap/ui/core/util/serializer/HTMLViewSerializer.js +1 -1
  175. package/src/sap/ui/core/util/serializer/Serializer.js +1 -1
  176. package/src/sap/ui/core/util/serializer/ViewSerializer.js +1 -1
  177. package/src/sap/ui/core/util/serializer/XMLViewSerializer.js +1 -1
  178. package/src/sap/ui/core/util/serializer/delegate/Delegate.js +1 -1
  179. package/src/sap/ui/core/util/serializer/delegate/HTML.js +1 -1
  180. package/src/sap/ui/core/util/serializer/delegate/XML.js +1 -1
  181. package/src/sap/ui/core/webc/WebComponent.js +1 -1
  182. package/src/sap/ui/core/webc/WebComponentMetadata.js +1 -1
  183. package/src/sap/ui/core/ws/ReadyState.js +1 -1
  184. package/src/sap/ui/core/ws/SapPcpWebSocket.js +1 -1
  185. package/src/sap/ui/core/ws/WebSocket.js +1 -1
  186. package/src/sap/ui/debug/ControlTree.js +1 -1
  187. package/src/sap/ui/debug/DebugEnv.js +1 -1
  188. package/src/sap/ui/debug/PropertyList.js +1 -1
  189. package/src/sap/ui/events/FocusEventFix.js +36 -0
  190. package/src/sap/ui/model/ClientModel.js +1 -1
  191. package/src/sap/ui/model/CompositeDataState.js +1 -1
  192. package/src/sap/ui/model/CompositeType.js +1 -1
  193. package/src/sap/ui/model/DataState.js +1 -1
  194. package/src/sap/ui/model/MetaModel.js +1 -1
  195. package/src/sap/ui/model/Model.js +1 -1
  196. package/src/sap/ui/model/SelectionModel.js +1 -1
  197. package/src/sap/ui/model/SimpleType.js +1 -1
  198. package/src/sap/ui/model/TreeAutoExpandMode.js +1 -1
  199. package/src/sap/ui/model/Type.js +1 -1
  200. package/src/sap/ui/model/json/JSONModel.js +1 -1
  201. package/src/sap/ui/model/message/MessageModel.js +1 -1
  202. package/src/sap/ui/model/odata/ODataAnnotations.js +1 -1
  203. package/src/sap/ui/model/odata/ODataMessageParser.js +1 -1
  204. package/src/sap/ui/model/odata/ODataMetaModel.js +1 -1
  205. package/src/sap/ui/model/odata/ODataMetadata.js +1 -1
  206. package/src/sap/ui/model/odata/ODataModel.js +1 -1
  207. package/src/sap/ui/model/odata/type/Boolean.js +1 -1
  208. package/src/sap/ui/model/odata/type/Byte.js +1 -1
  209. package/src/sap/ui/model/odata/type/Currency.js +1 -1
  210. package/src/sap/ui/model/odata/type/Date.js +1 -1
  211. package/src/sap/ui/model/odata/type/DateTime.js +1 -1
  212. package/src/sap/ui/model/odata/type/DateTimeBase.js +1 -1
  213. package/src/sap/ui/model/odata/type/DateTimeOffset.js +1 -1
  214. package/src/sap/ui/model/odata/type/DateTimeWithTimezone.js +1 -1
  215. package/src/sap/ui/model/odata/type/Decimal.js +1 -1
  216. package/src/sap/ui/model/odata/type/Double.js +1 -1
  217. package/src/sap/ui/model/odata/type/Guid.js +1 -1
  218. package/src/sap/ui/model/odata/type/Int.js +1 -1
  219. package/src/sap/ui/model/odata/type/Int16.js +1 -1
  220. package/src/sap/ui/model/odata/type/Int32.js +1 -1
  221. package/src/sap/ui/model/odata/type/Int64.js +1 -1
  222. package/src/sap/ui/model/odata/type/ODataType.js +1 -1
  223. package/src/sap/ui/model/odata/type/Raw.js +1 -1
  224. package/src/sap/ui/model/odata/type/SByte.js +1 -1
  225. package/src/sap/ui/model/odata/type/Single.js +1 -1
  226. package/src/sap/ui/model/odata/type/Stream.js +1 -1
  227. package/src/sap/ui/model/odata/type/String.js +1 -1
  228. package/src/sap/ui/model/odata/type/Time.js +1 -1
  229. package/src/sap/ui/model/odata/type/TimeOfDay.js +1 -1
  230. package/src/sap/ui/model/odata/type/Unit.js +1 -1
  231. package/src/sap/ui/model/odata/v2/Context.js +1 -1
  232. package/src/sap/ui/model/odata/v2/ODataAnnotations.js +1 -1
  233. package/src/sap/ui/model/odata/v2/ODataModel.js +1 -1
  234. package/src/sap/ui/model/odata/v2/ODataTreeBinding.js +1 -1
  235. package/src/sap/ui/model/odata/v4/Context.js +1 -1
  236. package/src/sap/ui/model/odata/v4/ODataContextBinding.js +1 -1
  237. package/src/sap/ui/model/odata/v4/ODataListBinding.js +2 -2
  238. package/src/sap/ui/model/odata/v4/ODataMetaModel.js +1 -1
  239. package/src/sap/ui/model/odata/v4/ODataModel.js +1 -1
  240. package/src/sap/ui/model/odata/v4/ODataPropertyBinding.js +1 -1
  241. package/src/sap/ui/model/odata/v4/lib/_AggregationCache.js +10 -5
  242. package/src/sap/ui/model/odata/v4/lib/_Requestor.js +15 -4
  243. package/src/sap/ui/model/resource/ResourceModel.js +1 -1
  244. package/src/sap/ui/model/type/Boolean.js +1 -1
  245. package/src/sap/ui/model/type/Currency.js +1 -1
  246. package/src/sap/ui/model/type/Date.js +1 -1
  247. package/src/sap/ui/model/type/DateInterval.js +1 -1
  248. package/src/sap/ui/model/type/DateTime.js +1 -1
  249. package/src/sap/ui/model/type/DateTimeInterval.js +1 -1
  250. package/src/sap/ui/model/type/FileSize.js +1 -1
  251. package/src/sap/ui/model/type/Float.js +1 -1
  252. package/src/sap/ui/model/type/Integer.js +1 -1
  253. package/src/sap/ui/model/type/String.js +1 -1
  254. package/src/sap/ui/model/type/Time.js +1 -1
  255. package/src/sap/ui/model/type/TimeInterval.js +1 -1
  256. package/src/sap/ui/model/type/Unit.js +1 -1
  257. package/src/sap/ui/model/xml/XMLModel.js +1 -1
  258. package/src/sap/ui/performance/Measurement.js +18 -24
  259. package/src/sap/ui/performance/trace/FESR.js +3 -2
  260. package/src/sap/ui/performance/trace/Interaction.js +35 -2
  261. package/src/sap/ui/performance/trace/_InteractionImpl.js +254 -166
  262. package/src/sap/ui/qunit/utils/ControlIterator.js +1 -1
  263. package/src/sap/ui/qunit/utils/MemoryLeakCheck.js +1 -1
  264. package/src/sap/ui/test/generic/TestBase.js +1 -1
  265. package/src/sap/ui/test/launchers/componentLauncher.js +3 -2
  266. package/src/sap/ui/test/launchers/iFrameLauncher.js +3 -1
  267. package/src/sap/ui/test/starter/_setupAndStart.js +3 -1
  268. package/src/sap/ui/thirdparty/require.js +255 -162
  269. package/src/sap/ui/util/Storage.js +1 -1
  270. package/src/ui5loader.js +1 -1
@@ -4,7 +4,6 @@
4
4
  * Licensed under the Apache License, Version 2.0 - see LICENSE.txt.
5
5
  */
6
6
 
7
- /*global HTMLScriptElement */
8
7
  sap.ui.define([
9
8
  "sap/ui/performance/Measurement",
10
9
  "sap/ui/performance/XHRInterceptor",
@@ -26,11 +25,18 @@ sap.ui.define([
26
25
  bPerfectMatch = false,
27
26
  bMatched = false,
28
27
  iInteractionStepTimer,
28
+ iRenderingCounter = 0,
29
+ iRequestCounter = 0,
29
30
  iInteractionCounter = 0,
30
31
  bIdle = false,
31
32
  bInteractionActive = false,
32
33
  FESR,
33
- oBrowserElement;
34
+ oBrowserElement,
35
+ lastHash;
36
+
37
+ const UI5_URL_SYMBOL = Symbol("ui5Url");
38
+ const UI5_REQUEST_INFO_SYMBOL = Symbol("ui5Url");
39
+ const mRequestInfo = new Map();
34
40
 
35
41
  const mCompressedMimeTypes = {
36
42
  "application/zip": true,
@@ -43,14 +49,9 @@ sap.ui.define([
43
49
  },
44
50
  sCompressedExtensions = "zip,rar,arj,z,gz,tar,lzh,cab,hqx,ace,jar,ear,war,jpg,jpeg,pdf,gzip";
45
51
 
46
- function hexToAscii(sValue) {
47
- var hex = sValue.toString();
48
- var str = '';
49
- for (var n = 0; n < hex.length; n += 2) {
50
- str += String.fromCharCode(parseInt(hex.substr(n, 2), 16));
51
- }
52
- return str.trim();
53
- }
52
+ let oAggregatedTiming;
53
+ let oValidAggregatedTiming;
54
+ let aTimingCache = [];
54
55
 
55
56
  function createMeasurement(iTime) {
56
57
  return {
@@ -58,7 +59,8 @@ sap.ui.define([
58
59
  trigger: "undetermined", // control which triggered interaction
59
60
  component: "undetermined", // component or app identifier
60
61
  appVersion: "undetermined", // application version as from app descriptor
61
- start: iTime || performance.timeOrigin, // interaction start - page timeOrigin if initial
62
+ start: iTime, // interaction start - page timeOrigin if initial
63
+ preliminaryEnd: 0,
62
64
  end: 0, // interaction end
63
65
  navigation: 0, // sum over all navigation times
64
66
  roundtrip: 0, // time from first request sent to last received response end - without gaps and ignored overlap
@@ -75,7 +77,10 @@ sap.ui.define([
75
77
  busyDuration: 0, // summed GlobalBusyIndicator duration during this interaction
76
78
  id: uid(), //Interaction ID
77
79
  passportAction: "undetermined_startup_0", //default PassportAction for startup
78
- rootId: undefined // root context ID
80
+ rootId: undefined, // root context ID
81
+ fesrecTime: 0, // sum over all backend times as reported by sap-perf-fesrec header
82
+ fesrecRequestTime: 0, // sum over all requests which have sap-perf-fesrec header
83
+ fesrecRequestCount: 0 // number of requests which have sap-perf-fesrec header
79
84
  };
80
85
  }
81
86
 
@@ -99,82 +104,107 @@ sap.ui.define([
99
104
  */
100
105
  function isValidInteractionXHR(oRequestTiming) {
101
106
  // if the request has been completed it has complete timing figures)
102
- var bComplete = oRequestTiming.startTime > 0 &&
103
- oRequestTiming.startTime <= oRequestTiming.requestStart &&
104
- oRequestTiming.requestStart <= oRequestTiming.responseEnd;
105
-
106
- var bPartOfInteraction = oPendingInteraction.start <= (performance.timeOrigin + oRequestTiming.requestStart) &&
107
- oPendingInteraction.end >= (performance.timeOrigin + oRequestTiming.responseEnd);
108
-
109
- return bPartOfInteraction && bComplete && oRequestTiming.initiatorType === "xmlhttprequest";
110
- }
111
-
112
- function aggregateRequestTiming(oRequest) {
113
- // aggregate navigation and roundtrip with respect to requests overlapping and times w/o requests (gaps)
114
- this.end = oRequest.responseEnd > this.end ? oRequest.responseEnd : this.end;
115
- // sum up request time as a grand total over all requests
116
- oPendingInteraction.requestTime += (oRequest.responseEnd - oRequest.startTime);
117
-
118
- // if there is a gap between requests we add the times to the aggrgate and shift the lower limits
119
- if (this.roundtripHigherLimit <= oRequest.startTime) {
120
- oPendingInteraction.navigation += (this.navigationHigherLimit - this.navigationLowerLimit);
121
- oPendingInteraction.roundtrip += (this.roundtripHigherLimit - this.roundtripLowerLimit);
122
- this.navigationLowerLimit = oRequest.startTime;
123
- this.roundtripLowerLimit = oRequest.startTime;
107
+ const bPartOfInteraction = oPendingInteraction.start - performance.timeOrigin <= oRequestTiming.startTime
108
+ && oPendingInteraction.end - performance.timeOrigin >= oRequestTiming.responseEnd;
109
+ const bStartsInInteraction = oPendingInteraction.start - performance.timeOrigin <= oRequestTiming.startTime;
110
+ const oRequestInfo = oRequestTiming[UI5_REQUEST_INFO_SYMBOL];
111
+ const bCached = oRequestTiming.transferSize === 0 && oRequestTiming.decodedBodySize >= 0;
112
+ const bIsValid = !bCached && !isCrossOriginURL(oRequestTiming.name) && oRequestInfo && bPartOfInteraction && oRequestTiming.initiatorType === "xmlhttprequest";
113
+
114
+ // calculate navigation and roundtrip time for all requests to calculate client CPU time
115
+ if (bStartsInInteraction) {
116
+ oAggregatedTiming ??= {
117
+ navigation: 0,
118
+ roundtrip: 0,
119
+ // for CPU calculation consider requests starting at interaction start to include index loading...
120
+ roundtripLowerLimit: oPendingInteraction.start - performance.timeOrigin ? oRequestTiming.startTime : 0,
121
+ roundtripHigherLimit: oRequestTiming.responseEnd
122
+ };
123
+ aggregateRequestTiming(oRequestTiming, oAggregatedTiming);
124
124
  }
125
125
 
126
- // shift the limits if this request was completed later than the earlier requests
127
- if (oRequest.responseEnd > this.roundtripHigherLimit) {
128
- this.roundtripHigherLimit = oRequest.responseEnd;
129
- }
130
- if (oRequest.requestStart > this.navigationHigherLimit) {
131
- this.navigationHigherLimit = oRequest.requestStart;
126
+ // calculate navigation and roundtrip time for all non CORS requests
127
+ if (bIsValid) {
128
+ oValidAggregatedTiming ??= {
129
+ navigation: 0,
130
+ roundtrip: 0,
131
+ roundtripLowerLimit: oRequestTiming.startTime,
132
+ roundtripHigherLimit: oRequestTiming.responseEnd
133
+ };
134
+ aggregateRequestTiming(oRequestTiming, oValidAggregatedTiming);
135
+ // collect bytes and network time for valid requests
136
+ oPendingInteraction.bytesReceived += oRequestInfo.bytesReceived;
137
+ oPendingInteraction.bytesSent += oRequestInfo.bytesSent;
138
+ // this should be true only if all responses are compressed
139
+ oPendingInteraction.requestCompression = oRequestInfo.requestCompression && (oPendingInteraction.requestCompression !== false);
140
+ // sum up request time as a grand total over all requests
141
+ oPendingInteraction.requestTime += (oRequestTiming.responseEnd - oRequestTiming.startTime);
142
+ if (oRequestInfo.fesrecTime) {
143
+ // sap-perf-fesrec header contains milliseconds
144
+ oPendingInteraction.fesrecTime += oRequestInfo.fesrecTime;
145
+ oPendingInteraction.fesrecRequestTime += (oRequestTiming.responseEnd - oRequestTiming.startTime);
146
+ oPendingInteraction.fesrecRequestCount++;
147
+ }
132
148
  }
149
+ return bIsValid;
133
150
  }
134
151
 
135
- function aggregateRequestTimings(aRequests) {
136
- var oTimings = {
137
- start: aRequests[0].startTime,
138
- end: aRequests[0].responseEnd,
139
- navigationLowerLimit: aRequests[0].startTime,
140
- navigationHigherLimit: aRequests[0].requestStart,
141
- roundtripLowerLimit: aRequests[0].startTime,
142
- roundtripHigherLimit: aRequests[0].responseEnd
143
- };
144
-
145
- // aggregate all timings by operating on the oTimings object
146
- aRequests.forEach(aggregateRequestTiming, oTimings);
147
- oPendingInteraction.navigation += (oTimings.navigationHigherLimit - oTimings.navigationLowerLimit);
148
- oPendingInteraction.roundtrip += (oTimings.roundtripHigherLimit - oTimings.roundtripLowerLimit);
149
-
150
- // calculate average network time per request
151
- if (oPendingInteraction.networkTime) {
152
- var iTotalNetworkTime = oPendingInteraction.requestTime - oPendingInteraction.networkTime;
153
- oPendingInteraction.networkTime = iTotalNetworkTime / aRequests.length;
154
- } else {
155
- oPendingInteraction.networkTime = 0;
152
+ function aggregateRequestTiming(oRequest, oTiming) {
153
+ if (oRequest.responseEnd <= oPendingInteraction.end - performance.timeOrigin) { // request is completely within interaction time
154
+ // if there is a gap between requests we add the times to the aggregate and shift the limits
155
+ if (oTiming.roundtripHigherLimit <= oRequest.startTime) {
156
+ oTiming.roundtrip += (oTiming.roundtripHigherLimit - oTiming.roundtripLowerLimit);
157
+ oTiming.roundtripLowerLimit = oRequest.startTime;
158
+ oTiming.roundtripHigherLimit = oRequest.responseEnd;
159
+ } else if (oRequest.responseEnd > oTiming.roundtripHigherLimit) { // no gap
160
+ // shift the limits if the request was completed later than the earlier requests
161
+ oTiming.roundtripHigherLimit = oRequest.responseEnd;
162
+ }
163
+ } else if (oRequest.startTime < oPendingInteraction.end - performance.timeOrigin) { // request was only partially within interaction time
164
+ // shift limit to end of interaction for CPU time calculation
165
+ oTiming.roundtripHigherLimit = oPendingInteraction.end - performance.timeOrigin;
156
166
  }
167
+ oTiming.navigation += oRequest.requestStart ? oRequest.requestStart - oRequest.startTime : 0;
157
168
  }
158
169
 
159
170
  function finalizeInteraction(iTime) {
160
171
  if (oPendingInteraction) {
161
- var aAllRequestTimings = performance.getEntriesByType("resource");
162
- var oFinshedInteraction;
163
- oPendingInteraction.end = iTime;
164
- oPendingInteraction.processing = iTime - oPendingInteraction.start;
165
- oPendingInteraction.duration = oPendingInteraction.processing;
166
- oPendingInteraction.requests = aAllRequestTimings.filter(isValidInteractionXHR);
172
+ let oFinshedInteraction;
173
+ oPendingInteraction.legacyEndTime = oPendingInteraction.legacyEndTime || now(); //ts
174
+ oPendingInteraction.legacyDuration = oPendingInteraction.legacyEndTime - oPendingInteraction.start; //ms
175
+ oPendingInteraction.end = iTime; //ts
176
+ oPendingInteraction.duration = oPendingInteraction.end - oPendingInteraction.start; //ms
177
+ // copy missing entries into cache
178
+ aTimingCache.push(...performance.getEntriesByType("resource"));
179
+ // sort by start time like done in performance.getEntriesByType
180
+ aTimingCache.sort((a, b) => {
181
+ return a.startTime - b.startTime;
182
+ });
183
+ oPendingInteraction.requests = aTimingCache.filter(isValidInteractionXHR);
184
+
185
+ // calculate the roundtrip time for all valid requests
186
+ oPendingInteraction.roundtrip = oValidAggregatedTiming ? oValidAggregatedTiming.roundtrip + (oValidAggregatedTiming.roundtripHigherLimit - oValidAggregatedTiming.roundtripLowerLimit) : 0;
187
+ // set navigation time for all valid requests
188
+ oPendingInteraction.navigation = oValidAggregatedTiming ? oValidAggregatedTiming.navigation : 0;
189
+
190
+ // calculate the last roundtrip time for all requests to calculate CPU time correctly
191
+ oPendingInteraction.roundtripAllRequests = oAggregatedTiming ? oAggregatedTiming.roundtrip + (oAggregatedTiming.roundtripHigherLimit - oAggregatedTiming.roundtripLowerLimit) : 0;
192
+
193
+ // calculate average network time per request
194
+ if (oPendingInteraction.fesrecTime) {
195
+ const iTotalNetworkTime = oPendingInteraction.fesrecRequestTime - oPendingInteraction.fesrecTime;
196
+ oPendingInteraction.networkTime = iTotalNetworkTime / oPendingInteraction.fesrecRequestCount;
197
+ } else {
198
+ oPendingInteraction.networkTime = 0;
199
+ }
200
+
167
201
  oPendingInteraction.completeRoundtrips = 0;
168
202
  oPendingInteraction.measurements = Measurement.filterMeasurements(isCompleteMeasurement, true);
169
- if (oPendingInteraction.requests.length > 0) {
170
- aggregateRequestTimings(oPendingInteraction.requests);
171
- }
172
203
  oPendingInteraction.completeRoundtrips = oPendingInteraction.requests.length;
173
204
 
174
- // calculate real processing time if any processing took place
175
- // cannot be negative as then requests took longer than processing
176
- var iProcessing = oPendingInteraction.processing - oPendingInteraction.navigation - oPendingInteraction.roundtrip;
177
- oPendingInteraction.processing = iProcessing > -1 ? iProcessing : 0;
205
+ // calculate CPU exclusive time if all neccessary infos are available. Otherwise set it to -1
206
+ const iProcessing = oPendingInteraction.duration - oPendingInteraction.roundtripAllRequests;
207
+ oPendingInteraction.processing = iRequestCounter > 0 ? -1 : iProcessing;
178
208
 
179
209
  oPendingInteraction.completed = true;
180
210
 
@@ -191,29 +221,32 @@ sap.ui.define([
191
221
  FESR.onInteractionFinished(oFinshedInteraction);
192
222
  }
193
223
  Object.freeze(oPendingInteraction);
224
+ oAggregatedTiming = null;
225
+ oValidAggregatedTiming = null;
194
226
  oPendingInteraction = null;
195
227
  oCurrentBrowserEvent = null;
196
228
  bIsNavigation = false;
197
229
  bMatched = false;
198
230
  bPerfectMatch = false;
231
+ aTimingCache = [];
199
232
  clearTimeout(iResetCurrentBrowserEventTimer);
200
233
  }
201
234
  }
202
235
 
203
236
  // component determination - heuristic
204
237
  function createOwnerComponentInfo(oSrcElement) {
205
- var sId, sVersion;
238
+ let sName, sId, sVersion;
206
239
  if (oSrcElement) {
207
- var Component, oComponent;
208
- Component = sap.ui.require("sap/ui/core/Component");
240
+ const Component = sap.ui.require("sap/ui/core/Component");
209
241
  if (Component) {
210
242
  while (oSrcElement && oSrcElement.getParent) {
211
- oComponent = Component.getOwnerComponentFor(oSrcElement);
243
+ let oComponent = Component.getOwnerComponentFor(oSrcElement);
212
244
  if (oComponent || oSrcElement instanceof Component) {
213
245
  oComponent = oComponent || oSrcElement;
214
- var oApp = oComponent.getManifestEntry("sap.app");
246
+ const oApp = oComponent.getManifestEntry("sap.app");
215
247
  // get app id or module name for FESR
216
- sId = oApp && oApp.id || oComponent.getMetadata().getName();
248
+ sId = oComponent.getId();
249
+ sName = oApp && oApp.id || oComponent.getMetadata().getName();
217
250
  sVersion = oApp && oApp.applicationVersion && oApp.applicationVersion.version;
218
251
  }
219
252
  oSrcElement = oSrcElement.getParent();
@@ -221,7 +254,8 @@ sap.ui.define([
221
254
  }
222
255
  }
223
256
  return {
224
- id: sId ? sId : "undetermined",
257
+ id: sId,
258
+ name: sName ? sName : "undetermined",
225
259
  version: sVersion ? sVersion : ""
226
260
  };
227
261
  }
@@ -239,7 +273,7 @@ sap.ui.define([
239
273
  var fnDone;
240
274
 
241
275
  if (!this.dataset.sapUiCoreInteractionHandled) {
242
- fnDone = _InteractionImpl.notifyAsyncStep();
276
+ fnDone = _InteractionImpl.notifyAsyncStep("request");
243
277
  this.addEventListener("load", function() {
244
278
  fnDone();
245
279
  });
@@ -257,61 +291,34 @@ sap.ui.define([
257
291
  function registerXHROverrides() {
258
292
  // store the byte size of the body
259
293
  XHRInterceptor.register("INTERACTION", "send" ,function() {
260
- if (this.oPendingInteraction) {
294
+ if (this.oPendingInteraction && !isCrossOriginURL(this[UI5_URL_SYMBOL])) {
261
295
  // double string length for byte length as in js characters are stored as 16 bit ints
262
- this.oPendingInteraction.bytesSent += arguments[0] ? arguments[0].length : 0;
296
+ mRequestInfo.get(this._id).bytesSent += arguments[0] ? arguments[0].length : 0;
263
297
  }
264
298
  });
265
299
 
266
300
  // store request header size
267
301
  XHRInterceptor.register("INTERACTION", "setRequestHeader", function(sHeader, sValue) {
268
- // count request header length consistent to what getAllResponseHeaders().length would return
269
- if (!this.requestHeaderLength) {
270
- this.requestHeaderLength = 0;
302
+ if (oPendingInteraction && !isCrossOriginURL(this[UI5_URL_SYMBOL])) {
303
+ mRequestInfo.get(this._id).bytesSent += (sHeader + "").length + (sValue + "").length;
271
304
  }
272
- // assume request header byte size
273
- this.requestHeaderLength += (sHeader + "").length + (sValue + "").length;
274
-
275
305
  });
276
306
 
277
307
  // register the response handler for data collection
278
308
  XHRInterceptor.register("INTERACTION", "open", function (sMethod, sUrl, bAsync) {
279
- var sEpp,
280
- sAction,
281
- sRootContextID;
282
309
 
283
- function handleInteraction(fnDone) {
284
- if (this.readyState === 4) {
285
- fnDone();
286
- }
287
- }
288
- // we only need to take care of requests when we have a running interaction
289
- if (oPendingInteraction) {
290
- var bIsNoCorsRequest = !isCrossOriginURL(sUrl);
310
+ // remember url for later use in handleResponse/setRequestHeader
311
+ this[UI5_URL_SYMBOL] = new URL(sUrl, document.baseURI).href;
312
+
313
+ if (oPendingInteraction && !isCrossOriginURL(this[UI5_URL_SYMBOL])) {
291
314
  // only use Interaction for non CORS requests
292
- if (bIsNoCorsRequest) {
293
- //only track if FESR.clientID == EPP.Action && FESR.rootContextID == EPP.rootContextID
294
- sEpp = FESR?.passportHeader.get(this);
295
- if (sEpp && sEpp.length >= 370) {
296
- sAction = hexToAscii(sEpp.substring(150, 230));
297
- if (parseInt(sEpp.substring(8, 10), 16) > 2) { // version number > 2 --> extended passport
298
- sRootContextID = sEpp.substring(372, 404);
299
- }
300
- }
301
- if (!sEpp || sAction && sRootContextID && oPendingInteraction.passportAction.endsWith(sAction)) {
302
- this.addEventListener("readystatechange", handleResponse.bind(this, oPendingInteraction.id));
303
- }
304
- }
305
- // arguments at position 2 is indicatior whether request is async or not
306
- // readystatechange must not be used for sync CORS request since it does not work properly
307
- // this is especially necessary in case request was not started by LoaderExtension
308
- // bAsync is by default true, therefore we need to check eplicitly for value 'false'
309
- if (bIsNoCorsRequest || bAsync !== false) {
310
- // notify async step for all XHRs (even CORS requests)
311
- this.addEventListener("readystatechange", handleInteraction.bind(this, _InteractionImpl.notifyAsyncStep()));
312
- }
315
+ this.addEventListener("readystatechange", handleResponse.bind(this, oPendingInteraction.id, _InteractionImpl.notifyAsyncStep("request")));
316
+ const oRequestInfo = Object.create(null);
317
+ // init bytesSent
318
+ oRequestInfo.bytesSent = 0;
313
319
  // assign the current interaction to the xhr for later response header retrieval.
314
- this.oPendingInteraction = oPendingInteraction;
320
+ oRequestInfo.pendingInteraction = oPendingInteraction;
321
+ mRequestInfo.set(this._id, oRequestInfo);
315
322
  }
316
323
  });
317
324
 
@@ -334,33 +341,44 @@ sap.ui.define([
334
341
  }
335
342
 
336
343
  // response handler which uses the custom properties we added to the xhr to retrieve information from the response headers
337
- function handleResponse(sId) {
344
+ function handleResponse(sId, fnDone) {
338
345
  if (this.readyState === 4) {
339
- if (this.oPendingInteraction && !this.oPendingInteraction.completed && oPendingInteraction.id === sId) {
340
- // enrich interaction with information
341
- var sContentLength = this.getResponseHeader("content-length"),
342
- bCompressed = checkCompression(this.responseURL, this.getResponseHeader("content-encoding"), this.getResponseHeader("content-type"), sContentLength),
343
- sFesrec = this.getResponseHeader("sap-perf-fesrec");
344
- this.oPendingInteraction.bytesReceived += sContentLength ? parseInt(sContentLength) : 0;
345
- this.oPendingInteraction.bytesReceived += this.getAllResponseHeaders().length;
346
- this.oPendingInteraction.bytesSent += this.requestHeaderLength || 0;
347
- // this should be true only if all responses are compressed
348
- this.oPendingInteraction.requestCompression = bCompressed && (this.oPendingInteraction.requestCompression !== false);
349
- // sap-perf-fesrec header contains milliseconds
350
- this.oPendingInteraction.networkTime += sFesrec ? Math.round(parseFloat(sFesrec, 10) / 1000) : 0;
351
- var sSapStatistics = this.getResponseHeader("sap-statistics");
352
- if (sSapStatistics) {
353
- var aTimings = performance.getEntriesByType("resource");
354
- this.oPendingInteraction.sapStatistics.push({
355
- // add response url for mapping purposes
356
- url: this.responseURL,
357
- statistics: sSapStatistics,
358
- timing: aTimings ? aTimings[aTimings.length - 1] : undefined
346
+ const oRequestInfo = mRequestInfo.get(this._id);
347
+ let aTimings = performance.getEntriesByType("resource");
348
+ aTimingCache.push(...aTimings);
349
+ performance.clearResourceTimings();
350
+ if (aTimings.length && !oPendingInteraction?.completed && oPendingInteraction?.id === sId) {
351
+ if (oRequestInfo) {
352
+ aTimings = aTimings.filter((timing) => {
353
+ return timing.name === this[UI5_URL_SYMBOL] && timing.decodedBodySize !== 0 && timing.transferSize !== 0;
359
354
  });
355
+ if (aTimings.length) {
356
+ // enrich interaction with information
357
+ const sContentLength = this.getResponseHeader("content-length"),
358
+ bCompressed = checkCompression(this.responseURL, this.getResponseHeader("content-encoding"), this.getResponseHeader("content-type"), sContentLength),
359
+ sFesrec = this.getResponseHeader("sap-perf-fesrec");
360
+
361
+ oRequestInfo.bytesReceived = sContentLength ? parseInt(sContentLength) : 0;
362
+ oRequestInfo.bytesReceived = this.getAllResponseHeaders().length;
363
+ // this should be true only if all responses are compressed
364
+ oRequestInfo.requestCompression = bCompressed;
365
+
366
+ // sap-perf-fesrec header contains milliseconds
367
+ oRequestInfo.fesrecTime = sFesrec ? Math.round(parseFloat(sFesrec, 10) / 1000) : 0;
368
+ const sSapStatistics = this.getResponseHeader("sap-statistics");
369
+ aTimings[0][UI5_REQUEST_INFO_SYMBOL] = oRequestInfo;
370
+ if (sSapStatistics) {
371
+ oRequestInfo.pendingInteraction.sapStatistics.push({
372
+ // add response url for mapping purposes
373
+ url: this.responseURL,
374
+ statistics: sSapStatistics,
375
+ timing: aTimings ? aTimings[aTimings.length - 1] : undefined
376
+ });
377
+ }
378
+ }
360
379
  }
361
- delete this.requestHeaderLength;
362
- delete this.oPendingInteraction;
363
380
  }
381
+ fnDone();
364
382
  }
365
383
  }
366
384
 
@@ -394,7 +412,7 @@ sap.ui.define([
394
412
  },
395
413
 
396
414
  start : function(sType, oSrcElement) {
397
- var iTime = now();
415
+ const iTime = sType === "startup" ? performance.timeOrigin : now();
398
416
 
399
417
  if (oPendingInteraction) {
400
418
  finalizeInteraction(iTime);
@@ -406,18 +424,22 @@ sap.ui.define([
406
424
  }
407
425
 
408
426
  iInteractionCounter = 0;
427
+ iRenderingCounter = 0;
428
+ iRequestCounter = 0;
409
429
 
410
430
  // clear request timings for new interaction
411
- if (performance.clearResourceTimings) {
431
+ if (sType !== "startup" && performance.clearResourceTimings) {
412
432
  performance.clearResourceTimings();
413
433
  }
414
434
 
415
- var oComponentInfo = createOwnerComponentInfo(oSrcElement);
416
-
417
435
  // setup new pending interaction
418
436
  oPendingInteraction = createMeasurement(iTime);
437
+
438
+ const oComponentInfo = createOwnerComponentInfo(oSrcElement);
439
+ oPendingInteraction.componentId = oComponentInfo.id;
440
+ oPendingInteraction.component = oComponentInfo.name;
441
+
419
442
  oPendingInteraction.event = sType;
420
- oPendingInteraction.component = oComponentInfo.id;
421
443
  oPendingInteraction.appVersion = oComponentInfo.version;
422
444
  if (oSrcElement && oSrcElement.getId) {
423
445
  oPendingInteraction.trigger = oSrcElement.getId();
@@ -559,7 +581,38 @@ sap.ui.define([
559
581
  }
560
582
  },
561
583
 
562
- notifyAsyncStep : function(sStepName) {
584
+ notifyControlRendering : function(sOwnerId, sStepName) {
585
+ if (oPendingInteraction) {
586
+ iRenderingCounter++;
587
+ if (Log.isLoggable()) {
588
+ Log.debug("Interaction relevant step started - Number of pending steps: " + (iInteractionCounter + iRenderingCounter + iRequestCounter));
589
+ }
590
+ return function() {
591
+ iRenderingCounter--;
592
+ const a2aComponentId = _InteractionImpl._a2aNavInfo.get(oPendingInteraction.hash);
593
+ if (oPendingInteraction.componentId) {
594
+ if (a2aComponentId && a2aComponentId === sOwnerId || sOwnerId === oPendingInteraction.componentId) {
595
+ _InteractionImpl.end(); // set preliminary end time
596
+ }
597
+ } else {
598
+ _InteractionImpl.end(); // set preliminary end time
599
+ }
600
+ _InteractionImpl.notifyStepEnd(true);
601
+ if (Log.isLoggable()) {
602
+ Log.debug("Interaction relevant step stopped - Number of pending steps: " + (iInteractionCounter + iRenderingCounter + iRequestCounter));
603
+ }
604
+ /*eslint-disable no-console */
605
+ if (Log.isLoggable(null, "sap.ui.Performance") && sStepName) {
606
+ console.timeEnd(sStepName);
607
+ }
608
+ /*eslint-enable no-console */
609
+ };
610
+ } else {
611
+ return function() {};
612
+ }
613
+ },
614
+
615
+ notifyAsyncStep : function(sType, sStepName) {
563
616
  if (oPendingInteraction) {
564
617
  /*eslint-disable no-console */
565
618
  if (Log.isLoggable(null, "sap.ui.Performance") && sStepName) {
@@ -567,10 +620,9 @@ sap.ui.define([
567
620
  }
568
621
  /*eslint-enable no-console */
569
622
  var sInteractionId = oPendingInteraction.id;
570
- delete oPendingInteraction.preliminaryEnd; // Delete prelimanry end to force current timestamp of finalization
571
- _InteractionImpl.notifyAsyncStepStart();
623
+ _InteractionImpl.notifyAsyncStepStart(sType);
572
624
  return function() {
573
- _InteractionImpl.notifyAsyncStepEnd(sInteractionId);
625
+ _InteractionImpl.notifyAsyncStepEnd(sType, sInteractionId);
574
626
  /*eslint-disable no-console */
575
627
  if (Log.isLoggable(null, "sap.ui.Performance") && sStepName) {
576
628
  console.timeEnd(sStepName);
@@ -582,30 +634,39 @@ sap.ui.define([
582
634
  }
583
635
  },
584
636
 
585
- notifyAsyncStepStart : function() {
637
+ notifyAsyncStepStart : function(sType) {
586
638
  if (oPendingInteraction) {
587
- iInteractionCounter++;
639
+ if (sType === "request") {
640
+ iRequestCounter++;
641
+ } else {
642
+ iInteractionCounter++;
643
+ }
588
644
  clearTimeout(iInteractionStepTimer);
645
+ delete oPendingInteraction.legacyEndTime;
589
646
  bIdle = false;
590
647
  if (Log.isLoggable()) {
591
- Log.debug("Interaction relevant step started - Number of pending steps: " + iInteractionCounter);
648
+ Log.debug("Interaction relevant step started - Number of pending steps: " + (iInteractionCounter + iRenderingCounter + iRequestCounter));
592
649
  }
593
650
  }
594
651
  },
595
652
 
596
- notifyAsyncStepEnd : function(sId) {
653
+ notifyAsyncStepEnd : function(sType, sId) {
597
654
  if (oPendingInteraction && sId === oPendingInteraction.id) {
598
- iInteractionCounter--;
655
+ if (sType === "request") {
656
+ iRequestCounter--;
657
+ } else {
658
+ iInteractionCounter--;
659
+ }
599
660
  _InteractionImpl.notifyStepEnd(true);
600
661
  if (Log.isLoggable()) {
601
- Log.debug("Interaction relevant step stopped - Number of pending steps: " + iInteractionCounter);
662
+ Log.debug("Interaction relevant step stopped - Number of pending steps: " + (iInteractionCounter + iRenderingCounter + iRequestCounter));
602
663
  }
603
664
  }
604
665
  },
605
666
 
606
667
  notifyStepEnd : function(bCheckIdle) {
607
668
  if (bInteractionActive) {
608
- if (iInteractionCounter === 0 || !bCheckIdle) {
669
+ if ((iInteractionCounter === 0 && iRenderingCounter === 0 && iRequestCounter === 0) || !bCheckIdle) {
609
670
  if (bIdle || !bCheckIdle) {
610
671
  _InteractionImpl.end(true);
611
672
  if (Log.isLoggable()) {
@@ -613,7 +674,7 @@ sap.ui.define([
613
674
  }
614
675
  bIdle = false;
615
676
  } else {
616
- _InteractionImpl.end(); //set preliminary end time
677
+ oPendingInteraction.legacyEndTime = now();
617
678
  bIdle = true;
618
679
  if (iInteractionStepTimer) {
619
680
  clearTimeout(iInteractionStepTimer);
@@ -623,7 +684,7 @@ sap.ui.define([
623
684
  // with 301ms to end the Interaction after execution of the debounced event
624
685
  iInteractionStepTimer = setTimeout(_InteractionImpl.notifyStepEnd, 301);
625
686
  if (Log.isLoggable()) {
626
- Log.debug("Interaction check for bIdle time - Number of pending steps: " + iInteractionCounter);
687
+ Log.debug("Interaction check for bIdle time - Number of pending steps: " + (iInteractionCounter + iRenderingCounter + iRequestCounter));
627
688
  }
628
689
  }
629
690
  }
@@ -682,18 +743,45 @@ sap.ui.define([
682
743
  bInteractionActive = bActive;
683
744
  if (bActive) {
684
745
  _InteractionImpl.notifyStepStart("startup", "startup", true);
746
+ // listen to hash changes. If the first degment changes we guess its an A2A navigation
747
+ globalThis.addEventListener('hashchange', function() {
748
+ // Get the hash from the current URL
749
+ const hash = globalThis.location.hash;
750
+
751
+ // Regular expression to extract the first segment of the hash
752
+ const match = hash.match(/#([^&/]+)/);
753
+
754
+ if (match?.[0]) {
755
+ if (!lastHash) {
756
+ lastHash = match[0];
757
+ } else if (lastHash !== match[0]) {
758
+ if (this.getPending() && !this.getPending().maybeA2A) {
759
+ // mark pending interaction as A2A navigation
760
+ this.getPending().maybeA2A = match[0];
761
+ }
762
+ lastHash = match[0];
763
+ }
764
+ }
765
+ }.bind(this));
766
+ // Get the initial hash from the current URL
767
+ lastHash = lastHash || globalThis.location.hash.match(/#([^&/]+)/)?.[0];
685
768
  }
686
769
  },
687
770
 
688
771
  _setFESR: function(oFESR) {
689
772
  FESR = oFESR;
690
- }
773
+ },
774
+
775
+ _a2aNavInfo: new Map(),
776
+
777
+ _createOwnerComponentInfo: createOwnerComponentInfo
778
+
691
779
  };
692
780
 
693
781
  registerXHROverrides();
694
782
  interceptScripts();
695
783
 
696
- LoaderExtensions.notifyResourceLoading = _InteractionImpl.notifyAsyncStep;
784
+ LoaderExtensions.notifyResourceLoading = _InteractionImpl.notifyAsyncStep.bind(this, "request");
697
785
 
698
786
  return _InteractionImpl;
699
787
  });
@@ -53,7 +53,7 @@ sap.ui.define(['sap/ui/core/Core', "sap/ui/VersionInfo", "sap/ui/core/Lib"],
53
53
  * @namespace
54
54
  *
55
55
  * @author SAP SE
56
- * @version 1.142.0
56
+ * @version 1.142.1
57
57
  *
58
58
  * @public
59
59
  * @since 1.48.0
@@ -30,7 +30,7 @@ sap.ui.define([ 'sap/ui/core/ElementRegistry', 'sap/ui/core/Control', "sap/ui/qu
30
30
  * @namespace
31
31
  *
32
32
  * @author SAP SE
33
- * @version 1.142.0
33
+ * @version 1.142.1
34
34
  *
35
35
  * @public
36
36
  * @since 1.48.0
@@ -26,7 +26,7 @@ sap.ui.define([
26
26
  * @extends sap.ui.base.Object
27
27
  * @abstract
28
28
  * @author SAP SE
29
- * @version 1.142.0
29
+ * @version 1.142.1
30
30
  * @since 1.100
31
31
  */
32
32
  return BaseObject.extend("sap.ui.test.generic.TestBase", {