@sapui5/sap.suite.ui.commons 1.145.1 → 1.147.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.
- package/package.json +1 -1
- package/src/sap/suite/ui/commons/.library +1 -1
- package/src/sap/suite/ui/commons/AriaProperties.js +1 -1
- package/src/sap/suite/ui/commons/CalculationBuilder.js +83 -4
- package/src/sap/suite/ui/commons/CalculationBuilderExpression.js +87 -14
- package/src/sap/suite/ui/commons/CalculationBuilderFunction.js +1 -1
- package/src/sap/suite/ui/commons/CalculationBuilderGroup.js +1 -1
- package/src/sap/suite/ui/commons/CalculationBuilderInput.js +11 -0
- package/src/sap/suite/ui/commons/CalculationBuilderItem.js +16 -3
- package/src/sap/suite/ui/commons/CalculationBuilderValidationResult.js +1 -1
- package/src/sap/suite/ui/commons/CalculationBuilderVariable.js +1 -1
- package/src/sap/suite/ui/commons/CloudFilePicker.js +1 -1
- package/src/sap/suite/ui/commons/ControlProxy.js +7 -4
- package/src/sap/suite/ui/commons/MicroProcessFlow.js +1 -1
- package/src/sap/suite/ui/commons/MicroProcessFlowItem.js +1 -1
- package/src/sap/suite/ui/commons/ProcessFlowRenderer.js +3 -0
- package/src/sap/suite/ui/commons/collaboration/ContactHelper.js +5 -1
- package/src/sap/suite/ui/commons/collaboration/ContactPopover.fragment.xml +10 -10
- package/src/sap/suite/ui/commons/collaboration/MinimalContactPopover.fragment.xml +12 -10
- package/src/sap/suite/ui/commons/collaboration/ServiceContainer.js +12 -2
- package/src/sap/suite/ui/commons/flexibility/changeHandler/PropertyChangeMapper.js +1 -1
- package/src/sap/suite/ui/commons/imageeditor/CropCustomShapeHistoryItem.js +1 -1
- package/src/sap/suite/ui/commons/imageeditor/CropEllipseHistoryItem.js +1 -1
- package/src/sap/suite/ui/commons/imageeditor/CropRectangleHistoryItem.js +1 -1
- package/src/sap/suite/ui/commons/imageeditor/CustomSizeItem.js +1 -1
- package/src/sap/suite/ui/commons/imageeditor/FilterHistoryItem.js +1 -1
- package/src/sap/suite/ui/commons/imageeditor/FlipHistoryItem.js +1 -1
- package/src/sap/suite/ui/commons/imageeditor/HistoryItem.js +1 -1
- package/src/sap/suite/ui/commons/imageeditor/ImageEditor.js +1 -1
- package/src/sap/suite/ui/commons/imageeditor/ImageEditorContainer.js +1 -1
- package/src/sap/suite/ui/commons/imageeditor/ImageEditorResponsiveContainer.js +9 -6
- package/src/sap/suite/ui/commons/imageeditor/ResizeHistoryItem.js +1 -1
- package/src/sap/suite/ui/commons/imageeditor/RotateHistoryItem.js +1 -1
- package/src/sap/suite/ui/commons/library.js +4 -4
- package/src/sap/suite/ui/commons/messagebundle.properties +16 -8
- package/src/sap/suite/ui/commons/messagebundle_ar.properties +11 -5
- package/src/sap/suite/ui/commons/messagebundle_bg.properties +11 -5
- package/src/sap/suite/ui/commons/messagebundle_ca.properties +10 -4
- package/src/sap/suite/ui/commons/messagebundle_cnr.properties +11 -5
- package/src/sap/suite/ui/commons/messagebundle_cs.properties +7 -1
- package/src/sap/suite/ui/commons/messagebundle_cy.properties +11 -5
- package/src/sap/suite/ui/commons/messagebundle_da.properties +10 -4
- package/src/sap/suite/ui/commons/messagebundle_de.properties +8 -2
- package/src/sap/suite/ui/commons/messagebundle_el.properties +11 -5
- package/src/sap/suite/ui/commons/messagebundle_en.properties +11 -5
- package/src/sap/suite/ui/commons/messagebundle_en_GB.properties +11 -5
- package/src/sap/suite/ui/commons/messagebundle_en_US_saprigi.properties +9 -5
- package/src/sap/suite/ui/commons/messagebundle_es.properties +11 -5
- package/src/sap/suite/ui/commons/messagebundle_es_MX.properties +10 -4
- package/src/sap/suite/ui/commons/messagebundle_et.properties +6 -0
- package/src/sap/suite/ui/commons/messagebundle_fi.properties +10 -4
- package/src/sap/suite/ui/commons/messagebundle_fr.properties +11 -5
- package/src/sap/suite/ui/commons/messagebundle_fr_CA.properties +11 -5
- package/src/sap/suite/ui/commons/messagebundle_hi.properties +11 -5
- package/src/sap/suite/ui/commons/messagebundle_hr.properties +10 -4
- package/src/sap/suite/ui/commons/messagebundle_hu.properties +9 -3
- package/src/sap/suite/ui/commons/messagebundle_id.properties +12 -6
- package/src/sap/suite/ui/commons/messagebundle_it.properties +11 -5
- package/src/sap/suite/ui/commons/messagebundle_iw.properties +11 -5
- package/src/sap/suite/ui/commons/messagebundle_ja.properties +9 -3
- package/src/sap/suite/ui/commons/messagebundle_kk.properties +10 -4
- package/src/sap/suite/ui/commons/messagebundle_ko.properties +10 -4
- package/src/sap/suite/ui/commons/messagebundle_lt.properties +11 -5
- package/src/sap/suite/ui/commons/messagebundle_lv.properties +11 -5
- package/src/sap/suite/ui/commons/messagebundle_mk.properties +9 -3
- package/src/sap/suite/ui/commons/messagebundle_ms.properties +11 -5
- package/src/sap/suite/ui/commons/messagebundle_nl.properties +8 -2
- package/src/sap/suite/ui/commons/messagebundle_no.properties +10 -4
- package/src/sap/suite/ui/commons/messagebundle_pl.properties +11 -5
- package/src/sap/suite/ui/commons/messagebundle_pt.properties +11 -5
- package/src/sap/suite/ui/commons/messagebundle_pt_PT.properties +11 -5
- package/src/sap/suite/ui/commons/messagebundle_ro.properties +11 -5
- package/src/sap/suite/ui/commons/messagebundle_ru.properties +12 -6
- package/src/sap/suite/ui/commons/messagebundle_sh.properties +11 -5
- package/src/sap/suite/ui/commons/messagebundle_sk.properties +10 -4
- package/src/sap/suite/ui/commons/messagebundle_sl.properties +10 -4
- package/src/sap/suite/ui/commons/messagebundle_sr.properties +11 -5
- package/src/sap/suite/ui/commons/messagebundle_sv.properties +10 -4
- package/src/sap/suite/ui/commons/messagebundle_th.properties +11 -5
- package/src/sap/suite/ui/commons/messagebundle_tr.properties +8 -2
- package/src/sap/suite/ui/commons/messagebundle_uk.properties +14 -8
- package/src/sap/suite/ui/commons/messagebundle_vi.properties +11 -5
- package/src/sap/suite/ui/commons/messagebundle_zh_CN.properties +11 -5
- package/src/sap/suite/ui/commons/messagebundle_zh_TW.properties +11 -5
- package/src/sap/suite/ui/commons/networkgraph/Graph.js +149 -40
- package/src/sap/suite/ui/commons/networkgraph/GraphMap.js +25 -3
- package/src/sap/suite/ui/commons/networkgraph/KeyboardNavigator.js +332 -13
- package/src/sap/suite/ui/commons/networkgraph/Line.js +110 -12
- package/src/sap/suite/ui/commons/networkgraph/Node.js +67 -5
- package/src/sap/suite/ui/commons/networkgraph/Utils.js +249 -10
- package/src/sap/suite/ui/commons/networkgraph/layout/NoopLayout.js +55 -8
- package/src/sap/suite/ui/commons/networkgraph/util/ConnectionPathUtils.js +34 -4
- package/src/sap/suite/ui/commons/networkgraph/util/DependencyLayoutHelper.js +230 -82
- package/src/sap/suite/ui/commons/networkgraph/util/DragDropManager.js +52 -50
- package/src/sap/suite/ui/commons/networkgraph/util/PortManager.js +12 -3
- package/src/sap/suite/ui/commons/statusindicator/Circle.js +1 -1
- package/src/sap/suite/ui/commons/statusindicator/CustomShape.js +1 -1
- package/src/sap/suite/ui/commons/statusindicator/DiscreteThreshold.js +1 -1
- package/src/sap/suite/ui/commons/statusindicator/FillingOption.js +1 -1
- package/src/sap/suite/ui/commons/statusindicator/LibraryShape.js +1 -1
- package/src/sap/suite/ui/commons/statusindicator/Path.js +1 -1
- package/src/sap/suite/ui/commons/statusindicator/PropertyThreshold.js +1 -1
- package/src/sap/suite/ui/commons/statusindicator/Rectangle.js +1 -1
- package/src/sap/suite/ui/commons/statusindicator/Shape.js +1 -1
- package/src/sap/suite/ui/commons/statusindicator/ShapeGroup.js +1 -1
- package/src/sap/suite/ui/commons/statusindicator/SimpleShape.js +1 -1
- package/src/sap/suite/ui/commons/statusindicator/StatusIndicator.js +1 -1
- package/src/sap/suite/ui/commons/taccount/TAccount.js +1 -1
- package/src/sap/suite/ui/commons/taccount/TAccountGroup.js +1 -1
- package/src/sap/suite/ui/commons/taccount/TAccountItem.js +1 -1
- package/src/sap/suite/ui/commons/taccount/TAccountItemProperty.js +1 -1
- package/src/sap/suite/ui/commons/taccount/TAccountPanel.js +1 -1
- package/src/sap/suite/ui/commons/themes/base/BusinessCard.less +5 -4
- package/src/sap/suite/ui/commons/themes/base/CalculationBuilder.less +33 -24
- package/src/sap/suite/ui/commons/themes/base/CalculationBuilderExpression.less +40 -31
- package/src/sap/suite/ui/commons/themes/base/CalculationBuilderInput.less +26 -10
- package/src/sap/suite/ui/commons/themes/base/CalculationBuilderItem.less +76 -63
- package/src/sap/suite/ui/commons/themes/base/ChartContainer.less +8 -11
- package/src/sap/suite/ui/commons/themes/base/ChartTile.less +5 -8
- package/src/sap/suite/ui/commons/themes/base/CollaborationPopover.less +116 -106
- package/src/sap/suite/ui/commons/themes/base/DateRangeScroller.less +5 -5
- package/src/sap/suite/ui/commons/themes/base/DateRangeSliderInternal.less +9 -10
- package/src/sap/suite/ui/commons/themes/base/FacetOverview.less +9 -10
- package/src/sap/suite/ui/commons/themes/base/FeedItemHeader.less +9 -12
- package/src/sap/suite/ui/commons/themes/base/FeedTile.less +23 -27
- package/src/sap/suite/ui/commons/themes/base/GenericTile2X2.less +15 -15
- package/src/sap/suite/ui/commons/themes/base/HeaderCell.less +7 -6
- package/src/sap/suite/ui/commons/themes/base/HeaderContainer.less +35 -37
- package/src/sap/suite/ui/commons/themes/base/ImageEditor.less +28 -10
- package/src/sap/suite/ui/commons/themes/base/ImageEditorContainer.less +29 -22
- package/src/sap/suite/ui/commons/themes/base/InfoTile.less +10 -4
- package/src/sap/suite/ui/commons/themes/base/InfoTileSize.less +5 -4
- package/src/sap/suite/ui/commons/themes/base/KpiTile.less +10 -11
- package/src/sap/suite/ui/commons/themes/base/LaunchTile.less +9 -8
- package/src/sap/suite/ui/commons/themes/base/LinkActionSheet.less +14 -43
- package/src/sap/suite/ui/commons/themes/base/MicroProcessFlow.less +51 -47
- package/src/sap/suite/ui/commons/themes/base/MonitoringContent.less +5 -5
- package/src/sap/suite/ui/commons/themes/base/NetworkGraph.less +57 -62
- package/src/sap/suite/ui/commons/themes/base/NetworkGroup.less +61 -65
- package/src/sap/suite/ui/commons/themes/base/NetworkLine.less +58 -55
- package/src/sap/suite/ui/commons/themes/base/NetworkNode.less +3 -0
- package/src/sap/suite/ui/commons/themes/base/NetworkTooltip.less +21 -25
- package/src/sap/suite/ui/commons/themes/base/NoteTaker.less +13 -18
- package/src/sap/suite/ui/commons/themes/base/NoteTakerCard.less +26 -27
- package/src/sap/suite/ui/commons/themes/base/NoteTakerFeeder.less +22 -44
- package/src/sap/suite/ui/commons/themes/base/NumericTile.less +7 -5
- package/src/sap/suite/ui/commons/themes/base/PictureZoomIn.less +6 -5
- package/src/sap/suite/ui/commons/themes/base/ProcessFlow.less +57 -76
- package/src/sap/suite/ui/commons/themes/base/ProcessFlowConnection.less +71 -17
- package/src/sap/suite/ui/commons/themes/base/ProcessFlowConnectionLabel.less +9 -13
- package/src/sap/suite/ui/commons/themes/base/ProcessFlowLaneHeader.less +37 -96
- package/src/sap/suite/ui/commons/themes/base/ProcessFlowNode.less +219 -238
- package/src/sap/suite/ui/commons/themes/base/SemanticColorMixins.less +55 -0
- package/src/sap/suite/ui/commons/themes/base/SplitButton.less +7 -20
- package/src/sap/suite/ui/commons/themes/base/StatusIndicator.less +10 -9
- package/src/sap/suite/ui/commons/themes/base/TAccount.less +78 -73
- package/src/sap/suite/ui/commons/themes/base/TargetFilter.less +50 -58
- package/src/sap/suite/ui/commons/themes/base/ThingCollection.less +18 -13
- package/src/sap/suite/ui/commons/themes/base/ThreePanelThingViewer.less +14 -14
- package/src/sap/suite/ui/commons/themes/base/TileContent2X2.less +9 -13
- package/src/sap/suite/ui/commons/themes/base/Timeline.less +16 -19
- package/src/sap/suite/ui/commons/themes/base/TimelineItem.less +95 -103
- package/src/sap/suite/ui/commons/themes/base/UnifiedThingGroup.less +7 -9
- package/src/sap/suite/ui/commons/themes/base/UnifiedThingInspector.less +12 -9
- package/src/sap/suite/ui/commons/themes/base/VerticalNavigationBar.less +10 -15
- package/src/sap/suite/ui/commons/themes/base/ViewRepeater.less +8 -9
- package/src/sap/suite/ui/commons/themes/base/library.source.less +0 -2
- package/src/sap/suite/ui/commons/themes/sap_fiori_3/MicroProcessFlow.less +9 -3
- package/src/sap/suite/ui/commons/themes/sap_fiori_3/ProcessFlowConnection.less +14 -7
- package/src/sap/suite/ui/commons/themes/sap_fiori_3/ProcessFlowConnectionLabel.less +38 -35
- package/src/sap/suite/ui/commons/themes/sap_fiori_3/ProcessFlowLaneHeader.less +29 -30
- package/src/sap/suite/ui/commons/themes/sap_fiori_3/ProcessFlowNode.less +158 -102
- package/src/sap/suite/ui/commons/themes/sap_fiori_3_dark/MicroProcessFlow.less +9 -3
- package/src/sap/suite/ui/commons/themes/sap_fiori_3_dark/ProcessFlowConnection.less +14 -7
- package/src/sap/suite/ui/commons/themes/sap_fiori_3_dark/ProcessFlowConnectionLabel.less +38 -35
- package/src/sap/suite/ui/commons/themes/sap_fiori_3_dark/ProcessFlowLaneHeader.less +30 -31
- package/src/sap/suite/ui/commons/themes/sap_fiori_3_dark/ProcessFlowNode.less +157 -101
- package/src/sap/suite/ui/commons/themes/sap_fiori_3_hcb/ProcessFlowConnection.less +14 -7
- package/src/sap/suite/ui/commons/themes/sap_fiori_3_hcb/ProcessFlowConnectionLabel.less +38 -35
- package/src/sap/suite/ui/commons/themes/sap_fiori_3_hcb/ProcessFlowLaneHeader.less +30 -31
- package/src/sap/suite/ui/commons/themes/sap_fiori_3_hcb/ProcessFlowNode.less +147 -101
- package/src/sap/suite/ui/commons/themes/sap_fiori_3_hcw/ProcessFlowConnection.less +14 -7
- package/src/sap/suite/ui/commons/themes/sap_fiori_3_hcw/ProcessFlowConnectionLabel.less +38 -35
- package/src/sap/suite/ui/commons/themes/sap_fiori_3_hcw/ProcessFlowLaneHeader.less +30 -31
- package/src/sap/suite/ui/commons/themes/sap_fiori_3_hcw/ProcessFlowNode.less +158 -102
- package/src/sap/suite/ui/commons/themes/sap_horizon/MicroProcessFlow.less +5 -0
- package/src/sap/suite/ui/commons/themes/sap_horizon/NetworkLine.less +12 -8
- package/src/sap/suite/ui/commons/themes/sap_horizon/ProcessFlowConnection.less +17 -10
- package/src/sap/suite/ui/commons/themes/sap_horizon/ProcessFlowConnectionLabel.less +154 -133
- package/src/sap/suite/ui/commons/themes/sap_horizon/ProcessFlowLaneHeader.less +30 -32
- package/src/sap/suite/ui/commons/themes/sap_horizon/ProcessFlowNode.less +113 -214
- package/src/sap/suite/ui/commons/themes/sap_horizon/TimelineItem.less +43 -39
- package/src/sap/suite/ui/commons/themes/sap_horizon_dark/MicroProcessFlow.less +5 -0
- package/src/sap/suite/ui/commons/themes/sap_horizon_dark/NetworkLine.less +12 -12
- package/src/sap/suite/ui/commons/themes/sap_horizon_dark/ProcessFlowConnection.less +17 -10
- package/src/sap/suite/ui/commons/themes/sap_horizon_dark/ProcessFlowConnectionLabel.less +154 -133
- package/src/sap/suite/ui/commons/themes/sap_horizon_dark/ProcessFlowLaneHeader.less +30 -31
- package/src/sap/suite/ui/commons/themes/sap_horizon_dark/ProcessFlowNode.less +114 -216
- package/src/sap/suite/ui/commons/themes/sap_horizon_dark/TimelineItem.less +41 -39
- package/src/sap/suite/ui/commons/themes/sap_horizon_hcb/MicroProcessFlow.less +4 -4
- package/src/sap/suite/ui/commons/themes/sap_horizon_hcb/ProcessFlowConnection.less +17 -10
- package/src/sap/suite/ui/commons/themes/sap_horizon_hcb/ProcessFlowConnectionLabel.less +153 -131
- package/src/sap/suite/ui/commons/themes/sap_horizon_hcb/ProcessFlowLaneHeader.less +29 -30
- package/src/sap/suite/ui/commons/themes/sap_horizon_hcb/ProcessFlowNode.less +159 -103
- package/src/sap/suite/ui/commons/themes/sap_horizon_hcb/TimelineItem.less +41 -39
- package/src/sap/suite/ui/commons/themes/sap_horizon_hcw/MicroProcessFlow.less +4 -4
- package/src/sap/suite/ui/commons/themes/sap_horizon_hcw/ProcessFlowConnection.less +16 -9
- package/src/sap/suite/ui/commons/themes/sap_horizon_hcw/ProcessFlowConnectionLabel.less +153 -131
- package/src/sap/suite/ui/commons/themes/sap_horizon_hcw/ProcessFlowLaneHeader.less +29 -30
- package/src/sap/suite/ui/commons/themes/sap_horizon_hcw/ProcessFlowNode.less +157 -101
- package/src/sap/suite/ui/commons/themes/sap_horizon_hcw/TimelineItem.less +41 -39
- package/src/sap/suite/ui/commons/windowmessages/CollaborationMessageConsumer.js +3 -3
- package/src/sap/suite/ui/commons/themes/base/DateRangeSlider.less +0 -3
- package/src/sap/suite/ui/commons/themes/base/MonitoringTile.less +0 -3
|
@@ -7,16 +7,36 @@
|
|
|
7
7
|
sap.ui.define(["sap/suite/ui/commons/library", "sap/base/Log"], function (library, Log) {
|
|
8
8
|
"use strict";
|
|
9
9
|
|
|
10
|
-
const
|
|
11
|
-
|
|
10
|
+
const oConnectionType = library.networkgraph.ConnectionType,
|
|
11
|
+
oComponentArrangement = library.networkgraph.ComponentArrangement;
|
|
12
12
|
const DEFAULT_HORIZONTAL_SPACING = 240;
|
|
13
13
|
const DEFAULT_VERTICAL_SPACING = 100;
|
|
14
|
+
const DRAG_DETECTION_THRESHOLD = 10;
|
|
14
15
|
|
|
15
16
|
/**
|
|
16
17
|
* Utility class for calculating node positions based on dependency relationships.
|
|
17
18
|
* This utility arranges nodes based on their dependency relationships using topological sorting,
|
|
18
19
|
* cycle detection, and layer-based positioning.
|
|
19
20
|
*
|
|
21
|
+
* Why a node may be positioned incorrectly after recalculation:
|
|
22
|
+
* After each run, node positions are cached with a flag indicating whether the user moved
|
|
23
|
+
* them (<code>bIsUserPositioned</code>). On the next call, nodes flagged as user-positioned
|
|
24
|
+
* are preserved as-is, and the algorithm-placed nodes are recalculated. A node appears in the
|
|
25
|
+
* wrong place if it is unexpectedly treated as user-positioned, most commonly because
|
|
26
|
+
* <code>clearCache: true</code> was passed. It wipes the cache, but leaves the coordinates intact.
|
|
27
|
+
* So every node with non-zero coordinates is immediately re-classified as user-positioned
|
|
28
|
+
* and freezes, rather than being recalculated.
|
|
29
|
+
*
|
|
30
|
+
* Drag and drop recalculation - correct pattern:
|
|
31
|
+
* Call <code>resetNode(oNode)</code> for each dragged node, then call
|
|
32
|
+
* <code>calculatePositions</code> without <code>clearCache</code> (default <code>false</code>).
|
|
33
|
+
* <code>resetNode</code> evicts the node from the cache and zeros its coordinates, so only
|
|
34
|
+
* that node is repositioned; all the other nodes remain stable.
|
|
35
|
+
*
|
|
36
|
+
* Sentinel value:
|
|
37
|
+
* Coordinates <code>(0, 0)</code> mean "unpositioned". To place a node at the canvas origin,
|
|
38
|
+
* use <code>(0.1, 0.1)</code> or <code>(1, 1)</code> instead.
|
|
39
|
+
*
|
|
20
40
|
* @namespace sap.suite.ui.commons.networkgraph.util.DependencyLayoutHelper
|
|
21
41
|
* @public
|
|
22
42
|
* @since 1.144
|
|
@@ -28,16 +48,41 @@ sap.ui.define(["sap/suite/ui/commons/library", "sap/base/Log"], function (librar
|
|
|
28
48
|
*/
|
|
29
49
|
_lastCalculated: new WeakMap(),
|
|
30
50
|
|
|
51
|
+
/**
|
|
52
|
+
* Evicts one or more nodes from the position cache and zeros their coordinates so the next
|
|
53
|
+
* <code>calculatePositions</code> call repositions them while all other nodes remain stable.
|
|
54
|
+
* To understand the use for drag and drop recalculation, see the class-level JSDoc for the full pattern.
|
|
55
|
+
*
|
|
56
|
+
* @param {sap.suite.ui.commons.networkgraph.Node|sap.suite.ui.commons.networkgraph.Node[]} vNode - A single node or an array of nodes to reset
|
|
57
|
+
* @public
|
|
58
|
+
*/
|
|
59
|
+
resetNode: function (vNode) {
|
|
60
|
+
const aNodes = Array.isArray(vNode) ? vNode : [vNode];
|
|
61
|
+
aNodes.forEach((oNode) => {
|
|
62
|
+
if (!oNode || !oNode.setX || !oNode.setY) {
|
|
63
|
+
return;
|
|
64
|
+
}
|
|
65
|
+
this._lastCalculated.delete(oNode);
|
|
66
|
+
oNode.setX(0);
|
|
67
|
+
oNode.setY(0);
|
|
68
|
+
});
|
|
69
|
+
},
|
|
70
|
+
|
|
31
71
|
/**
|
|
32
72
|
* Calculates and sets positions for nodes without coordinates based on their dependency relationships.
|
|
33
73
|
* Uses topological sorting (Kahn's algorithm) and DFS-based cycle detection to arrange nodes
|
|
34
74
|
* in layers from left to right, ensuring no overlaps and minimal line crossings.
|
|
75
|
+
* Note: Drag and drop functionality is only available for nodes. Groups cannot be dragged and dropped, even when NoopLayout is used and enableDragAndDrop is set to true.
|
|
35
76
|
*
|
|
36
|
-
* @param {sap.suite.ui.commons.networkgraph.Graph} oGraph - The
|
|
77
|
+
* @param {sap.suite.ui.commons.networkgraph.Graph} oGraph - The graph instance
|
|
37
78
|
* @param {object} [mConfig] - Configuration object
|
|
38
79
|
* @param {number} [mConfig.horizontalSpacing=240] - Horizontal spacing between layers
|
|
39
80
|
* @param {number} [mConfig.verticalSpacing=100] - Vertical spacing between nodes
|
|
40
81
|
* @param {sap.suite.ui.commons.networkgraph.ComponentArrangement} [mConfig.componentArrangement=Horizontal] - Component arrangement: "Horizontal" or "Vertical"
|
|
82
|
+
* @param {boolean} [mConfig.clearCache=false] - Wipes the position cache; node coordinates are not modified.
|
|
83
|
+
* <code>_detectUserChanges</code> then re-classifies every non-zero node as user-positioned and freezes it.
|
|
84
|
+
* Use only to discard all layout history (e.g. switching <code>componentArrangement</code>).
|
|
85
|
+
* For drag and drop recalculation, use <code>resetNode()</code> with the default <code>clearCache: false</code>.
|
|
41
86
|
* @public
|
|
42
87
|
*/
|
|
43
88
|
calculatePositions: function (oGraph, mConfig) {
|
|
@@ -49,19 +94,29 @@ sap.ui.define(["sap/suite/ui/commons/library", "sap/base/Log"], function (librar
|
|
|
49
94
|
{
|
|
50
95
|
horizontalSpacing: DEFAULT_HORIZONTAL_SPACING,
|
|
51
96
|
verticalSpacing: DEFAULT_VERTICAL_SPACING,
|
|
52
|
-
componentArrangement:
|
|
97
|
+
componentArrangement: oComponentArrangement.Horizontal,
|
|
98
|
+
clearCache: false
|
|
53
99
|
},
|
|
54
100
|
mConfig || {}
|
|
55
101
|
);
|
|
102
|
+
|
|
103
|
+
// Clear cache if requested (e.g., when changing arrangement)
|
|
104
|
+
if (config.clearCache) {
|
|
105
|
+
this._lastCalculated = new WeakMap();
|
|
106
|
+
}
|
|
107
|
+
|
|
56
108
|
try {
|
|
57
|
-
this._detectUserChanges(oGraph);
|
|
109
|
+
this._detectUserChanges(oGraph, config.horizontalSpacing);
|
|
58
110
|
this._buildDependencyGraph(oGraph);
|
|
59
111
|
const aComponents = this._identifyComponents(oGraph);
|
|
60
112
|
this._processComponents(aComponents, config);
|
|
61
113
|
this._calculateCoordinates(oGraph, config);
|
|
62
114
|
this._adjustHorizontalSpacingForNodeWidths(oGraph, config);
|
|
63
115
|
this._adjustVerticalSpacingForNodeHeights(oGraph, config);
|
|
64
|
-
|
|
116
|
+
if (oGraph._bIsRtl) {
|
|
117
|
+
this._horizontalMirror(oGraph, config.horizontalSpacing);
|
|
118
|
+
}
|
|
119
|
+
this._storeFinalPositions(oGraph, config.horizontalSpacing);
|
|
65
120
|
} catch (e) {
|
|
66
121
|
Log.error("DependencyLayoutHelper error: " + e.message, e);
|
|
67
122
|
throw new Error("DependencyLayoutHelper error: " + e.message);
|
|
@@ -87,11 +142,6 @@ sap.ui.define(["sap/suite/ui/commons/library", "sap/base/Log"], function (librar
|
|
|
87
142
|
|
|
88
143
|
aNodes.forEach((oNode) => {
|
|
89
144
|
mNodeMap.set(oNode.getKey(), oNode);
|
|
90
|
-
const fX = oNode.getX();
|
|
91
|
-
const fY = oNode.getY();
|
|
92
|
-
const oLastPos = this._lastCalculated.get(oNode);
|
|
93
|
-
// Only preserve coordinates if they were original or user-dragged
|
|
94
|
-
const bShouldPreserve = oLastPos?.bIsUserPositioned;
|
|
95
145
|
|
|
96
146
|
oNode._layoutData = {
|
|
97
147
|
layer: -1,
|
|
@@ -101,10 +151,7 @@ sap.ui.define(["sap/suite/ui/commons/library", "sap/base/Log"], function (librar
|
|
|
101
151
|
parallelNodes: [],
|
|
102
152
|
backwardEdges: [],
|
|
103
153
|
backwardEdgeLines: [],
|
|
104
|
-
isBackwardSource: false
|
|
105
|
-
bShouldPreserve,
|
|
106
|
-
userX: fX,
|
|
107
|
-
userY: fY
|
|
154
|
+
isBackwardSource: false
|
|
108
155
|
};
|
|
109
156
|
});
|
|
110
157
|
|
|
@@ -129,13 +176,13 @@ sap.ui.define(["sap/suite/ui/commons/library", "sap/base/Log"], function (librar
|
|
|
129
176
|
this._lineMap.get(sFromKey).set(sToKey, oLine);
|
|
130
177
|
|
|
131
178
|
switch (sConnectionType) {
|
|
132
|
-
case
|
|
133
|
-
case
|
|
179
|
+
case oConnectionType.RightToRight:
|
|
180
|
+
case oConnectionType.LeftToLeft:
|
|
134
181
|
oFromNode._layoutData.parallelNodes.push(oToNode);
|
|
135
182
|
oToNode._layoutData.parallelNodes.push(oFromNode);
|
|
136
183
|
break;
|
|
137
|
-
case
|
|
138
|
-
case
|
|
184
|
+
case oConnectionType.RightToLeft:
|
|
185
|
+
case oConnectionType.LeftToRight:
|
|
139
186
|
default:
|
|
140
187
|
oFromNode._layoutData.outgoing.push(oToNode);
|
|
141
188
|
oToNode._layoutData.incoming.push(oFromNode);
|
|
@@ -270,8 +317,7 @@ sap.ui.define(["sap/suite/ui/commons/library", "sap/base/Log"], function (librar
|
|
|
270
317
|
const bIsIsolated =
|
|
271
318
|
aComponentNodes.length === 1 &&
|
|
272
319
|
aComponentNodes[0]._layoutData.incoming.length === 0 &&
|
|
273
|
-
aComponentNodes[0]._layoutData.outgoing.length === 0
|
|
274
|
-
!aComponentNodes[0]._layoutData.bShouldPreserve;
|
|
320
|
+
aComponentNodes[0]._layoutData.outgoing.length === 0;
|
|
275
321
|
|
|
276
322
|
if (bIsIsolated) {
|
|
277
323
|
aIsolatedNodes.push(aComponentNodes[0]);
|
|
@@ -279,7 +325,7 @@ sap.ui.define(["sap/suite/ui/commons/library", "sap/base/Log"], function (librar
|
|
|
279
325
|
aConnectedComponents.push(aComponentNodes);
|
|
280
326
|
}
|
|
281
327
|
});
|
|
282
|
-
const bSideBySide = componentArrangement !==
|
|
328
|
+
const bSideBySide = componentArrangement !== oComponentArrangement.Vertical;
|
|
283
329
|
let iMaxVerticalPosition = 0;
|
|
284
330
|
let iMaxLayerAcrossAll = 0;
|
|
285
331
|
|
|
@@ -326,18 +372,17 @@ sap.ui.define(["sap/suite/ui/commons/library", "sap/base/Log"], function (librar
|
|
|
326
372
|
});
|
|
327
373
|
|
|
328
374
|
if (aIsolatedNodes.length > 0) {
|
|
329
|
-
const iRightSideOffset = iMaxLayerAcrossAll + 1;
|
|
330
|
-
|
|
331
|
-
aIsolatedNodes.forEach((oNode
|
|
332
|
-
if (
|
|
333
|
-
|
|
334
|
-
oNode._layoutData.position = idx % 2;
|
|
335
|
-
oNode._layoutData.componentOffset = iMaxLayerAcrossAll;
|
|
336
|
-
} else {
|
|
337
|
-
oNode._layoutData.layer = idx % 2;
|
|
338
|
-
oNode._layoutData.position = Math.floor(idx / 2);
|
|
339
|
-
oNode._layoutData.componentOffset = iRightSideOffset;
|
|
375
|
+
const iRightSideOffset = bSideBySide ? iMaxLayerAcrossAll : iMaxLayerAcrossAll + 1;
|
|
376
|
+
let iIsolatedIdx = 0;
|
|
377
|
+
aIsolatedNodes.forEach((oNode) => {
|
|
378
|
+
if (this._lastCalculated.get(oNode)?.bIsUserPositioned) {
|
|
379
|
+
return;
|
|
340
380
|
}
|
|
381
|
+
const idx = iIsolatedIdx++;
|
|
382
|
+
|
|
383
|
+
oNode._layoutData.layer = Math.floor(idx / 2);
|
|
384
|
+
oNode._layoutData.position = idx % 2;
|
|
385
|
+
oNode._layoutData.componentOffset = iRightSideOffset;
|
|
341
386
|
});
|
|
342
387
|
}
|
|
343
388
|
},
|
|
@@ -702,10 +747,10 @@ sap.ui.define(["sap/suite/ui/commons/library", "sap/base/Log"], function (librar
|
|
|
702
747
|
});
|
|
703
748
|
|
|
704
749
|
aNodes.forEach((oNode) => {
|
|
705
|
-
|
|
706
|
-
|
|
707
|
-
oNode.setX(
|
|
708
|
-
oNode.setY(
|
|
750
|
+
const oLastPos = this._lastCalculated.get(oNode);
|
|
751
|
+
if (oLastPos?.bIsUserPositioned) {
|
|
752
|
+
oNode.setX(oLastPos.x);
|
|
753
|
+
oNode.setY(oLastPos.y);
|
|
709
754
|
}
|
|
710
755
|
});
|
|
711
756
|
},
|
|
@@ -722,16 +767,16 @@ sap.ui.define(["sap/suite/ui/commons/library", "sap/base/Log"], function (librar
|
|
|
722
767
|
let iMaxLayer = -1;
|
|
723
768
|
|
|
724
769
|
aNodes.forEach((oNode) => {
|
|
725
|
-
|
|
726
|
-
|
|
727
|
-
|
|
728
|
-
|
|
729
|
-
|
|
730
|
-
|
|
731
|
-
|
|
732
|
-
|
|
733
|
-
|
|
734
|
-
|
|
770
|
+
const iLayer =
|
|
771
|
+
oNode._layoutData.layer + (oNode._layoutData.componentOffset || 0);
|
|
772
|
+
// Skip nodes with unassigned layout
|
|
773
|
+
if (iLayer < 0) return;
|
|
774
|
+
iMaxLayer = Math.max(iMaxLayer, iLayer);
|
|
775
|
+
|
|
776
|
+
if (oNode._iWidth) {
|
|
777
|
+
const iWidth = oNode._iWidth;
|
|
778
|
+
if (!mLayerWidths[iLayer] || mLayerWidths[iLayer] < iWidth) {
|
|
779
|
+
mLayerWidths[iLayer] = iWidth;
|
|
735
780
|
}
|
|
736
781
|
}
|
|
737
782
|
});
|
|
@@ -748,7 +793,7 @@ sap.ui.define(["sap/suite/ui/commons/library", "sap/base/Log"], function (librar
|
|
|
748
793
|
}
|
|
749
794
|
|
|
750
795
|
aNodes.forEach((oNode) => {
|
|
751
|
-
if (!
|
|
796
|
+
if (!this._lastCalculated.get(oNode)?.bIsUserPositioned) {
|
|
752
797
|
const iLayer =
|
|
753
798
|
oNode._layoutData.layer + (oNode._layoutData.componentOffset || 0);
|
|
754
799
|
const iOffset = mLayerOffsets[iLayer] || 0;
|
|
@@ -769,18 +814,18 @@ sap.ui.define(["sap/suite/ui/commons/library", "sap/base/Log"], function (librar
|
|
|
769
814
|
const mAllPositions = {};
|
|
770
815
|
|
|
771
816
|
aNodes.forEach((oNode) => {
|
|
772
|
-
|
|
773
|
-
|
|
774
|
-
|
|
817
|
+
const iPosition = oNode._layoutData.position;
|
|
818
|
+
// Skip nodes with unassigned layout
|
|
819
|
+
if (iPosition < 0) return;
|
|
820
|
+
mAllPositions[iPosition] = true;
|
|
775
821
|
|
|
776
|
-
|
|
777
|
-
|
|
778
|
-
|
|
779
|
-
|
|
780
|
-
|
|
781
|
-
|
|
782
|
-
|
|
783
|
-
}
|
|
822
|
+
if (oNode._iHeight) {
|
|
823
|
+
const iHeight = oNode._iHeight;
|
|
824
|
+
if (
|
|
825
|
+
!mPositionHeights[iPosition] ||
|
|
826
|
+
mPositionHeights[iPosition] < iHeight
|
|
827
|
+
) {
|
|
828
|
+
mPositionHeights[iPosition] = iHeight;
|
|
784
829
|
}
|
|
785
830
|
}
|
|
786
831
|
});
|
|
@@ -800,7 +845,7 @@ sap.ui.define(["sap/suite/ui/commons/library", "sap/base/Log"], function (librar
|
|
|
800
845
|
});
|
|
801
846
|
|
|
802
847
|
aNodes.forEach((oNode) => {
|
|
803
|
-
if (!
|
|
848
|
+
if (!this._lastCalculated.get(oNode)?.bIsUserPositioned) {
|
|
804
849
|
const iPosition = oNode._layoutData.position;
|
|
805
850
|
const iOffset = mPositionOffsets[iPosition] || 0;
|
|
806
851
|
oNode.setY(oNode.getY() + iOffset);
|
|
@@ -813,19 +858,38 @@ sap.ui.define(["sap/suite/ui/commons/library", "sap/base/Log"], function (librar
|
|
|
813
858
|
* Only stores positions for nodes that were calculated (not original/dragged).
|
|
814
859
|
*
|
|
815
860
|
* @param {sap.suite.ui.commons.networkgraph.Graph} oGraph - The network graph instance
|
|
861
|
+
* @param {number} iHSpacing - Horizontal spacing used as RTL mirror offset
|
|
816
862
|
* @private
|
|
817
863
|
*/
|
|
818
|
-
_storeFinalPositions: function (oGraph) {
|
|
864
|
+
_storeFinalPositions: function (oGraph, iHSpacing) {
|
|
819
865
|
const aNodes = oGraph.getNodes();
|
|
866
|
+
const bIsRtl = oGraph._bIsRtl || false;
|
|
867
|
+
|
|
868
|
+
// Reuse fMaxX from _horizontalMirror to ensure consistent mirror/unmirror
|
|
869
|
+
let fMaxX = 0;
|
|
870
|
+
if (bIsRtl) {
|
|
871
|
+
fMaxX = oGraph._rtlMirrorMaxX || 0;
|
|
872
|
+
}
|
|
820
873
|
|
|
821
874
|
aNodes.forEach((oNode) => {
|
|
822
|
-
|
|
823
|
-
|
|
824
|
-
|
|
825
|
-
|
|
826
|
-
|
|
827
|
-
|
|
875
|
+
const fCurrentX = oNode.getX();
|
|
876
|
+
const fCurrentY = oNode.getY();
|
|
877
|
+
|
|
878
|
+
// Always store in LTR space
|
|
879
|
+
let fLtrX = fCurrentX;
|
|
880
|
+
if (bIsRtl) {
|
|
881
|
+
const fNodeWidth = oNode._iWidth || 0;
|
|
882
|
+
fLtrX = fMaxX - fCurrentX - fNodeWidth + iHSpacing;
|
|
828
883
|
}
|
|
884
|
+
|
|
885
|
+
const bIsUserPositioned = this._lastCalculated.get(oNode)?.bIsUserPositioned ?? false;
|
|
886
|
+
|
|
887
|
+
this._lastCalculated.set(oNode, {
|
|
888
|
+
x: fLtrX,
|
|
889
|
+
y: fCurrentY,
|
|
890
|
+
lastRtl: bIsRtl,
|
|
891
|
+
bIsUserPositioned
|
|
892
|
+
});
|
|
829
893
|
});
|
|
830
894
|
},
|
|
831
895
|
|
|
@@ -834,36 +898,120 @@ sap.ui.define(["sap/suite/ui/commons/library", "sap/base/Log"], function (librar
|
|
|
834
898
|
* Marks nodes with original coordinates and tracks drag operations.
|
|
835
899
|
*
|
|
836
900
|
* @param {sap.suite.ui.commons.networkgraph.Graph} oGraph - The network graph instance
|
|
901
|
+
* @param {number} iHSpacing - Horizontal spacing used as RTL mirror offset
|
|
837
902
|
* @private
|
|
838
903
|
*/
|
|
839
|
-
_detectUserChanges: function (oGraph) {
|
|
904
|
+
_detectUserChanges: function (oGraph, iHSpacing) {
|
|
840
905
|
const aNodes = oGraph.getNodes();
|
|
906
|
+
const bIsRtl = oGraph._bIsRtl || false;
|
|
907
|
+
|
|
908
|
+
// Use stored fMaxX from previous mirror operation if available, otherwise calculate.
|
|
909
|
+
// We need it both when in RTL mode AND when switching RTL→LTR (to detect pre-switch drags).
|
|
910
|
+
let fMaxX = oGraph._rtlMirrorMaxX || 0;
|
|
911
|
+
if (bIsRtl && !fMaxX) {
|
|
912
|
+
aNodes.forEach((n) => {
|
|
913
|
+
const fRight = n.getX() + (n._iWidth || 0);
|
|
914
|
+
if (fRight > fMaxX) fMaxX = fRight;
|
|
915
|
+
});
|
|
916
|
+
}
|
|
841
917
|
|
|
842
918
|
aNodes.forEach((oNode) => {
|
|
843
|
-
const
|
|
844
|
-
const
|
|
845
|
-
//
|
|
846
|
-
//
|
|
847
|
-
|
|
919
|
+
const fCurrentX = oNode.getX();
|
|
920
|
+
const fCurrentY = oNode.getY();
|
|
921
|
+
// (0,0) is the sentinel for "unpositioned": resetNode() sets coordinates to (0,0)
|
|
922
|
+
// so the algorithm treats the node as if it were never placed.
|
|
923
|
+
// To legitimately position a node at the canvas origin, use (0.1, 0.1) or (1, 1).
|
|
924
|
+
const bHasCoordinates = fCurrentX !== undefined && fCurrentY !== undefined && (fCurrentX !== 0 || fCurrentY !== 0);
|
|
848
925
|
const oLastPos = this._lastCalculated.get(oNode);
|
|
849
926
|
|
|
850
|
-
|
|
851
|
-
|
|
927
|
+
// Convert current position to LTR coordinates for comparison
|
|
928
|
+
let fLtrX = fCurrentX;
|
|
929
|
+
if (bIsRtl) {
|
|
930
|
+
const fNodeWidth = oNode._iWidth || 0;
|
|
931
|
+
fLtrX = fMaxX - fCurrentX - fNodeWidth + iHSpacing;
|
|
932
|
+
}
|
|
933
|
+
|
|
934
|
+
if (oLastPos && !bHasCoordinates) {
|
|
935
|
+
// Coordinates were cleared (sentinel value 0,0) — evict cache so the algorithm
|
|
936
|
+
// repositions this node on the next layout pass.
|
|
937
|
+
this._lastCalculated.delete(oNode);
|
|
938
|
+
} else if (!oLastPos && bHasCoordinates) {
|
|
939
|
+
// No cache entry + non-zero coords: node has model-provided position (first call).
|
|
940
|
+
// Treated as user-positioned → preserved. Use resetNode() to opt a node out.
|
|
852
941
|
this._lastCalculated.set(oNode, {
|
|
853
|
-
x:
|
|
854
|
-
y:
|
|
942
|
+
x: fLtrX,
|
|
943
|
+
y: fCurrentY,
|
|
944
|
+
lastRtl: bIsRtl,
|
|
855
945
|
bIsUserPositioned: true
|
|
856
946
|
});
|
|
857
947
|
} else if (oLastPos) {
|
|
858
|
-
|
|
859
|
-
|
|
860
|
-
|
|
861
|
-
|
|
862
|
-
|
|
948
|
+
const bModeChanged = (oLastPos.lastRtl !== bIsRtl);
|
|
949
|
+
|
|
950
|
+
if (bModeChanged) {
|
|
951
|
+
const bPrevRtl = oLastPos.lastRtl;
|
|
952
|
+
let fLtrXBeforeSwitch;
|
|
953
|
+
|
|
954
|
+
if (bPrevRtl) {
|
|
955
|
+
const fNodeWidth = oNode._iWidth || 0;
|
|
956
|
+
fLtrXBeforeSwitch = fMaxX - fCurrentX - fNodeWidth + iHSpacing;
|
|
957
|
+
} else {
|
|
958
|
+
fLtrXBeforeSwitch = fCurrentX;
|
|
959
|
+
}
|
|
960
|
+
|
|
961
|
+
const fDeltaX = Math.abs(fLtrXBeforeSwitch - oLastPos.x);
|
|
962
|
+
const fDeltaY = Math.abs(fCurrentY - oLastPos.y);
|
|
963
|
+
|
|
964
|
+
if (fDeltaX > DRAG_DETECTION_THRESHOLD || fDeltaY > DRAG_DETECTION_THRESHOLD) {
|
|
965
|
+
oLastPos.x = fLtrXBeforeSwitch;
|
|
966
|
+
oLastPos.y = fCurrentY;
|
|
967
|
+
oLastPos.bIsUserPositioned = true;
|
|
968
|
+
}
|
|
969
|
+
|
|
970
|
+
oLastPos.lastRtl = bIsRtl;
|
|
971
|
+
} else {
|
|
972
|
+
const fDeltaX = Math.abs(fLtrX - oLastPos.x);
|
|
973
|
+
const fDeltaY = Math.abs(fCurrentY - oLastPos.y);
|
|
974
|
+
|
|
975
|
+
if (fDeltaX > DRAG_DETECTION_THRESHOLD || fDeltaY > DRAG_DETECTION_THRESHOLD) {
|
|
976
|
+
oLastPos.x = fLtrX;
|
|
977
|
+
oLastPos.y = fCurrentY;
|
|
978
|
+
oLastPos.bIsUserPositioned = true;
|
|
979
|
+
}
|
|
863
980
|
}
|
|
864
981
|
}
|
|
865
982
|
});
|
|
866
983
|
},
|
|
984
|
+
|
|
985
|
+
/**
|
|
986
|
+
* Mirrors all node X positions horizontally for RTL layout.
|
|
987
|
+
*
|
|
988
|
+
* @param {sap.suite.ui.commons.networkgraph.Graph} oGraph - The network graph instance
|
|
989
|
+
* @param {number} iHSpacing - Horizontal spacing used as left-side padding offset after mirroring
|
|
990
|
+
* @private
|
|
991
|
+
*/
|
|
992
|
+
_horizontalMirror: function (oGraph, iHSpacing) {
|
|
993
|
+
const aNodes = oGraph.getNodes();
|
|
994
|
+
|
|
995
|
+
// Find the rightmost edge of all nodes
|
|
996
|
+
let fMaxX = 0;
|
|
997
|
+
aNodes.forEach((oNode) => {
|
|
998
|
+
const fX = oNode.getX();
|
|
999
|
+
const fWidth = oNode._iWidth || 0;
|
|
1000
|
+
const fRightEdge = fX + fWidth;
|
|
1001
|
+
if (fRightEdge > fMaxX) {
|
|
1002
|
+
fMaxX = fRightEdge;
|
|
1003
|
+
}
|
|
1004
|
+
});
|
|
1005
|
+
|
|
1006
|
+
oGraph._rtlMirrorMaxX = fMaxX;
|
|
1007
|
+
|
|
1008
|
+
aNodes.forEach((oNode) => {
|
|
1009
|
+
const fCurrentX = oNode.getX();
|
|
1010
|
+
const fWidth = oNode._iWidth || 0;
|
|
1011
|
+
const fMirroredX = fMaxX - fCurrentX - fWidth + iHSpacing;
|
|
1012
|
+
oNode.setX(fMirroredX);
|
|
1013
|
+
});
|
|
1014
|
+
}
|
|
867
1015
|
};
|
|
868
1016
|
|
|
869
1017
|
return DependencyLayoutHelper;
|
|
@@ -7,8 +7,9 @@
|
|
|
7
7
|
sap.ui.define([
|
|
8
8
|
"sap/ui/core/dnd/DragInfo",
|
|
9
9
|
"sap/ui/core/dnd/DropInfo",
|
|
10
|
-
"sap/base/Log"
|
|
11
|
-
|
|
10
|
+
"sap/base/Log",
|
|
11
|
+
"sap/suite/ui/commons/networkgraph/Utils"
|
|
12
|
+
], function (DragInfo, DropInfo, Log, Utils) {
|
|
12
13
|
"use strict";
|
|
13
14
|
|
|
14
15
|
// constants
|
|
@@ -22,12 +23,32 @@ sap.ui.define([
|
|
|
22
23
|
AUTO_SCROLL_SPEED: 10, // Pixels to scroll per frame (16ms)
|
|
23
24
|
};
|
|
24
25
|
|
|
26
|
+
/**
|
|
27
|
+
* Minimum position offsets to ensure action buttons remain visible.
|
|
28
|
+
* LEFT: 60px accounts for line and port
|
|
29
|
+
* TOP: 40px accounts for top action buttons (-2.25rem ≈ 36px) plus margin
|
|
30
|
+
*/
|
|
31
|
+
const POSITION_CLAMP_OFFSET = {
|
|
32
|
+
LEFT: 60,
|
|
33
|
+
TOP: 40
|
|
34
|
+
};
|
|
35
|
+
|
|
25
36
|
// Instance object: Only one will exist
|
|
26
37
|
var instance = null;
|
|
27
38
|
var sDragSessionKey = "networkGraphDragSession";
|
|
28
39
|
var oUtilityFunctions = {
|
|
29
40
|
diff: function (a, b) {
|
|
30
41
|
return Math.abs(a - b);
|
|
42
|
+
},
|
|
43
|
+
clampPosition: function (x, y) {
|
|
44
|
+
/**
|
|
45
|
+
* Clamps position coordinates to minimum thresholds.
|
|
46
|
+
* Prevents nodes from being positioned where action buttons would be off-screen.
|
|
47
|
+
*/
|
|
48
|
+
return {
|
|
49
|
+
x: Math.max(POSITION_CLAMP_OFFSET.LEFT, x),
|
|
50
|
+
y: Math.max(POSITION_CLAMP_OFFSET.TOP, y)
|
|
51
|
+
};
|
|
31
52
|
}
|
|
32
53
|
};
|
|
33
54
|
|
|
@@ -276,45 +297,6 @@ sap.ui.define([
|
|
|
276
297
|
oControl.isA("sap.suite.ui.commons.networkgraph.Node");
|
|
277
298
|
}
|
|
278
299
|
|
|
279
|
-
/**
|
|
280
|
-
* Retains the scroll position of the graph after node drop.
|
|
281
|
-
* This method ensures that the viewport remains stable after drag and drop operations.
|
|
282
|
-
*
|
|
283
|
-
* @param {sap.suite.ui.commons.networkgraph.Graph} oGraph - The graph control
|
|
284
|
-
* @param {number} scrollLeft - The horizontal scroll position to maintain
|
|
285
|
-
* @param {number} scrollTop - The vertical scroll position to maintain
|
|
286
|
-
* @private
|
|
287
|
-
*/
|
|
288
|
-
DragDropManager.prototype._retainScrollPosition = function (oGraph, scrollLeft, scrollTop) {
|
|
289
|
-
if (!oGraph || !oGraph.$scroller || !oGraph.$scroller[0]) {
|
|
290
|
-
Log.warning("DragDropManager: Invalid graph or scroller element for scroll position retention.");
|
|
291
|
-
return;
|
|
292
|
-
}
|
|
293
|
-
|
|
294
|
-
const scrollerElement = oGraph.$scroller[0];
|
|
295
|
-
|
|
296
|
-
// Use requestAnimationFrame for better performance and timing
|
|
297
|
-
this._iRequestAnimationFrameId = requestAnimationFrame(() => {
|
|
298
|
-
try {
|
|
299
|
-
scrollerElement.scrollLeft = scrollLeft;
|
|
300
|
-
scrollerElement.scrollTop = scrollTop;
|
|
301
|
-
|
|
302
|
-
// Fallback verification - ensure the scroll position was actually set
|
|
303
|
-
if (Math.abs(scrollerElement.scrollLeft - scrollLeft) > 1 ||
|
|
304
|
-
Math.abs(scrollerElement.scrollTop - scrollTop) > 1) {
|
|
305
|
-
|
|
306
|
-
// If the scroll position wasn't set correctly, try again after DOM updates
|
|
307
|
-
setTimeout(() => {
|
|
308
|
-
scrollerElement.scrollLeft = scrollLeft;
|
|
309
|
-
scrollerElement.scrollTop = scrollTop;
|
|
310
|
-
}, 10);
|
|
311
|
-
}
|
|
312
|
-
} catch (error) {
|
|
313
|
-
Log.error("DragDropManager: Failed to retain scroll position", error);
|
|
314
|
-
}
|
|
315
|
-
});
|
|
316
|
-
}
|
|
317
|
-
|
|
318
300
|
/**
|
|
319
301
|
* Handles the drag start event for nodes.
|
|
320
302
|
*
|
|
@@ -325,6 +307,7 @@ sap.ui.define([
|
|
|
325
307
|
let dragSession = oEvent.getParameter("dragSession");
|
|
326
308
|
let browserEvent = oEvent.getParameter("browserEvent");
|
|
327
309
|
let oGraph = oEvent.getParameter("target")?.getParent();
|
|
310
|
+
let oNode = oEvent.getParameter("target");
|
|
328
311
|
let boundingRectScroller = oGraph?.$scroller?.[0]?.getBoundingClientRect() || { x: 0, y: 0 };
|
|
329
312
|
let boundingRectInnerScroller = oGraph?._$innerscroller?.[0]?.getBoundingClientRect() || { x: 0, y: 0 };
|
|
330
313
|
|
|
@@ -336,6 +319,9 @@ sap.ui.define([
|
|
|
336
319
|
// Stop any existing auto-scroll from previous drag operations
|
|
337
320
|
this._stopAutoScroll();
|
|
338
321
|
|
|
322
|
+
// Create custom drag image that includes the border
|
|
323
|
+
this._oDragImageNode = Utils.createCustomDragImage(oNode, browserEvent);
|
|
324
|
+
|
|
339
325
|
dragSession.setComplexData(sDragSessionKey, {
|
|
340
326
|
// Mouse cursor position when drag starts (in viewport coordinates)
|
|
341
327
|
cursorX: browserEvent.clientX,
|
|
@@ -369,6 +355,12 @@ sap.ui.define([
|
|
|
369
355
|
|
|
370
356
|
// Stop auto-scrolling when drag ends
|
|
371
357
|
this._stopAutoScroll();
|
|
358
|
+
|
|
359
|
+
// Clean up the drag image node
|
|
360
|
+
if (this._oDragImageNode && this._oDragImageNode.parentNode) {
|
|
361
|
+
this._oDragImageNode.parentNode.removeChild(this._oDragImageNode);
|
|
362
|
+
this._oDragImageNode = null;
|
|
363
|
+
}
|
|
372
364
|
};
|
|
373
365
|
|
|
374
366
|
/**
|
|
@@ -543,6 +535,9 @@ sap.ui.define([
|
|
|
543
535
|
let newX = dropData.draggedControl.getX() + deltaX + (deltaSignatureX * deltaInnerScrollerX),
|
|
544
536
|
newY = dropData.draggedControl.getY() + deltaY + (deltaSignatureY * deltaInnerScrollerY);
|
|
545
537
|
|
|
538
|
+
// Clamp position to prevent nodes from going off-screen (especially for action buttons)
|
|
539
|
+
var oClampedPosition = oUtilityFunctions.clampPosition(newX, newY);
|
|
540
|
+
|
|
546
541
|
// Store current scroll position before any DOM changes
|
|
547
542
|
let currentScrollLeft = oGraph?.$scroller?.[0]?.scrollLeft || 0;
|
|
548
543
|
let currentScrollTop = oGraph?.$scroller?.[0]?.scrollTop || 0;
|
|
@@ -550,14 +545,11 @@ sap.ui.define([
|
|
|
550
545
|
oGraph.fireEvent("nodeDropped", {
|
|
551
546
|
...oEvent.getParameters(),
|
|
552
547
|
node: dropData.draggedControl,
|
|
553
|
-
newX:
|
|
554
|
-
newY:
|
|
548
|
+
newX: oClampedPosition.x,
|
|
549
|
+
newY: oClampedPosition.y
|
|
555
550
|
});
|
|
556
|
-
//
|
|
557
|
-
|
|
558
|
-
setTimeout(() => {
|
|
559
|
-
this._retainScrollPosition(oGraph, currentScrollLeft, currentScrollTop);
|
|
560
|
-
}, 0);
|
|
551
|
+
// Preserve scroll position after event
|
|
552
|
+
Utils.preserveScrollPosition(oGraph, currentScrollLeft, currentScrollTop, 0);
|
|
561
553
|
};
|
|
562
554
|
|
|
563
555
|
/**
|
|
@@ -574,12 +566,22 @@ sap.ui.define([
|
|
|
574
566
|
x = dropData.clientX - boundingRect.left,
|
|
575
567
|
y = dropData.clientY - boundingRect.top;
|
|
576
568
|
|
|
569
|
+
// Clamp position to prevent nodes from going off-screen (especially for action buttons)
|
|
570
|
+
var oClampedPosition = oUtilityFunctions.clampPosition(x, y);
|
|
571
|
+
|
|
572
|
+
// Store current scroll position before any DOM changes
|
|
573
|
+
let currentScrollLeft = oGraph?.$scroller?.[0]?.scrollLeft || 0;
|
|
574
|
+
let currentScrollTop = oGraph?.$scroller?.[0]?.scrollTop || 0;
|
|
575
|
+
|
|
577
576
|
oGraph.fireEvent("nodeDropped", {
|
|
578
577
|
...oEvent.getParameters(),
|
|
579
578
|
node: dropData.draggedControl,
|
|
580
|
-
newX: x,
|
|
581
|
-
newY: y
|
|
579
|
+
newX: oClampedPosition.x,
|
|
580
|
+
newY: oClampedPosition.y
|
|
582
581
|
});
|
|
582
|
+
|
|
583
|
+
// Preserve scroll position after event
|
|
584
|
+
Utils.preserveScrollPosition(oGraph, currentScrollLeft, currentScrollTop, 0);
|
|
583
585
|
};
|
|
584
586
|
|
|
585
587
|
/**
|
|
@@ -6,8 +6,9 @@
|
|
|
6
6
|
*/
|
|
7
7
|
sap.ui.define([
|
|
8
8
|
"sap/ui/thirdparty/jquery",
|
|
9
|
-
"sap/suite/ui/commons/library"
|
|
10
|
-
|
|
9
|
+
"sap/suite/ui/commons/library",
|
|
10
|
+
"sap/suite/ui/commons/networkgraph/Utils"
|
|
11
|
+
], function (jQuery, Library, Utils) {
|
|
11
12
|
"use strict";
|
|
12
13
|
/**
|
|
13
14
|
* PortManager class for managing network graph ports.
|
|
@@ -485,6 +486,11 @@ sap.ui.define([
|
|
|
485
486
|
const targetPortSide = target.dataset.portSide;
|
|
486
487
|
// Check if the target node is valid
|
|
487
488
|
if (targetNode) {
|
|
489
|
+
const oGraph = sourceNode.getParent();
|
|
490
|
+
// Capture current scroll position before firing event
|
|
491
|
+
const scrollerElement = oGraph.$scroller[0];
|
|
492
|
+
const currentScrollLeft = scrollerElement.scrollLeft || 0;
|
|
493
|
+
const currentScrollTop = scrollerElement.scrollTop || 0;
|
|
488
494
|
const mParameters = {
|
|
489
495
|
from: sourceNode.getKey(),
|
|
490
496
|
to: targetNode.getKey(),
|
|
@@ -493,7 +499,10 @@ sap.ui.define([
|
|
|
493
499
|
toNode: targetNode
|
|
494
500
|
};
|
|
495
501
|
// Fire the connectionCreated event
|
|
496
|
-
|
|
502
|
+
oGraph.fireConnectionCreated(mParameters);
|
|
503
|
+
|
|
504
|
+
// Preserve scroll position after event
|
|
505
|
+
Utils.preserveScrollPosition(oGraph, currentScrollLeft, currentScrollTop, 0);
|
|
497
506
|
}
|
|
498
507
|
}
|
|
499
508
|
// Remove inlet ports from other nodes
|