pict-section-flow 1.4.0 → 2.0.0

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (164) hide show
  1. package/package.json +7 -2
  2. package/source/Pict-Section-Flow.js +20 -14
  3. package/source/providers/PictProvider-Flow-Background.js +303 -0
  4. package/source/providers/PictProvider-Flow-CSS.js +73 -7
  5. package/source/providers/PictProvider-Flow-Geometry.js +11 -421
  6. package/source/providers/PictProvider-Flow-Icons.js +12 -0
  7. package/source/providers/PictProvider-Flow-Layouts.js +107 -0
  8. package/source/services/PictService-Flow-ConnectionRenderer.js +1 -1
  9. package/source/services/PictService-Flow-CursorManager.js +113 -0
  10. package/source/services/PictService-Flow-InteractionManager.js +439 -59
  11. package/source/services/PictService-Flow-Layout.js +21 -16
  12. package/source/services/PictService-Flow-PathGenerator.js +30 -417
  13. package/source/services/PictService-Flow-RenderManager.js +9 -1
  14. package/source/services/PictService-Flow-ViewportManager.js +102 -0
  15. package/source/views/PictView-Flow-FloatingToolbar.js +5 -1
  16. package/source/views/PictView-Flow-Node.js +29 -0
  17. package/source/views/PictView-Flow-Toolbar.js +50 -3
  18. package/source/views/PictView-Flow.js +591 -2
  19. package/.claude/launch.json +0 -11
  20. package/docs/.nojekyll +0 -0
  21. package/docs/Architecture.md +0 -163
  22. package/docs/Custom-Styling.md +0 -275
  23. package/docs/Data_Model.md +0 -149
  24. package/docs/Event_System.md +0 -156
  25. package/docs/Getting_Started.md +0 -237
  26. package/docs/Implementation_Reference.md +0 -528
  27. package/docs/Layout_Persistence.md +0 -117
  28. package/docs/README.md +0 -103
  29. package/docs/Theme_Integration.md +0 -150
  30. package/docs/_brand.json +0 -18
  31. package/docs/_cover.md +0 -17
  32. package/docs/_playground.json +0 -24
  33. package/docs/_sidebar.md +0 -57
  34. package/docs/_topbar.md +0 -8
  35. package/docs/_version.json +0 -7
  36. package/docs/api/PictFlowCard.md +0 -216
  37. package/docs/api/PictFlowCardPropertiesPanel.md +0 -235
  38. package/docs/api/addConnection.md +0 -101
  39. package/docs/api/addNode.md +0 -137
  40. package/docs/api/autoLayout.md +0 -77
  41. package/docs/api/getFlowData.md +0 -112
  42. package/docs/api/marshalToView.md +0 -95
  43. package/docs/api/openPanel.md +0 -128
  44. package/docs/api/registerHandler.md +0 -174
  45. package/docs/api/registerNodeType.md +0 -142
  46. package/docs/api/removeConnection.md +0 -57
  47. package/docs/api/removeNode.md +0 -80
  48. package/docs/api/saveLayout.md +0 -152
  49. package/docs/api/screenToSVGCoords.md +0 -68
  50. package/docs/api/selectNode.md +0 -116
  51. package/docs/api/setTheme.md +0 -168
  52. package/docs/api/setZoom.md +0 -97
  53. package/docs/api/toggleFullscreen.md +0 -68
  54. package/docs/card-help/EACH.md +0 -19
  55. package/docs/card-help/FREAD.md +0 -24
  56. package/docs/card-help/FWRITE.md +0 -24
  57. package/docs/card-help/GET.md +0 -22
  58. package/docs/card-help/ITE.md +0 -23
  59. package/docs/card-help/LOG.md +0 -23
  60. package/docs/card-help/NOTE.md +0 -17
  61. package/docs/card-help/PREV.md +0 -18
  62. package/docs/card-help/SET.md +0 -27
  63. package/docs/card-help/SPKL.md +0 -22
  64. package/docs/card-help/STAT.md +0 -23
  65. package/docs/card-help/SW.md +0 -25
  66. package/docs/diagrams/architecture-at-a-glance.excalidraw +0 -4270
  67. package/docs/diagrams/architecture-at-a-glance.mmd +0 -30
  68. package/docs/diagrams/architecture-at-a-glance.svg +0 -2
  69. package/docs/diagrams/data-flow.excalidraw +0 -1451
  70. package/docs/diagrams/data-flow.mmd +0 -17
  71. package/docs/diagrams/data-flow.svg +0 -2
  72. package/docs/diagrams/high-level-design.excalidraw +0 -5767
  73. package/docs/diagrams/high-level-design.mmd +0 -86
  74. package/docs/diagrams/high-level-design.svg +0 -2
  75. package/docs/diagrams/relationships.excalidraw +0 -3852
  76. package/docs/diagrams/relationships.mmd +0 -9
  77. package/docs/diagrams/relationships.svg +0 -2
  78. package/docs/diagrams/service-initialization-sequence.excalidraw +0 -1466
  79. package/docs/diagrams/service-initialization-sequence.mmd +0 -19
  80. package/docs/diagrams/service-initialization-sequence.svg +0 -2
  81. package/docs/diagrams/svg-layer-structure.excalidraw +0 -1060
  82. package/docs/diagrams/svg-layer-structure.mmd +0 -18
  83. package/docs/diagrams/svg-layer-structure.svg +0 -2
  84. package/docs/examples/README.md +0 -9
  85. package/docs/examples/simple_cards/README.md +0 -677
  86. package/docs/examples/simple_cards/css/flowexample.css +0 -65
  87. package/docs/examples/simple_cards/index.html +0 -32
  88. package/docs/examples/simple_cards/js/pict.min.js +0 -12
  89. package/docs/examples/simple_cards/pict-section-flow-example-simple-cards.compatible.min.js +0 -1
  90. package/docs/index.html +0 -38
  91. package/docs/playground/app.json +0 -6
  92. package/docs/playground/appdata.json +0 -85
  93. package/docs/playground/application.js +0 -23
  94. package/docs/playground/pict.json +0 -17
  95. package/docs/playground/runtime/pict-application.min.js +0 -2
  96. package/docs/playground/runtime/pict-section-flow.min.js +0 -2
  97. package/docs/playground/runtime/pict-section-modal.min.js +0 -2
  98. package/docs/playground/runtime/pict.min.js +0 -12
  99. package/docs/retold-catalog.json +0 -244
  100. package/docs/retold-keyword-index.json +0 -26028
  101. package/example_applications/simple_cards/css/flowexample.css +0 -65
  102. package/example_applications/simple_cards/html/index.html +0 -32
  103. package/example_applications/simple_cards/package.json +0 -52
  104. package/example_applications/simple_cards/source/Pict-Application-FlowExample-Configuration.json +0 -15
  105. package/example_applications/simple_cards/source/Pict-Application-FlowExample.js +0 -539
  106. package/example_applications/simple_cards/source/card-help-content.js +0 -16
  107. package/example_applications/simple_cards/source/cards/FlowCard-Comment.js +0 -38
  108. package/example_applications/simple_cards/source/cards/FlowCard-DataPreview.js +0 -44
  109. package/example_applications/simple_cards/source/cards/FlowCard-Each.js +0 -38
  110. package/example_applications/simple_cards/source/cards/FlowCard-FileRead.js +0 -56
  111. package/example_applications/simple_cards/source/cards/FlowCard-FileWrite.js +0 -50
  112. package/example_applications/simple_cards/source/cards/FlowCard-GetValue.js +0 -37
  113. package/example_applications/simple_cards/source/cards/FlowCard-IfThenElse.js +0 -49
  114. package/example_applications/simple_cards/source/cards/FlowCard-LogValues.js +0 -55
  115. package/example_applications/simple_cards/source/cards/FlowCard-SetValue.js +0 -97
  116. package/example_applications/simple_cards/source/cards/FlowCard-Sparkline.js +0 -100
  117. package/example_applications/simple_cards/source/cards/FlowCard-StatusMonitor.js +0 -46
  118. package/example_applications/simple_cards/source/cards/FlowCard-Switch.js +0 -39
  119. package/example_applications/simple_cards/source/providers/PictRouter-FlowExample-Configuration.json +0 -22
  120. package/example_applications/simple_cards/source/sample-flows.js +0 -410
  121. package/example_applications/simple_cards/source/views/PictView-FlowExample-About.js +0 -184
  122. package/example_applications/simple_cards/source/views/PictView-FlowExample-BottomBar.js +0 -77
  123. package/example_applications/simple_cards/source/views/PictView-FlowExample-Documentation.js +0 -325
  124. package/example_applications/simple_cards/source/views/PictView-FlowExample-FileWriteInfo.js +0 -59
  125. package/example_applications/simple_cards/source/views/PictView-FlowExample-Layout.js +0 -90
  126. package/example_applications/simple_cards/source/views/PictView-FlowExample-MainWorkspace.js +0 -453
  127. package/example_applications/simple_cards/source/views/PictView-FlowExample-TopBar.js +0 -95
  128. package/scripts/generate-card-help.js +0 -214
  129. package/source/providers/edges/Edge-Bezier.js +0 -41
  130. package/source/providers/edges/Edge-Orthogonal.js +0 -37
  131. package/source/providers/edges/Edge-OrthogonalSnap.js +0 -72
  132. package/source/providers/edges/Edge-Perimeter-Linear.js +0 -31
  133. package/source/providers/edges/Edge-Perimeter-Orthogonal.js +0 -39
  134. package/source/providers/edges/Edge-Perimeter.js +0 -48
  135. package/source/providers/edges/Edge-PerimeterMath.js +0 -92
  136. package/source/providers/edges/Edge-Straight.js +0 -24
  137. package/source/providers/layouts/Layout-Circular.js +0 -203
  138. package/source/providers/layouts/Layout-Coerce.js +0 -40
  139. package/source/providers/layouts/Layout-Columnar.js +0 -134
  140. package/source/providers/layouts/Layout-Custom.js +0 -27
  141. package/source/providers/layouts/Layout-ForcedFromCenter.js +0 -256
  142. package/source/providers/layouts/Layout-Grid.js +0 -134
  143. package/source/providers/layouts/Layout-Layered.js +0 -155
  144. package/source/providers/layouts/Layout-Rank.js +0 -141
  145. package/source/providers/layouts/Layout-Staggered.js +0 -131
  146. package/source/providers/layouts/Layout-Tabular.js +0 -94
  147. package/test/CardPalette_tests.js +0 -43
  148. package/test/ConnectionHandleManager_tests.js +0 -717
  149. package/test/ConnectionRenderer_tests.js +0 -591
  150. package/test/ConnectionStyle_tests.js +0 -90
  151. package/test/DataManager_tests.js +0 -859
  152. package/test/Geometry_tests.js +0 -767
  153. package/test/InteractionManager_tests.js +0 -279
  154. package/test/Layout_tests.js +0 -1604
  155. package/test/NodeView_tests.js +0 -66
  156. package/test/PanelManager_tests.js +0 -172
  157. package/test/PathGenerator_tests.js +0 -978
  158. package/test/PortRenderer_tests.js +0 -376
  159. package/test/RenderManager_tests.js +0 -756
  160. package/test/Renderer_tests.js +0 -133
  161. package/test/SelectionManager_tests.js +0 -185
  162. package/test/StylePresets_tests.js +0 -153
  163. package/test/ToolbarExtraButtons_tests.js +0 -138
  164. package/test/UndirectedConnections_tests.js +0 -70
@@ -1,133 +0,0 @@
1
- const libFable = require('fable');
2
- const libChai = require('chai');
3
- const libExpect = libChai.expect;
4
-
5
- const libRenderer = require('../source/providers/PictProvider-Flow-Renderer.js');
6
-
7
- suite('PictProvider-Flow-Renderer',
8
- function ()
9
- {
10
- let _Fable;
11
- let _Renderer;
12
-
13
- setup(function ()
14
- {
15
- _Fable = new libFable({});
16
- _Renderer = new libRenderer(_Fable, {}, 'Renderer-Test');
17
- });
18
-
19
- suite('Built-in renderer registry', function ()
20
- {
21
- test('registers clean, bracket, sketch, crt, workstation by default', function ()
22
- {
23
- let tmpKeys = _Renderer.getRendererKeys();
24
- libExpect(tmpKeys).to.include('clean');
25
- libExpect(tmpKeys).to.include('bracket');
26
- libExpect(tmpKeys).to.include('sketch');
27
- libExpect(tmpKeys).to.include('crt');
28
- libExpect(tmpKeys).to.include('workstation');
29
- });
30
-
31
- test('clean is the default active renderer', function ()
32
- {
33
- libExpect(_Renderer.getActiveRendererKey()).to.equal('clean');
34
- });
35
-
36
- test('each built-in renderer has the required shape', function ()
37
- {
38
- let tmpKeys = _Renderer.getRendererKeys();
39
- for (let i = 0; i < tmpKeys.length; i++)
40
- {
41
- let tmpR = _Renderer.getActiveRenderer.call(
42
- { _Renderers: _Renderer._Renderers, _ActiveRendererKey: tmpKeys[i] });
43
- libExpect(tmpR, `renderer ${tmpKeys[i]}`).to.have.property('Key', tmpKeys[i]);
44
- libExpect(tmpR).to.have.property('NodeBodyMode');
45
- libExpect(tmpR).to.have.property('NoiseConfig');
46
- libExpect(tmpR).to.have.property('ConnectionConfig');
47
- libExpect(tmpR).to.have.property('GeometryCSS');
48
- }
49
- });
50
- });
51
-
52
- suite('setRenderer()', function ()
53
- {
54
- test('switches the active renderer + updates noise default', function ()
55
- {
56
- _Renderer.setRenderer('sketch');
57
- libExpect(_Renderer.getActiveRendererKey()).to.equal('sketch');
58
- let tmpActive = _Renderer.getActiveRenderer();
59
- libExpect(tmpActive.NodeBodyMode).to.equal('bracket');
60
- libExpect(_Renderer.getNoiseLevel()).to.equal(0.4);
61
- });
62
-
63
- test('returns false for unknown renderer + leaves state unchanged', function ()
64
- {
65
- _Renderer.setRenderer('sketch');
66
- let tmpResult = _Renderer.setRenderer('nonexistent');
67
- libExpect(tmpResult).to.equal(false);
68
- libExpect(_Renderer.getActiveRendererKey()).to.equal('sketch');
69
- });
70
-
71
- test('switching to a renderer with noise disabled resets noise to 0', function ()
72
- {
73
- _Renderer.setRenderer('sketch'); // 0.4
74
- _Renderer.setRenderer('clean'); // 0
75
- libExpect(_Renderer.getNoiseLevel()).to.equal(0);
76
- });
77
- });
78
-
79
- suite('register()', function ()
80
- {
81
- test('registers a custom renderer + reads back through getActiveRenderer', function ()
82
- {
83
- _Renderer.register('custom', {
84
- Label: 'Custom',
85
- NodeBodyMode: 'rect',
86
- NoiseConfig: { Enabled: false, DefaultLevel: 0, MaxJitterPx: 0, AffectsNodes: false, AffectsConnections: false },
87
- ConnectionConfig: { StrokeWidth: 3, ArrowheadStyle: 'triangle' },
88
- GeometryCSS: '',
89
- AdditionalCSS: ''
90
- });
91
- let tmpResult = _Renderer.setRenderer('custom');
92
- libExpect(tmpResult).to.equal(true);
93
- let tmpActive = _Renderer.getActiveRenderer();
94
- libExpect(tmpActive.Key).to.equal('custom');
95
- libExpect(tmpActive.Label).to.equal('Custom');
96
- });
97
- });
98
-
99
- suite('Noise APIs', function ()
100
- {
101
- test('setNoiseLevel clamps to [0,1]', function ()
102
- {
103
- _Renderer.setNoiseLevel(-1);
104
- libExpect(_Renderer.getNoiseLevel()).to.equal(0);
105
- _Renderer.setNoiseLevel(2);
106
- libExpect(_Renderer.getNoiseLevel()).to.equal(1);
107
- _Renderer.setNoiseLevel(0.5);
108
- libExpect(_Renderer.getNoiseLevel()).to.equal(0.5);
109
- });
110
-
111
- test('getNodeNoiseAmplitude is 0 when active renderer disables noise', function ()
112
- {
113
- _Renderer.setRenderer('clean');
114
- _Renderer.setNoiseLevel(1);
115
- libExpect(_Renderer.getNodeNoiseAmplitude()).to.equal(0);
116
- });
117
-
118
- test('getNodeNoiseAmplitude scales with noise level when sketch is active', function ()
119
- {
120
- _Renderer.setRenderer('sketch');
121
- _Renderer.setNoiseLevel(0.5);
122
- // sketch.MaxJitterPx is 4 — 0.5 * 4 = 2
123
- libExpect(_Renderer.getNodeNoiseAmplitude()).to.equal(2);
124
- });
125
-
126
- test('processPathString is a no-op when noise is disabled', function ()
127
- {
128
- _Renderer.setRenderer('clean');
129
- let tmpResult = _Renderer.processPathString('M 0 0 L 10 10', 'seed');
130
- libExpect(tmpResult).to.equal('M 0 0 L 10 10');
131
- });
132
- });
133
- });
@@ -1,185 +0,0 @@
1
- const libFable = require('fable');
2
- const libChai = require('chai');
3
- const libExpect = libChai.expect;
4
-
5
- const libSelectionManager = require('../source/services/PictService-Flow-SelectionManager.js');
6
-
7
- // A minimal FlowView stand-in: just the surface the selection manager touches.
8
- function makeMockFlowView(pNodes)
9
- {
10
- let tmpFired = [];
11
- let tmpRemoved = [];
12
- return {
13
- _FlowData:
14
- {
15
- Nodes: pNodes.slice(),
16
- Connections: [],
17
- OpenPanels: [],
18
- ViewState: { SelectedNodeHash: null, SelectedNodeHashes: [], SelectedConnectionHash: null, SelectedTetherHash: null }
19
- },
20
- renderFlow: function () { this._rendered = (this._rendered || 0) + 1; },
21
- removeNode: function (pHash) { tmpRemoved.push(pHash); this._FlowData.Nodes = this._FlowData.Nodes.filter((n) => n.Hash !== pHash); return true; },
22
- removeConnection: function (pHash) { tmpRemoved.push('conn:' + pHash); return true; },
23
- _EventHandlerProvider: { fireEvent: function (pName, pPayload) { tmpFired.push({ Name: pName, Payload: pPayload }); } },
24
- _firedEvents: tmpFired,
25
- _removed: tmpRemoved
26
- };
27
- }
28
-
29
- function makeManager(pFable, pNodes)
30
- {
31
- let tmpFV = makeMockFlowView(pNodes);
32
- let tmpSM = new libSelectionManager(pFable, { FlowView: tmpFV }, 'SM-Test');
33
- return { sm: tmpSM, fv: tmpFV, vs: tmpFV._FlowData.ViewState };
34
- }
35
-
36
- suite('PictService-Flow-SelectionManager',
37
- function ()
38
- {
39
- let _Fable;
40
- let _Nodes;
41
- setup(function ()
42
- {
43
- _Fable = new libFable({});
44
- _Nodes = [ { Hash: 'n1', X: 0, Y: 0, Width: 100, Height: 80 }, { Hash: 'n2', X: 200, Y: 0, Width: 100, Height: 80 }, { Hash: 'n3', X: 400, Y: 0, Width: 100, Height: 80 } ];
45
- });
46
-
47
- suite('single selection keeps the set in lockstep',
48
- function ()
49
- {
50
- test('selectNode sets the primary and a one-element set',
51
- function ()
52
- {
53
- let tmp = makeManager(_Fable, _Nodes);
54
- tmp.sm.selectNode('n2');
55
- libExpect(tmp.vs.SelectedNodeHash).to.equal('n2');
56
- libExpect(tmp.vs.SelectedNodeHashes).to.deep.equal(['n2']);
57
- });
58
-
59
- test('selectNode(null) clears both the primary and the set',
60
- function ()
61
- {
62
- let tmp = makeManager(_Fable, _Nodes);
63
- tmp.sm.selectNode('n2');
64
- tmp.sm.selectNode(null);
65
- libExpect(tmp.vs.SelectedNodeHash).to.equal(null);
66
- libExpect(tmp.vs.SelectedNodeHashes).to.deep.equal([]);
67
- });
68
- });
69
-
70
- suite('toggleNodeSelection',
71
- function ()
72
- {
73
- test('adds a node, then a second, then removes the first',
74
- function ()
75
- {
76
- let tmp = makeManager(_Fable, _Nodes);
77
- tmp.sm.toggleNodeSelection('n1');
78
- libExpect(tmp.vs.SelectedNodeHashes).to.deep.equal(['n1']);
79
- libExpect(tmp.vs.SelectedNodeHash).to.equal('n1');
80
-
81
- tmp.sm.toggleNodeSelection('n3');
82
- libExpect(tmp.vs.SelectedNodeHashes).to.deep.equal(['n1', 'n3']);
83
- libExpect(tmp.vs.SelectedNodeHash).to.equal('n3');
84
-
85
- tmp.sm.toggleNodeSelection('n1');
86
- libExpect(tmp.vs.SelectedNodeHashes).to.deep.equal(['n3']);
87
- libExpect(tmp.vs.SelectedNodeHash).to.equal('n3');
88
- });
89
-
90
- test('toggling the last member empties the set and nulls the primary',
91
- function ()
92
- {
93
- let tmp = makeManager(_Fable, _Nodes);
94
- tmp.sm.toggleNodeSelection('n1');
95
- tmp.sm.toggleNodeSelection('n1');
96
- libExpect(tmp.vs.SelectedNodeHashes).to.deep.equal([]);
97
- libExpect(tmp.vs.SelectedNodeHash).to.equal(null);
98
- });
99
- });
100
-
101
- suite('selectNodes',
102
- function ()
103
- {
104
- test('replaces the set and sets the primary to the last hash',
105
- function ()
106
- {
107
- let tmp = makeManager(_Fable, _Nodes);
108
- tmp.sm.selectNode('n1');
109
- tmp.sm.selectNodes(['n2', 'n3']);
110
- libExpect(tmp.vs.SelectedNodeHashes).to.deep.equal(['n2', 'n3']);
111
- libExpect(tmp.vs.SelectedNodeHash).to.equal('n3');
112
- });
113
-
114
- test('an empty array clears the selection',
115
- function ()
116
- {
117
- let tmp = makeManager(_Fable, _Nodes);
118
- tmp.sm.selectNodes(['n1', 'n2']);
119
- tmp.sm.selectNodes([]);
120
- libExpect(tmp.vs.SelectedNodeHashes).to.deep.equal([]);
121
- libExpect(tmp.vs.SelectedNodeHash).to.equal(null);
122
- });
123
-
124
- test('getSelectedNodeHashes returns a copy (mutating it does not change state)',
125
- function ()
126
- {
127
- let tmp = makeManager(_Fable, _Nodes);
128
- tmp.sm.selectNodes(['n1', 'n2']);
129
- let tmpCopy = tmp.sm.getSelectedNodeHashes();
130
- tmpCopy.push('n3');
131
- libExpect(tmp.vs.SelectedNodeHashes).to.deep.equal(['n1', 'n2']);
132
- });
133
- });
134
-
135
- suite('deleteSelected (multi)',
136
- function ()
137
- {
138
- test('removes every node in the selection set',
139
- function ()
140
- {
141
- let tmp = makeManager(_Fable, _Nodes);
142
- tmp.sm.selectNodes(['n1', 'n3']);
143
- let tmpResult = tmp.sm.deleteSelected();
144
- libExpect(tmpResult).to.equal(true);
145
- libExpect(tmp.fv._removed).to.deep.equal(['n1', 'n3']);
146
- libExpect(tmp.vs.SelectedNodeHashes).to.deep.equal([]);
147
- libExpect(tmp.vs.SelectedNodeHash).to.equal(null);
148
- });
149
-
150
- test('falls back to the single primary when the set is empty',
151
- function ()
152
- {
153
- let tmp = makeManager(_Fable, _Nodes);
154
- tmp.fv._FlowData.ViewState.SelectedNodeHash = 'n2';
155
- tmp.fv._FlowData.ViewState.SelectedNodeHashes = [];
156
- tmp.sm.deleteSelected();
157
- libExpect(tmp.fv._removed).to.deep.equal(['n2']);
158
- });
159
-
160
- test('deletes the selected connection when no nodes are selected',
161
- function ()
162
- {
163
- let tmp = makeManager(_Fable, _Nodes);
164
- tmp.fv._FlowData.ViewState.SelectedConnectionHash = 'c1';
165
- tmp.sm.deleteSelected();
166
- libExpect(tmp.fv._removed).to.deep.equal(['conn:c1']);
167
- });
168
- });
169
-
170
- suite('deselectAll',
171
- function ()
172
- {
173
- test('clears the primary, the set, and the connection/tether selections',
174
- function ()
175
- {
176
- let tmp = makeManager(_Fable, _Nodes);
177
- tmp.sm.selectNodes(['n1', 'n2']);
178
- tmp.fv._FlowData.ViewState.SelectedConnectionHash = 'c1';
179
- tmp.sm.deselectAll();
180
- libExpect(tmp.vs.SelectedNodeHash).to.equal(null);
181
- libExpect(tmp.vs.SelectedNodeHashes).to.deep.equal([]);
182
- libExpect(tmp.vs.SelectedConnectionHash).to.equal(null);
183
- });
184
- });
185
- });
@@ -1,153 +0,0 @@
1
- const libFable = require('fable');
2
- const libChai = require('chai');
3
- const libExpect = libChai.expect;
4
-
5
- const libRenderer = require('../source/providers/PictProvider-Flow-Renderer.js');
6
- const libStylePresets = require('../source/providers/PictProvider-Flow-StylePresets.js');
7
-
8
- // Minimal FlowView shim — captures the apply calls so we can verify each
9
- // preset axis fires. The real FlowView wires Renderer + setEdgeTheme; here
10
- // we substitute a fake whose setEdgeTheme just records its argument.
11
- function makeFakeFlowView(pFable)
12
- {
13
- let tmpRenderer = new libRenderer(pFable, {}, 'Renderer-Test');
14
- let tmpView =
15
- {
16
- _RendererProvider: tmpRenderer,
17
- setEdgeThemeCalls: [],
18
- setEdgeTheme: function (pName)
19
- {
20
- tmpView.setEdgeThemeCalls.push(pName);
21
- }
22
- };
23
- tmpRenderer._FlowView = tmpView;
24
- return tmpView;
25
- }
26
-
27
- // pict-provider-theme mock that records applyTheme calls.
28
- function attachFakeThemeProvider(pFable)
29
- {
30
- pFable.providers = pFable.providers || {};
31
- let tmpCalls = [];
32
- pFable.providers.Theme =
33
- {
34
- applyTheme: function (pHash) { tmpCalls.push(pHash); }
35
- };
36
- return tmpCalls;
37
- }
38
-
39
- suite('PictProvider-Flow-StylePresets',
40
- function ()
41
- {
42
- let _Fable;
43
- let _FlowView;
44
- let _ThemeCalls;
45
- let _Presets;
46
-
47
- setup(function ()
48
- {
49
- _Fable = new libFable({});
50
- _FlowView = makeFakeFlowView(_Fable);
51
- _ThemeCalls = attachFakeThemeProvider(_Fable);
52
- _Presets = new libStylePresets(_Fable, { FlowView: _FlowView }, 'Presets-Test');
53
- });
54
-
55
- suite('Built-in preset registry', function ()
56
- {
57
- test('registers all 7 bundled presets', function ()
58
- {
59
- let tmpHashes = _Presets.getPresetHashes();
60
- libExpect(tmpHashes).to.include('modern');
61
- libExpect(tmpHashes).to.include('sketch');
62
- libExpect(tmpHashes).to.include('blueprint');
63
- libExpect(tmpHashes).to.include('mono');
64
- libExpect(tmpHashes).to.include('retro-80s');
65
- libExpect(tmpHashes).to.include('retro-90s');
66
- libExpect(tmpHashes).to.include('whiteboard');
67
- });
68
-
69
- test('each bundled preset has ColorTheme + Renderer + EdgeTheme', function ()
70
- {
71
- let tmpHashes = _Presets.getPresetHashes();
72
- for (let i = 0; i < tmpHashes.length; i++)
73
- {
74
- let tmpPreset = _Presets.getPreset(tmpHashes[i]);
75
- libExpect(tmpPreset, `preset ${tmpHashes[i]}`).to.have.property('Hash', tmpHashes[i]);
76
- libExpect(tmpPreset).to.have.property('ColorTheme');
77
- libExpect(tmpPreset).to.have.property('Renderer');
78
- libExpect(tmpPreset).to.have.property('EdgeTheme');
79
- }
80
- });
81
- });
82
-
83
- suite('applyPreset()', function ()
84
- {
85
- test('applies ColorTheme + Renderer + EdgeTheme + optional NoiseLevel', function ()
86
- {
87
- let tmpOk = _Presets.applyPreset('sketch');
88
- libExpect(tmpOk).to.equal(true);
89
- libExpect(_ThemeCalls).to.deep.equal(['flow-sketch']);
90
- libExpect(_FlowView._RendererProvider.getActiveRendererKey()).to.equal('sketch');
91
- libExpect(_FlowView.setEdgeThemeCalls).to.deep.equal(['bezier']);
92
- libExpect(_FlowView._RendererProvider.getNoiseLevel()).to.equal(0.4);
93
- });
94
-
95
- test('blueprint applies bracket renderer + orthogonal edges', function ()
96
- {
97
- _Presets.applyPreset('blueprint');
98
- libExpect(_ThemeCalls).to.deep.equal(['flow-blueprint']);
99
- libExpect(_FlowView._RendererProvider.getActiveRendererKey()).to.equal('bracket');
100
- libExpect(_FlowView.setEdgeThemeCalls).to.deep.equal(['orthogonal']);
101
- });
102
-
103
- test('returns false + leaves state unchanged for unknown preset hash', function ()
104
- {
105
- _Presets.applyPreset('sketch');
106
- let tmpResult = _Presets.applyPreset('nonexistent');
107
- libExpect(tmpResult).to.equal(false);
108
- libExpect(_Presets.getActivePresetHash()).to.equal('sketch');
109
- });
110
-
111
- test('records active preset hash on success', function ()
112
- {
113
- libExpect(_Presets.getActivePresetHash()).to.equal(null);
114
- _Presets.applyPreset('mono');
115
- libExpect(_Presets.getActivePresetHash()).to.equal('mono');
116
- });
117
- });
118
-
119
- suite('register() + custom presets', function ()
120
- {
121
- test('apps can register their own preset and apply it', function ()
122
- {
123
- _Presets.register({
124
- Hash: 'corporate',
125
- Label: 'Corporate',
126
- ColorTheme: 'pict-default',
127
- Renderer: 'clean',
128
- EdgeTheme: 'orthogonal'
129
- });
130
- let tmpOk = _Presets.applyPreset('corporate');
131
- libExpect(tmpOk).to.equal(true);
132
- libExpect(_ThemeCalls).to.deep.equal(['pict-default']);
133
- libExpect(_FlowView._RendererProvider.getActiveRendererKey()).to.equal('clean');
134
- });
135
-
136
- test('register() rejects payloads missing a Hash', function ()
137
- {
138
- let tmpOk = _Presets.register({ Label: 'Bad' });
139
- libExpect(tmpOk).to.equal(false);
140
- });
141
- });
142
-
143
- suite('markCustomized()', function ()
144
- {
145
- test('clears the active preset hash so consumers know we deviated', function ()
146
- {
147
- _Presets.applyPreset('sketch');
148
- libExpect(_Presets.getActivePresetHash()).to.equal('sketch');
149
- _Presets.markCustomized();
150
- libExpect(_Presets.getActivePresetHash()).to.equal(null);
151
- });
152
- });
153
- });
@@ -1,138 +0,0 @@
1
- const libChai = require('chai');
2
- const libExpect = libChai.expect;
3
-
4
- const libPictViewFlow = require('../source/views/PictView-Flow.js');
5
- const libPictViewFlowToolbar = require('../source/views/PictView-Flow-Toolbar.js');
6
- const libPictViewFlowFloatingToolbar = require('../source/views/PictView-Flow-FloatingToolbar.js');
7
-
8
- // The toolbar custom-button API (ToolbarExtraButtons + onToolbarButton) lets a host add its own buttons
9
- // to the flow toolbar. They render in both the docked and the floating toolbar (so they survive every
10
- // toolbar mode) and, on click, fire the FlowView's onToolbarButton hook. These are harness-free unit
11
- // tests: the render-time stamping and the click dispatch are prototype methods called against light
12
- // stubs, so no DOM or full Pict app is needed.
13
- suite('Flow Toolbar custom buttons (ToolbarExtraButtons)',
14
- function ()
15
- {
16
- suite('default_configuration is additive + backward compatible',
17
- function ()
18
- {
19
- test('the flow view defaults to no extra buttons and no hook',
20
- function ()
21
- {
22
- libExpect(libPictViewFlow.default_configuration.ToolbarExtraButtons).to.be.an('array');
23
- libExpect(libPictViewFlow.default_configuration.ToolbarExtraButtons.length).to.equal(0);
24
- libExpect(libPictViewFlow.default_configuration.onToolbarButton).to.equal(false);
25
- });
26
-
27
- test('both toolbar views default to an empty extra-button list',
28
- function ()
29
- {
30
- libExpect(libPictViewFlowToolbar.default_configuration.ToolbarExtraButtons).to.be.an('array');
31
- libExpect(libPictViewFlowToolbar.default_configuration.ToolbarExtraButtons.length).to.equal(0);
32
- libExpect(libPictViewFlowFloatingToolbar.default_configuration.ToolbarExtraButtons).to.be.an('array');
33
- libExpect(libPictViewFlowFloatingToolbar.default_configuration.ToolbarExtraButtons.length).to.equal(0);
34
- });
35
-
36
- test('both toolbar templates render the extra-button group + row template',
37
- function ()
38
- {
39
- let tmpDockedTemplates = libPictViewFlowToolbar.default_configuration.Templates;
40
- let tmpDockedBar = tmpDockedTemplates.find((pT) => pT.Hash === 'Flow-Toolbar-Template');
41
- let tmpDockedRow = tmpDockedTemplates.find((pT) => pT.Hash === 'Flow-Toolbar-Extra-Button');
42
- libExpect(tmpDockedBar.Template).to.contain('{~TS:Flow-Toolbar-Extra-Button:Record.ToolbarExtraButtons~}');
43
- libExpect(tmpDockedRow).to.be.an('object');
44
- libExpect(tmpDockedRow.Template).to.contain('_handleExtraAction');
45
-
46
- let tmpFloatTemplates = libPictViewFlowFloatingToolbar.default_configuration.Templates;
47
- let tmpFloatBar = tmpFloatTemplates.find((pT) => pT.Hash === 'Flow-FloatingToolbar-Template');
48
- let tmpFloatRow = tmpFloatTemplates.find((pT) => pT.Hash === 'Flow-FloatingToolbar-Extra-Button');
49
- libExpect(tmpFloatBar.Template).to.contain('{~TS:Flow-FloatingToolbar-Extra-Button:Record.ToolbarExtraButtons~}');
50
- libExpect(tmpFloatRow).to.be.an('object');
51
- libExpect(tmpFloatRow.Template).to.contain('_handleExtraClick');
52
- });
53
- });
54
-
55
- suite('_stampExtraButtons (render-time per-row fields)',
56
- function ()
57
- {
58
- test('stamps FlowViewIdentifier and an empty ActiveClass onto each button',
59
- function ()
60
- {
61
- let tmpStub =
62
- {
63
- options:
64
- {
65
- FlowViewIdentifier: 'MB-FlowView-7',
66
- ToolbarExtraButtons: [ { Hash: 'background', Icon: 'background' }, { Hash: 'done', Icon: 'check' } ]
67
- }
68
- };
69
- libPictViewFlowToolbar.prototype._stampExtraButtons.call(tmpStub);
70
- libExpect(tmpStub.options.ToolbarExtraButtons[0].FlowViewIdentifier).to.equal('MB-FlowView-7');
71
- libExpect(tmpStub.options.ToolbarExtraButtons[0].ActiveClass).to.equal('');
72
- libExpect(tmpStub.options.ToolbarExtraButtons[1].FlowViewIdentifier).to.equal('MB-FlowView-7');
73
- });
74
-
75
- test('an Active button gets the active class',
76
- function ()
77
- {
78
- let tmpStub =
79
- {
80
- options:
81
- {
82
- FlowViewIdentifier: 'Pict-Flow',
83
- ToolbarExtraButtons: [ { Hash: 'edit', Icon: 'edit', Active: true } ]
84
- }
85
- };
86
- libPictViewFlowToolbar.prototype._stampExtraButtons.call(tmpStub);
87
- libExpect(tmpStub.options.ToolbarExtraButtons[0].ActiveClass).to.equal(' pict-flow-toolbar-btn-active');
88
- });
89
-
90
- test('a non-array extra-button option is tolerated',
91
- function ()
92
- {
93
- let tmpStub = { options: { FlowViewIdentifier: 'Pict-Flow', ToolbarExtraButtons: false } };
94
- libExpect(function () { libPictViewFlowToolbar.prototype._stampExtraButtons.call(tmpStub); }).to.not.throw();
95
- });
96
- });
97
-
98
- suite('click dispatch fires onToolbarButton(hash, element)',
99
- function ()
100
- {
101
- test('the docked toolbar routes a click to the FlowView hook with the element',
102
- function ()
103
- {
104
- let tmpFired = [];
105
- let tmpElement = { id: 'the-button' };
106
- let tmpStub =
107
- {
108
- _FlowView: { options: { onToolbarButton: (pHash, pEl) => { tmpFired.push({ Hash: pHash, El: pEl }); } } }
109
- };
110
- libPictViewFlowToolbar.prototype._handleExtraAction.call(tmpStub, 'background', tmpElement);
111
- libExpect(tmpFired.length).to.equal(1);
112
- libExpect(tmpFired[0].Hash).to.equal('background');
113
- libExpect(tmpFired[0].El).to.equal(tmpElement);
114
- });
115
-
116
- test('no hook configured is a no-op (does not throw)',
117
- function ()
118
- {
119
- let tmpStub = { _FlowView: { options: { onToolbarButton: false } } };
120
- libExpect(function () { libPictViewFlowToolbar.prototype._handleExtraAction.call(tmpStub, 'edit', {}); }).to.not.throw();
121
- });
122
-
123
- test('the floating toolbar routes its click through the docked toolbar dispatch',
124
- function ()
125
- {
126
- let tmpSeen = [];
127
- let tmpElement = { id: 'floating-button' };
128
- let tmpFloatStub =
129
- {
130
- _ToolbarView: { _handleExtraAction: (pHash, pEl) => { tmpSeen.push({ Hash: pHash, El: pEl }); } }
131
- };
132
- libPictViewFlowFloatingToolbar.prototype._handleExtraClick.call(tmpFloatStub, 'done', tmpElement);
133
- libExpect(tmpSeen.length).to.equal(1);
134
- libExpect(tmpSeen[0].Hash).to.equal('done');
135
- libExpect(tmpSeen[0].El).to.equal(tmpElement);
136
- });
137
- });
138
- });
@@ -1,70 +0,0 @@
1
- const libFable = require('fable');
2
- const libChai = require('chai');
3
- const libExpect = libChai.expect;
4
-
5
- const libInteractionManager = require('../source/services/PictService-Flow-InteractionManager.js');
6
- const STATES = libInteractionManager.INTERACTION_STATES;
7
-
8
- // EnableUndirectedConnections lets a connection be drawn between ANY two ports rather than only
9
- // output -> input. A free-form canvas (a moodboard) turns it on so a card's ports connect in any
10
- // direction; directed graphs (workflows) leave it off. These tests cover the start side of the drag
11
- // (the gate that previously hard-required an output port). The completion side uses
12
- // document.elementFromPoint, so it is exercised in the browser rather than here.
13
- function makeFlowView(pUndirected)
14
- {
15
- return {
16
- options: { EnableConnectionCreation: true, EnableUndirectedConnections: pUndirected },
17
- // Returning null skips the drag-line DOM creation, so no document is needed.
18
- getPortPosition: function () { return null; },
19
- _ViewportElement: { appendChild: function () {} }
20
- };
21
- }
22
-
23
- function makeManager(pFable, pFlowView)
24
- {
25
- let tmpManager = new libInteractionManager(pFable, { FlowView: pFlowView }, 'IM-Test');
26
- tmpManager._SVGElement = { classList: { add: function () {}, remove: function () {} } };
27
- return tmpManager;
28
- }
29
-
30
- function makePort(pNodeHash, pPortHash, pDirection)
31
- {
32
- let tmpAttrs = { 'data-node-hash': pNodeHash, 'data-port-hash': pPortHash, 'data-port-direction': pDirection };
33
- return { getAttribute: function (pName) { return Object.prototype.hasOwnProperty.call(tmpAttrs, pName) ? tmpAttrs[pName] : null; } };
34
- }
35
-
36
- suite('Flow undirected connections (EnableUndirectedConnections)',
37
- function ()
38
- {
39
- let _Fable;
40
- setup(function () { _Fable = new libFable({}); });
41
-
42
- test('directed mode (default): an input port does NOT start a connection',
43
- function ()
44
- {
45
- let tmpManager = makeManager(_Fable, makeFlowView(false));
46
- tmpManager._startConnection({ stopPropagation: function () {} }, makePort('n1', 'p1', 'input'));
47
- libExpect(tmpManager._State).to.not.equal(STATES.CONNECTING);
48
- });
49
-
50
- test('undirected mode: an input port DOES start a connection',
51
- function ()
52
- {
53
- let tmpManager = makeManager(_Fable, makeFlowView(true));
54
- tmpManager._startConnection({ stopPropagation: function () {} }, makePort('n1', 'p1', 'input'));
55
- libExpect(tmpManager._State).to.equal(STATES.CONNECTING);
56
- libExpect(tmpManager._ConnectSourceNodeHash).to.equal('n1');
57
- libExpect(tmpManager._ConnectSourcePortHash).to.equal('p1');
58
- });
59
-
60
- test('an output port starts a connection in either mode',
61
- function ()
62
- {
63
- [ false, true ].forEach(function (pUndirected)
64
- {
65
- let tmpManager = makeManager(_Fable, makeFlowView(pUndirected));
66
- tmpManager._startConnection({ stopPropagation: function () {} }, makePort('n1', 'p1', 'output'));
67
- libExpect(tmpManager._State).to.equal(STATES.CONNECTING);
68
- });
69
- });
70
- });