@sapui5/sap.suite.ui.commons 1.136.12 → 1.136.13

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 (68) 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 +1 -1
  5. package/src/sap/suite/ui/commons/CalculationBuilderExpression.js +1 -1
  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 +1 -1
  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/TimelineRenderManager.js +8 -4
  15. package/src/sap/suite/ui/commons/flexibility/changeHandler/PropertyChangeMapper.js +1 -1
  16. package/src/sap/suite/ui/commons/imageeditor/CropCustomShapeHistoryItem.js +1 -1
  17. package/src/sap/suite/ui/commons/imageeditor/CropEllipseHistoryItem.js +1 -1
  18. package/src/sap/suite/ui/commons/imageeditor/CropRectangleHistoryItem.js +1 -1
  19. package/src/sap/suite/ui/commons/imageeditor/CustomSizeItem.js +1 -1
  20. package/src/sap/suite/ui/commons/imageeditor/FilterHistoryItem.js +1 -1
  21. package/src/sap/suite/ui/commons/imageeditor/FlipHistoryItem.js +1 -1
  22. package/src/sap/suite/ui/commons/imageeditor/HistoryItem.js +1 -1
  23. package/src/sap/suite/ui/commons/imageeditor/ImageEditor.js +1 -1
  24. package/src/sap/suite/ui/commons/imageeditor/ImageEditorContainer.js +1 -1
  25. package/src/sap/suite/ui/commons/imageeditor/ImageEditorResponsiveContainer.js +1 -1
  26. package/src/sap/suite/ui/commons/imageeditor/ResizeHistoryItem.js +1 -1
  27. package/src/sap/suite/ui/commons/imageeditor/RotateHistoryItem.js +1 -1
  28. package/src/sap/suite/ui/commons/library.js +100 -3
  29. package/src/sap/suite/ui/commons/messagebundle.properties +73 -12
  30. package/src/sap/suite/ui/commons/messagebundle_en_US_saprigi.properties +39 -5
  31. package/src/sap/suite/ui/commons/messagebundle_fr_CA.properties +1 -1
  32. package/src/sap/suite/ui/commons/networkgraph/ElementBase.js +19 -1
  33. package/src/sap/suite/ui/commons/networkgraph/Graph.js +554 -45
  34. package/src/sap/suite/ui/commons/networkgraph/GraphMap.js +25 -3
  35. package/src/sap/suite/ui/commons/networkgraph/GraphRenderer.js +19 -8
  36. package/src/sap/suite/ui/commons/networkgraph/KeyboardNavigator.js +367 -12
  37. package/src/sap/suite/ui/commons/networkgraph/Line.js +814 -22
  38. package/src/sap/suite/ui/commons/networkgraph/Node.js +573 -79
  39. package/src/sap/suite/ui/commons/networkgraph/Tooltip.js +4 -0
  40. package/src/sap/suite/ui/commons/networkgraph/Utils.js +249 -10
  41. package/src/sap/suite/ui/commons/networkgraph/layout/NoopLayout.js +77 -7
  42. package/src/sap/suite/ui/commons/networkgraph/util/ConnectionPathUtils.js +1174 -0
  43. package/src/sap/suite/ui/commons/networkgraph/util/CreateConnectionPopover.js +374 -0
  44. package/src/sap/suite/ui/commons/networkgraph/util/DependencyLayoutHelper.js +1017 -0
  45. package/src/sap/suite/ui/commons/networkgraph/util/DragDropManager.js +721 -0
  46. package/src/sap/suite/ui/commons/networkgraph/util/PortManager.js +582 -0
  47. package/src/sap/suite/ui/commons/statusindicator/Circle.js +1 -1
  48. package/src/sap/suite/ui/commons/statusindicator/CustomShape.js +1 -1
  49. package/src/sap/suite/ui/commons/statusindicator/DiscreteThreshold.js +1 -1
  50. package/src/sap/suite/ui/commons/statusindicator/FillingOption.js +1 -1
  51. package/src/sap/suite/ui/commons/statusindicator/LibraryShape.js +1 -1
  52. package/src/sap/suite/ui/commons/statusindicator/Path.js +1 -1
  53. package/src/sap/suite/ui/commons/statusindicator/PropertyThreshold.js +1 -1
  54. package/src/sap/suite/ui/commons/statusindicator/Rectangle.js +1 -1
  55. package/src/sap/suite/ui/commons/statusindicator/Shape.js +1 -1
  56. package/src/sap/suite/ui/commons/statusindicator/ShapeGroup.js +1 -1
  57. package/src/sap/suite/ui/commons/statusindicator/SimpleShape.js +1 -1
  58. package/src/sap/suite/ui/commons/statusindicator/StatusIndicator.js +1 -1
  59. package/src/sap/suite/ui/commons/taccount/TAccount.js +1 -1
  60. package/src/sap/suite/ui/commons/taccount/TAccountGroup.js +1 -1
  61. package/src/sap/suite/ui/commons/taccount/TAccountItem.js +1 -1
  62. package/src/sap/suite/ui/commons/taccount/TAccountItemProperty.js +1 -1
  63. package/src/sap/suite/ui/commons/taccount/TAccountPanel.js +1 -1
  64. package/src/sap/suite/ui/commons/themes/base/NetworkGraph.less +26 -13
  65. package/src/sap/suite/ui/commons/themes/base/NetworkGroup.less +4 -0
  66. package/src/sap/suite/ui/commons/themes/base/NetworkLine.less +58 -13
  67. package/src/sap/suite/ui/commons/themes/base/NetworkNode.less +251 -47
  68. package/src/sap/suite/ui/commons/themes/base/SemanticColorMixins.less +55 -0
@@ -31,7 +31,10 @@ sap.ui.define([
31
31
  "sap/ui/performance/Measurement",
32
32
  "sap/base/security/encodeXML",
33
33
  "sap/m/ToggleButton",
34
+ "sap/m/BusyIndicator",
34
35
  "sap/m/library",
36
+ "sap/m/IllustratedMessage",
37
+ "sap/m/IllustratedMessageType",
35
38
  "sap/suite/ui/commons/util/FullScreenUtil",
36
39
  "sap/ui/core/InvisibleMessage",
37
40
  "sap/ui/core/library",
@@ -42,7 +45,10 @@ sap.ui.define([
42
45
  "sap/ui/core/RenderManager",
43
46
  "sap/ui/core/Theming",
44
47
  'sap/ui/core/InvisibleText',
45
- "./GraphRenderer"
48
+ "./GraphRenderer",
49
+ "./util/DragDropManager",
50
+ "./util/PortManager",
51
+ "sap/ui/core/IconPool"
46
52
  ], function (
47
53
  library,
48
54
  jQuery,
@@ -69,7 +75,10 @@ sap.ui.define([
69
75
  Measurement,
70
76
  encodeXML,
71
77
  ToggleButton,
78
+ BusyIndicator,
72
79
  MobileLibrary,
80
+ IllustratedMessage,
81
+ IllustratedMessageType,
73
82
  FullScreenUtil,
74
83
  InvisibleMessage,
75
84
  coreLibrary,
@@ -80,7 +89,10 @@ sap.ui.define([
80
89
  RenderManager,
81
90
  Theming,
82
91
  InvisibleText,
83
- GraphRenderer
92
+ GraphRenderer,
93
+ DragDropManager,
94
+ PortManager,
95
+ IconPool
84
96
  ) {
85
97
  "use strict";
86
98
 
@@ -89,7 +101,8 @@ sap.ui.define([
89
101
  Orientation = library.networkgraph.Orientation,
90
102
  LayoutRenderType = library.networkgraph.LayoutRenderType,
91
103
  RenderType = library.networkgraph.RenderType,
92
- SemanticColorType = library.SemanticColorType;
104
+ SemanticColorType = library.SemanticColorType,
105
+ NodePorts = library.networkgraph.NodePorts;
93
106
 
94
107
  var AGG_NODES = "nodes",
95
108
  AGG_LINES = "lines",
@@ -136,6 +149,7 @@ sap.ui.define([
136
149
  var Graph = SvgBase.extend("sap.suite.ui.commons.networkgraph.Graph", {
137
150
  metadata: {
138
151
  library: "sap.suite.ui.commons",
152
+ dnd: { draggable: false, droppable: true },
139
153
  properties: {
140
154
  /**
141
155
  * The height of the graph. If this property is set to 'auto', the network graph will be resized to fit the height of its content, regardless of the height of the parent control.
@@ -205,15 +219,88 @@ sap.ui.define([
205
219
  noDataText: {
206
220
  type: "string", group: "Behavior", defaultValue: ""
207
221
  },
222
+ /**
223
+ * Set this property to <code>true</code> to display a loading indicator while the data loads.
224
+ * @public
225
+ * @since 1.136.19
226
+ */
227
+ loading: {
228
+ type: "boolean", group: "Behavior", defaultValue: false
229
+ },
230
+ /**
231
+ * Text that is displayed when the loading is set. <br> This property takes effect only when the <code>loading</code> property is set to <code>true</code>.
232
+ * @public
233
+ * @since 1.136.19
234
+ */
235
+ loadingText: {
236
+ type: "string", group: "Behavior", defaultValue: ""
237
+ },
208
238
  /**
209
239
  * Adds delay in wheel scrolling to make zooming smooth.
210
240
  * Only works when enableWheelZoom is set to true or 'ctrl' key is pressed while wheel scrolling.
211
241
  * Add delay in milliseconds.
212
242
  *
213
- * @private since 1.125
243
+ * @private
214
244
  */
215
245
  _smoothWheelZoom: {
216
246
  type: "int", group: "Behavior", defaultValue: 125, visibility: "hidden"
247
+ },
248
+ /**
249
+ * Enables the drag and drop of nodes. This property is ignored if the layout property is not set to noop.
250
+ * If set to <code>true</code>, nodes can be dragged and dropped within the graph.
251
+ * @public
252
+ * @since 1.136.19
253
+ */
254
+ enableDragAndDrop: {
255
+ type: "boolean", group: "Behavior", defaultValue: false
256
+ },
257
+ /**
258
+ * Specifies the ports that are to be displayed on nodes. Ports are used for creating connections between nodes.
259
+ * Ports are available only when the layout algorithm is set to "NoopLayout", and when the drag and drop is enabled. Otherwise, this property is ignored.
260
+ * @public
261
+ * @since 1.136.19
262
+ */
263
+ nodePorts: {
264
+ type: "sap.suite.ui.commons.networkgraph.NodePorts", group: "Behavior", defaultValue: NodePorts.None
265
+ },
266
+ /**
267
+ * This action button is used to create connections between nodes as an accessible alternative to node ports.
268
+ * The button is displayed on each node when the layout algorithm is set to "NoopLayout" and drag and drop is enabled.
269
+ * shows the 'Create Connection' action button on node.
270
+ * If set to <code>false</code>, the button remains hidden.
271
+ * Hide this button when you want to implement your own way of creating connections between nodes as an accessible alternative to node ports.
272
+ * @public
273
+ * @since 1.136.19
274
+ */
275
+ showCreateConnectionButton: {
276
+ type: "boolean", group: "Behavior", defaultValue: true
277
+ },
278
+ /**
279
+ * Mapping of connection types to their display text keys or custom text values.
280
+ * This allows customization of how connection types are displayed in the connection creation popover.
281
+ * The mapping should be an object where keys are connection type values (LeftToLeft, LeftToRight, RightToLeft, RightToRight)
282
+ * and values are custom text that follows the correct format (e.g., "Start to End", "Source to Target").
283
+ * If the format is invalid or not provided, default values are used
284
+ * @public
285
+ * @since 1.136.19
286
+ */
287
+ connectionTypeMapping: {
288
+ type: "object", group: "Behavior", defaultValue: {
289
+ "LeftToLeft": "Start to Start",
290
+ "LeftToRight": "Start to Finish",
291
+ "RightToLeft": "Finish to Start",
292
+ "RightToRight": "Finish to Finish"
293
+ }
294
+ },
295
+ /**
296
+ * Custom labels for element types displayed in the SearchField suggestions and Legend section headers.
297
+ * Supported keys: nodeLabel, nodeLabelPlural, lineLabel, lineLabelPlural, groupLabel, groupLabelPlural.
298
+ * Reverts to the default values for keys that are not set.
299
+ * @public
300
+ * @since 1.149
301
+ */
302
+ labels: {
303
+ type: "object", group: "Appearance", defaultValue: {}
217
304
  }
218
305
  },
219
306
  aggregations: {
@@ -264,7 +351,12 @@ sap.ui.define([
264
351
  /**
265
352
  * Controls or IDs that label this control. This association is used by screen reader software.
266
353
  */
267
- ariaLabelledBy: { type: "sap.ui.core.Control", multiple: true, singularName: "ariaLabelledBy" }
354
+ ariaLabelledBy: { type: "sap.ui.core.Control", multiple: true, singularName: "ariaLabelledBy" },
355
+ /**
356
+ * Control or ID of an auxiliary control associated with this graph.
357
+ * @since 1.136.19
358
+ */
359
+ associatedControl: { type: "sap.ui.core.Control", multiple: false, singularName: "associatedControl" }
268
360
  },
269
361
  events: {
270
362
  /**
@@ -327,7 +419,79 @@ sap.ui.define([
327
419
  term: { type: "string" },
328
420
  key: { type: "string" }
329
421
  }
330
- }
422
+ },
423
+ /**
424
+ * This event is fired when a user drops a node in the graph.
425
+ * This event is available only when the layout algorithm is set to "NoopLayout" and the <code>enableDragAndDrop</code> property is set to <code>true</code>.
426
+ * @public
427
+ * @since 1.136.19
428
+ */
429
+ nodeDropped: {
430
+ parameters: {
431
+ /**
432
+ * The node that was moved.
433
+ */
434
+ node: { type: "sap.suite.ui.commons.networkgraph.Node" },
435
+ /**
436
+ * The new x coordinate of the node.
437
+ */
438
+ newX: { type: "float" },
439
+ /**
440
+ * The new y coordinate of the node.
441
+ */
442
+ newY: { type: "float" }
443
+ }
444
+ },
445
+ /**
446
+ * This event is fired when a new connection is created between two nodes by using node ports.
447
+ * @public
448
+ * @since 1.136.19
449
+ */
450
+ connectionCreated: {
451
+ parameters: {
452
+ /**
453
+ * The key of the source node.
454
+ **/
455
+ from: { type: "string" },
456
+ /**
457
+ * The key of the target node.
458
+ **/
459
+ to: { type: "string" },
460
+ /**
461
+ * The connection type defining how the line connects the source and target nodes.
462
+ */
463
+ connectionType: {type: "sap.suite.ui.commons.networkgraph.ConnectionType"},
464
+ /**
465
+ * The source node control instance.
466
+ **/
467
+ fromNode: { type: "sap.suite.ui.commons.networkgraph.Node" },
468
+ /**
469
+ * The target node control instance.
470
+ **/
471
+ toNode: { type: "sap.suite.ui.commons.networkgraph.Node" }
472
+ }
473
+ },
474
+ /**
475
+ * This event is fired when a user presses the delete key on a focused node or line.
476
+ * This event is available only when the layout algorithm is set to "NoopLayout" and the <code>enableDragAndDrop</code> property is set to <code>true</code>.
477
+ * @public
478
+ * @since 1.136.19
479
+ */
480
+ itemDeleted: {
481
+ parameters: {
482
+ /**
483
+ * The item (node or line) that is to be deleted.
484
+ */
485
+ item: { type: "sap.suite.ui.commons.networkgraph.ElementBase" }
486
+ }
487
+ },
488
+ /**
489
+ * Fired when the user requests to add a node via INSERT or Ctrl+Alt+N.
490
+ * Only available when NoopLayout is used and enableDragAndDrop is <code>true</code>.
491
+ * @public
492
+ * @since 1.136.19
493
+ */
494
+ nodeAdded: {}
331
495
  }
332
496
  }
333
497
  });
@@ -388,6 +552,9 @@ sap.ui.define([
388
552
  // RTL mode - it's reset in 'onBeforeRendering' in case it changed runtime
389
553
  this._bIsRtl = Localization.getRTL();
390
554
 
555
+ // Private variable for multiple directed arrows feature
556
+ this._enableMultipleDirectedArrows = false;
557
+
391
558
  // element with focus
392
559
  this._oFocus = null;
393
560
 
@@ -406,8 +573,71 @@ sap.ui.define([
406
573
  // flag to check if the events has been added to the graph
407
574
  this._bEventsAdded = false;
408
575
 
576
+ // illustrated message instance for empty state
577
+ this._oIllustratedMessage = null;
578
+
409
579
  this._createToolbar();
410
580
 
581
+ /**
582
+ * Attach drag and drop events
583
+ */
584
+ if (this.getDragDropConfig().length === 0) {
585
+ try {
586
+ DragDropManager.injectDnD(this);
587
+ } catch (error) {
588
+ Log.warning("Graph injectDnD issue: ", error);
589
+ }
590
+ }
591
+ // Initialize PortManager with this graph instance
592
+ PortManager.setGraphInstance(this);
593
+ Core.ready(this._handleCoreInitialized.bind(this));
594
+
595
+ };
596
+
597
+ /**
598
+ * Handler for the core's init event. Attaches listener for localization changes.
599
+ * @private
600
+ */
601
+ Graph.prototype._handleCoreInitialized = function () {
602
+ Localization.attachChange(this._handleLocalizationChanged.bind(this));
603
+ };
604
+
605
+ /**
606
+ * Handler for localization changes. Sets a pending flag when RTL mode changes so that
607
+ * node dimensions are re-measured after RTL CSS files finish loading.
608
+ * UI5 automatically re-renders all UIAreas on RTL change; the flag prevents premature
609
+ * layout calculation in onAfterRendering before CSS dimensions are stable.
610
+ * @private
611
+ */
612
+ Graph.prototype._handleLocalizationChanged = function () {
613
+ const bNewRtl = Localization.getRTL();
614
+ if (this._bIsRtl !== bNewRtl) {
615
+ this._bIsRtl = bNewRtl;
616
+ this._bRtlMeasurementPending = true;
617
+
618
+ const fnOnApplied = function () {
619
+ Theming.detachApplied(fnOnApplied);
620
+ if (this._bRtlMeasurementPending) {
621
+ this._bRtlMeasurementPending = false;
622
+ this._measureAndLayout();
623
+ }
624
+ }.bind(this);
625
+ Theming.attachApplied(fnOnApplied);
626
+ }
627
+ };
628
+
629
+ Graph.prototype._measureAndLayout = function () {
630
+ var aNodes = this.getNodes();
631
+ aNodes.forEach(function (oNode) {
632
+ if (this._isUseNodeHtml()) {
633
+ oNode._setupDivDimensions();
634
+ } else {
635
+ oNode.calculateSizes();
636
+ oNode._setupWidthAndHeight();
637
+ }
638
+ }.bind(this));
639
+ this._bTriggerLayoutCalculation = true;
640
+ this._preprocessData();
411
641
  };
412
642
 
413
643
  Graph.prototype.onBeforeRendering = function () {
@@ -467,7 +697,6 @@ sap.ui.define([
467
697
  this.$().addClass("sapSuiteUiCommonsNetworkGraphFullScreen");
468
698
  }
469
699
 
470
-
471
700
  if (aNodes.length === 0 || this._bIsInvalid || this.getNoData()) {
472
701
  if (this._bIsInvalid) {
473
702
  oRm.openStart("span");
@@ -529,29 +758,18 @@ sap.ui.define([
529
758
  oRm.flush(this._$innerscroller[0], true, this._$innerscroller.children().length);
530
759
  }
531
760
 
532
- // make sure everything is rendered
533
- aNodes.forEach(function (oNode) {
534
- if (this._isUseNodeHtml()) {
535
- // call after rendering before layouter starts - can be handy when user custom renders
536
- oNode._setupDivDimensions();
537
- } else {
538
- oNode.calculateSizes();
539
- oNode._setupWidthAndHeight();
540
- }
541
- }.bind(this));
542
-
543
- this._preprocessData();
544
- Theming.detachApplied(fnProcess);
761
+ if (!this._bRtlMeasurementPending) {
762
+ this._measureAndLayout();
763
+ }
545
764
  }.bind(this);
546
765
 
547
- // In case theme is applied fnProcess will be called immediately,
548
- // else it will be called once theme is applied.
549
- Theming.attachApplied(fnProcess);
766
+ fnProcess();
550
767
  }
551
768
  this.oInvisibleMessage = InvisibleMessage.getInstance();
552
769
  oRm.destroy();
553
770
 
554
771
  };
772
+
555
773
  Graph.prototype.exit = function () {
556
774
  // if (this.oHashChanger) {
557
775
  // this.oHashChanger.destroy();
@@ -559,6 +777,20 @@ sap.ui.define([
559
777
  if (this._oFullScreenUtil) {
560
778
  this._oFullScreenUtil.cleanUpFullScreen(this);
561
779
  }
780
+
781
+ // Clean up busy indicator
782
+ if (this._oBusyIndicator) {
783
+ this._oBusyIndicator.destroy();
784
+ this._oBusyIndicator = null;
785
+ }
786
+
787
+ // Clean up illustrated message
788
+ if (this._oIllustratedMessage) {
789
+ this._oIllustratedMessage.destroy();
790
+ this._oIllustratedMessage = null;
791
+ }
792
+
793
+ DragDropManager.removeDnD(this);
562
794
  };
563
795
  /* =========================================================== */
564
796
  /* Pseudo events and event triggers */
@@ -589,6 +821,7 @@ sap.ui.define([
589
821
  /**
590
822
  * Returns <code>true</code> if the graph is in full screen mode.
591
823
  * @public
824
+ * @returns {boolean} Returns whether the graph is in full screen mode.
592
825
  */
593
826
  Graph.prototype.isFullScreen = function () {
594
827
  return this._bIsFullScreen;
@@ -723,6 +956,33 @@ sap.ui.define([
723
956
  return this._mNodes[sKey];
724
957
  };
725
958
 
959
+ /**
960
+ * Re-rendering a node and all connected lines to update the positions of both the node and the lines.
961
+ * Note: This method should be used only when the layout algorithm is set to NoopLayout and enableDragAndDrop is set to true.
962
+ *
963
+ * @param {sap.suite.ui.commons.networkgraph.Node|string} vNode Node instance or node key
964
+ * @param {number} iX New X coordinate
965
+ * @param {number} iY New Y coordinate
966
+ * @returns {sap.suite.ui.commons.networkgraph.Graph} Reference to this for method chaining
967
+ * @public
968
+ * @since 1.136.19
969
+ */
970
+ Graph.prototype.updateNodePosition = function (vNode, iX, iY) {
971
+ if (!this._isDnDEnabled()) {
972
+ return this;
973
+ }
974
+
975
+ var oNode = typeof vNode === "string" ? this.getNodeByKey(vNode) : vNode;
976
+
977
+ if (!oNode) {
978
+ Log.warning("Node not found", "updateNodePosition", "sap.suite.ui.commons.networkgraph.Graph");
979
+ return this;
980
+ }
981
+
982
+ this.invalidate();
983
+ return this;
984
+ };
985
+
726
986
  /**
727
987
  * Sets a custom label for the legend.
728
988
  * @param {object} mArguments Parameters for this method
@@ -759,6 +1019,13 @@ sap.ui.define([
759
1019
  this._createLegend();
760
1020
  };
761
1021
 
1022
+ Graph.prototype.setLabels = function (oValue) {
1023
+ this.setProperty("labels", oValue, true);
1024
+ this._createSearchSuggestItems();
1025
+ this._createLegend();
1026
+ return this;
1027
+ };
1028
+
762
1029
 
763
1030
  /**
764
1031
  * Zooms in or out of the graph.
@@ -797,7 +1064,7 @@ sap.ui.define([
797
1064
  /**
798
1065
  * Returns current zoom level.
799
1066
  *
800
- * @return {number}
1067
+ * @return {number} Current zoom level
801
1068
  * @public
802
1069
  */
803
1070
  Graph.prototype.getCurrentZoomLevel = function () {
@@ -817,6 +1084,31 @@ sap.ui.define([
817
1084
  this._oZoomLevelInvisibleText.setText(oResourceBundle.getText("NETWORK_GRAPH_ZOOM_LEVEL") + ": " + this._getZoomText());
818
1085
  };
819
1086
 
1087
+ /**
1088
+ * Restores keyboard focus to the last focused item in the graph, or falls back to the graph wrapper.
1089
+ * @private
1090
+ */
1091
+ Graph.prototype._restoreFocusToGraph = function () {
1092
+ if (this._oFocus) {
1093
+ const oFocusToRestore = this._oFocus;
1094
+ // Force setFocus to re-apply even if the item hasn't changed.
1095
+ this._oFocus = null;
1096
+ this.setFocus(oFocusToRestore);
1097
+ } else {
1098
+ this.getFocusDomRef().focus();
1099
+ }
1100
+ };
1101
+
1102
+ /**
1103
+ * Gets the associated control linked to this graph instance using the 'associatedControl' association.
1104
+ * This can be any UI5 control that is related to the graph.
1105
+ * @returns {sap.ui.core.Control|null} The associated control instance or null if not set.
1106
+ * @public
1107
+ */
1108
+ Graph.prototype.getAssociatedControl = function () {
1109
+ var sId = this.getAssociation("associatedControl");
1110
+ return sId ? Element.getElementById(sId) : null;
1111
+ };
820
1112
 
821
1113
  /* =========================================================== */
822
1114
  /* Private methods */
@@ -843,6 +1135,24 @@ sap.ui.define([
843
1135
  };
844
1136
  };
845
1137
 
1138
+ /**
1139
+ * Returns a busy indicator instance for loading states.
1140
+ * @returns {sap.m.BusyIndicator} BusyIndicator instance
1141
+ * @private
1142
+ */
1143
+ Graph.prototype._getBusyIndicator = function () {
1144
+ var sText = this.getLoadingText() || oResourceBundle.getText("NETWORK_GRAPH_OPENING_CANVAS");
1145
+
1146
+ if (!this._oBusyIndicator) {
1147
+ this._oBusyIndicator = new BusyIndicator({ text: sText });
1148
+ this.addDependent(this._oBusyIndicator);
1149
+ } else {
1150
+ this._oBusyIndicator.setText(sText);
1151
+ }
1152
+
1153
+ return this._oBusyIndicator;
1154
+ };
1155
+
846
1156
  Graph.prototype._createTooltip = function () {
847
1157
  var oTooltip = new Tooltip(this.getId() + "-tooltip");
848
1158
  this.addDependent(oTooltip);
@@ -858,6 +1168,7 @@ sap.ui.define([
858
1168
  return;
859
1169
  }
860
1170
 
1171
+ this._oFocus = null;
861
1172
  this.setFocus(oFocus);
862
1173
 
863
1174
  if (oFocus.button == "menu") {
@@ -871,12 +1182,91 @@ sap.ui.define([
871
1182
  };
872
1183
 
873
1184
  /**
1185
+ * Gets or creates an IllustratedMessage instance for displaying empty state.
1186
+ * This method reuses the same instance to avoid memory leaks.
1187
+ * The illustrated message content depends on whether drag-and-drop is enabled:
1188
+ * - When drag-and-drop is enabled: Shows "AddDimensions" illustration with plan-building message
1189
+ * - When drag-and-drop is disabled: Shows "NoChartData" illustration with custom or default no-data text
1190
+ *
1191
+ * @returns {sap.m.IllustratedMessage} The illustrated message instance for empty state
874
1192
  * @private
875
1193
  */
1194
+ Graph.prototype._getIllustratedMessage = function () {
1195
+ // Helper function to get configuration based on current state
1196
+ var fnConfigureIllustratedMessage = function () {
1197
+ var sText = this.getNoDataText(),
1198
+ sTextInline = sText || oResourceBundle.getText("NETWORK_GRAPH_NO_DATA");
1199
+
1200
+ if (this._isDnDEnabled()) {
1201
+ return {
1202
+ illustrationType: IllustratedMessageType.AddDimensions,
1203
+ title: oResourceBundle.getText("NETWORK_GRAPH_DND_EMPTY_TITLE"),
1204
+ description: oResourceBundle.getText("NETWORK_GRAPH_DND_EMPTY_DESCRIPTION"),
1205
+ enableDefaultTitleAndDescription: false
1206
+ };
1207
+ } else {
1208
+ return {
1209
+ illustrationType: IllustratedMessageType.NoChartData,
1210
+ title: sTextInline,
1211
+ enableDefaultTitleAndDescription: false
1212
+ };
1213
+ }
1214
+ }.bind(this);
1215
+
1216
+ if (!this._oIllustratedMessage) {
1217
+ var oConfig = fnConfigureIllustratedMessage();
1218
+ this._oIllustratedMessage = new IllustratedMessage(oConfig);
1219
+ this.addDependent(this._oIllustratedMessage);
1220
+ } else {
1221
+ var oConfig = fnConfigureIllustratedMessage();
1222
+ this._oIllustratedMessage.setIllustrationType(oConfig.illustrationType);
1223
+ this._oIllustratedMessage.setTitle(oConfig.title);
1224
+ this._oIllustratedMessage.setDescription(oConfig.description);
1225
+ }
1226
+
1227
+ return this._oIllustratedMessage;
1228
+ };
1229
+
1230
+ /**
1231
+ * @private
1232
+ * Defocuses the currently focused element.
1233
+ */
876
1234
  Graph.prototype.defocus = function () {
877
1235
  this.$().find("." + this.FOCUS_CLASS).removeClass(this.FOCUS_CLASS);
878
1236
  };
879
1237
 
1238
+ /**
1239
+ * Sets whether drag and drop is enabled.
1240
+ * @param {boolean} bEnabled Whether drag and drop should be enabled
1241
+ * @private
1242
+ */
1243
+ Graph.prototype.setEnableDragAndDrop = function (bEnabled) {
1244
+ this.setProperty("enableDragAndDrop", bEnabled, true);
1245
+
1246
+ // Update zoom button visibility
1247
+ if (this._zoomIn && this._zoomOut && this._zoomToFitButton) {
1248
+ var bZoomVisible = !this._isDnDEnabled();
1249
+ this._zoomIn.setVisible(bZoomVisible);
1250
+ this._zoomOut.setVisible(bZoomVisible);
1251
+ this._zoomToFitButton.setVisible(bZoomVisible);
1252
+ }
1253
+
1254
+ // remove the node ports when drag and drop is disabled
1255
+ if (!bEnabled) {
1256
+ PortManager.removeAllPorts();
1257
+ }
1258
+
1259
+ return this;
1260
+ };
1261
+
1262
+ /**
1263
+ * @private
1264
+ * @returns {boolean} Returns whether drag and drop is enabled.
1265
+ */
1266
+ Graph.prototype.getEnableDragAndDrop = function () {
1267
+ return this.getProperty("enableDragAndDrop");
1268
+ };
1269
+
880
1270
  /**
881
1271
  * Sets focus of the graph. Since one element at max can be focused at one time, handling of this belongs to the graph itself.
882
1272
  * @param {object} oFocus Element (and optionally button) to focus
@@ -900,12 +1290,12 @@ sap.ui.define([
900
1290
  this._oFocus.item.isA("sap.suite.ui.commons.networkgraph.Node")))) {
901
1291
  this._updateAccessibility(oFocus);
902
1292
  }
903
- this._updateAccessibility(oFocus);
904
- return;
1293
+ this._updateAccessibility(oFocus);
1294
+ return;
905
1295
  }
906
1296
 
907
1297
  this.defocus();
908
- if (this.getFocusDomRef()) {
1298
+ if (this.getFocusDomRef() && !(oFocus && oFocus.button && oFocus.button.id && oFocus.button.id.indexOf("actionOverflow") !== -1)) {
909
1299
  this.getFocusDomRef().focus();
910
1300
  }
911
1301
 
@@ -945,7 +1335,7 @@ sap.ui.define([
945
1335
  this._setAccessibilityTitle(oResourceBundle.getText("NETWORK_GRAPH_ACCESSIBILITY_CONTENT"));
946
1336
  }.bind(this),
947
1337
  fnBuildTitleForButton = function (sLabel) {
948
- var sTitleLabel = sLabel + " " + oResourceBundle.getText("NETWORK_GRAPH_ACCESSIBILITY_ACTION_BUTTON") ;
1338
+ var sTitleLabel = sLabel + " " + oResourceBundle.getText("NETWORK_GRAPH_ACCESSIBILITY_ACTION_BUTTON");
949
1339
  if (sLabel === "Expand/Collapse") {
950
1340
  if (oFocus.item.getCollapsed()) {
951
1341
  sTitleLabel = sTitleLabel + " " + oResourceBundle.getText("NETWORK_GRAPH_COLLAPSED");
@@ -1049,6 +1439,14 @@ sap.ui.define([
1049
1439
  return this.getNodes().concat(this.getGroups());
1050
1440
  };
1051
1441
 
1442
+ Graph.prototype._isNoopLayout = function () {
1443
+ return this._getLayoutAlgorithm().isA("sap.suite.ui.commons.networkgraph.layout.NoopLayout");
1444
+ };
1445
+
1446
+ Graph.prototype._isDnDEnabled = function() {
1447
+ return this._isNoopLayout() && this.getEnableDragAndDrop();
1448
+ };
1449
+
1052
1450
  Graph.prototype._render = function () {
1053
1451
  this._beforeRender();
1054
1452
 
@@ -1077,8 +1475,9 @@ sap.ui.define([
1077
1475
  this.$background.width(iSvgWidth * this._fZoomLevel);
1078
1476
  this.$background.height(iSvgHeight * this._fZoomLevel);
1079
1477
 
1478
+ var sScale = "";
1080
1479
  if (this._isUseNodeHtml()) {
1081
- var sScale = "scale(" + this._fZoomLevel + ")";
1480
+ sScale = "scale(" + this._fZoomLevel + ")";
1082
1481
  this.$("divnodes").css("transform", sScale);
1083
1482
  }
1084
1483
 
@@ -1125,6 +1524,10 @@ sap.ui.define([
1125
1524
 
1126
1525
  if (!this._isSwimLane() && !this._isTwoColumnsLayout()) {
1127
1526
  this.$("innerscroller").addClass(" sapSuiteUiCommonsNetworkGraphInnerScrollerCenter ");
1527
+ if (this._isDnDEnabled()) {
1528
+ // If NoopLayout is used, users must set certain styles to ensure precise coordinates setting.
1529
+ this.$("innerscroller").addClass("sapSuiteUiCommonsNetworkGraphInnerScrollerNoMargin");
1530
+ }
1128
1531
  }
1129
1532
  };
1130
1533
 
@@ -1348,6 +1751,8 @@ sap.ui.define([
1348
1751
  oRm.openStart("g", this.getId() + "-svgbody");
1349
1752
  oRm.openEnd();
1350
1753
  fnRenderItems("lines", aLines, "sapSuiteUiCommonsNetworkLines");
1754
+ // Render line texts after all lines are rendered to handle overlaps
1755
+ this._renderAllLineTexts(aLines, oRm);
1351
1756
  if (!this._isUseNodeHtml()) {
1352
1757
  fnRenderItems("nodes", aNodes, "sapSuiteUiCommonsNetworkNodes");
1353
1758
  }
@@ -1372,6 +1777,45 @@ sap.ui.define([
1372
1777
 
1373
1778
  };
1374
1779
 
1780
+ /**
1781
+ * Renders text labels for all lines in a dedicated SVG group container.
1782
+ *
1783
+ * This method creates a batch rendering context for line labels, enabling
1784
+ * potential overlap handling and positioning optimizations. Labels are only
1785
+ * rendered for lines that meet all of the following conditions:
1786
+ * - The line has a labelName property value set
1787
+ * - The graph is using NoopLayout
1788
+ * - The line's arrowPosition is set to "Both"
1789
+ *
1790
+ * @param {sap.suite.ui.commons.networkgraph.Line[]} aLines Array of line objects to render text labels for
1791
+ * @param {sap.ui.core.RenderManager} oRm The RenderManager instance used for SVG rendering
1792
+ * @private
1793
+ */
1794
+ Graph.prototype._renderAllLineTexts = function (aLines, oRm) {
1795
+ // Early return if line labels are disabled or NoopLayout is not active
1796
+ if (!this._isNoopLayout()) {
1797
+ return;
1798
+ }
1799
+
1800
+ // Create a dedicated SVG group container for all line text labels
1801
+ // This enables batch processing and potential overlap handling
1802
+ oRm.openStart("g");
1803
+ oRm.attr("id", this.getId() + "-line-texts");
1804
+ oRm.class("sapSuiteUiCommonsNetworkLineTexts");
1805
+ oRm.openEnd();
1806
+
1807
+ // Iterate through all lines and render their text labels within the group
1808
+ // Only process lines that are valid, not ignored by layout, and visible
1809
+ aLines.forEach(function (oLine) {
1810
+ if (oLine && !oLine._isIgnored() && oLine.getVisible()) {
1811
+ oLine._renderLineText(oRm);
1812
+ }
1813
+ });
1814
+
1815
+ // Close the SVG group container
1816
+ oRm.close("g");
1817
+ };
1818
+
1375
1819
  Graph.prototype._isProperKey = function (sKey) {
1376
1820
  return sKey || (sKey === "0");
1377
1821
  };
@@ -1452,7 +1896,11 @@ sap.ui.define([
1452
1896
  }
1453
1897
  }
1454
1898
 
1455
- this._isUseNodeHtml() ? oNode._resetDimensions() : oNode._setupWidthAndHeight();
1899
+ if (this._isUseNodeHtml()) {
1900
+ oNode._resetDimensions();
1901
+ } else {
1902
+ oNode._setupWidthAndHeight();
1903
+ }
1456
1904
  oNode._clearChildren();
1457
1905
  oNode._rendered = false;
1458
1906
 
@@ -1881,16 +2329,24 @@ sap.ui.define([
1881
2329
  }
1882
2330
  });
1883
2331
  this._toolbar.addContent(this._zoomOut);
1884
- }
2332
+ }
1885
2333
 
1886
2334
  // fit to viewport
1887
- this._toolbar.addContent(new OverflowToolbarButton({
2335
+ this._zoomToFitButton = new OverflowToolbarButton({
1888
2336
  type: ButtonType.Transparent,
1889
2337
  icon: "sap-icon://popup-window",
1890
2338
  tooltip: oResourceBundle.getText("NETWORK_GRAPH_ZOOMTOFIT"),
1891
2339
  text: oResourceBundle.getText("NETWORK_GRAPH_ZOOMTOFIT"),
1892
2340
  press: this._fitToScreen.bind(this)
1893
- }));
2341
+ });
2342
+ this._toolbar.addContent(this._zoomToFitButton);
2343
+
2344
+ // Hide zoom buttons if drag and drop is enabled
2345
+ if (this._isDnDEnabled()) {
2346
+ this._zoomIn.setVisible(false);
2347
+ this._zoomOut.setVisible(false);
2348
+ this._zoomToFitButton.setVisible(false);
2349
+ }
1894
2350
 
1895
2351
  // toggle full screen
1896
2352
  this._oFullScreenButton = new OverflowToolbarButton({
@@ -2172,7 +2628,9 @@ sap.ui.define([
2172
2628
 
2173
2629
  $wrapper.on("mouseleave", this._endDragging.bind(this));
2174
2630
  $wrapper.on("mouseup", this._mouseUp.bind(this));
2175
- if (this.getEnableZoom()) {
2631
+ if (this.getEnableZoom() && !this._isDnDEnabled()) {
2632
+ // Disabling zooming capability in edit mode.
2633
+ // TODO: consider scaling when dragging and dropping nodes and update ghost image dimenstion and coordinates prediction, to allow zooming.
2176
2634
  $wrapper.on("wheel", function (oEvent) {
2177
2635
  if (this._wheel({
2178
2636
  x: oEvent.originalEvent.clientX,
@@ -2230,6 +2688,7 @@ sap.ui.define([
2230
2688
  this._oZoomLevelInvisibleText.setText(oResourceBundle.getText("NETWORK_GRAPH_ZOOM_LEVEL") + ": " + this._getZoomText());
2231
2689
  return true;
2232
2690
  }
2691
+ return false;
2233
2692
  };
2234
2693
 
2235
2694
  Graph.prototype._endDragging = function () {
@@ -2262,6 +2721,11 @@ sap.ui.define([
2262
2721
  this._oPanning.dragging = true;
2263
2722
 
2264
2723
  this._tooltip.instantClose();
2724
+
2725
+ // Remove all ports when deselecting
2726
+ if (PortManager._currentTriggerNodeKey !== null) {
2727
+ PortManager.removeAllPorts();
2728
+ }
2265
2729
  };
2266
2730
 
2267
2731
  Graph.prototype._mouseUp = function () {
@@ -2410,6 +2874,11 @@ sap.ui.define([
2410
2874
  // indicates current count of suggestion items when they are rendered
2411
2875
  this._oSuggestionItemsModel.setSizeLimit(SUGGESTION_ITEMS_LIMIT);
2412
2876
 
2877
+ const oLabels = this.getLabels() || {};
2878
+ const sNodeLabel = oLabels.nodeLabel || oResourceBundle.getText("NETWORK_GRAPH_NODE");
2879
+ const sLineLabel = oLabels.lineLabel || oResourceBundle.getText("NETWORK_GRAPH_LINE");
2880
+ const sGroupLabel = oLabels.groupLabel || oResourceBundle.getText("NETWORK_GRAPH_GROUP");
2881
+
2413
2882
  aNodes.forEach(function (oNode) {
2414
2883
  var sTitle = Utils.trimText(oNode.getTitle(), TITLE_LENGTH);
2415
2884
  oData.items.push({
@@ -2417,7 +2886,7 @@ sap.ui.define([
2417
2886
  type: SUGGESTIONS.Node,
2418
2887
  icon: oNode.getIcon(),
2419
2888
  key: oNode.getKey(),
2420
- description: "(" + oResourceBundle.getText("NETWORK_GRAPH_NODE") + ")"
2889
+ description: "(" + sNodeLabel + ")"
2421
2890
  });
2422
2891
  });
2423
2892
 
@@ -2430,7 +2899,7 @@ sap.ui.define([
2430
2899
  text: oLine._createSuggestionHelpText(),
2431
2900
  type: SUGGESTIONS.Line,
2432
2901
  key: oLine._getLineId(),
2433
- description: "(" + oResourceBundle.getText("NETWORK_GRAPH_LINE") + ")"
2902
+ description: "(" + sLineLabel + ")"
2434
2903
  });
2435
2904
  }
2436
2905
  });
@@ -2442,7 +2911,7 @@ sap.ui.define([
2442
2911
  text: sTitle ? sTitle : oGroup.getKey(),
2443
2912
  key: oGroup.getKey(),
2444
2913
  type: SUGGESTIONS.Group,
2445
- description: "(" + oResourceBundle.getText("NETWORK_GRAPH_GROUP") + ")"
2914
+ description: "(" + sGroupLabel + ")"
2446
2915
  });
2447
2916
  }
2448
2917
  });
@@ -2486,7 +2955,13 @@ sap.ui.define([
2486
2955
  fHeight = oItem._iHeight;
2487
2956
  }
2488
2957
 
2489
- this.$scroller.get(0).scrollLeft = ((fX + (fWidth ? fWidth : 0) / 2) * this._fZoomLevel) - (this.$scroller.width() / 2);
2958
+ const fScrollLeft = ((fX + (fWidth ? fWidth : 0) / 2) * this._fZoomLevel) - (this.$scroller.width() / 2);
2959
+
2960
+ if (this._bIsRtl) {
2961
+ this.$scroller.get(0).scrollLeft = -fScrollLeft;
2962
+ } else {
2963
+ this.$scroller.get(0).scrollLeft = fScrollLeft;
2964
+ }
2490
2965
  this.$scroller.get(0).scrollTop = ((fY + (fHeight ? fHeight : 0) / 2) * this._fZoomLevel) - (this.$scroller.height() / 2);
2491
2966
  };
2492
2967
 
@@ -2507,6 +2982,14 @@ sap.ui.define([
2507
2982
  iRight = iLeft + this.$scroller.width() / this._fZoomLevel,
2508
2983
  iBottom = iTop + this.$scroller.height() / this._fZoomLevel;
2509
2984
 
2985
+ if (this._bIsRtl) {
2986
+ const iGraphWidth = this.$svg.width() / this._fZoomLevel;
2987
+ const iViewportWidth = this.$scroller.width() / this._fZoomLevel;
2988
+ const iScrollPosAbs = Math.abs(iLeft);
2989
+ iLeft = iGraphWidth - iScrollPosAbs - iViewportWidth;
2990
+ iRight = iLeft + iViewportWidth;
2991
+ }
2992
+
2510
2993
  if (!oItem._isOnScreen(iLeft, iRight, iTop, iBottom)) {
2511
2994
  if (oItem instanceof Node) {
2512
2995
  iCenterX = oItem.getX() + oItem._iWidth / 2;
@@ -2521,7 +3004,14 @@ sap.ui.define([
2521
3004
  }
2522
3005
 
2523
3006
  if (iCenterX < iLeft || iCenterX > iRight) {
2524
- oScroller.scrollLeft = iCenterX * this._fZoomLevel - this.$scroller.width() / 2;
3007
+ let iTargetScrollLeft = iCenterX * this._fZoomLevel - this.$scroller.width() / 2;
3008
+
3009
+ if (this._bIsRtl) {
3010
+ const iScrollRange = oScroller.scrollWidth - oScroller.clientWidth;
3011
+ iTargetScrollLeft = -(iScrollRange - iTargetScrollLeft);
3012
+ }
3013
+
3014
+ oScroller.scrollLeft = iTargetScrollLeft;
2525
3015
  }
2526
3016
  if (iCenterY < iTop || iCenterY > iBottom) {
2527
3017
  oScroller.scrollTop = iCenterY * this._fZoomLevel - this.$scroller.height() / 2;
@@ -2586,7 +3076,7 @@ sap.ui.define([
2586
3076
  if (fnHasStatus(oCollection)) {
2587
3077
  oRm.openStart("div").class(sClass).openEnd();
2588
3078
  oRm.openStart("label").class("sapSuiteUiCommonsNetworkGraphLegendTitle").openEnd();
2589
- oRm.text(oResourceBundle.getText(sTitle));
3079
+ oRm.text(sTitle);
2590
3080
  oRm.close("label");
2591
3081
  oRm.close("div");
2592
3082
  // get the status labels for sorting (some statuses can have custom labels)
@@ -2621,12 +3111,13 @@ sap.ui.define([
2621
3111
  return;
2622
3112
  }
2623
3113
 
3114
+ const oLabels = this.getLabels() || {};
2624
3115
  fnProcessElements(this.getNodes(), oNodeStatuses, "sapSuiteUiCommonsNetworkGraphLegendTitleNode",
2625
- "NETWORK_GRAPH_NODES", StatusType.Node);
3116
+ oLabels.nodeLabelPlural || oResourceBundle.getText("NETWORK_GRAPH_NODES"), StatusType.Node);
2626
3117
  fnProcessElements(this.getLines(), oLineStatuses, "sapSuiteUiCommonsNetworkGraphLegendTitleLine",
2627
- "NETWORK_GRAPH_LINES", StatusType.Line);
3118
+ oLabels.lineLabelPlural || oResourceBundle.getText("NETWORK_GRAPH_LINES"), StatusType.Line);
2628
3119
  fnProcessElements(this.getGroups(), oGroupStatuses, "sapSuiteUiCommonsNetworkGraphLegendTitleLine",
2629
- "NETWORK_GRAPH_GROUPS", StatusType.Group);
3120
+ oLabels.groupLabelPlural || oResourceBundle.getText("NETWORK_GRAPH_GROUPS"), StatusType.Group);
2630
3121
  oRm.flush($legend[0]);
2631
3122
  oRm.destroy();
2632
3123
  // $legend.html(sHtml);
@@ -2786,8 +3277,15 @@ sap.ui.define([
2786
3277
  };
2787
3278
 
2788
3279
  Graph.prototype._isTopBottom = function () {
2789
- return this.getOrientation() === Orientation.TopBottom ||
2790
- this.getOrientation() === Orientation.BottomTop;
3280
+ return this.getOrientation() === Orientation.TopBottom
3281
+ };
3282
+
3283
+ Graph.prototype._isBottomTop = function () {
3284
+ return this.getOrientation() === Orientation.BottomTop;
3285
+ };
3286
+
3287
+ Graph.prototype._isRightLeft = function () {
3288
+ return this.getOrientation() === Orientation.RightLeft;
2791
3289
  };
2792
3290
 
2793
3291
  /* =========================================================== */
@@ -2929,5 +3427,16 @@ sap.ui.define([
2929
3427
  }
2930
3428
  };
2931
3429
 
3430
+ /**
3431
+ * Checks if the current layout algorithm supports node ports functionality.
3432
+ * For now, only NoopLayout algorithms support node ports.
3433
+ *
3434
+ * @returns {boolean} True if the layout supports node ports, false otherwise
3435
+ * @private
3436
+ */
3437
+ Graph.prototype._supportsNodePorts = function () {
3438
+ return this.getNodePorts() !== "None" && this._isDnDEnabled();
3439
+ };
3440
+
2932
3441
  return Graph;
2933
3442
  });