@sapui5/sap.suite.ui.commons 1.146.0 → 1.148.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 (206) hide show
  1. package/package.json +1 -1
  2. package/src/sap/suite/ui/commons/.library +1 -1
  3. package/src/sap/suite/ui/commons/AriaProperties.js +1 -1
  4. package/src/sap/suite/ui/commons/CalculationBuilder.js +56 -2
  5. package/src/sap/suite/ui/commons/CalculationBuilderExpression.js +87 -14
  6. package/src/sap/suite/ui/commons/CalculationBuilderFunction.js +1 -1
  7. package/src/sap/suite/ui/commons/CalculationBuilderGroup.js +1 -1
  8. package/src/sap/suite/ui/commons/CalculationBuilderItem.js +16 -3
  9. package/src/sap/suite/ui/commons/CalculationBuilderValidationResult.js +1 -1
  10. package/src/sap/suite/ui/commons/CalculationBuilderVariable.js +1 -1
  11. package/src/sap/suite/ui/commons/CloudFilePicker.js +1 -1
  12. package/src/sap/suite/ui/commons/MicroProcessFlow.js +1 -1
  13. package/src/sap/suite/ui/commons/MicroProcessFlowItem.js +1 -1
  14. package/src/sap/suite/ui/commons/collaboration/ContactPopover.fragment.xml +8 -8
  15. package/src/sap/suite/ui/commons/collaboration/MinimalContactPopover.fragment.xml +5 -5
  16. package/src/sap/suite/ui/commons/flexibility/changeHandler/PropertyChangeMapper.js +1 -1
  17. package/src/sap/suite/ui/commons/imageeditor/CropCustomShapeHistoryItem.js +1 -1
  18. package/src/sap/suite/ui/commons/imageeditor/CropEllipseHistoryItem.js +1 -1
  19. package/src/sap/suite/ui/commons/imageeditor/CropRectangleHistoryItem.js +1 -1
  20. package/src/sap/suite/ui/commons/imageeditor/CustomSizeItem.js +1 -1
  21. package/src/sap/suite/ui/commons/imageeditor/FilterHistoryItem.js +1 -1
  22. package/src/sap/suite/ui/commons/imageeditor/FlipHistoryItem.js +1 -1
  23. package/src/sap/suite/ui/commons/imageeditor/HistoryItem.js +1 -1
  24. package/src/sap/suite/ui/commons/imageeditor/ImageEditor.js +1 -1
  25. package/src/sap/suite/ui/commons/imageeditor/ImageEditorContainer.js +1 -1
  26. package/src/sap/suite/ui/commons/imageeditor/ImageEditorResponsiveContainer.js +1 -1
  27. package/src/sap/suite/ui/commons/imageeditor/ResizeHistoryItem.js +1 -1
  28. package/src/sap/suite/ui/commons/imageeditor/RotateHistoryItem.js +1 -1
  29. package/src/sap/suite/ui/commons/library.js +4 -4
  30. package/src/sap/suite/ui/commons/messagebundle.properties +12 -8
  31. package/src/sap/suite/ui/commons/messagebundle_ar.properties +10 -8
  32. package/src/sap/suite/ui/commons/messagebundle_bg.properties +10 -8
  33. package/src/sap/suite/ui/commons/messagebundle_ca.properties +10 -8
  34. package/src/sap/suite/ui/commons/messagebundle_cnr.properties +14 -12
  35. package/src/sap/suite/ui/commons/messagebundle_cs.properties +10 -8
  36. package/src/sap/suite/ui/commons/messagebundle_cy.properties +8 -6
  37. package/src/sap/suite/ui/commons/messagebundle_da.properties +10 -8
  38. package/src/sap/suite/ui/commons/messagebundle_de.properties +10 -8
  39. package/src/sap/suite/ui/commons/messagebundle_el.properties +10 -8
  40. package/src/sap/suite/ui/commons/messagebundle_en.properties +10 -8
  41. package/src/sap/suite/ui/commons/messagebundle_en_GB.properties +10 -8
  42. package/src/sap/suite/ui/commons/messagebundle_en_US_saprigi.properties +10 -8
  43. package/src/sap/suite/ui/commons/messagebundle_es.properties +10 -8
  44. package/src/sap/suite/ui/commons/messagebundle_es_MX.properties +11 -9
  45. package/src/sap/suite/ui/commons/messagebundle_et.properties +10 -8
  46. package/src/sap/suite/ui/commons/messagebundle_fi.properties +10 -8
  47. package/src/sap/suite/ui/commons/messagebundle_fr.properties +10 -8
  48. package/src/sap/suite/ui/commons/messagebundle_fr_CA.properties +10 -8
  49. package/src/sap/suite/ui/commons/messagebundle_hi.properties +10 -8
  50. package/src/sap/suite/ui/commons/messagebundle_hr.properties +10 -8
  51. package/src/sap/suite/ui/commons/messagebundle_hu.properties +11 -9
  52. package/src/sap/suite/ui/commons/messagebundle_id.properties +12 -10
  53. package/src/sap/suite/ui/commons/messagebundle_it.properties +11 -9
  54. package/src/sap/suite/ui/commons/messagebundle_iw.properties +10 -8
  55. package/src/sap/suite/ui/commons/messagebundle_ja.properties +10 -8
  56. package/src/sap/suite/ui/commons/messagebundle_kk.properties +10 -8
  57. package/src/sap/suite/ui/commons/messagebundle_ko.properties +10 -8
  58. package/src/sap/suite/ui/commons/messagebundle_lt.properties +10 -8
  59. package/src/sap/suite/ui/commons/messagebundle_lv.properties +10 -8
  60. package/src/sap/suite/ui/commons/messagebundle_mk.properties +11 -9
  61. package/src/sap/suite/ui/commons/messagebundle_ms.properties +10 -8
  62. package/src/sap/suite/ui/commons/messagebundle_nl.properties +10 -8
  63. package/src/sap/suite/ui/commons/messagebundle_no.properties +10 -8
  64. package/src/sap/suite/ui/commons/messagebundle_pl.properties +10 -8
  65. package/src/sap/suite/ui/commons/messagebundle_pt.properties +10 -8
  66. package/src/sap/suite/ui/commons/messagebundle_pt_PT.properties +10 -8
  67. package/src/sap/suite/ui/commons/messagebundle_ro.properties +14 -12
  68. package/src/sap/suite/ui/commons/messagebundle_ru.properties +10 -8
  69. package/src/sap/suite/ui/commons/messagebundle_sh.properties +14 -12
  70. package/src/sap/suite/ui/commons/messagebundle_sk.properties +10 -8
  71. package/src/sap/suite/ui/commons/messagebundle_sl.properties +10 -8
  72. package/src/sap/suite/ui/commons/messagebundle_sr.properties +14 -12
  73. package/src/sap/suite/ui/commons/messagebundle_sv.properties +10 -8
  74. package/src/sap/suite/ui/commons/messagebundle_th.properties +10 -8
  75. package/src/sap/suite/ui/commons/messagebundle_tr.properties +10 -8
  76. package/src/sap/suite/ui/commons/messagebundle_uk.properties +10 -8
  77. package/src/sap/suite/ui/commons/messagebundle_vi.properties +10 -8
  78. package/src/sap/suite/ui/commons/messagebundle_zh_CN.properties +10 -8
  79. package/src/sap/suite/ui/commons/messagebundle_zh_TW.properties +10 -8
  80. package/src/sap/suite/ui/commons/networkgraph/Graph.js +142 -29
  81. package/src/sap/suite/ui/commons/networkgraph/GraphMap.js +25 -3
  82. package/src/sap/suite/ui/commons/networkgraph/GraphRenderer.js +1 -1
  83. package/src/sap/suite/ui/commons/networkgraph/KeyboardNavigator.js +331 -14
  84. package/src/sap/suite/ui/commons/networkgraph/Line.js +5 -1
  85. package/src/sap/suite/ui/commons/networkgraph/Node.js +67 -5
  86. package/src/sap/suite/ui/commons/networkgraph/Utils.js +10 -0
  87. package/src/sap/suite/ui/commons/networkgraph/util/ConnectionPathUtils.js +34 -4
  88. package/src/sap/suite/ui/commons/networkgraph/util/DependencyLayoutHelper.js +213 -74
  89. package/src/sap/suite/ui/commons/statusindicator/Circle.js +1 -1
  90. package/src/sap/suite/ui/commons/statusindicator/CustomShape.js +1 -1
  91. package/src/sap/suite/ui/commons/statusindicator/DiscreteThreshold.js +1 -1
  92. package/src/sap/suite/ui/commons/statusindicator/FillingOption.js +1 -1
  93. package/src/sap/suite/ui/commons/statusindicator/LibraryShape.js +1 -1
  94. package/src/sap/suite/ui/commons/statusindicator/Path.js +1 -1
  95. package/src/sap/suite/ui/commons/statusindicator/PropertyThreshold.js +1 -1
  96. package/src/sap/suite/ui/commons/statusindicator/Rectangle.js +1 -1
  97. package/src/sap/suite/ui/commons/statusindicator/Shape.js +1 -1
  98. package/src/sap/suite/ui/commons/statusindicator/ShapeGroup.js +1 -1
  99. package/src/sap/suite/ui/commons/statusindicator/SimpleShape.js +1 -1
  100. package/src/sap/suite/ui/commons/statusindicator/StatusIndicator.js +1 -1
  101. package/src/sap/suite/ui/commons/taccount/TAccount.js +1 -1
  102. package/src/sap/suite/ui/commons/taccount/TAccountGroup.js +1 -1
  103. package/src/sap/suite/ui/commons/taccount/TAccountItem.js +1 -1
  104. package/src/sap/suite/ui/commons/taccount/TAccountItemProperty.js +1 -1
  105. package/src/sap/suite/ui/commons/taccount/TAccountPanel.js +1 -1
  106. package/src/sap/suite/ui/commons/themes/base/BusinessCard.less +5 -4
  107. package/src/sap/suite/ui/commons/themes/base/CalculationBuilder.less +33 -24
  108. package/src/sap/suite/ui/commons/themes/base/CalculationBuilderExpression.less +40 -31
  109. package/src/sap/suite/ui/commons/themes/base/CalculationBuilderInput.less +26 -10
  110. package/src/sap/suite/ui/commons/themes/base/CalculationBuilderItem.less +76 -63
  111. package/src/sap/suite/ui/commons/themes/base/ChartContainer.less +8 -11
  112. package/src/sap/suite/ui/commons/themes/base/ChartTile.less +5 -8
  113. package/src/sap/suite/ui/commons/themes/base/CollaborationPopover.less +116 -106
  114. package/src/sap/suite/ui/commons/themes/base/DateRangeScroller.less +5 -5
  115. package/src/sap/suite/ui/commons/themes/base/DateRangeSliderInternal.less +9 -10
  116. package/src/sap/suite/ui/commons/themes/base/FacetOverview.less +9 -10
  117. package/src/sap/suite/ui/commons/themes/base/FeedItemHeader.less +9 -12
  118. package/src/sap/suite/ui/commons/themes/base/FeedTile.less +23 -27
  119. package/src/sap/suite/ui/commons/themes/base/GenericTile2X2.less +15 -15
  120. package/src/sap/suite/ui/commons/themes/base/HeaderCell.less +7 -6
  121. package/src/sap/suite/ui/commons/themes/base/HeaderContainer.less +35 -37
  122. package/src/sap/suite/ui/commons/themes/base/ImageEditor.less +28 -10
  123. package/src/sap/suite/ui/commons/themes/base/ImageEditorContainer.less +29 -22
  124. package/src/sap/suite/ui/commons/themes/base/InfoTile.less +10 -4
  125. package/src/sap/suite/ui/commons/themes/base/InfoTileSize.less +5 -4
  126. package/src/sap/suite/ui/commons/themes/base/KpiTile.less +10 -11
  127. package/src/sap/suite/ui/commons/themes/base/LaunchTile.less +9 -8
  128. package/src/sap/suite/ui/commons/themes/base/LinkActionSheet.less +14 -43
  129. package/src/sap/suite/ui/commons/themes/base/MicroProcessFlow.less +51 -47
  130. package/src/sap/suite/ui/commons/themes/base/MonitoringContent.less +5 -5
  131. package/src/sap/suite/ui/commons/themes/base/NetworkGraph.less +57 -62
  132. package/src/sap/suite/ui/commons/themes/base/NetworkGroup.less +61 -65
  133. package/src/sap/suite/ui/commons/themes/base/NetworkLine.less +58 -55
  134. package/src/sap/suite/ui/commons/themes/base/NetworkNode.less +3 -0
  135. package/src/sap/suite/ui/commons/themes/base/NetworkTooltip.less +21 -25
  136. package/src/sap/suite/ui/commons/themes/base/NoteTaker.less +13 -18
  137. package/src/sap/suite/ui/commons/themes/base/NoteTakerCard.less +26 -27
  138. package/src/sap/suite/ui/commons/themes/base/NoteTakerFeeder.less +22 -44
  139. package/src/sap/suite/ui/commons/themes/base/NumericTile.less +7 -5
  140. package/src/sap/suite/ui/commons/themes/base/PictureZoomIn.less +6 -5
  141. package/src/sap/suite/ui/commons/themes/base/ProcessFlow.less +57 -76
  142. package/src/sap/suite/ui/commons/themes/base/ProcessFlowConnection.less +71 -17
  143. package/src/sap/suite/ui/commons/themes/base/ProcessFlowConnectionLabel.less +9 -13
  144. package/src/sap/suite/ui/commons/themes/base/ProcessFlowLaneHeader.less +37 -96
  145. package/src/sap/suite/ui/commons/themes/base/ProcessFlowNode.less +219 -238
  146. package/src/sap/suite/ui/commons/themes/base/SemanticColorMixins.less +55 -0
  147. package/src/sap/suite/ui/commons/themes/base/SplitButton.less +7 -20
  148. package/src/sap/suite/ui/commons/themes/base/StatusIndicator.less +10 -9
  149. package/src/sap/suite/ui/commons/themes/base/TAccount.less +78 -73
  150. package/src/sap/suite/ui/commons/themes/base/TargetFilter.less +50 -58
  151. package/src/sap/suite/ui/commons/themes/base/ThingCollection.less +18 -13
  152. package/src/sap/suite/ui/commons/themes/base/ThreePanelThingViewer.less +14 -14
  153. package/src/sap/suite/ui/commons/themes/base/TileContent2X2.less +9 -13
  154. package/src/sap/suite/ui/commons/themes/base/Timeline.less +16 -19
  155. package/src/sap/suite/ui/commons/themes/base/TimelineItem.less +95 -103
  156. package/src/sap/suite/ui/commons/themes/base/UnifiedThingGroup.less +7 -9
  157. package/src/sap/suite/ui/commons/themes/base/UnifiedThingInspector.less +12 -9
  158. package/src/sap/suite/ui/commons/themes/base/VerticalNavigationBar.less +10 -15
  159. package/src/sap/suite/ui/commons/themes/base/ViewRepeater.less +8 -9
  160. package/src/sap/suite/ui/commons/themes/base/library.source.less +0 -2
  161. package/src/sap/suite/ui/commons/themes/sap_fiori_3/MicroProcessFlow.less +9 -3
  162. package/src/sap/suite/ui/commons/themes/sap_fiori_3/ProcessFlowConnection.less +14 -7
  163. package/src/sap/suite/ui/commons/themes/sap_fiori_3/ProcessFlowConnectionLabel.less +38 -35
  164. package/src/sap/suite/ui/commons/themes/sap_fiori_3/ProcessFlowLaneHeader.less +29 -30
  165. package/src/sap/suite/ui/commons/themes/sap_fiori_3/ProcessFlowNode.less +158 -102
  166. package/src/sap/suite/ui/commons/themes/sap_fiori_3_dark/MicroProcessFlow.less +9 -3
  167. package/src/sap/suite/ui/commons/themes/sap_fiori_3_dark/ProcessFlowConnection.less +14 -7
  168. package/src/sap/suite/ui/commons/themes/sap_fiori_3_dark/ProcessFlowConnectionLabel.less +38 -35
  169. package/src/sap/suite/ui/commons/themes/sap_fiori_3_dark/ProcessFlowLaneHeader.less +30 -31
  170. package/src/sap/suite/ui/commons/themes/sap_fiori_3_dark/ProcessFlowNode.less +157 -101
  171. package/src/sap/suite/ui/commons/themes/sap_fiori_3_hcb/ProcessFlowConnection.less +14 -7
  172. package/src/sap/suite/ui/commons/themes/sap_fiori_3_hcb/ProcessFlowConnectionLabel.less +38 -35
  173. package/src/sap/suite/ui/commons/themes/sap_fiori_3_hcb/ProcessFlowLaneHeader.less +30 -31
  174. package/src/sap/suite/ui/commons/themes/sap_fiori_3_hcb/ProcessFlowNode.less +147 -101
  175. package/src/sap/suite/ui/commons/themes/sap_fiori_3_hcw/ProcessFlowConnection.less +14 -7
  176. package/src/sap/suite/ui/commons/themes/sap_fiori_3_hcw/ProcessFlowConnectionLabel.less +38 -35
  177. package/src/sap/suite/ui/commons/themes/sap_fiori_3_hcw/ProcessFlowLaneHeader.less +30 -31
  178. package/src/sap/suite/ui/commons/themes/sap_fiori_3_hcw/ProcessFlowNode.less +158 -102
  179. package/src/sap/suite/ui/commons/themes/sap_horizon/MicroProcessFlow.less +5 -0
  180. package/src/sap/suite/ui/commons/themes/sap_horizon/NetworkLine.less +12 -8
  181. package/src/sap/suite/ui/commons/themes/sap_horizon/ProcessFlowConnection.less +17 -10
  182. package/src/sap/suite/ui/commons/themes/sap_horizon/ProcessFlowConnectionLabel.less +154 -133
  183. package/src/sap/suite/ui/commons/themes/sap_horizon/ProcessFlowLaneHeader.less +30 -32
  184. package/src/sap/suite/ui/commons/themes/sap_horizon/ProcessFlowNode.less +113 -214
  185. package/src/sap/suite/ui/commons/themes/sap_horizon/TimelineItem.less +43 -39
  186. package/src/sap/suite/ui/commons/themes/sap_horizon_dark/MicroProcessFlow.less +5 -0
  187. package/src/sap/suite/ui/commons/themes/sap_horizon_dark/NetworkLine.less +12 -12
  188. package/src/sap/suite/ui/commons/themes/sap_horizon_dark/ProcessFlowConnection.less +17 -10
  189. package/src/sap/suite/ui/commons/themes/sap_horizon_dark/ProcessFlowConnectionLabel.less +154 -133
  190. package/src/sap/suite/ui/commons/themes/sap_horizon_dark/ProcessFlowLaneHeader.less +30 -31
  191. package/src/sap/suite/ui/commons/themes/sap_horizon_dark/ProcessFlowNode.less +114 -216
  192. package/src/sap/suite/ui/commons/themes/sap_horizon_dark/TimelineItem.less +41 -39
  193. package/src/sap/suite/ui/commons/themes/sap_horizon_hcb/MicroProcessFlow.less +4 -4
  194. package/src/sap/suite/ui/commons/themes/sap_horizon_hcb/ProcessFlowConnection.less +17 -10
  195. package/src/sap/suite/ui/commons/themes/sap_horizon_hcb/ProcessFlowConnectionLabel.less +153 -131
  196. package/src/sap/suite/ui/commons/themes/sap_horizon_hcb/ProcessFlowLaneHeader.less +29 -30
  197. package/src/sap/suite/ui/commons/themes/sap_horizon_hcb/ProcessFlowNode.less +159 -103
  198. package/src/sap/suite/ui/commons/themes/sap_horizon_hcb/TimelineItem.less +41 -39
  199. package/src/sap/suite/ui/commons/themes/sap_horizon_hcw/MicroProcessFlow.less +4 -4
  200. package/src/sap/suite/ui/commons/themes/sap_horizon_hcw/ProcessFlowConnection.less +16 -9
  201. package/src/sap/suite/ui/commons/themes/sap_horizon_hcw/ProcessFlowConnectionLabel.less +153 -131
  202. package/src/sap/suite/ui/commons/themes/sap_horizon_hcw/ProcessFlowLaneHeader.less +29 -30
  203. package/src/sap/suite/ui/commons/themes/sap_horizon_hcw/ProcessFlowNode.less +157 -101
  204. package/src/sap/suite/ui/commons/themes/sap_horizon_hcw/TimelineItem.less +41 -39
  205. package/src/sap/suite/ui/commons/themes/base/DateRangeSlider.less +0 -3
  206. package/src/sap/suite/ui/commons/themes/base/MonitoringTile.less +0 -3
@@ -367,12 +367,28 @@ sap.ui.define([
367
367
  }
368
368
  };
369
369
 
370
+ /**
371
+ * Returns the horizontal scroll position in graph coordinates, accounting for RTL.
372
+ */
373
+ GraphMap.prototype._getScrollLeftForMap = function (oGraph) {
374
+ const fScrollLeft = oGraph.$scroller[0].scrollLeft;
375
+
376
+ if (oGraph._bIsRtl) {
377
+ const iGraphWidth = oGraph.$svg.width() / oGraph._fZoomLevel;
378
+ const iViewportWidth = oGraph.$scroller.width() / oGraph._fZoomLevel;
379
+ const iScrollPosAbs = Math.abs(fScrollLeft) / oGraph._fZoomLevel;
380
+ return iGraphWidth - iScrollPosAbs - iViewportWidth;
381
+ }
382
+
383
+ return fScrollLeft / oGraph._fZoomLevel;
384
+ };
385
+
370
386
  GraphMap.prototype._resize = function () {
371
387
  var oGraph = this.getGraph(),
372
388
  $scroller = oGraph.$scroller,
373
389
  $mapNavigator = this.$("mapNavigator");
374
390
 
375
- $mapNavigator.attr("x", Math.max(NAVIGATORLINESIZE / 2, $scroller[0].scrollLeft / oGraph._fZoomLevel));
391
+ $mapNavigator.attr("x", Math.max(NAVIGATORLINESIZE / 2, this._getScrollLeftForMap(oGraph)));
376
392
  $mapNavigator.attr("y", Math.max(NAVIGATORLINESIZE / 2, $scroller[0].scrollTop / oGraph._fZoomLevel));
377
393
 
378
394
  $mapNavigator.attr("width", $scroller.width() / oGraph._fZoomLevel);
@@ -403,7 +419,7 @@ sap.ui.define([
403
419
  $mapNavigator = this.$("mapNavigator");
404
420
 
405
421
  if (oGraph && $scroller[0]) {
406
- $mapNavigator.attr("x", Math.max(NAVIGATORLINESIZE / 2, $scroller[0].scrollLeft / oGraph._fZoomLevel));
422
+ $mapNavigator.attr("x", Math.max(NAVIGATORLINESIZE / 2, this._getScrollLeftForMap(oGraph)));
407
423
  $mapNavigator.attr("y", Math.max(NAVIGATORLINESIZE / 2, $scroller[0].scrollTop / oGraph._fZoomLevel));
408
424
 
409
425
  this._correctMapNavigator();
@@ -424,7 +440,13 @@ sap.ui.define([
424
440
  fRealStartX = $border.offset().left,
425
441
  fRealStartY = $border.offset().top;
426
442
 
427
- oScroller.scrollLeft = (oScrollData.pageX - fRealStartX) * iRatio - ($scroller.width() / 2);
443
+ const fTargetScrollLeft = (oScrollData.pageX - fRealStartX) * iRatio - ($scroller.width() / 2);
444
+ if (oGraph._bIsRtl) {
445
+ const iScrollRange = oScroller.scrollWidth - oScroller.clientWidth;
446
+ oScroller.scrollLeft = -(iScrollRange - fTargetScrollLeft);
447
+ } else {
448
+ oScroller.scrollLeft = fTargetScrollLeft;
449
+ }
428
450
  oScroller.scrollTop = (oScrollData.pageY - fRealStartY) * iRatio - ($scroller.height() / 2);
429
451
  };
430
452
 
@@ -43,7 +43,6 @@ sap.ui.define([
43
43
  oRM.openStart("div", oNetworkGraph.getId() + "-wrapper" );
44
44
  oRM.class("sapSuiteUiCommonsNetworkGraphContentWrapper");
45
45
  oRM.attr("tabindex", "0");
46
- oRM.attr("aria-live", "assertive");
47
46
  oRM.attr("aria-label", oResourceBundle.getText("NETWORK_GRAPH_ACCESSIBILITY_LABEL"));
48
47
  oRM.attr("role", "application");
49
48
  oRM.openEnd();
@@ -54,6 +53,7 @@ sap.ui.define([
54
53
  */
55
54
  oRM.openStart("div", oNetworkGraph.getId() + "-accessibility" );
56
55
  oRM.class("sapSuiteUiCommonsNetworkGraphContentWrapperAccessibility");
56
+ oRM.attr("aria-live", "off");
57
57
  oRM.openEnd();
58
58
  oRM.text(oResourceBundle.getText("NETWORK_GRAPH_ACCESSIBILITY_CONTENT"));
59
59
  oRM.close("div");
@@ -14,11 +14,12 @@ sap.ui.define([
14
14
  "sap/ui/events/KeyCodes",
15
15
  "sap/ui/dom/containsOrEquals",
16
16
  "sap/base/Log",
17
- "sap/ui/core/Lib",
18
- "sap/ui/core/Element"
19
- ], function (jQuery, BaseObject, Group, Node, Line, KeyCodes, containsOrEquals, Log, CoreLib, Element) {
17
+ "sap/ui/core/Lib"
18
+ ], function (jQuery, BaseObject, Group, Node, Line, KeyCodes, containsOrEquals, Log, CoreLib) {
20
19
  "use strict";
21
20
 
21
+ const oResourceBundle = CoreLib.getResourceBundleFor("sap.suite.ui.commons");
22
+
22
23
  var mDirections = {
23
24
  LEFT: "left",
24
25
  RIGHT: "right",
@@ -74,6 +75,13 @@ sap.ui.define([
74
75
  this._oFocusPosition = null;
75
76
  this._oWrapperDom = null;
76
77
  this.isFromFullscreen = null;
78
+ this._oAltNode = null;
79
+ this._oAltConnectors = null;
80
+ this._oAltAnnouncement = null;
81
+ this._oAssociatedControl = null;
82
+ this._oAssociatedContainer = null;
83
+ this._oAssociatedDelegate = null;
84
+ this._bCtrlAltDown = false;
77
85
  }
78
86
  });
79
87
 
@@ -124,6 +132,14 @@ sap.ui.define([
124
132
  this._iColumns = aRow.length;
125
133
  }
126
134
  }, this);
135
+
136
+ const oControl = this._oGraph.getAssociatedControl();
137
+ if (oControl !== this._oAssociatedControl) {
138
+ this._updateAssociatedDelegate(oControl);
139
+ }
140
+ this._oAltNode = null;
141
+ this._oAltConnectors = null;
142
+ this._oAltAnnouncement = null;
127
143
  };
128
144
 
129
145
  KeyboardNavigator.prototype.setWrapperDom = function (oDom) {
@@ -229,6 +245,12 @@ sap.ui.define([
229
245
  KeyboardNavigator.prototype.onkeydown = function (oEvent) {
230
246
  var oItem, oBtn,
231
247
  oFocus = this.getFocus();
248
+
249
+ // On Windows, Ctrl+Alt = AltGr — browsers strip ctrlKey/altKey from the character keydown.
250
+ if (oEvent.keyCode === KeyCodes.ALT && oEvent.ctrlKey) {
251
+ this._bCtrlAltDown = true;
252
+ }
253
+
232
254
  if (!oFocus) {
233
255
  return;
234
256
  }
@@ -256,11 +278,7 @@ sap.ui.define([
256
278
  }
257
279
  oEvent.stopPropagation();
258
280
  } else if (oEvent.keyCode === KeyCodes.F6) {
259
- if (oItem && oBtn) {
260
- oFocus.button = null;
261
- this._oGraph.setFocus(oFocus);
262
- }
263
- this._handleArrow(oEvent, oEvent.shiftKey ? mDirections.LEFT : mDirections.RIGHT);
281
+ this._handleF6(oEvent);
264
282
  } else if (oEvent.keyCode === KeyCodes.F7 && !oEvent.shiftKey) {
265
283
  if (oItem && oBtn) {
266
284
  oFocus.button = null;
@@ -272,12 +290,24 @@ sap.ui.define([
272
290
  this._onCtrlPlus(oEvent);
273
291
  } else if (oEvent.ctrlKey && (oEvent.keyCode === KeyCodes.SLASH || oEvent.keyCode === KeyCodes.NUMPAD_MINUS)) {
274
292
  this._onCtrlMinus(oEvent);
275
- } else if(oEvent.ctrlKey && oEvent.altKey && oEvent.keyCode === KeyCodes.P) {
276
- var oAssociatedControl = this._oGraph.getAssociatedControl();
293
+ } else if (this._bCtrlAltDown && oEvent.keyCode === KeyCodes.P) {
294
+ this._bCtrlAltDown = false;
295
+ const oAssociatedControl = this._oGraph.getAssociatedControl();
277
296
  if (oAssociatedControl) {
278
297
  oAssociatedControl.focus();
279
298
  oItem._setFocus(false);
280
299
  }
300
+ oEvent.preventDefault();
301
+ oEvent.stopPropagation();
302
+ } else if (oEvent.altKey && !oEvent.ctrlKey && !oEvent.shiftKey && oItem instanceof Node) {
303
+ if (oEvent.keyCode === KeyCodes.PLUS || oEvent.keyCode === KeyCodes.NUMPAD_PLUS) {
304
+ this._handleAltAnnounce(oEvent, oItem);
305
+ } else {
306
+ const iDigitIndex = this._getAltDigitIndex(oEvent.keyCode);
307
+ if (iDigitIndex >= 0) {
308
+ this._handleAltConnectorNavigation(oEvent, oItem, iDigitIndex);
309
+ }
310
+ }
281
311
  }
282
312
  };
283
313
 
@@ -285,6 +315,59 @@ sap.ui.define([
285
315
  /* Private methods */
286
316
  /* =========================================================== */
287
317
 
318
+ KeyboardNavigator.prototype._getAltDigitIndex = function (iKeyCode) {
319
+ if (iKeyCode >= KeyCodes.DIGIT_1 && iKeyCode <= KeyCodes.DIGIT_9) {
320
+ return iKeyCode - KeyCodes.DIGIT_1;
321
+ }
322
+ if (iKeyCode >= KeyCodes.NUMPAD_1 && iKeyCode <= KeyCodes.NUMPAD_9) {
323
+ return iKeyCode - KeyCodes.NUMPAD_1;
324
+ }
325
+ return -1;
326
+ };
327
+
328
+ /**
329
+ * Handles F6 / Shift+F6 — skip to next/previous visible group regardless of what is focused.
330
+ * @private
331
+ */
332
+ KeyboardNavigator.prototype._handleF6 = function (oEvent) {
333
+ const bBackward = oEvent.shiftKey,
334
+ oFocus = this.getFocus(),
335
+ oItem = oFocus ? oFocus.item : null,
336
+ bIsRtl = this._oGraph._bIsRtl,
337
+ aGroups = this._oGraph.getGroups().filter(function (oGroup) {
338
+ return !oGroup.isHidden() && oGroup.getVisible();
339
+ }).sort(function (oA, oB) {
340
+ // Top-to-bottom, then by reading direction (RTL: descending x, LTR: ascending x)
341
+ const iDeltaY = oA.getY() - oB.getY();
342
+ if (iDeltaY !== 0) { return iDeltaY; }
343
+ const iDeltaX = oA.getX() - oB.getX();
344
+ return bIsRtl ? -iDeltaX : iDeltaX;
345
+ });
346
+
347
+ if (aGroups.length === 0) {
348
+ return;
349
+ }
350
+
351
+ let iCurrentIndex = -1;
352
+ if (oItem instanceof Group) {
353
+ iCurrentIndex = aGroups.indexOf(oItem);
354
+ } else if (oItem instanceof Node && oItem._oGroup) {
355
+ iCurrentIndex = aGroups.indexOf(oItem._oGroup);
356
+ }
357
+
358
+ const iTargetIndex = bBackward
359
+ ? (iCurrentIndex > 0 ? iCurrentIndex - 1 : aGroups.length - 1)
360
+ : (iCurrentIndex < aGroups.length - 1 ? iCurrentIndex + 1 : 0);
361
+
362
+ // Ensure setFocus lands on the group header, not the menu button
363
+ if (this._oGraph._oFocus) {
364
+ this._oGraph._oFocus.groupInFocused = false;
365
+ }
366
+ this._oGraph.setFocus({ item: aGroups[iTargetIndex], button: null });
367
+ oEvent.preventDefault();
368
+ oEvent.stopPropagation();
369
+ };
370
+
288
371
  KeyboardNavigator.prototype._handleEnter = function () {
289
372
  var oItem, oBtn,
290
373
  oFocus = this.getFocus();
@@ -372,12 +455,33 @@ sap.ui.define([
372
455
  }
373
456
  };
374
457
 
458
+ /**
459
+ * Fires the nodeAdded event and shifts focus to the newly added node after re-render.
460
+ * Only active when DnD is enabled.
461
+ * @private
462
+ */
463
+ KeyboardNavigator.prototype._handleAddNode = function (oEvent) {
464
+ if (!this._oGraph._isDnDEnabled()) {
465
+ return;
466
+ }
467
+ this._oGraph.fireEvent("nodeAdded", {}, false);
468
+ const fnFocus = () => {
469
+ this._oGraph.detachGraphReady(fnFocus);
470
+ const aNodes = this._oGraph.getNodes();
471
+ if (aNodes.length) {
472
+ this._oGraph.setFocus({ item: aNodes.at(-1), button: null });
473
+ }
474
+ };
475
+ this._oGraph.attachGraphReady(fnFocus);
476
+ oEvent.preventDefault();
477
+ oEvent.stopPropagation();
478
+ };
479
+
375
480
  KeyboardNavigator.prototype._handleTab = function (oEvent, sDirection) {
376
- var oResourceBundle = CoreLib.getResourceBundleFor("sap.suite.ui.commons");
377
- this._oWrapperDom.setAttribute("aria-live","assertive");
481
+ const oFocus = this.getFocus(),
482
+ bBackward = sDirection === mDirections.LEFT;
378
483
  this._oGraph._setAriaLabelForWrapper(oResourceBundle.getText("NETWORK_GRAPH_ACCESSIBILITY_LABEL"));
379
484
  if (this._ignoreEvent(oEvent)) {
380
- this._oWrapperDom.setAttribute("aria-live","off");
381
485
  this._oWrapperDom.classList.remove("sapSuiteUiCommonsNetworkGraphContentFocusHidden");
382
486
  if (oEvent.target.getAttribute("title") === oResourceBundle.getText("CALCULATION_BUILDER_ENTER_FULL_SCREEN_BUTTON")){
383
487
  this.isFromFullscreen = true;
@@ -386,6 +490,12 @@ sap.ui.define([
386
490
  }
387
491
  return;
388
492
  } else {
493
+ if (sDirection === mDirections.LEFT && this._bWrapperHighlighted && !this.getFocus()) {
494
+ this._oWrapperDom.classList.add("sapSuiteUiCommonsNetworkGraphContentFocusHidden");
495
+ this._bWrapperHighlighted = false;
496
+ return;
497
+ }
498
+ this._bWrapperHighlighted = false;
389
499
  this._oWrapperDom.classList.add("sapSuiteUiCommonsNetworkGraphContentFocusHidden");
390
500
  }
391
501
 
@@ -396,7 +506,118 @@ sap.ui.define([
396
506
  return;
397
507
  }
398
508
 
399
- this._moveItemFocus(oEvent, sDirection);
509
+ if (oFocus?.item instanceof Node) {
510
+ const bMoved = this._navigateFromNode(oFocus.item, bBackward);
511
+ if (!bMoved && bBackward) {
512
+ const oGroup = oFocus.item._oGroup;
513
+ if (oGroup) {
514
+ this._oGraph.setFocus({ item: oGroup, button: Group.BUTTONS.COLLAPSE });
515
+ oEvent.preventDefault();
516
+ oEvent.stopPropagation();
517
+ } else {
518
+ this._moveItemFocus(oEvent, mDirections.LEFT);
519
+ }
520
+ return;
521
+ }
522
+ } else if (oFocus?.item instanceof Line) {
523
+ this._navigateFromConnector(oFocus.item, bBackward);
524
+ } else {
525
+ this._moveItemFocus(oEvent, sDirection);
526
+ return;
527
+ }
528
+
529
+ oEvent.preventDefault();
530
+ oEvent.stopPropagation();
531
+ };
532
+
533
+ /**
534
+ * Navigate from a node to its first connector.
535
+ * @returns {boolean} True if focus moved to a connector, false otherwise
536
+ * @private
537
+ */
538
+ KeyboardNavigator.prototype._navigateFromNode = function (oNode, bBackward) {
539
+ const aLines = bBackward ? oNode.getParentLines() : oNode.getChildLines();
540
+ const aVisibleLines = this._getVisibleLines(aLines, bBackward);
541
+
542
+ if (aVisibleLines.length > 0) {
543
+ this._oGraph.setFocus({
544
+ item: aVisibleLines[0],
545
+ button: null
546
+ });
547
+ return true;
548
+ }
549
+ return false;
550
+ };
551
+
552
+ /**
553
+ * Navigate from a connector to its connected node
554
+ * @param {Line} oLine - The connector to navigate from
555
+ * @param {boolean} bBackward - True for source node, false for target node
556
+ * @private
557
+ */
558
+ KeyboardNavigator.prototype._navigateFromConnector = function (oLine, bBackward) {
559
+ const oNode = bBackward ? oLine.getFromNode() : oLine.getToNode();
560
+
561
+ if (oNode && !oNode.isHidden()) {
562
+ this._oGraph.setFocus({
563
+ item: oNode,
564
+ button: null
565
+ });
566
+ }
567
+ };
568
+
569
+ /**
570
+ * Returns visible lines sorted top-to-bottom.
571
+ * @param {Array} aLines - Array of lines to filter and sort
572
+ * @param {boolean} bSortBySource - If true, sort by source node Y position; otherwise by target node
573
+ * @private
574
+ */
575
+ KeyboardNavigator.prototype._getVisibleLines = function (aLines, bSortBySource) {
576
+ if (!aLines || aLines.length === 0) {
577
+ return [];
578
+ }
579
+
580
+ const aVisibleLines = aLines.filter(function (oLine) {
581
+ return !oLine.isHidden() && !oLine._isIgnored() && oLine.getVisible();
582
+ });
583
+
584
+ const fnGetSortY = (oLine) => {
585
+ const oNode = bSortBySource ? oLine.getFromNode() : oLine.getToNode();
586
+ if (oNode && !oNode.isHidden()) {
587
+ return oNode.getY();
588
+ }
589
+ const aCoords = oLine.getCoordinates();
590
+ return (aCoords && aCoords.length > 0) ? aCoords[0].getY() : 0;
591
+ };
592
+ return aVisibleLines.sort((oLine1, oLine2) => fnGetSortY(oLine1) - fnGetSortY(oLine2));
593
+ };
594
+
595
+ KeyboardNavigator.prototype._handleAltAnnounce = function (oEvent, oNode) {
596
+ if (this._oAltNode !== oNode) {
597
+ this._oAltNode = oNode;
598
+ this._oAltConnectors = oNode._getAltNavigationConnectors();
599
+ const { aIncomingConnectors, aOutgoingConnectors, aConnectors } = this._oAltConnectors;
600
+ this._oAltAnnouncement = (aIncomingConnectors.length >= 2 || aOutgoingConnectors.length >= 2)
601
+ ? oNode._getAltConnectorsAnnouncement(aConnectors)
602
+ : null;
603
+ }
604
+ if (!this._oAltAnnouncement) { return; }
605
+ this._oGraph._setAccessibilityTitle(this._oAltAnnouncement);
606
+ oEvent.preventDefault();
607
+ oEvent.stopPropagation();
608
+ };
609
+
610
+ KeyboardNavigator.prototype._handleAltConnectorNavigation = function (oEvent, oNode, iIndex) {
611
+ if (this._oAltNode !== oNode || !this._oAltConnectors) {
612
+ this._oAltNode = oNode;
613
+ this._oAltConnectors = oNode._getAltNavigationConnectors();
614
+ }
615
+ const { aConnectors } = this._oAltConnectors;
616
+ if (iIndex < aConnectors.length) {
617
+ this._oGraph.setFocus({ item: aConnectors[iIndex].line, button: null });
618
+ oEvent.preventDefault();
619
+ oEvent.stopPropagation();
620
+ }
400
621
  };
401
622
 
402
623
  KeyboardNavigator.prototype._handleTabOverLinesWithButtons = function (oEvent, sDirection) {
@@ -624,12 +845,64 @@ sap.ui.define([
624
845
  return;
625
846
  }
626
847
 
848
+ const oFocus = this.getFocus();
849
+ const oItem = oFocus.item;
850
+ if (oItem instanceof Line) {
851
+ if (sDirection === mDirections.UP || sDirection === mDirections.DOWN) {
852
+ this._navigateBetweenConnectors(oEvent, sDirection);
853
+ return;
854
+ }
855
+ }
856
+
857
+ // For all other cases, use default behavior
627
858
  this._moveItemFocus(oEvent, sDirection, true);
628
859
  };
629
860
 
861
+ /**
862
+ * Navigate between multiple connectors from the same source node
863
+ * @private
864
+ */
865
+ KeyboardNavigator.prototype._navigateBetweenConnectors = function (oEvent, sDirection) {
866
+ const oFocus = this.getFocus(),
867
+ oLine = oFocus.item;
868
+
869
+ if (!(oLine instanceof Line)) {
870
+ return;
871
+ }
872
+
873
+ // ↑/↓ navigates among the outgoing connectors of this line's source node,
874
+ // giving a consistent vertical ordering regardless of which connector is focused.
875
+ const oSourceNode = oLine.getFromNode();
876
+ if (!oSourceNode) {
877
+ return;
878
+ }
879
+
880
+ const aVisibleLines = this._getVisibleLines(oSourceNode.getChildLines());
881
+ if (aVisibleLines.length <= 1) {
882
+ return;
883
+ }
884
+
885
+ const iCurrentIndex = aVisibleLines.indexOf(oLine);
886
+ if (iCurrentIndex === -1) {
887
+ return;
888
+ }
889
+
890
+ const iTargetIndex = sDirection === mDirections.DOWN ? iCurrentIndex + 1 : iCurrentIndex - 1;
891
+ if (iTargetIndex >= 0 && iTargetIndex < aVisibleLines.length) {
892
+ this._oGraph.setFocus({
893
+ item: aVisibleLines[iTargetIndex],
894
+ button: null
895
+ });
896
+ }
897
+
898
+ oEvent.preventDefault();
899
+ oEvent.stopPropagation();
900
+ };
901
+
630
902
  KeyboardNavigator.prototype._moveItemFocus = function (oEvent, sDirection, bStopOnLast) {
631
903
  var oFocus,
632
904
  bBackTab = (sDirection === mDirections.LEFT && oEvent.key === "Tab"),
905
+ bHadFocus = !!this.getFocus(),
633
906
  oPosition,
634
907
  oNewItem,
635
908
  aBtns;
@@ -667,6 +940,11 @@ sap.ui.define([
667
940
  if (oEvent && oNewItem) {
668
941
  oEvent.preventDefault();
669
942
  oEvent.stopPropagation();
943
+ } else if (bBackTab && !oNewItem && bHadFocus) {
944
+ this._oWrapperDom.classList.remove("sapSuiteUiCommonsNetworkGraphContentFocusHidden");
945
+ this._bWrapperHighlighted = true;
946
+ oEvent.preventDefault();
947
+ oEvent.stopPropagation();
670
948
  }
671
949
  };
672
950
 
@@ -815,6 +1093,45 @@ sap.ui.define([
815
1093
  oEvent.stopPropagation();
816
1094
  };
817
1095
 
1096
+ KeyboardNavigator.prototype._updateAssociatedDelegate = function (oControl) {
1097
+ if (this._oAssociatedContainer) {
1098
+ this._oAssociatedContainer.removeEventDelegate(this._oAssociatedDelegate);
1099
+ this._oAssociatedContainer = null;
1100
+ this._oAssociatedDelegate = null;
1101
+ }
1102
+ const oContainer = oControl && oControl.getParent();
1103
+ if (oContainer) {
1104
+ this._oAssociatedDelegate = {
1105
+ onkeydown: (oEvent) => {
1106
+ if (oEvent.keyCode === KeyCodes.ALT && oEvent.ctrlKey) {
1107
+ this._bCtrlAltDown = true;
1108
+ }
1109
+
1110
+ if (oEvent.shiftKey && oEvent.keyCode === KeyCodes.F10) {
1111
+ this._oGraph._restoreFocusToGraph();
1112
+ oEvent.preventDefault();
1113
+ oEvent.stopPropagation();
1114
+ } else if (oEvent.keyCode === KeyCodes.INSERT || (this._bCtrlAltDown && oEvent.keyCode === KeyCodes.N)) {
1115
+ this._bCtrlAltDown = false;
1116
+ this._handleAddNode(oEvent);
1117
+ }
1118
+ }
1119
+ };
1120
+ this._oAssociatedContainer = oContainer;
1121
+ oContainer.addEventDelegate(this._oAssociatedDelegate);
1122
+ }
1123
+ this._oAssociatedControl = oControl;
1124
+ };
1125
+
1126
+ KeyboardNavigator.prototype.destroy = function () {
1127
+ if (this._oAssociatedContainer) {
1128
+ this._oAssociatedContainer.removeEventDelegate(this._oAssociatedDelegate);
1129
+ this._oAssociatedContainer = null;
1130
+ this._oAssociatedDelegate = null;
1131
+ }
1132
+ BaseObject.prototype.destroy.apply(this, arguments);
1133
+ };
1134
+
818
1135
  KeyboardNavigator.prototype._ignoreEvent = function (oEvent) {
819
1136
  return !containsOrEquals(this._oWrapperDom, oEvent.target);
820
1137
  };
@@ -883,7 +883,11 @@ sap.ui.define([
883
883
  Line.prototype._getAccessibilityLabel = function (oGraph) {
884
884
  const aSentenceParts = [];
885
885
  const sConnectionType = this.getConnectionType();
886
- const sConnectionTypeText = oGraph.getConnectionTypeMapping()[sConnectionType];
886
+ const oMapping = oGraph.getConnectionTypeMapping();
887
+ // In RTL mode, left and right sides of nodes are semantically swapped
888
+ const bRTL = this.getParent()._bIsRtl;
889
+ const sResolvedType = bRTL ? (Utils.mRTLSwap[sConnectionType] || sConnectionType) : sConnectionType;
890
+ const sConnectionTypeText = oMapping[sResolvedType];
887
891
  const sFromNodeTitle = this.getFromNode().getTitle();
888
892
  const sFromNodeText = sFromNodeTitle ? sFromNodeTitle : this.getFromNode().getAltText();
889
893
  const sToNodeTitle = this.getToNode().getTitle();
@@ -1001,10 +1001,10 @@ sap.ui.define([
1001
1001
  }, false);
1002
1002
 
1003
1003
  let { style: sBorderColor, class: sBorderClass } = this._getStatusStyle({
1004
- "border-color": ElementBase.ColorType.Border,
1004
+ "outline-color": ElementBase.ColorType.Border,
1005
1005
  "background-color": this.getSelected() ? ElementBase.ColorType.SelectedBackground : "",
1006
- "border-width": ElementBase.ColorType.BorderWidth,
1007
- "border-style": ElementBase.ColorType.BorderStyle
1006
+ "outline-width": ElementBase.ColorType.BorderWidth,
1007
+ "outline-style": ElementBase.ColorType.BorderStyle
1008
1008
  }, false);
1009
1009
 
1010
1010
  mOptions.renderManager.openStart("div", sId + "-wrapperwithbuttons");
@@ -2754,9 +2754,71 @@ sap.ui.define([
2754
2754
  aSentenceParts.push(oResourceBundle.getText("NETWORK_GRAPH_NAVIGATION_SHIFT_TAB_TO_INCOMING"));
2755
2755
  }
2756
2756
 
2757
+ const { aIncomingConnectors, aOutgoingConnectors } = this._getAltNavigationConnectors();
2758
+ if (aIncomingConnectors.length >= 2 || aOutgoingConnectors.length >= 2) {
2759
+ aSentenceParts.push(oResourceBundle.getText("NETWORK_GRAPH_NAVIGATION_ALT_CONNECTORS"));
2760
+ }
2761
+
2757
2762
  return `${sLabel}. ${aSentenceParts.join(". ")}.`;
2758
2763
  };
2759
2764
 
2765
+ Node.prototype._getAltNavigationConnectors = function () {
2766
+ const iThisX = this.getX();
2767
+ const fnDir = (oNode) => oNode?.getX() < iThisX ? "left" : "right";
2768
+ const fnActive = (oLine) => oLine.getVisible() && !oLine.isHidden() && !oLine._isIgnored();
2769
+
2770
+ // Incoming: all valid lines, sorted top-to-bottom by source node Y, then by node key for stability
2771
+ const aIncomingConnectors = this.getParentLines()
2772
+ .filter((oLine) => fnActive(oLine) && oLine.getFromNode())
2773
+ .sort((a, b) => {
2774
+ const iY = a.getFromNode().getY() - b.getFromNode().getY();
2775
+ return iY !== 0 ? iY : a.getFromNode().getKey().localeCompare(b.getFromNode().getKey());
2776
+ })
2777
+ .map((oLine) => ({ line: oLine, type: "incoming", direction: fnDir(oLine.getFromNode()) }));
2778
+
2779
+ // Outgoing: all valid lines, sorted top-to-bottom by target node Y, then by node key for stability
2780
+ const aOutgoingConnectors = this.getChildLines()
2781
+ .filter((oLine) => fnActive(oLine) && oLine.getToNode())
2782
+ .sort((a, b) => {
2783
+ const iY = a.getToNode().getY() - b.getToNode().getY();
2784
+ return iY !== 0 ? iY : a.getToNode().getKey().localeCompare(b.getToNode().getKey());
2785
+ })
2786
+ .map((oLine) => ({ line: oLine, type: "outgoing", direction: fnDir(oLine.getToNode()) }));
2787
+
2788
+ const aConnectors = ["left", "right"].flatMap((sDir) => [
2789
+ ...aIncomingConnectors.filter((o) => o.direction === sDir),
2790
+ ...aOutgoingConnectors.filter((o) => o.direction === sDir)
2791
+ ]);
2792
+
2793
+ return { aIncomingConnectors, aOutgoingConnectors, aConnectors };
2794
+ };
2795
+
2796
+ Node.prototype._getAltConnectorsAnnouncement = function (aConnectors) {
2797
+ const oGraph = this.getParent();
2798
+ const oMapping = oGraph.getConnectionTypeMapping();
2799
+ const bRTL = oGraph._bIsRtl;
2800
+ return aConnectors.map((oConnector, i) => {
2801
+ const oLine = oConnector.line;
2802
+ const sConnectionType = oLine.getConnectionType();
2803
+ const sResolvedType = bRTL ? (Utils.mRTLSwap[sConnectionType] || sConnectionType) : sConnectionType;
2804
+ const sConnectionTypeText = oMapping[sResolvedType] || sResolvedType;
2805
+ const sFromNodeTitle = oLine.getFromNode().getTitle() || oLine.getFromNode().getAltText();
2806
+ const sToNodeTitle = oLine.getToNode().getTitle() || oLine.getToNode().getAltText();
2807
+ // Determine the physical port side from connection type (Left key = left port, Right key = right port)
2808
+ const sSide = oConnector.type === "outgoing"
2809
+ ? (sResolvedType.startsWith("Left") ? "left" : "right")
2810
+ : (sResolvedType.endsWith("Left") ? "left" : "right");
2811
+ return oResourceBundle.getText("NETWORK_GRAPH_NAVIGATION_ALT_CONNECTOR_ANNOUNCE", [
2812
+ oConnector.type,
2813
+ sSide,
2814
+ sConnectionTypeText,
2815
+ sFromNodeTitle,
2816
+ sToNodeTitle,
2817
+ i + 1
2818
+ ]);
2819
+ }).join(". ");
2820
+ };
2821
+
2760
2822
  Node.prototype._setStatusColors = function(sType) {
2761
2823
  var fnSetAttrColor = function(item, sStatus) {
2762
2824
  if (sStatus && item) {
@@ -2818,10 +2880,10 @@ sap.ui.define([
2818
2880
  $titleText = this.$().find(".sapSuiteUiCommonsNetworkGraphDivNodeTitleText");
2819
2881
 
2820
2882
  if(SemanticColorType.hasOwnProperty(sBackgroundColor)){
2821
- $wrapper.addClass(Utils.SEMANTIC_CLASS_NAME.BORDER + sBackgroundColor);
2883
+ $wrapper.addClass(Utils.SEMANTIC_CLASS_NAME.OUTLINE + sBackgroundColor);
2822
2884
  } else {
2823
2885
  /** @deprecated As of 1.120 */
2824
- $wrapper.css("border-color", sBorderColor);
2886
+ $wrapper.css("outline-color", sBorderColor);
2825
2887
  }
2826
2888
 
2827
2889
  let sFocusColor = this._getColor(ElementBase.ColorType[sType + "Focus"])
@@ -24,6 +24,8 @@ sap.ui.define(["sap/base/Log"], function (Log) {
24
24
  'BACKGROUND-COLOR': 'backgroundSemanticColor',
25
25
  BORDER: 'borderSemanticColor',
26
26
  'BORDER-COLOR': 'borderSemanticColor',
27
+ OUTLINE: 'outlineSemanticColor',
28
+ 'OUTLINE-COLOR': 'outlineSemanticColor',
27
29
  TEXT: 'textSemanticColor',
28
30
  FILL: 'fillSemanticColor',
29
31
  STROKE: 'strokeSemanticColor',
@@ -312,5 +314,13 @@ sap.ui.define(["sap/base/Log"], function (Log) {
312
314
  }, delay);
313
315
  };
314
316
 
317
+ // RTL swap map for connection types: mirrors Left↔Right side labels.
318
+ Utils.mRTLSwap = {
319
+ "LeftToLeft": "RightToRight",
320
+ "LeftToRight": "RightToLeft",
321
+ "RightToLeft": "LeftToRight",
322
+ "RightToRight": "LeftToLeft"
323
+ };
324
+
315
325
  return Utils;
316
326
  }, true);