@sapui5/sap.suite.ui.commons 1.136.11 → 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 (74) 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_ar.properties +1 -1
  31. package/src/sap/suite/ui/commons/messagebundle_en_US_saprigi.properties +39 -5
  32. package/src/sap/suite/ui/commons/messagebundle_fr_CA.properties +1 -1
  33. package/src/sap/suite/ui/commons/messagebundle_hu.properties +1 -1
  34. package/src/sap/suite/ui/commons/messagebundle_id.properties +2 -2
  35. package/src/sap/suite/ui/commons/messagebundle_it.properties +1 -1
  36. package/src/sap/suite/ui/commons/messagebundle_pt.properties +1 -1
  37. package/src/sap/suite/ui/commons/messagebundle_ru.properties +1 -1
  38. package/src/sap/suite/ui/commons/networkgraph/ElementBase.js +19 -1
  39. package/src/sap/suite/ui/commons/networkgraph/Graph.js +590 -48
  40. package/src/sap/suite/ui/commons/networkgraph/GraphMap.js +25 -3
  41. package/src/sap/suite/ui/commons/networkgraph/GraphRenderer.js +19 -8
  42. package/src/sap/suite/ui/commons/networkgraph/KeyboardNavigator.js +367 -12
  43. package/src/sap/suite/ui/commons/networkgraph/Line.js +814 -22
  44. package/src/sap/suite/ui/commons/networkgraph/Node.js +573 -79
  45. package/src/sap/suite/ui/commons/networkgraph/Tooltip.js +4 -0
  46. package/src/sap/suite/ui/commons/networkgraph/Utils.js +249 -10
  47. package/src/sap/suite/ui/commons/networkgraph/layout/NoopLayout.js +77 -7
  48. package/src/sap/suite/ui/commons/networkgraph/util/ConnectionPathUtils.js +1174 -0
  49. package/src/sap/suite/ui/commons/networkgraph/util/CreateConnectionPopover.js +374 -0
  50. package/src/sap/suite/ui/commons/networkgraph/util/DependencyLayoutHelper.js +1017 -0
  51. package/src/sap/suite/ui/commons/networkgraph/util/DragDropManager.js +721 -0
  52. package/src/sap/suite/ui/commons/networkgraph/util/PortManager.js +582 -0
  53. package/src/sap/suite/ui/commons/statusindicator/Circle.js +1 -1
  54. package/src/sap/suite/ui/commons/statusindicator/CustomShape.js +1 -1
  55. package/src/sap/suite/ui/commons/statusindicator/DiscreteThreshold.js +1 -1
  56. package/src/sap/suite/ui/commons/statusindicator/FillingOption.js +1 -1
  57. package/src/sap/suite/ui/commons/statusindicator/LibraryShape.js +1 -1
  58. package/src/sap/suite/ui/commons/statusindicator/Path.js +1 -1
  59. package/src/sap/suite/ui/commons/statusindicator/PropertyThreshold.js +1 -1
  60. package/src/sap/suite/ui/commons/statusindicator/Rectangle.js +1 -1
  61. package/src/sap/suite/ui/commons/statusindicator/Shape.js +1 -1
  62. package/src/sap/suite/ui/commons/statusindicator/ShapeGroup.js +1 -1
  63. package/src/sap/suite/ui/commons/statusindicator/SimpleShape.js +1 -1
  64. package/src/sap/suite/ui/commons/statusindicator/StatusIndicator.js +1 -1
  65. package/src/sap/suite/ui/commons/taccount/TAccount.js +1 -1
  66. package/src/sap/suite/ui/commons/taccount/TAccountGroup.js +1 -1
  67. package/src/sap/suite/ui/commons/taccount/TAccountItem.js +1 -1
  68. package/src/sap/suite/ui/commons/taccount/TAccountItemProperty.js +1 -1
  69. package/src/sap/suite/ui/commons/taccount/TAccountPanel.js +1 -1
  70. package/src/sap/suite/ui/commons/themes/base/NetworkGraph.less +26 -13
  71. package/src/sap/suite/ui/commons/themes/base/NetworkGroup.less +4 -0
  72. package/src/sap/suite/ui/commons/themes/base/NetworkLine.less +58 -13
  73. package/src/sap/suite/ui/commons/themes/base/NetworkNode.less +251 -47
  74. 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,14 +573,83 @@ 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 () {
414
644
  // indicates RTL
415
645
  this._bIsRtl = Localization.getRTL();
416
646
 
647
+ // Check if the currently focused item has been destroyed and clear it
648
+ if (this._oFocus && this._oFocus.item && (this._oFocus.item.bIsDestroyed || this._oFocus.item.isDestroyed?.())) {
649
+ Log.info("NetworkGraph: Focused item was destroyed before rendering, clearing focus");
650
+ this._oFocus = null;
651
+ }
652
+
417
653
  this.setBusy(false);
418
654
  this.setBusyIndicatorDelay(0);
419
655
 
@@ -461,7 +697,6 @@ sap.ui.define([
461
697
  this.$().addClass("sapSuiteUiCommonsNetworkGraphFullScreen");
462
698
  }
463
699
 
464
-
465
700
  if (aNodes.length === 0 || this._bIsInvalid || this.getNoData()) {
466
701
  if (this._bIsInvalid) {
467
702
  oRm.openStart("span");
@@ -523,29 +758,18 @@ sap.ui.define([
523
758
  oRm.flush(this._$innerscroller[0], true, this._$innerscroller.children().length);
524
759
  }
525
760
 
526
- // make sure everything is rendered
527
- aNodes.forEach(function (oNode) {
528
- if (this._isUseNodeHtml()) {
529
- // call after rendering before layouter starts - can be handy when user custom renders
530
- oNode._setupDivDimensions();
531
- } else {
532
- oNode.calculateSizes();
533
- oNode._setupWidthAndHeight();
534
- }
535
- }.bind(this));
536
-
537
- this._preprocessData();
538
- Theming.detachApplied(fnProcess);
761
+ if (!this._bRtlMeasurementPending) {
762
+ this._measureAndLayout();
763
+ }
539
764
  }.bind(this);
540
765
 
541
- // In case theme is applied fnProcess will be called immediately,
542
- // else it will be called once theme is applied.
543
- Theming.attachApplied(fnProcess);
766
+ fnProcess();
544
767
  }
545
768
  this.oInvisibleMessage = InvisibleMessage.getInstance();
546
769
  oRm.destroy();
547
770
 
548
771
  };
772
+
549
773
  Graph.prototype.exit = function () {
550
774
  // if (this.oHashChanger) {
551
775
  // this.oHashChanger.destroy();
@@ -553,6 +777,20 @@ sap.ui.define([
553
777
  if (this._oFullScreenUtil) {
554
778
  this._oFullScreenUtil.cleanUpFullScreen(this);
555
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);
556
794
  };
557
795
  /* =========================================================== */
558
796
  /* Pseudo events and event triggers */
@@ -583,6 +821,7 @@ sap.ui.define([
583
821
  /**
584
822
  * Returns <code>true</code> if the graph is in full screen mode.
585
823
  * @public
824
+ * @returns {boolean} Returns whether the graph is in full screen mode.
586
825
  */
587
826
  Graph.prototype.isFullScreen = function () {
588
827
  return this._bIsFullScreen;
@@ -717,6 +956,33 @@ sap.ui.define([
717
956
  return this._mNodes[sKey];
718
957
  };
719
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
+
720
986
  /**
721
987
  * Sets a custom label for the legend.
722
988
  * @param {object} mArguments Parameters for this method
@@ -753,6 +1019,13 @@ sap.ui.define([
753
1019
  this._createLegend();
754
1020
  };
755
1021
 
1022
+ Graph.prototype.setLabels = function (oValue) {
1023
+ this.setProperty("labels", oValue, true);
1024
+ this._createSearchSuggestItems();
1025
+ this._createLegend();
1026
+ return this;
1027
+ };
1028
+
756
1029
 
757
1030
  /**
758
1031
  * Zooms in or out of the graph.
@@ -791,7 +1064,7 @@ sap.ui.define([
791
1064
  /**
792
1065
  * Returns current zoom level.
793
1066
  *
794
- * @return {number}
1067
+ * @return {number} Current zoom level
795
1068
  * @public
796
1069
  */
797
1070
  Graph.prototype.getCurrentZoomLevel = function () {
@@ -811,6 +1084,31 @@ sap.ui.define([
811
1084
  this._oZoomLevelInvisibleText.setText(oResourceBundle.getText("NETWORK_GRAPH_ZOOM_LEVEL") + ": " + this._getZoomText());
812
1085
  };
813
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
+ };
814
1112
 
815
1113
  /* =========================================================== */
816
1114
  /* Private methods */
@@ -837,6 +1135,24 @@ sap.ui.define([
837
1135
  };
838
1136
  };
839
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
+
840
1156
  Graph.prototype._createTooltip = function () {
841
1157
  var oTooltip = new Tooltip(this.getId() + "-tooltip");
842
1158
  this.addDependent(oTooltip);
@@ -844,7 +1160,15 @@ sap.ui.define([
844
1160
  oTooltip.attachEvent("afterClose", function () {
845
1161
  var oFocus = this.getFocus();
846
1162
 
847
- if (oFocus) {
1163
+ if (oFocus && oFocus.item) {
1164
+ // Check if the focused item is destroyed before trying to restore focus
1165
+ if (oFocus.item.bIsDestroyed || oFocus.item.isDestroyed?.()) {
1166
+ Log.info("NetworkGraph: Cannot restore focus on destroyed control after tooltip close");
1167
+ this._oFocus = null;
1168
+ return;
1169
+ }
1170
+
1171
+ this._oFocus = null;
848
1172
  this.setFocus(oFocus);
849
1173
 
850
1174
  if (oFocus.button == "menu") {
@@ -858,12 +1182,91 @@ sap.ui.define([
858
1182
  };
859
1183
 
860
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
861
1192
  * @private
862
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
+ */
863
1234
  Graph.prototype.defocus = function () {
864
1235
  this.$().find("." + this.FOCUS_CLASS).removeClass(this.FOCUS_CLASS);
865
1236
  };
866
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
+
867
1270
  /**
868
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.
869
1272
  * @param {object} oFocus Element (and optionally button) to focus
@@ -871,6 +1274,13 @@ sap.ui.define([
871
1274
  * @private
872
1275
  */
873
1276
  Graph.prototype.setFocus = function (oFocus, bIsClickOrEnter) {
1277
+ // Check if the focused item has been destroyed and clear it
1278
+ if (oFocus && oFocus.item && (oFocus.item.bIsDestroyed || oFocus.item.isDestroyed?.())) {
1279
+ Log.info("NetworkGraph: Cannot set focus on destroyed control, clearing focus");
1280
+ this._oFocus = null;
1281
+ return;
1282
+ }
1283
+
874
1284
  // Identity redundant
875
1285
  if (!oFocus && !this._oFocus ||
876
1286
  oFocus && this._oFocus && oFocus.item === this._oFocus.item && oFocus.button === this._oFocus.button && oFocus.groupInFocused === this._oFocus.groupInFocused) {
@@ -880,12 +1290,12 @@ sap.ui.define([
880
1290
  this._oFocus.item.isA("sap.suite.ui.commons.networkgraph.Node")))) {
881
1291
  this._updateAccessibility(oFocus);
882
1292
  }
883
- this._updateAccessibility(oFocus);
884
- return;
1293
+ this._updateAccessibility(oFocus);
1294
+ return;
885
1295
  }
886
1296
 
887
1297
  this.defocus();
888
- if (this.getFocusDomRef()) {
1298
+ if (this.getFocusDomRef() && !(oFocus && oFocus.button && oFocus.button.id && oFocus.button.id.indexOf("actionOverflow") !== -1)) {
889
1299
  this.getFocusDomRef().focus();
890
1300
  }
891
1301
 
@@ -925,7 +1335,7 @@ sap.ui.define([
925
1335
  this._setAccessibilityTitle(oResourceBundle.getText("NETWORK_GRAPH_ACCESSIBILITY_CONTENT"));
926
1336
  }.bind(this),
927
1337
  fnBuildTitleForButton = function (sLabel) {
928
- var sTitleLabel = sLabel + " " + oResourceBundle.getText("NETWORK_GRAPH_ACCESSIBILITY_ACTION_BUTTON") ;
1338
+ var sTitleLabel = sLabel + " " + oResourceBundle.getText("NETWORK_GRAPH_ACCESSIBILITY_ACTION_BUTTON");
929
1339
  if (sLabel === "Expand/Collapse") {
930
1340
  if (oFocus.item.getCollapsed()) {
931
1341
  sTitleLabel = sTitleLabel + " " + oResourceBundle.getText("NETWORK_GRAPH_COLLAPSED");
@@ -1029,6 +1439,14 @@ sap.ui.define([
1029
1439
  return this.getNodes().concat(this.getGroups());
1030
1440
  };
1031
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
+
1032
1450
  Graph.prototype._render = function () {
1033
1451
  this._beforeRender();
1034
1452
 
@@ -1057,8 +1475,9 @@ sap.ui.define([
1057
1475
  this.$background.width(iSvgWidth * this._fZoomLevel);
1058
1476
  this.$background.height(iSvgHeight * this._fZoomLevel);
1059
1477
 
1478
+ var sScale = "";
1060
1479
  if (this._isUseNodeHtml()) {
1061
- var sScale = "scale(" + this._fZoomLevel + ")";
1480
+ sScale = "scale(" + this._fZoomLevel + ")";
1062
1481
  this.$("divnodes").css("transform", sScale);
1063
1482
  }
1064
1483
 
@@ -1076,12 +1495,25 @@ sap.ui.define([
1076
1495
 
1077
1496
  // While Expand/Collapse, focus will still remain to the button
1078
1497
  if (this._oFocus && this._oFocus.button === Group.BUTTONS.COLLAPSE) {
1079
- this._oFocus.item._setCollapseButtonFocus(true);
1498
+ // Check if the focused item still exists and is not destroyed
1499
+ if (this._oFocus.item && !this._oFocus.item.bIsDestroyed && !this._oFocus.item.isDestroyed?.()) {
1500
+ this._oFocus.item._setCollapseButtonFocus(true);
1501
+ } else {
1502
+ Log.info("NetworkGraph: Focused item was destroyed, clearing focus");
1503
+ this._oFocus = null;
1504
+ }
1080
1505
  }
1081
1506
  this._bIsLayedOut = true;
1082
1507
  this._setupEvents();
1083
1508
  this._setupKeyboardNavigation();
1084
- this.setFocus(this.getFocus());
1509
+ // Only restore focus if the focused item still exists and is not destroyed
1510
+ var oCurrentFocus = this.getFocus();
1511
+ if (oCurrentFocus && oCurrentFocus.item && (oCurrentFocus.item.bIsDestroyed || oCurrentFocus.item.isDestroyed?.())) {
1512
+ Log.info("NetworkGraph: Cannot restore focus on destroyed control, clearing focus");
1513
+ this._oFocus = null;
1514
+ } else {
1515
+ this.setFocus(oCurrentFocus);
1516
+ }
1085
1517
 
1086
1518
  // when there is background image, busy is set false after image is loaded (own event)
1087
1519
  // in case image was already loaded continue as usual
@@ -1092,6 +1524,10 @@ sap.ui.define([
1092
1524
 
1093
1525
  if (!this._isSwimLane() && !this._isTwoColumnsLayout()) {
1094
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
+ }
1095
1531
  }
1096
1532
  };
1097
1533
 
@@ -1315,6 +1751,8 @@ sap.ui.define([
1315
1751
  oRm.openStart("g", this.getId() + "-svgbody");
1316
1752
  oRm.openEnd();
1317
1753
  fnRenderItems("lines", aLines, "sapSuiteUiCommonsNetworkLines");
1754
+ // Render line texts after all lines are rendered to handle overlaps
1755
+ this._renderAllLineTexts(aLines, oRm);
1318
1756
  if (!this._isUseNodeHtml()) {
1319
1757
  fnRenderItems("nodes", aNodes, "sapSuiteUiCommonsNetworkNodes");
1320
1758
  }
@@ -1339,6 +1777,45 @@ sap.ui.define([
1339
1777
 
1340
1778
  };
1341
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
+
1342
1819
  Graph.prototype._isProperKey = function (sKey) {
1343
1820
  return sKey || (sKey === "0");
1344
1821
  };
@@ -1419,7 +1896,11 @@ sap.ui.define([
1419
1896
  }
1420
1897
  }
1421
1898
 
1422
- this._isUseNodeHtml() ? oNode._resetDimensions() : oNode._setupWidthAndHeight();
1899
+ if (this._isUseNodeHtml()) {
1900
+ oNode._resetDimensions();
1901
+ } else {
1902
+ oNode._setupWidthAndHeight();
1903
+ }
1423
1904
  oNode._clearChildren();
1424
1905
  oNode._rendered = false;
1425
1906
 
@@ -1848,16 +2329,24 @@ sap.ui.define([
1848
2329
  }
1849
2330
  });
1850
2331
  this._toolbar.addContent(this._zoomOut);
1851
- }
2332
+ }
1852
2333
 
1853
2334
  // fit to viewport
1854
- this._toolbar.addContent(new OverflowToolbarButton({
2335
+ this._zoomToFitButton = new OverflowToolbarButton({
1855
2336
  type: ButtonType.Transparent,
1856
2337
  icon: "sap-icon://popup-window",
1857
2338
  tooltip: oResourceBundle.getText("NETWORK_GRAPH_ZOOMTOFIT"),
1858
2339
  text: oResourceBundle.getText("NETWORK_GRAPH_ZOOMTOFIT"),
1859
2340
  press: this._fitToScreen.bind(this)
1860
- }));
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
+ }
1861
2350
 
1862
2351
  // toggle full screen
1863
2352
  this._oFullScreenButton = new OverflowToolbarButton({
@@ -2139,7 +2628,9 @@ sap.ui.define([
2139
2628
 
2140
2629
  $wrapper.on("mouseleave", this._endDragging.bind(this));
2141
2630
  $wrapper.on("mouseup", this._mouseUp.bind(this));
2142
- 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.
2143
2634
  $wrapper.on("wheel", function (oEvent) {
2144
2635
  if (this._wheel({
2145
2636
  x: oEvent.originalEvent.clientX,
@@ -2197,6 +2688,7 @@ sap.ui.define([
2197
2688
  this._oZoomLevelInvisibleText.setText(oResourceBundle.getText("NETWORK_GRAPH_ZOOM_LEVEL") + ": " + this._getZoomText());
2198
2689
  return true;
2199
2690
  }
2691
+ return false;
2200
2692
  };
2201
2693
 
2202
2694
  Graph.prototype._endDragging = function () {
@@ -2229,6 +2721,11 @@ sap.ui.define([
2229
2721
  this._oPanning.dragging = true;
2230
2722
 
2231
2723
  this._tooltip.instantClose();
2724
+
2725
+ // Remove all ports when deselecting
2726
+ if (PortManager._currentTriggerNodeKey !== null) {
2727
+ PortManager.removeAllPorts();
2728
+ }
2232
2729
  };
2233
2730
 
2234
2731
  Graph.prototype._mouseUp = function () {
@@ -2377,6 +2874,11 @@ sap.ui.define([
2377
2874
  // indicates current count of suggestion items when they are rendered
2378
2875
  this._oSuggestionItemsModel.setSizeLimit(SUGGESTION_ITEMS_LIMIT);
2379
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
+
2380
2882
  aNodes.forEach(function (oNode) {
2381
2883
  var sTitle = Utils.trimText(oNode.getTitle(), TITLE_LENGTH);
2382
2884
  oData.items.push({
@@ -2384,7 +2886,7 @@ sap.ui.define([
2384
2886
  type: SUGGESTIONS.Node,
2385
2887
  icon: oNode.getIcon(),
2386
2888
  key: oNode.getKey(),
2387
- description: "(" + oResourceBundle.getText("NETWORK_GRAPH_NODE") + ")"
2889
+ description: "(" + sNodeLabel + ")"
2388
2890
  });
2389
2891
  });
2390
2892
 
@@ -2397,7 +2899,7 @@ sap.ui.define([
2397
2899
  text: oLine._createSuggestionHelpText(),
2398
2900
  type: SUGGESTIONS.Line,
2399
2901
  key: oLine._getLineId(),
2400
- description: "(" + oResourceBundle.getText("NETWORK_GRAPH_LINE") + ")"
2902
+ description: "(" + sLineLabel + ")"
2401
2903
  });
2402
2904
  }
2403
2905
  });
@@ -2409,7 +2911,7 @@ sap.ui.define([
2409
2911
  text: sTitle ? sTitle : oGroup.getKey(),
2410
2912
  key: oGroup.getKey(),
2411
2913
  type: SUGGESTIONS.Group,
2412
- description: "(" + oResourceBundle.getText("NETWORK_GRAPH_GROUP") + ")"
2914
+ description: "(" + sGroupLabel + ")"
2413
2915
  });
2414
2916
  }
2415
2917
  });
@@ -2453,7 +2955,13 @@ sap.ui.define([
2453
2955
  fHeight = oItem._iHeight;
2454
2956
  }
2455
2957
 
2456
- 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
+ }
2457
2965
  this.$scroller.get(0).scrollTop = ((fY + (fHeight ? fHeight : 0) / 2) * this._fZoomLevel) - (this.$scroller.height() / 2);
2458
2966
  };
2459
2967
 
@@ -2474,6 +2982,14 @@ sap.ui.define([
2474
2982
  iRight = iLeft + this.$scroller.width() / this._fZoomLevel,
2475
2983
  iBottom = iTop + this.$scroller.height() / this._fZoomLevel;
2476
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
+
2477
2993
  if (!oItem._isOnScreen(iLeft, iRight, iTop, iBottom)) {
2478
2994
  if (oItem instanceof Node) {
2479
2995
  iCenterX = oItem.getX() + oItem._iWidth / 2;
@@ -2488,7 +3004,14 @@ sap.ui.define([
2488
3004
  }
2489
3005
 
2490
3006
  if (iCenterX < iLeft || iCenterX > iRight) {
2491
- 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;
2492
3015
  }
2493
3016
  if (iCenterY < iTop || iCenterY > iBottom) {
2494
3017
  oScroller.scrollTop = iCenterY * this._fZoomLevel - this.$scroller.height() / 2;
@@ -2553,7 +3076,7 @@ sap.ui.define([
2553
3076
  if (fnHasStatus(oCollection)) {
2554
3077
  oRm.openStart("div").class(sClass).openEnd();
2555
3078
  oRm.openStart("label").class("sapSuiteUiCommonsNetworkGraphLegendTitle").openEnd();
2556
- oRm.text(oResourceBundle.getText(sTitle));
3079
+ oRm.text(sTitle);
2557
3080
  oRm.close("label");
2558
3081
  oRm.close("div");
2559
3082
  // get the status labels for sorting (some statuses can have custom labels)
@@ -2588,12 +3111,13 @@ sap.ui.define([
2588
3111
  return;
2589
3112
  }
2590
3113
 
3114
+ const oLabels = this.getLabels() || {};
2591
3115
  fnProcessElements(this.getNodes(), oNodeStatuses, "sapSuiteUiCommonsNetworkGraphLegendTitleNode",
2592
- "NETWORK_GRAPH_NODES", StatusType.Node);
3116
+ oLabels.nodeLabelPlural || oResourceBundle.getText("NETWORK_GRAPH_NODES"), StatusType.Node);
2593
3117
  fnProcessElements(this.getLines(), oLineStatuses, "sapSuiteUiCommonsNetworkGraphLegendTitleLine",
2594
- "NETWORK_GRAPH_LINES", StatusType.Line);
3118
+ oLabels.lineLabelPlural || oResourceBundle.getText("NETWORK_GRAPH_LINES"), StatusType.Line);
2595
3119
  fnProcessElements(this.getGroups(), oGroupStatuses, "sapSuiteUiCommonsNetworkGraphLegendTitleLine",
2596
- "NETWORK_GRAPH_GROUPS", StatusType.Group);
3120
+ oLabels.groupLabelPlural || oResourceBundle.getText("NETWORK_GRAPH_GROUPS"), StatusType.Group);
2597
3121
  oRm.flush($legend[0]);
2598
3122
  oRm.destroy();
2599
3123
  // $legend.html(sHtml);
@@ -2753,8 +3277,15 @@ sap.ui.define([
2753
3277
  };
2754
3278
 
2755
3279
  Graph.prototype._isTopBottom = function () {
2756
- return this.getOrientation() === Orientation.TopBottom ||
2757
- 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;
2758
3289
  };
2759
3290
 
2760
3291
  /* =========================================================== */
@@ -2896,5 +3427,16 @@ sap.ui.define([
2896
3427
  }
2897
3428
  };
2898
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
+
2899
3441
  return Graph;
2900
3442
  });