@sapui5/sap.suite.ui.commons 1.143.0 → 1.145.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 (126) 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 +26 -14
  5. package/src/sap/suite/ui/commons/CalculationBuilderExpression.js +2 -2
  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/CalculationBuilderInput.js +5 -5
  9. package/src/sap/suite/ui/commons/CalculationBuilderItem.js +1 -1
  10. package/src/sap/suite/ui/commons/CalculationBuilderValidationResult.js +1 -1
  11. package/src/sap/suite/ui/commons/CalculationBuilderVariable.js +1 -1
  12. package/src/sap/suite/ui/commons/CloudFilePicker.js +1 -3
  13. package/src/sap/suite/ui/commons/MicroProcessFlow.js +77 -73
  14. package/src/sap/suite/ui/commons/MicroProcessFlowItem.js +3 -3
  15. package/src/sap/suite/ui/commons/Timeline.js +9 -0
  16. package/src/sap/suite/ui/commons/TimelineNavigator.js +37 -5
  17. package/src/sap/suite/ui/commons/TimelineRenderer.js +3 -3
  18. package/src/sap/suite/ui/commons/collaboration/BaseHelperService.js +0 -1
  19. package/src/sap/suite/ui/commons/collaboration/CollaborationHelper.js +0 -3
  20. package/src/sap/suite/ui/commons/collaboration/CollaborationManagerService.js +0 -1
  21. package/src/sap/suite/ui/commons/collaboration/ContactHelper.js +7 -0
  22. package/src/sap/suite/ui/commons/collaboration/ContactPopover.fragment.xml +4 -1
  23. package/src/sap/suite/ui/commons/collaboration/MinimalContactPopover.fragment.xml +2 -1
  24. package/src/sap/suite/ui/commons/collaboration/TeamsHelperService.js +0 -6
  25. package/src/sap/suite/ui/commons/collaboration/channels/MessageChannel.js +0 -2
  26. package/src/sap/suite/ui/commons/collaboration/flpplugins/msplugin/Component-preload.js +1 -1
  27. package/src/sap/suite/ui/commons/collaboration/flpplugins/msplugin/Component.js +1 -2
  28. package/src/sap/suite/ui/commons/flexibility/changeHandler/PropertyChangeMapper.js +1 -1
  29. package/src/sap/suite/ui/commons/imageeditor/CropCustomShapeHistoryItem.js +1 -1
  30. package/src/sap/suite/ui/commons/imageeditor/CropEllipseHistoryItem.js +1 -1
  31. package/src/sap/suite/ui/commons/imageeditor/CropRectangleHistoryItem.js +1 -1
  32. package/src/sap/suite/ui/commons/imageeditor/CustomSizeItem.js +1 -1
  33. package/src/sap/suite/ui/commons/imageeditor/FilterHistoryItem.js +1 -1
  34. package/src/sap/suite/ui/commons/imageeditor/FlipHistoryItem.js +1 -1
  35. package/src/sap/suite/ui/commons/imageeditor/HistoryItem.js +1 -1
  36. package/src/sap/suite/ui/commons/imageeditor/ImageEditor.js +1 -1
  37. package/src/sap/suite/ui/commons/imageeditor/ImageEditorContainer.js +1 -1
  38. package/src/sap/suite/ui/commons/imageeditor/ImageEditorResponsiveContainer.js +1 -1
  39. package/src/sap/suite/ui/commons/imageeditor/ResizeHistoryItem.js +1 -1
  40. package/src/sap/suite/ui/commons/imageeditor/RotateHistoryItem.js +1 -1
  41. package/src/sap/suite/ui/commons/library.js +100 -3
  42. package/src/sap/suite/ui/commons/messagebundle.properties +76 -10
  43. package/src/sap/suite/ui/commons/messagebundle_ar.properties +51 -5
  44. package/src/sap/suite/ui/commons/messagebundle_bg.properties +62 -16
  45. package/src/sap/suite/ui/commons/messagebundle_ca.properties +52 -6
  46. package/src/sap/suite/ui/commons/messagebundle_cnr.properties +52 -6
  47. package/src/sap/suite/ui/commons/messagebundle_cs.properties +51 -5
  48. package/src/sap/suite/ui/commons/messagebundle_cy.properties +51 -5
  49. package/src/sap/suite/ui/commons/messagebundle_da.properties +51 -5
  50. package/src/sap/suite/ui/commons/messagebundle_de.properties +52 -6
  51. package/src/sap/suite/ui/commons/messagebundle_el.properties +52 -6
  52. package/src/sap/suite/ui/commons/messagebundle_en.properties +50 -7
  53. package/src/sap/suite/ui/commons/messagebundle_en_GB.properties +52 -6
  54. package/src/sap/suite/ui/commons/messagebundle_en_US_saprigi.properties +54 -6
  55. package/src/sap/suite/ui/commons/messagebundle_es.properties +53 -7
  56. package/src/sap/suite/ui/commons/messagebundle_es_MX.properties +54 -8
  57. package/src/sap/suite/ui/commons/messagebundle_et.properties +51 -5
  58. package/src/sap/suite/ui/commons/messagebundle_fi.properties +51 -5
  59. package/src/sap/suite/ui/commons/messagebundle_fr.properties +52 -6
  60. package/src/sap/suite/ui/commons/messagebundle_fr_CA.properties +52 -6
  61. package/src/sap/suite/ui/commons/messagebundle_hi.properties +52 -6
  62. package/src/sap/suite/ui/commons/messagebundle_hr.properties +52 -6
  63. package/src/sap/suite/ui/commons/messagebundle_hu.properties +51 -5
  64. package/src/sap/suite/ui/commons/messagebundle_id.properties +60 -14
  65. package/src/sap/suite/ui/commons/messagebundle_it.properties +53 -7
  66. package/src/sap/suite/ui/commons/messagebundle_iw.properties +51 -5
  67. package/src/sap/suite/ui/commons/messagebundle_ja.properties +52 -6
  68. package/src/sap/suite/ui/commons/messagebundle_kk.properties +51 -5
  69. package/src/sap/suite/ui/commons/messagebundle_ko.properties +51 -5
  70. package/src/sap/suite/ui/commons/messagebundle_lt.properties +51 -5
  71. package/src/sap/suite/ui/commons/messagebundle_lv.properties +52 -6
  72. package/src/sap/suite/ui/commons/messagebundle_mk.properties +51 -5
  73. package/src/sap/suite/ui/commons/messagebundle_ms.properties +59 -13
  74. package/src/sap/suite/ui/commons/messagebundle_nl.properties +51 -5
  75. package/src/sap/suite/ui/commons/messagebundle_no.properties +52 -6
  76. package/src/sap/suite/ui/commons/messagebundle_pl.properties +51 -5
  77. package/src/sap/suite/ui/commons/messagebundle_pt.properties +52 -6
  78. package/src/sap/suite/ui/commons/messagebundle_pt_PT.properties +51 -5
  79. package/src/sap/suite/ui/commons/messagebundle_ro.properties +51 -5
  80. package/src/sap/suite/ui/commons/messagebundle_ru.properties +51 -5
  81. package/src/sap/suite/ui/commons/messagebundle_sh.properties +52 -6
  82. package/src/sap/suite/ui/commons/messagebundle_sk.properties +51 -5
  83. package/src/sap/suite/ui/commons/messagebundle_sl.properties +51 -5
  84. package/src/sap/suite/ui/commons/messagebundle_sr.properties +52 -6
  85. package/src/sap/suite/ui/commons/messagebundle_sv.properties +51 -5
  86. package/src/sap/suite/ui/commons/messagebundle_th.properties +52 -6
  87. package/src/sap/suite/ui/commons/messagebundle_tr.properties +51 -5
  88. package/src/sap/suite/ui/commons/messagebundle_uk.properties +53 -7
  89. package/src/sap/suite/ui/commons/messagebundle_vi.properties +55 -9
  90. package/src/sap/suite/ui/commons/messagebundle_zh_CN.properties +51 -5
  91. package/src/sap/suite/ui/commons/messagebundle_zh_TW.properties +53 -7
  92. package/src/sap/suite/ui/commons/networkgraph/ElementBase.js +19 -1
  93. package/src/sap/suite/ui/commons/networkgraph/Graph.js +371 -29
  94. package/src/sap/suite/ui/commons/networkgraph/GraphRenderer.js +23 -10
  95. package/src/sap/suite/ui/commons/networkgraph/Group.js +43 -22
  96. package/src/sap/suite/ui/commons/networkgraph/KeyboardNavigator.js +54 -6
  97. package/src/sap/suite/ui/commons/networkgraph/Line.js +736 -31
  98. package/src/sap/suite/ui/commons/networkgraph/Node.js +546 -96
  99. package/src/sap/suite/ui/commons/networkgraph/Tooltip.js +5 -0
  100. package/src/sap/suite/ui/commons/networkgraph/layout/NoopLayout.js +28 -5
  101. package/src/sap/suite/ui/commons/networkgraph/util/ConnectionPathUtils.js +1144 -0
  102. package/src/sap/suite/ui/commons/networkgraph/util/CreateConnectionPopover.js +374 -0
  103. package/src/sap/suite/ui/commons/networkgraph/util/DependencyLayoutHelper.js +870 -0
  104. package/src/sap/suite/ui/commons/networkgraph/util/DragDropManager.js +563 -41
  105. package/src/sap/suite/ui/commons/networkgraph/util/PortManager.js +573 -0
  106. package/src/sap/suite/ui/commons/statusindicator/Circle.js +1 -1
  107. package/src/sap/suite/ui/commons/statusindicator/CustomShape.js +1 -1
  108. package/src/sap/suite/ui/commons/statusindicator/DiscreteThreshold.js +1 -1
  109. package/src/sap/suite/ui/commons/statusindicator/FillingOption.js +1 -1
  110. package/src/sap/suite/ui/commons/statusindicator/LibraryShape.js +1 -1
  111. package/src/sap/suite/ui/commons/statusindicator/Path.js +1 -1
  112. package/src/sap/suite/ui/commons/statusindicator/PropertyThreshold.js +1 -1
  113. package/src/sap/suite/ui/commons/statusindicator/Rectangle.js +1 -1
  114. package/src/sap/suite/ui/commons/statusindicator/Shape.js +1 -1
  115. package/src/sap/suite/ui/commons/statusindicator/ShapeGroup.js +1 -1
  116. package/src/sap/suite/ui/commons/statusindicator/SimpleShape.js +1 -1
  117. package/src/sap/suite/ui/commons/statusindicator/StatusIndicator.js +1 -1
  118. package/src/sap/suite/ui/commons/taccount/TAccount.js +1 -1
  119. package/src/sap/suite/ui/commons/taccount/TAccountGroup.js +1 -1
  120. package/src/sap/suite/ui/commons/taccount/TAccountItem.js +1 -1
  121. package/src/sap/suite/ui/commons/taccount/TAccountItemProperty.js +1 -1
  122. package/src/sap/suite/ui/commons/taccount/TAccountPanel.js +1 -1
  123. package/src/sap/suite/ui/commons/themes/base/NetworkGraph.less +13 -13
  124. package/src/sap/suite/ui/commons/themes/base/NetworkGroup.less +34 -2
  125. package/src/sap/suite/ui/commons/themes/base/NetworkLine.less +58 -13
  126. package/src/sap/suite/ui/commons/themes/base/NetworkNode.less +206 -1
@@ -22,20 +22,26 @@ sap.ui.define([
22
22
  "sap/ui/core/Lib",
23
23
  "./Utils",
24
24
  "sap/base/Log",
25
- "./util/DragDropManager"
26
- ], function(jQuery, library, ElementBase, ElementAttribute, IconPool, Device, encodeXML, sanitizeHTML, CheckBox, Text, NodeRenderer, Core, Theming, CoreLib, Utils, Log, DragDropManager) {
25
+ "./util/DragDropManager",
26
+ "./util/PortManager",
27
+ "./util/CreateConnectionPopover",
28
+ "sap/m/Menu",
29
+ "sap/m/MenuItem"
30
+ ], function(jQuery, library, ElementBase, ElementAttribute, IconPool, Device, encodeXML, sanitizeHTML, CheckBox, Text, NodeRenderer, Core, Theming, CoreLib, Utils, Log, DragDropManager, PortManager, CreateConnectionPopover, Menu, MenuItem) {
27
31
  "use strict";
28
32
 
29
33
  var Shape = library.networkgraph.NodeShape,
30
34
  ActionButtonPosition = library.networkgraph.ActionButtonPosition,
31
35
  HeaderCheckboxState = library.networkgraph.HeaderCheckboxState,
32
- SemanticColorType = library.SemanticColorType;
36
+ SemanticColorType = library.SemanticColorType,
37
+ NodePorts = library.networkgraph.NodePorts;
33
38
 
34
39
  var HEADER_SIZE = 32,
35
40
  TITLE_OFFSET = 5,
36
41
  MIN_WIDTH = 160,
37
42
  MAX_ACTION_BUTTONS = 4,
38
- ACTION_BUTTONS_OFFSET = -34;
43
+ ACTION_BUTTONS_OFFSET = -34,
44
+ MAX_VISIBLE_BUTTONS_ON_TOP = 3;
39
45
 
40
46
  var Size = {
41
47
  Circle: {
@@ -94,6 +100,21 @@ sap.ui.define([
94
100
 
95
101
  var oResourceBundle = CoreLib.getResourceBundleFor("sap.suite.ui.commons");
96
102
 
103
+ // Register BusinessSuiteInAppSymbols font for custom icons
104
+ // IconPool.registerFont({
105
+ // fontFamily: "BusinessSuiteInAppSymbols",
106
+ // collectionName: "BusinessSuiteInAppSymbols",
107
+ // fontURI: sap.ui.require.toUrl("sap/ushell/themes/base/fonts/")
108
+ // });
109
+
110
+ // register TNT icon font
111
+ IconPool.registerFont({
112
+ collectionName: "tnt",
113
+ fontFamily: "SAP-icons-TNT",
114
+ fontURI: sap.ui.require.toUrl("sap/tnt/themes/base/fonts"),
115
+ lazy: false
116
+ });
117
+
97
118
  var Status = library.networkgraph.ElementStatus;
98
119
  var oStatusIconMap = {
99
120
  [Status.Success]: 'sap-icon://sys-enter-2',
@@ -278,6 +299,27 @@ sap.ui.define([
278
299
  */
279
300
  nodeTitleBackground: {
280
301
  type: "boolean", group: "Appearance", defaultValue: false
302
+ },
303
+ /**
304
+ * Determines the port configuration for this node. When set, it overrides the graph-level nodePorts setting.
305
+ * If not set (defaults to None), the graph-level setting is used.
306
+ * Ports are available only when the layout algorithm is set to "NoopLayout", and when the drag and drop is enabled.
307
+ * @public
308
+ * @since 1.145
309
+ */
310
+ nodePorts: {
311
+ type: "sap.suite.ui.commons.networkgraph.NodePorts", group: "Behavior"
312
+ },
313
+ /**
314
+ * Determines whether the 'Create Connection' action button is displayed on this node.
315
+ * When set, it overrides the graph-level showCreateConnectionButton setting.
316
+ * If set to default (true), the graph-level setting is used.
317
+ * The button is used to create connections between nodes as an accessible alternative to node ports.
318
+ * @public
319
+ * @since 1.145
320
+ */
321
+ showCreateConnectionButton: {
322
+ type: "boolean", group: "Behavior", defaultValue: true
281
323
  }
282
324
  },
283
325
  aggregations: {
@@ -469,6 +511,11 @@ sap.ui.define([
469
511
 
470
512
  Node.prototype.exit = function () {
471
513
  DragDropManager.removeDnD(this);
514
+ // Cleanup connection popover utility
515
+ if (this._oConnectionPopoverUtil) {
516
+ this._oConnectionPopoverUtil.destroy();
517
+ this._oConnectionPopoverUtil = null;
518
+ }
472
519
  };
473
520
 
474
521
  Node.prototype._isInteractiveNode = function() {
@@ -477,9 +524,10 @@ sap.ui.define([
477
524
  bIsShowActionLinksButton = this.getShowActionLinksButton() && this._hasActionLinks(),
478
525
  aActionButtons = this.getActionButtons(),
479
526
  bIsActionButton = aActionButtons && aActionButtons.length > 0,
480
- bIsPress = this.mEventRegistry.press;
527
+ bIsPress = this.mEventRegistry.press,
528
+ bIsPortButton = this._hasPortActionButton();
481
529
 
482
- return bIsShowExpandButton || bIsShowDetailButton || bIsShowActionLinksButton || bIsActionButton || bIsPress;
530
+ return bIsShowExpandButton || bIsShowDetailButton || bIsShowActionLinksButton || bIsActionButton || bIsPress || bIsPortButton;
483
531
 
484
532
  };
485
533
 
@@ -544,32 +592,53 @@ sap.ui.define([
544
592
  }
545
593
  if (SemanticColorType.hasOwnProperty(sColor)) {
546
594
  var sColorClass = Utils.SEMANTIC_CLASS_NAME.TEXT + sColor;
595
+ var sDivClass = "sapSuiteUiCommonsNetworkGraphDivNodeText";
596
+ if (sClass) {
597
+ sDivClass += " " + sClass;
598
+ }
599
+ if (iSize === 1) {
600
+ sDivClass += " sapSuiteUiCommonsNetworkGraphDivTextBreakAll";
601
+ }
602
+ sDivClass += " " + sColorClass;
547
603
  this._renderHtmlElement("div", {
548
604
  "-webkit-line-clamp": iSize === 0 ? "" : iSize
549
605
  }, {
550
- "class": "sapSuiteUiCommonsNetworkGraphDivNodeText " + (sClass || "") + ((iSize === 1) ? " sapSuiteUiCommonsNetworkGraphDivTextBreakAll " : " ") + sColorClass
606
+ "class": sDivClass
551
607
  }, oRm);
552
608
  fnRenderTitleWithBackground();
553
609
  } else if (!sColor) {
554
610
  // in case of title.
611
+ var sDivClass2 = "sapSuiteUiCommonsNetworkGraphDivNodeText";
612
+ if (sClass) {
613
+ sDivClass2 += " " + sClass;
614
+ }
615
+ if (iSize === 1) {
616
+ sDivClass2 += " sapSuiteUiCommonsNetworkGraphDivTextBreakAll";
617
+ }
555
618
  this._renderHtmlElement("div", {
556
619
  "-webkit-line-clamp": iSize === 0 ? "" : iSize,
557
620
  "color": sColor
558
621
  }, {
559
- "class": "sapSuiteUiCommonsNetworkGraphDivNodeText " + (sClass || "") + ((iSize === 1) ? " sapSuiteUiCommonsNetworkGraphDivTextBreakAll " : "")
622
+ "class": sDivClass2
560
623
  }, oRm);
561
624
  fnRenderTitleWithBackground();
562
625
  } else {
563
626
  /** @deprecated As of 1.120 */
564
627
  {
628
+ var sDivClass3 = "sapSuiteUiCommonsNetworkGraphDivNodeText";
629
+ if (sClass) {
630
+ sDivClass3 += " " + sClass;
631
+ }
632
+ if (iSize === 1) {
633
+ sDivClass3 += " sapSuiteUiCommonsNetworkGraphDivTextBreakAll";
634
+ }
565
635
  this._renderHtmlElement("div", {
566
636
  "-webkit-line-clamp": iSize === 0 ? "" : iSize,
567
637
  "color": sColor
568
638
  }, {
569
- "class": "sapSuiteUiCommonsNetworkGraphDivNodeText " + (sClass || "") + ((iSize === 1) ? " sapSuiteUiCommonsNetworkGraphDivTextBreakAll " : "")
639
+ "class": sDivClass3
570
640
  }, oRm);
571
641
  fnRenderTitleWithBackground();
572
-
573
642
  }
574
643
  }
575
644
  };
@@ -618,32 +687,54 @@ sap.ui.define([
618
687
 
619
688
  Node.prototype._showDivActionButtons = function(bShow) {
620
689
  var that = this,
690
+ $top = this.$("topdivbuttons"),
621
691
  $right = this.$("rightdivbuttons"),
622
- $left = this.$("leftdivbuttons");
692
+ $left = this.$("leftdivbuttons"),
693
+ oGraph = this.getParent(),
694
+ bShouldShowPortButton = this._showCreateConnectionButton() && oGraph?.getEnableDragAndDrop(),
695
+ oLayoutAlgorithm = oGraph.getLayoutAlgorithm(),
696
+ bShowButtonsOnTop = oGraph._isNoopLayout() && oLayoutAlgorithm.getEnableOptimizedLineAlgorithm();
623
697
 
698
+ // Force re-render if buttons haven't been rendered yet
624
699
  if (bShow && !this._bActionButtonsRendered) {
700
+
701
+ $top.html("");
625
702
  $right.html("");
626
703
  $left.html("");
627
704
 
628
- var iButtonRight = 0,
629
- iButtonLeft = 0;
705
+ var iButtonTop = 0,
706
+ iButtonRight = 0,
707
+ iButtonLeft = 0,
708
+ $defaultWrapper = bShowButtonsOnTop ? $top : $right,
709
+ aOverflowButtons = [];
710
+
711
+ // When buttons are on top, only count enabled buttons for overflow calculation
712
+ // Disabled buttons are hidden with display:none so shouldn't count toward limit
630
713
 
631
714
  if (this.getShowExpandButton()) {
632
- this._appendActionButton({
715
+ var oExpandButtonConfig = {
633
716
  "class": "sapSuiteUiCommonsNetworkNodeActionCollapseIcon",
634
717
  icon: this._getExpandIcon(true),
635
718
  enable: this._hasVisibleChildren(),
636
719
  title: this._getExpandStateTitle(),
637
720
  id: this._getDomId("actionCollapse"),
638
721
  click: this._expandClick.bind(this)
639
- }, $right);
722
+ };
640
723
 
641
- iButtonRight++;
724
+ this._appendActionButton(oExpandButtonConfig, $defaultWrapper);
725
+ // Only increment counter if button is enabled (disabled buttons are hidden)
726
+ if (oExpandButtonConfig.enable) {
727
+ if (bShowButtonsOnTop) {
728
+ iButtonTop++;
729
+ } else {
730
+ iButtonRight++;
731
+ }
732
+ }
642
733
  }
643
734
 
644
735
  if (this.getShowDetailButton()) {
645
736
  var sNodeTitle = this.getTitle();
646
- this._appendActionButton({
737
+ var oDetailButtonConfig = {
647
738
  icon: "sap-icon://menu2",
648
739
  enable: this._hasDetailData() || (sNodeTitle ? sNodeTitle : this.getAltText()),
649
740
  id: this._getDomId("actionDetail"),
@@ -651,15 +742,44 @@ sap.ui.define([
651
742
  click: function(evt) {
652
743
  this._detailClick(evt.target);
653
744
  }.bind(this)
654
- }, $right);
745
+ };
746
+
747
+ this._appendActionButton(oDetailButtonConfig, $defaultWrapper);
655
748
  if (document.getElementById(this._getDomId("actionDetail"))) {
656
749
  document.getElementById(this._getDomId("actionDetail")).setAttribute("aria-haspopup", "dialog");
657
750
  }
658
- iButtonRight++;
751
+ // Only increment counter if button is enabled (disabled buttons are hidden)
752
+ if (oDetailButtonConfig.enable) {
753
+ if (bShowButtonsOnTop) {
754
+ iButtonTop++;
755
+ } else {
756
+ iButtonRight++;
757
+ }
758
+ }
759
+ }
760
+
761
+ // Add port action button if nodePorts is not "None"
762
+ if (bShouldShowPortButton) {
763
+ var oPortButtonConfig = {
764
+ icon: "sap-icon://tnt/item-flow",
765
+ enable: true,
766
+ title: oResourceBundle.getText("NETWORK_GRAPH_CREATE_CONNECTION"),
767
+ id: this._getDomId("actionPorts"),
768
+ click: function(evt) {
769
+ this._showConnectionPopover(evt);
770
+ }.bind(this)
771
+ };
772
+
773
+ this._appendActionButton(oPortButtonConfig, $defaultWrapper);
774
+ if (bShowButtonsOnTop) {
775
+ iButtonTop++;
776
+ } else {
777
+ iButtonRight++;
778
+ }
659
779
  }
660
780
 
661
781
  if (this.getShowActionLinksButton()) {
662
- this._appendActionButton({
782
+ var oLinksButtonConfig = {
663
783
  icon: "sap-icon://chain-link",
664
784
  enable: this._hasActionLinks(),
665
785
  title: oResourceBundle.getText("NETWORK_GRAPH_NODE_LINKS"),
@@ -667,44 +787,118 @@ sap.ui.define([
667
787
  click: function(evt) {
668
788
  this._linksClick(evt.target);
669
789
  }.bind(this)
670
- }, $right);
671
- if (document.getElementById(this._getDomId("actionLinks"))) {
672
- document.getElementById(this._getDomId("actionLinks")).setAttribute("aria-haspopup", "dialog");
790
+ };
791
+
792
+ // Overflow logic: button goes to overflow if we've already placed 3 enabled buttons
793
+ if (bShowButtonsOnTop && iButtonTop >= MAX_VISIBLE_BUTTONS_ON_TOP && oLinksButtonConfig.enable) {
794
+ aOverflowButtons.push(oLinksButtonConfig);
795
+ } else {
796
+ this._appendActionButton(oLinksButtonConfig, $defaultWrapper);
797
+ if (document.getElementById(this._getDomId("actionLinks"))) {
798
+ document.getElementById(this._getDomId("actionLinks")).setAttribute("aria-haspopup", "dialog");
799
+ }
800
+ // Only increment counter if button is enabled (disabled buttons are hidden)
801
+ if (oLinksButtonConfig.enable) {
802
+ if (bShowButtonsOnTop) {
803
+ iButtonTop++;
804
+ } else {
805
+ iButtonRight++;
806
+ }
807
+ }
673
808
  }
674
- iButtonRight++;
675
809
  }
676
810
 
677
- for (var i = 0; (iButtonRight + iButtonLeft) < (MAX_ACTION_BUTTONS * 2) && i < this.getActionButtons().length; i++) {
678
- (function(oButton) { // eslint-disable-line
679
- var sPosition = oButton.getPosition(),
680
- iIndex = sPosition === ActionButtonPosition.Right ? iButtonRight : iButtonLeft;
811
+ for (var i = 0; (iButtonTop + iButtonRight + iButtonLeft) < (MAX_ACTION_BUTTONS * 3) && i < this.getActionButtons().length; i++) {
812
+ (function(oButton) { // eslint-disable-line
813
+ var sPosition = oButton.getPosition();
814
+ var iIndex, $wrapper;
815
+
816
+ // When buttons are shown on top, custom action buttons always go to top position
817
+ if (bShowButtonsOnTop) {
818
+ sPosition = "Top";
819
+ iIndex = iButtonTop;
820
+ $wrapper = $top;
821
+ } else {
822
+ if (sPosition === ActionButtonPosition.Right) {
823
+ iIndex = iButtonRight;
824
+ $wrapper = $right;
825
+ } else if (sPosition === ActionButtonPosition.Left) {
826
+ iIndex = iButtonLeft;
827
+ $wrapper = $left;
828
+ } else {
829
+ iIndex = iButtonTop;
830
+ $wrapper = $top;
831
+ }
681
832
 
682
833
  // switch lanes if there is more then 4 items on the line
683
834
  if (iIndex >= MAX_ACTION_BUTTONS) {
684
- sPosition = sPosition === ActionButtonPosition.Left ? ActionButtonPosition.Right : ActionButtonPosition.Left;
835
+ if (sPosition === ActionButtonPosition.Right) {
836
+ sPosition = ActionButtonPosition.Left;
837
+ $wrapper = $left;
838
+ } else if (sPosition === ActionButtonPosition.Left) {
839
+ sPosition = "Top"; // Custom position for top
840
+ $wrapper = $top;
841
+ } else {
842
+ sPosition = ActionButtonPosition.Right;
843
+ $wrapper = $right;
844
+ }
685
845
  }
846
+ }
686
847
 
687
- var $wrapper = sPosition === ActionButtonPosition.Right ? $right : $left;
848
+ var oButtonConfig = {
849
+ icon: oButton.getIcon(),
850
+ enable: oButton.getEnabled(),
851
+ title: oButton.getTitle(),
852
+ id: oButton.getId(),
853
+ click: function(evt) {
854
+ oButton.firePress({
855
+ buttonElement: evt.target
856
+ });
857
+ // Restore focus after a small timeout (to let any rerender settle)
858
+ setTimeout(function () {
859
+ if (oButton && oButton.getDomRef()) {
860
+ that.getParent().setFocus({item:oButton.getParent(), button: oButton.getDomRef()});
861
+ }
862
+ }, 0);
863
+ }
864
+ };
688
865
 
689
- that._appendActionButton({
690
- icon: oButton.getIcon(),
691
- enable: oButton.getEnabled(),
692
- title: oButton.getTitle(),
693
- id: oButton.getId(),
694
- click: function(evt) {
695
- oButton.firePress({
696
- buttonElement: evt.target
697
- });
698
- // Restore focus after a small timeout (to let any rerender settle)
699
- setTimeout(function () {
700
- if (oButton && oButton.getDomRef()) {
701
- that.getParent().setFocus({item:oButton.getParent(), button: oButton.getDomRef()});
702
- }
703
- }, 0);
866
+ // Apply overflow logic only when buttons are shown on top
867
+ // Custom buttons go to overflow if we've already placed 3 enabled buttons
868
+ if (bShowButtonsOnTop && iButtonTop >= MAX_VISIBLE_BUTTONS_ON_TOP && oButtonConfig.enable) {
869
+ aOverflowButtons.push(oButtonConfig);
870
+ } else {
871
+ that._appendActionButton(oButtonConfig, $wrapper);
872
+ // Only increment counter if button is enabled (disabled buttons are hidden)
873
+ if (oButtonConfig.enable) {
874
+ // Increment the correct counter
875
+ if (bShowButtonsOnTop) {
876
+ iButtonTop++;
877
+ } else if (sPosition === ActionButtonPosition.Right) {
878
+ iButtonRight++;
879
+ } else if (sPosition === ActionButtonPosition.Left) {
880
+ iButtonLeft++;
881
+ } else {
882
+ iButtonTop++;
704
883
  }
705
- }, $wrapper);
706
- })(this.getActionButtons()[i]);
884
+ }
885
+ }
886
+ })(this.getActionButtons()[i], i);
887
+ }
888
+
889
+ // Add overflow button if there are overflow items
890
+ if (bShowButtonsOnTop && aOverflowButtons.length > 0) {
891
+ this._appendActionButton({
892
+ icon: "sap-icon://overflow",
893
+ enable: true,
894
+ title: "More Actions",
895
+ id: this._getDomId("actionOverflow"),
896
+ click: function(evt) {
897
+ this._showOverflowPopover(evt.target, aOverflowButtons);
898
+ }.bind(this)
899
+ }, $top);
707
900
  }
901
+
708
902
  this._bActionButtonsRendered = true;
709
903
  }
710
904
 
@@ -1132,9 +1326,13 @@ sap.ui.define([
1132
1326
  var {style: sStatusStyle, class: sStatusClass} = this._getStatusStyle({
1133
1327
  fill: ElementBase.ColorType.Content
1134
1328
  });
1329
+ var sIconClass = "sapSuiteUiCommonsNetworkGraphIcon sapSuiteUiCommonsNetworkCircleNodeIcon sapSuiteUiCommonsNetworkStatusText";
1330
+ if (sStatusClass) {
1331
+ sIconClass += " " + sStatusClass;
1332
+ }
1135
1333
  oIconArgs = {
1136
1334
  attributes: {
1137
- "class": "sapSuiteUiCommonsNetworkGraphIcon sapSuiteUiCommonsNetworkCircleNodeIcon sapSuiteUiCommonsNetworkStatusText " + sStatusClass,
1335
+ "class": sIconClass,
1138
1336
  style: (this.getIconSize() ? ("font-size:" + this.getIconSize() + "px;") : "") +
1139
1337
  sStatusStyle,
1140
1338
  x: fX + this._iWidth / 2,
@@ -1230,27 +1428,33 @@ sap.ui.define([
1230
1428
  var { style: sInnerBoxStyle, class: sInnerBoxClass } = this._getStatusStyle({
1231
1429
  stroke: ElementBase.ColorType.Border
1232
1430
  });
1431
+ var sInnerCircleClass = "sapSuiteUiCommonsNetworkInnerCircle";
1432
+ if (sInnerBoxClass) {
1433
+ sInnerCircleClass += " " + sInnerBoxClass;
1434
+ }
1233
1435
  var oInnerBoxArgs = {
1234
1436
  id: this.getId() + "-innerBox",
1235
1437
  cx: fX + this._iWidth / 2,
1236
1438
  cy: fY + iCircleSize / 2,
1237
1439
  style: sInnerBoxStyle,
1238
1440
  r: iCircleSize / 2,
1239
- "class": "sapSuiteUiCommonsNetworkInnerCircle " + sInnerBoxClass
1441
+ "class": sInnerCircleClass
1240
1442
  };
1241
1443
  var { style: sFocusCircleStyle, class: sFocusCircleClass } = this._getStatusStyle({
1242
1444
  stroke: ElementBase.ColorType.Focus
1243
1445
  });
1446
+ var sFocusClass = "sapSuiteUiCommonsNetworkCircleFocus";
1447
+ if (sFocusCircleClass) {
1448
+ sFocusClass += " " + sFocusCircleClass;
1449
+ }
1244
1450
  var oFocusCircleArgs = {
1245
1451
  id: this.getId() + "-focusCircle",
1246
1452
  cx: fX + this._iWidth / 2,
1247
1453
  cy: fY + iCircleSize / 2,
1248
1454
  style: sFocusCircleStyle,
1249
1455
  r: iCircleSize / 2 + FOCUS_OFFSET,
1250
- "class": "sapSuiteUiCommonsNetworkCircleFocus " + sFocusCircleClass
1251
- };
1252
-
1253
- if (!oRm) {
1456
+ "class": sFocusClass
1457
+ }; if (!oRm) {
1254
1458
  var sHtml = "";
1255
1459
  sHtml += this._renderControl("circle", oInnerBoxArgs);
1256
1460
  sHtml += this._renderControl("circle", oFocusCircleArgs);
@@ -1299,10 +1503,14 @@ sap.ui.define([
1299
1503
  var { style: sIconStyle, class: sIconClass } = this._getStatusStyle({
1300
1504
  fill: ElementBase.ColorType.Content
1301
1505
  });
1506
+ var sTitleIconClass = "sapSuiteUiCommonsNetworkGraphIcon sapSuiteUiCommonsNetworkNodeTitleIcon sapSuiteUiCommonsNetworkStatusText";
1507
+ if (sIconClass) {
1508
+ sTitleIconClass += " " + sIconClass;
1509
+ }
1302
1510
  oIconArgs = {
1303
1511
  attributes: {
1304
1512
  style: sIconStyle,
1305
- "class": "sapSuiteUiCommonsNetworkGraphIcon sapSuiteUiCommonsNetworkNodeTitleIcon sapSuiteUiCommonsNetworkStatusText " + sIconClass,
1513
+ "class": sTitleIconClass,
1306
1514
  x: bIsRtl ? fX + this._iWidth - Size.Title.ICON_X_OFFSET : fX + Size.Title.ICON_X_OFFSET,
1307
1515
  y: fY + TITLE_SIZE_Y
1308
1516
  },
@@ -1324,8 +1532,12 @@ sap.ui.define([
1324
1532
  var { style: sTitleStyle, class: sTitleClass } = this._getStatusStyle({
1325
1533
  fill: ElementBase.ColorType.Content
1326
1534
  });
1535
+ var sTitleTextClass = "sapSuiteUiCommonsNetworkNodeTitle sapSuiteUiCommonsNetworkNodeText sapSuiteUiCommonsNetworkStatusText";
1536
+ if (sTitleClass) {
1537
+ sTitleTextClass += " " + sTitleClass;
1538
+ }
1327
1539
  oTitleArgs = {
1328
- "class": "sapSuiteUiCommonsNetworkNodeTitle sapSuiteUiCommonsNetworkNodeText sapSuiteUiCommonsNetworkStatusText " + sTitleClass,
1540
+ "class": sTitleTextClass,
1329
1541
  style: sTitleStyle,
1330
1542
  x: bIsRtl ? fX + this._iWidth - sTitleLeft : fX + sTitleLeft,
1331
1543
  y: fY + TITLE_SIZE_Y,
@@ -1431,12 +1643,16 @@ sap.ui.define([
1431
1643
  var { style: sInnerBoxStyle, class: sInnerBoxClass } = this._getStatusStyle({
1432
1644
  stroke: ElementBase.ColorType.Border
1433
1645
  });
1646
+ var sInnerRectClass = "sapSuiteUiCommonsNetworkInnerRect";
1647
+ if (sInnerBoxClass) {
1648
+ sInnerRectClass += " " + sInnerBoxClass;
1649
+ }
1434
1650
  var oInnerBoxArgs = {
1435
1651
  id: this.getId() + "-innerBox",
1436
1652
  x: fX,
1437
1653
  y: fY,
1438
1654
  style: sInnerBoxStyle,
1439
- "class": "sapSuiteUiCommonsNetworkInnerRect " + sInnerBoxClass,
1655
+ "class": sInnerRectClass,
1440
1656
  rx: RADIUS,
1441
1657
  ry: RADIUS,
1442
1658
  width: this._iWidth,
@@ -1446,12 +1662,16 @@ sap.ui.define([
1446
1662
  var { style: sInnerStatusBoxStyle, class: sInnerStatusBoxClass } = this._getStatusStyle({
1447
1663
  fill: ElementBase.ColorType.Background
1448
1664
  });
1665
+ var sStatusBoxClass = "sapSuiteUiCommonsNetworkNodeBoxStatus";
1666
+ if (sInnerStatusBoxClass) {
1667
+ sStatusBoxClass += " " + sInnerStatusBoxClass;
1668
+ }
1449
1669
  var oInnerStatusBoxArgs = {
1450
1670
  id: this.getId() + "-innerStatusBox",
1451
1671
  x: fX,
1452
1672
  y: fY,
1453
1673
  style: sInnerStatusBoxStyle,
1454
- "class": "sapSuiteUiCommonsNetworkNodeBoxStatus " + sInnerStatusBoxClass,
1674
+ "class": sStatusBoxClass,
1455
1675
  topRight: RADIUS,
1456
1676
  topLeft: RADIUS,
1457
1677
  bottomRight: bRoundedBottom ? RADIUS : 0,
@@ -1463,11 +1683,15 @@ sap.ui.define([
1463
1683
  var { style: sFocusCircleStyle, class: sFocusCircleClass } = this._getStatusStyle({
1464
1684
  stroke: ElementBase.ColorType.Focus
1465
1685
  });
1686
+ var sBoxFocusClass = "sapSuiteUiCommonsNetworkBoxFocus";
1687
+ if (sFocusCircleClass) {
1688
+ sBoxFocusClass += " " + sFocusCircleClass;
1689
+ }
1466
1690
  var oFocusCircleArgs = {
1467
1691
  id: this.getId() + "-focusCircle",
1468
1692
  x: fX - FOCUS_OFFSET,
1469
1693
  y: fY - FOCUS_OFFSET,
1470
- "class": "sapSuiteUiCommonsNetworkBoxFocus " + sFocusCircleClass,
1694
+ "class": sBoxFocusClass,
1471
1695
  style: sFocusCircleStyle,
1472
1696
  rx: 5,
1473
1697
  ry: 5,
@@ -1679,7 +1903,7 @@ sap.ui.define([
1679
1903
  sLabelWrapper += this._renderText({
1680
1904
  attributes: {
1681
1905
  style: sAttributeStyleOrClass.includes("fill") ? sAttributeStyleOrClass : "",
1682
- "class": "sapSuiteUiCommonsNetworkGraphAttribute sapSuiteUiCommonsNetworkStatusText " + sAttributeStyleOrClass.includes("fill") ? "" : sAttributeStyleOrClass,
1906
+ "class": "sapSuiteUiCommonsNetworkGraphAttribute sapSuiteUiCommonsNetworkStatusText " + (sAttributeStyleOrClass.includes("fill") ? "" : sAttributeStyleOrClass),
1683
1907
  x: iLabelStart,
1684
1908
  id: oItem.getId() + "-label",
1685
1909
  y: iY
@@ -1690,7 +1914,7 @@ sap.ui.define([
1690
1914
  sValueWrapper += this._renderText({
1691
1915
  attributes: {
1692
1916
  style: sAttributeStyleOrClass_.includes("fill") ? sAttributeStyleOrClass_ : "",
1693
- "class": "sapSuiteUiCommonsNetworkGraphAttribute sapSuiteUiCommonsNetworkGraphAttributeValue sapSuiteUiCommonsNetworkStatusText " + sAttributeStyleOrClass_.includes("fill") ? "" : sAttributeStyleOrClass_,
1917
+ "class": "sapSuiteUiCommonsNetworkGraphAttribute sapSuiteUiCommonsNetworkGraphAttributeValue sapSuiteUiCommonsNetworkStatusText " + (sAttributeStyleOrClass_.includes("fill") ? "" : sAttributeStyleOrClass_),
1694
1918
  x: iValueStart,
1695
1919
  y: iY,
1696
1920
  id: oItem.getId() + "-value"
@@ -1726,13 +1950,13 @@ sap.ui.define([
1726
1950
  id: this.getId() + "-attrLabel"
1727
1951
  }, false, oRm);
1728
1952
 
1729
- this.getVisibleAttributes().forEach(function(oItem, i) {
1953
+ this.getVisibleAttributes().forEach(function(oItem, i) {
1730
1954
  var iY = fStart + Size.Attributes.LINE * (i + 1);
1731
1955
  let sAttributeStyleOrClass = this._getAttributeColorString(oItem, ElementAttribute.Type.Label, ElementBase.ColorType.Content);
1732
1956
  this._renderText({
1733
1957
  attributes: {
1734
1958
  style: sAttributeStyleOrClass.includes("fill") ? sAttributeStyleOrClass : "",
1735
- "class": "sapSuiteUiCommonsNetworkGraphAttribute sapSuiteUiCommonsNetworkStatusText " + sAttributeStyleOrClass.includes("fill") ? "" : sAttributeStyleOrClass,
1959
+ "class": "sapSuiteUiCommonsNetworkGraphAttribute sapSuiteUiCommonsNetworkStatusText " + (sAttributeStyleOrClass.includes("fill") ? "" : sAttributeStyleOrClass),
1736
1960
  x: iLabelStart,
1737
1961
  id: oItem.getId() + "-label",
1738
1962
  y: iY
@@ -1750,13 +1974,13 @@ sap.ui.define([
1750
1974
  id: this.getId() + "-attrValue"
1751
1975
  }, false,oRm);
1752
1976
 
1753
- this.getVisibleAttributes().forEach(function(oItem, i) {
1977
+ this.getVisibleAttributes().forEach(function(oItem, i) {
1754
1978
  var iY = fStart + Size.Attributes.LINE * (i + 1);
1755
1979
  let sAttributeStyleOrClass = this._getAttributeColorString(oItem, ElementAttribute.Type.Value, ElementBase.ColorType.Content);
1756
1980
  this._renderText({
1757
1981
  attributes: {
1758
1982
  style: sAttributeStyleOrClass.includes("fill") ? sAttributeStyleOrClass : "",
1759
- "class": "sapSuiteUiCommonsNetworkGraphAttribute sapSuiteUiCommonsNetworkGraphAttributeValue sapSuiteUiCommonsNetworkStatusText " + sAttributeStyleOrClass.includes("fill") ? "" : sAttributeStyleOrClass,
1983
+ "class": "sapSuiteUiCommonsNetworkGraphAttribute sapSuiteUiCommonsNetworkGraphAttributeValue sapSuiteUiCommonsNetworkStatusText " + (sAttributeStyleOrClass.includes("fill") ? "" : sAttributeStyleOrClass),
1760
1984
  x: iValueStart,
1761
1985
  y: iY,
1762
1986
  id: oItem.getId() + "-value"
@@ -1810,21 +2034,21 @@ sap.ui.define([
1810
2034
 
1811
2035
  //Recursive Traversal ensures all shared parents of collapsed descendants have their action buttons re-rendered correctly.
1812
2036
  Node.prototype._invalidateSharedParents = function(oNode, oOrigin = oNode, oVisited = new Set()) {
1813
- if (oVisited.has(oNode)) {
1814
- return;
1815
- }
1816
- oVisited.add(oNode);
1817
-
1818
- oNode.getParentNodes().forEach(parent => {
1819
- if (parent !== oOrigin) {
1820
- parent._bActionButtonsRendered = false;
2037
+ if (oVisited.has(oNode)) {
2038
+ return;
1821
2039
  }
1822
- });
2040
+ oVisited.add(oNode);
1823
2041
 
1824
- oNode.getChildNodes().forEach(oChild => {
1825
- this._invalidateSharedParents(oChild, oOrigin, oVisited);
1826
- });
1827
- }
2042
+ oNode.getParentNodes().forEach(parent => {
2043
+ if (parent !== oOrigin) {
2044
+ parent._bActionButtonsRendered = false;
2045
+ }
2046
+ });
2047
+
2048
+ oNode.getChildNodes().forEach(oChild => {
2049
+ this._invalidateSharedParents(oChild, oOrigin, oVisited);
2050
+ });
2051
+ }
1828
2052
 
1829
2053
  Node.prototype._setTextHeight = function($el, iMaxLines) {
1830
2054
  if ($el[0] && iMaxLines > 0) {
@@ -1989,6 +2213,7 @@ sap.ui.define([
1989
2213
  $wrapper.on("click", function(oEvent) {
1990
2214
  if (oEvent.which === 1) {
1991
2215
  this._onClick(oEvent.ctrlKey);
2216
+ this._togglePortsOnNode();
1992
2217
  }
1993
2218
  oEvent.preventDefault();
1994
2219
  }.bind(this));
@@ -2460,31 +2685,76 @@ sap.ui.define([
2460
2685
  }
2461
2686
  };
2462
2687
 
2463
- Node.prototype._getAccessibilityLabel = function(oGraph) {
2464
- var oParent = oGraph ? oGraph : this.getParent();
2465
- var sNodeTitle = this.getTitle();
2466
- var sNodeTitleText = sNodeTitle ? sNodeTitle : this.getAltText();
2467
- var sLabel = oResourceBundle.getText("NETWORK_GRAPH_NODE") + " " + sNodeTitleText;
2688
+ Node.prototype._getAccessibilityLabel = function (oGraph) {
2689
+ const oParent = oGraph || this.getParent();
2690
+ const sNodeTitle = this.getTitle();
2691
+ const sNodeTitleText = sNodeTitle || this.getAltText();
2692
+ let sLabel = `${oResourceBundle.getText(
2693
+ "NETWORK_GRAPH_NODE"
2694
+ )} ${sNodeTitleText}`;
2695
+ const aSentenceParts = [];
2696
+
2468
2697
  if (this.getDescription()) {
2469
- sLabel += " " + oResourceBundle.getText("NETWORK_GRAPH_NODE_DESCRIPTION") + " " + this.getDescription();
2698
+ aSentenceParts.push(
2699
+ `${oResourceBundle.getText(
2700
+ "NETWORK_GRAPH_NODE_DESCRIPTION"
2701
+ )} ${this.getDescription()}`
2702
+ );
2470
2703
  }
2471
- if (this._isBox(oParent)) {
2472
- this.getVisibleAttributes().forEach(function(oAttribute) {
2473
- sLabel += " " + oAttribute.getLabel() + " " + oAttribute.getValue();
2704
+
2705
+ if (this._isBox(oParent) && this.getVisibleAttributes().length > 0) {
2706
+ const aAttributeParts = [
2707
+ oResourceBundle.getText("NETWORK_GRAPH_NODE_ATTRIBUTES"),
2708
+ ];
2709
+ this.getVisibleAttributes().forEach((oAttribute) => {
2710
+ aAttributeParts.push(
2711
+ `${oAttribute.getLabel()} ${oAttribute.getValue()}`
2712
+ );
2474
2713
  });
2714
+ aSentenceParts.push(aAttributeParts.join(" "));
2475
2715
  }
2476
- if (this.getStatus() && this.getStatus() != ""){
2477
- var statusID = this.getStatus();
2478
- if (oParent._oStatuses[statusID]) {
2479
- sLabel += " " + oResourceBundle.getText("PF_ARIA_STATUS") + " " + oParent._oStatuses[statusID].getTitle();
2480
- } else {
2481
- sLabel += " " + oResourceBundle.getText("PF_ARIA_STATUS") + " " + this.getStatus();
2482
- }
2716
+
2717
+ const sStatusText = this._getStatusText(oParent._oStatuses);
2718
+
2719
+ if (sStatusText) {
2720
+ aSentenceParts.push(
2721
+ `${oResourceBundle.getText(
2722
+ "NETWORK_GRAPH_NODE_ACCESSIBILITY_STATUS"
2723
+ )} ${sStatusText}`
2724
+ );
2483
2725
  }
2726
+
2484
2727
  if (this.getSelected()) {
2485
- sLabel += " " + oResourceBundle.getText("NETWORK_GRAPH_SELECTED_NODE");
2728
+ aSentenceParts.push(
2729
+ oResourceBundle.getText("NETWORK_GRAPH_SELECTED_NODE")
2730
+ );
2486
2731
  }
2487
- return sLabel + "." + oResourceBundle.getText("NETWORK_GRAPH_ACCESSIBILITY_TOGGLE_STATE");
2732
+
2733
+ aSentenceParts.push(
2734
+ oResourceBundle.getText("NETWORK_GRAPH_ACCESSIBILITY_TOGGLE_STATE")
2735
+ );
2736
+
2737
+ const iIncomingConnectors = this.getParentLines().length;
2738
+ const sIncomingTextKey = iIncomingConnectors === 1
2739
+ ? "NETWORK_GRAPH_INCOMING_CONNECTOR_SINGULAR"
2740
+ : "NETWORK_GRAPH_INCOMING_CONNECTORS_PLURAL";
2741
+ aSentenceParts.push(oResourceBundle.getText(sIncomingTextKey, [iIncomingConnectors]));
2742
+
2743
+ const iOutgoingConnectors = this.getChildLines().length;
2744
+ const sOutgoingTextKey = iOutgoingConnectors === 1
2745
+ ? "NETWORK_GRAPH_OUTGOING_CONNECTOR_SINGULAR"
2746
+ : "NETWORK_GRAPH_OUTGOING_CONNECTORS_PLURAL";
2747
+ aSentenceParts.push(oResourceBundle.getText(sOutgoingTextKey, [iOutgoingConnectors]));
2748
+
2749
+ if (iOutgoingConnectors > 0) {
2750
+ aSentenceParts.push(oResourceBundle.getText("NETWORK_GRAPH_NAVIGATION_TAB_TO_OUTGOING"));
2751
+ }
2752
+
2753
+ if (iIncomingConnectors > 0) {
2754
+ aSentenceParts.push(oResourceBundle.getText("NETWORK_GRAPH_NAVIGATION_SHIFT_TAB_TO_INCOMING"));
2755
+ }
2756
+
2757
+ return `${sLabel}. ${aSentenceParts.join(". ")}.`;
2488
2758
  };
2489
2759
 
2490
2760
  Node.prototype._setStatusColors = function(sType) {
@@ -2863,13 +3133,15 @@ sap.ui.define([
2863
3133
  */
2864
3134
  Node.prototype.renderHtmlActionButtons = function(mOptions) {
2865
3135
  mOptions = mOptions || {};
2866
- var sRightId = this._getElementId(mOptions.idSufix) + "-rightdivbuttons",
3136
+ var sTopId = this._getElementId(mOptions.idSufix) + "-topdivbuttons",
3137
+ sRightId = this._getElementId(mOptions.idSufix) + "-rightdivbuttons",
2867
3138
  sLeftId = this._getElementId(mOptions.idSufix) + "-leftdivbuttons",
2868
3139
  bIsRtl = this.getParent()._bIsRtl,
2869
3140
  fBorderWidth = parseFloat(this._getStatusValue(ElementBase.ColorType.BorderWidth)) || 0,
2870
3141
  sOffsetPosition = (ACTION_BUTTONS_OFFSET - fBorderWidth) + "px",
2871
3142
  oRm = mOptions.renderManager;
2872
3143
 
3144
+ oRm.openStart("div").attr("id", sTopId).class("sapSuiteUiCommonsNetworkGraphDivActionButtons").class("sapSuiteUiCommonsNetworkGraphDivActionButtonsTop").openEnd().close("div");
2873
3145
  oRm.openStart("div").attr("id", sLeftId).class("sapSuiteUiCommonsNetworkGraphDivActionButtons").class("sapSuiteUiCommonsNetworkGraphDivActionButtonsLeft").openEnd().close("div");
2874
3146
  oRm.openStart("div").attr("id", sRightId).class("sapSuiteUiCommonsNetworkGraphDivActionButtons").class("sapSuiteUiCommonsNetworkGraphDivActionButtonsRight");
2875
3147
  if (fBorderWidth) {
@@ -3762,5 +4034,183 @@ sap.ui.define([
3762
4034
  return this;
3763
4035
  };
3764
4036
 
4037
+ /**
4038
+ * Checks if the port action button should be shown.
4039
+ * @returns {boolean} True if the port action button should be displayed
4040
+ * @private
4041
+ */
4042
+ Node.prototype._hasPortActionButton = function() {
4043
+ return this._showCreateConnectionButton();
4044
+ };
4045
+
4046
+ /**
4047
+ * Toggles ports on the node when the port action button is clicked.
4048
+ * @private
4049
+ */
4050
+ Node.prototype._togglePortsOnNode = function() {
4051
+ // Check if the layout algorithm supports node ports
4052
+ if (this._supportsNodePortsForNode()) {
4053
+ // Ports are only available for supported layout algorithms
4054
+ this._addPortsToNode(true);
4055
+ }
4056
+ };
4057
+
4058
+ /**
4059
+ * Adds ports to the node or removes them if they are already present.
4060
+ * @param {boolean} bTriggerNode Indicates whether this node is the trigger node for ports.
4061
+ * @private
4062
+ */
4063
+ Node.prototype._addPortsToNode = function (bTriggerNode) {
4064
+ var oGraph = this.getParent();
4065
+
4066
+ // Check if ports are enabled for this node
4067
+ if (!oGraph || this._getNodePorts() === "None") {
4068
+ PortManager.removeAllPorts();
4069
+ return;
4070
+ }
4071
+
4072
+ var sCurrentNodeKey = this.getKey();
4073
+ var sCurrentTriggerNodeKey = PortManager.getCurrentTriggerNodeKey();
4074
+
4075
+ // Scenario 1: Clicking on the same node that already has trigger ports -> remove ports
4076
+ if (sCurrentTriggerNodeKey === sCurrentNodeKey) {
4077
+ PortManager.removeAllPorts();
4078
+ return;
4079
+ }
4080
+
4081
+ // Scenario 2: Clicking on a different node (or no current trigger node) -> remove all ports and add to this node
4082
+ PortManager.removeAllPorts();
4083
+ PortManager.addPortsToNode(this, true);
4084
+ };
4085
+
4086
+ /**
4087
+ * Uses node-level setting if explicitly set, otherwise it reverts to the graph-level setting.
4088
+ * If the node-level property is set to any value (including None), it takes precedence over the graph-level setting.
4089
+ * @returns {string} The effective nodePorts value
4090
+ * @private
4091
+ */
4092
+ Node.prototype._getNodePorts = function() {
4093
+ // Check if the property was explicitly set on the node (stored in mProperties)
4094
+ var mProperties = this.mProperties;
4095
+ if (mProperties && mProperties.hasOwnProperty("nodePorts")) {
4096
+ var sNodePorts = this.getNodePorts();
4097
+ // Validate that the value is one of the valid NodePorts enum values
4098
+ var bIsValidValue = Object.values(NodePorts).indexOf(sNodePorts) !== -1;
4099
+ if (bIsValidValue) {
4100
+ // Use node-level setting if it's a valid enum value
4101
+ return sNodePorts;
4102
+ }
4103
+ }
4104
+ // Otherwise, fall back to graph-level setting
4105
+ var oGraph = this.getParent();
4106
+ return oGraph ? oGraph.getNodePorts() : NodePorts.None;
4107
+ };
4108
+
4109
+ /**
4110
+ * Gets the effective showCreateConnectionButton setting for this node.
4111
+ * Uses node-level setting if explicitly set, otherwise falls back to graph-level setting.
4112
+ * @returns {boolean} The effective showCreateConnectionButton value
4113
+ * @private
4114
+ */
4115
+ Node.prototype._showCreateConnectionButton = function() {
4116
+ // Check if the property was explicitly set on the node (stored in mProperties)
4117
+ var mProperties = this.mProperties;
4118
+ if (mProperties && mProperties.hasOwnProperty("showCreateConnectionButton")) {
4119
+ return this.getShowCreateConnectionButton();
4120
+ }
4121
+ // Otherwise, fall back to graph-level setting
4122
+ var oGraph = this.getParent();
4123
+ return oGraph ? oGraph.getShowCreateConnectionButton() : true;
4124
+ };
4125
+
4126
+ /**
4127
+ * Checks if node ports are supported for this node based on node-level or graph-level settings.
4128
+ * @returns {boolean} True if node ports are supported
4129
+ * @private
4130
+ */
4131
+ Node.prototype._supportsNodePortsForNode = function() {
4132
+ var oGraph = this.getParent();
4133
+ if (!oGraph) {
4134
+ return false;
4135
+ }
4136
+ return this._getNodePorts() !== "None" && oGraph.getEnableDragAndDrop();
4137
+ };
4138
+
4139
+ /**
4140
+ * Shows the connection popover instead of toggling ports.
4141
+ * @param {Event} oEvent - The click event from the action button
4142
+ * @private
4143
+ */
4144
+ Node.prototype._showConnectionPopover = function(oEvent) {
4145
+ // Create connection popover utility if it doesn't exist
4146
+ if (!this._oConnectionPopoverUtil) {
4147
+ this._oConnectionPopoverUtil = new CreateConnectionPopover();
4148
+ }
4149
+
4150
+ // Show the connection popover
4151
+ this._oConnectionPopoverUtil.show({
4152
+ sourceNode: this,
4153
+ event: oEvent,
4154
+ onConnectionCreate: function(oConnectionData) {
4155
+ var oGraph = this.getParent();
4156
+ if (oGraph) {
4157
+ // Fire the connectionCreated event
4158
+ oGraph.fireConnectionCreated(oConnectionData);
4159
+ }
4160
+ }.bind(this)
4161
+ });
4162
+ };
4163
+
4164
+ /**
4165
+ * Shows the overflow menu with additional action buttons.
4166
+ * @param {sap.ui.core.Control} oControl The control to open the menu next to
4167
+ * @param {Array} aOverflowButtons Array of button configurations to display in the overflow
4168
+ * @private
4169
+ */
4170
+ Node.prototype._showOverflowPopover = function(oControl, aOverflowButtons) {
4171
+ var that = this;
4172
+
4173
+ // Filter out disabled buttons (same behavior as _appendActionButton which hides disabled buttons)
4174
+ var aEnabledButtons = aOverflowButtons.filter(function(oButtonConfig) {
4175
+ return oButtonConfig.enable !== false;
4176
+ });
4177
+
4178
+ // If no enabled buttons, don't show the menu
4179
+ if (aEnabledButtons.length === 0) {
4180
+ return;
4181
+ }
4182
+
4183
+ // Create menu items for each enabled overflow item
4184
+ var aMenuItems = aEnabledButtons.map(function(oButtonConfig) {
4185
+ return new MenuItem({
4186
+ id: oButtonConfig.id ? oButtonConfig.id + "-overflow" : undefined,
4187
+ text: oButtonConfig.title,
4188
+ icon: oButtonConfig.icon,
4189
+ customData: [new sap.ui.core.CustomData({
4190
+ key: "buttonConfig",
4191
+ value: oButtonConfig
4192
+ })]
4193
+ });
4194
+ });
4195
+
4196
+ // Create the menu
4197
+ var oMenu = new Menu({
4198
+ items: aMenuItems,
4199
+ itemSelected: function(oEvent) {
4200
+ var oItem = oEvent.getParameter("item");
4201
+ var oButtonConfig = oItem.data("buttonConfig");
4202
+ if (oButtonConfig && oButtonConfig.click) {
4203
+ // Call the click handler with the overflow button as the target (not the menu item)
4204
+ oButtonConfig.click({ target: oControl });
4205
+ }
4206
+ },
4207
+ closed: function() {
4208
+ oMenu.destroy();
4209
+ }
4210
+ });
4211
+
4212
+ oMenu.openBy(oControl);
4213
+ };
4214
+
3765
4215
  return Node;
3766
4216
  });