pict-section-flow 0.0.10 → 0.0.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 (88) hide show
  1. package/.claude/launch.json +1 -1
  2. package/README.md +176 -0
  3. package/docs/.nojekyll +0 -0
  4. package/docs/Architecture.md +303 -0
  5. package/docs/Custom-Styling.md +275 -0
  6. package/docs/Data_Model.md +158 -0
  7. package/docs/Event_System.md +156 -0
  8. package/docs/Getting_Started.md +237 -0
  9. package/docs/Implementation_Reference.md +528 -0
  10. package/docs/Layout_Persistence.md +117 -0
  11. package/docs/README.md +115 -52
  12. package/docs/_cover.md +11 -0
  13. package/docs/_sidebar.md +52 -0
  14. package/docs/_topbar.md +8 -0
  15. package/docs/api/PictFlowCard.md +216 -0
  16. package/docs/api/PictFlowCardPropertiesPanel.md +235 -0
  17. package/docs/api/addConnection.md +101 -0
  18. package/docs/api/addNode.md +137 -0
  19. package/docs/api/autoLayout.md +77 -0
  20. package/docs/api/getFlowData.md +112 -0
  21. package/docs/api/marshalToView.md +95 -0
  22. package/docs/api/openPanel.md +128 -0
  23. package/docs/api/registerHandler.md +174 -0
  24. package/docs/api/registerNodeType.md +142 -0
  25. package/docs/api/removeConnection.md +57 -0
  26. package/docs/api/removeNode.md +80 -0
  27. package/docs/api/saveLayout.md +152 -0
  28. package/docs/api/screenToSVGCoords.md +68 -0
  29. package/docs/api/selectNode.md +116 -0
  30. package/docs/api/setTheme.md +168 -0
  31. package/docs/api/setZoom.md +97 -0
  32. package/docs/api/toggleFullscreen.md +68 -0
  33. package/docs/card-help/EACH.md +19 -0
  34. package/docs/card-help/FREAD.md +24 -0
  35. package/docs/card-help/FWRITE.md +24 -0
  36. package/docs/card-help/GET.md +22 -0
  37. package/docs/card-help/ITE.md +23 -0
  38. package/docs/card-help/LOG.md +23 -0
  39. package/docs/card-help/NOTE.md +17 -0
  40. package/docs/card-help/PREV.md +18 -0
  41. package/docs/card-help/SET.md +27 -0
  42. package/docs/card-help/SPKL.md +22 -0
  43. package/docs/card-help/STAT.md +23 -0
  44. package/docs/card-help/SW.md +25 -0
  45. package/docs/css/docuserve.css +73 -0
  46. package/docs/index.html +39 -0
  47. package/docs/retold-catalog.json +169 -0
  48. package/docs/retold-keyword-index.json +13942 -0
  49. package/example_applications/simple_cards/package.json +1 -0
  50. package/example_applications/simple_cards/source/card-help-content.js +16 -0
  51. package/example_applications/simple_cards/source/cards/FlowCard-Comment.js +2 -0
  52. package/example_applications/simple_cards/source/cards/FlowCard-DataPreview.js +2 -0
  53. package/example_applications/simple_cards/source/cards/FlowCard-Each.js +2 -0
  54. package/example_applications/simple_cards/source/cards/FlowCard-FileRead.js +2 -0
  55. package/example_applications/simple_cards/source/cards/FlowCard-FileWrite.js +2 -0
  56. package/example_applications/simple_cards/source/cards/FlowCard-GetValue.js +2 -0
  57. package/example_applications/simple_cards/source/cards/FlowCard-IfThenElse.js +2 -0
  58. package/example_applications/simple_cards/source/cards/FlowCard-LogValues.js +2 -0
  59. package/example_applications/simple_cards/source/cards/FlowCard-SetValue.js +2 -0
  60. package/example_applications/simple_cards/source/cards/FlowCard-Sparkline.js +2 -0
  61. package/example_applications/simple_cards/source/cards/FlowCard-StatusMonitor.js +2 -0
  62. package/example_applications/simple_cards/source/cards/FlowCard-Switch.js +2 -0
  63. package/package.json +11 -7
  64. package/scripts/generate-card-help.js +214 -0
  65. package/source/Pict-Section-Flow.js +4 -0
  66. package/source/PictFlowCard.js +3 -1
  67. package/source/providers/PictProvider-Flow-CSS.js +245 -152
  68. package/source/providers/PictProvider-Flow-ConnectorShapes.js +24 -0
  69. package/source/providers/PictProvider-Flow-Geometry.js +195 -38
  70. package/source/providers/PictProvider-Flow-PanelChrome.js +14 -12
  71. package/source/services/PictService-Flow-ConnectionHandleManager.js +263 -0
  72. package/source/services/PictService-Flow-ConnectionRenderer.js +134 -183
  73. package/source/services/PictService-Flow-DataManager.js +338 -0
  74. package/source/services/PictService-Flow-InteractionManager.js +165 -7
  75. package/source/services/PictService-Flow-PathGenerator.js +282 -0
  76. package/source/services/PictService-Flow-PortRenderer.js +269 -0
  77. package/source/services/PictService-Flow-RenderManager.js +281 -0
  78. package/source/services/PictService-Flow-Tether.js +6 -42
  79. package/source/views/PictView-Flow-Node.js +2 -220
  80. package/source/views/PictView-Flow-PropertiesPanel.js +89 -44
  81. package/source/views/PictView-Flow.js +130 -882
  82. package/test/ConnectionHandleManager_tests.js +717 -0
  83. package/test/ConnectionRenderer_tests.js +591 -0
  84. package/test/DataManager_tests.js +859 -0
  85. package/test/Geometry_tests.js +767 -0
  86. package/test/PathGenerator_tests.js +978 -0
  87. package/test/PortRenderer_tests.js +367 -0
  88. package/test/RenderManager_tests.js +756 -0
@@ -0,0 +1,367 @@
1
+ const libFable = require('fable');
2
+ const libChai = require('chai');
3
+ const libExpect = libChai.expect;
4
+
5
+ const libPortRenderer = require('../source/services/PictService-Flow-PortRenderer.js');
6
+ const libGeometry = require('../source/providers/PictProvider-Flow-Geometry.js');
7
+
8
+ suite
9
+ (
10
+ 'PictService-Flow-PortRenderer',
11
+ function ()
12
+ {
13
+ let _Fable;
14
+ let _PortRenderer;
15
+ let _GeometryProvider;
16
+ let _MockFlowView;
17
+
18
+ // Simple mock SVG element for testing
19
+ function createMockSVGElement()
20
+ {
21
+ let tmpSelf =
22
+ {
23
+ _tag: '',
24
+ _attrs: {},
25
+ _children: [],
26
+ textContent: '',
27
+ setAttribute: function (pKey, pVal)
28
+ {
29
+ tmpSelf._attrs[pKey] = pVal;
30
+ },
31
+ getAttribute: function (pKey)
32
+ {
33
+ return tmpSelf._attrs[pKey] || null;
34
+ },
35
+ appendChild: function (pChild)
36
+ {
37
+ tmpSelf._children.push(pChild);
38
+ }
39
+ };
40
+ return tmpSelf;
41
+ }
42
+
43
+ setup
44
+ (
45
+ function ()
46
+ {
47
+ _Fable = new libFable({});
48
+
49
+ _GeometryProvider = new libGeometry(_Fable, {}, 'Geometry-Test');
50
+
51
+ _MockFlowView =
52
+ {
53
+ _GeometryProvider: _GeometryProvider,
54
+ _ConnectorShapesProvider: null,
55
+ _SVGHelperProvider:
56
+ {
57
+ createSVGElement: function (pTag)
58
+ {
59
+ let tmpEl = createMockSVGElement();
60
+ tmpEl._tag = pTag;
61
+ return tmpEl;
62
+ }
63
+ }
64
+ };
65
+
66
+ _PortRenderer = new libPortRenderer(
67
+ _Fable, { FlowView: _MockFlowView }, 'PortRend-Test');
68
+ }
69
+ );
70
+
71
+ // ---- Constructor ----
72
+
73
+ suite
74
+ (
75
+ 'Constructor',
76
+ function ()
77
+ {
78
+ test
79
+ (
80
+ 'should instantiate with correct serviceType',
81
+ function (fDone)
82
+ {
83
+ libExpect(_PortRenderer.serviceType).to.equal('PictServiceFlowPortRenderer');
84
+ fDone();
85
+ }
86
+ );
87
+
88
+ test
89
+ (
90
+ 'should store FlowView reference',
91
+ function (fDone)
92
+ {
93
+ libExpect(_PortRenderer._FlowView).to.equal(_MockFlowView);
94
+ fDone();
95
+ }
96
+ );
97
+
98
+ test
99
+ (
100
+ 'should handle missing FlowView',
101
+ function (fDone)
102
+ {
103
+ let tmpRenderer = new libPortRenderer(_Fable, {}, 'NoView');
104
+ libExpect(tmpRenderer._FlowView).to.be.null;
105
+ fDone();
106
+ }
107
+ );
108
+ }
109
+ );
110
+
111
+ // ---- renderPorts ----
112
+
113
+ suite
114
+ (
115
+ 'renderPorts',
116
+ function ()
117
+ {
118
+ test
119
+ (
120
+ 'should render port circles into the group',
121
+ function (fDone)
122
+ {
123
+ let tmpGroup = createMockSVGElement();
124
+ let tmpNodeData =
125
+ {
126
+ Hash: 'node-1',
127
+ Ports:
128
+ [
129
+ { Hash: 'p1', Direction: 'input', Label: null },
130
+ { Hash: 'p2', Direction: 'output', Label: null }
131
+ ]
132
+ };
133
+
134
+ _PortRenderer.renderPorts(tmpNodeData, tmpGroup, 180, 80, null, 22);
135
+
136
+ // Should have appended port circle elements
137
+ libExpect(tmpGroup._children.length).to.be.at.least(2);
138
+
139
+ // Verify at least one circle element was created
140
+ let tmpCircles = tmpGroup._children.filter(function (pChild)
141
+ {
142
+ return pChild._tag === 'circle';
143
+ });
144
+ libExpect(tmpCircles.length).to.equal(2);
145
+ fDone();
146
+ }
147
+ );
148
+
149
+ test
150
+ (
151
+ 'should render port labels when Label is set',
152
+ function (fDone)
153
+ {
154
+ let tmpGroup = createMockSVGElement();
155
+ let tmpNodeData =
156
+ {
157
+ Hash: 'node-2',
158
+ Ports:
159
+ [
160
+ { Hash: 'p1', Direction: 'input', Label: 'Trigger' }
161
+ ]
162
+ };
163
+
164
+ _PortRenderer.renderPorts(tmpNodeData, tmpGroup, 180, 80, null, 22);
165
+
166
+ // Should have badge bg, border path, stripe, circle, text = 5 elements
167
+ libExpect(tmpGroup._children.length).to.equal(5);
168
+
169
+ // Verify text element exists with correct content
170
+ let tmpTextEls = tmpGroup._children.filter(function (pChild)
171
+ {
172
+ return pChild._tag === 'text';
173
+ });
174
+ libExpect(tmpTextEls.length).to.equal(1);
175
+ libExpect(tmpTextEls[0].textContent).to.equal('Trigger');
176
+ fDone();
177
+ }
178
+ );
179
+
180
+ test
181
+ (
182
+ 'should do nothing for empty ports array',
183
+ function (fDone)
184
+ {
185
+ let tmpGroup = createMockSVGElement();
186
+ let tmpNodeData = { Hash: 'node-3', Ports: [] };
187
+
188
+ _PortRenderer.renderPorts(tmpNodeData, tmpGroup, 180, 80, null, 22);
189
+
190
+ libExpect(tmpGroup._children.length).to.equal(0);
191
+ fDone();
192
+ }
193
+ );
194
+
195
+ test
196
+ (
197
+ 'should do nothing when Ports is missing',
198
+ function (fDone)
199
+ {
200
+ let tmpGroup = createMockSVGElement();
201
+ let tmpNodeData = { Hash: 'node-4' };
202
+
203
+ _PortRenderer.renderPorts(tmpNodeData, tmpGroup, 180, 80, null, 22);
204
+
205
+ libExpect(tmpGroup._children.length).to.equal(0);
206
+ fDone();
207
+ }
208
+ );
209
+
210
+ test
211
+ (
212
+ 'should do nothing when no FlowView',
213
+ function (fDone)
214
+ {
215
+ let tmpRenderer = new libPortRenderer(_Fable, {}, 'NoView');
216
+ let tmpGroup = createMockSVGElement();
217
+ let tmpNodeData =
218
+ {
219
+ Hash: 'node-5',
220
+ Ports: [{ Hash: 'p1', Direction: 'input' }]
221
+ };
222
+
223
+ tmpRenderer.renderPorts(tmpNodeData, tmpGroup, 180, 80, null, 22);
224
+ libExpect(tmpGroup._children.length).to.equal(0);
225
+ fDone();
226
+ }
227
+ );
228
+
229
+ test
230
+ (
231
+ 'should use ConnectorShapesProvider when available',
232
+ function (fDone)
233
+ {
234
+ let tmpCreatePortCalled = false;
235
+ _MockFlowView._ConnectorShapesProvider =
236
+ {
237
+ createPortElement: function (pPort, pPos, pNodeHash)
238
+ {
239
+ tmpCreatePortCalled = true;
240
+ let tmpEl = createMockSVGElement();
241
+ tmpEl._tag = 'circle';
242
+ return tmpEl;
243
+ }
244
+ };
245
+
246
+ let tmpGroup = createMockSVGElement();
247
+ let tmpNodeData =
248
+ {
249
+ Hash: 'node-6',
250
+ Ports: [{ Hash: 'p1', Direction: 'input' }]
251
+ };
252
+
253
+ _PortRenderer.renderPorts(tmpNodeData, tmpGroup, 180, 80, null, 22);
254
+ libExpect(tmpCreatePortCalled).to.be.true;
255
+
256
+ // Clean up
257
+ _MockFlowView._ConnectorShapesProvider = null;
258
+ fDone();
259
+ }
260
+ );
261
+
262
+ test
263
+ (
264
+ 'should set port-type data attribute when PortType is set',
265
+ function (fDone)
266
+ {
267
+ let tmpGroup = createMockSVGElement();
268
+ let tmpNodeData =
269
+ {
270
+ Hash: 'node-7',
271
+ Ports:
272
+ [
273
+ { Hash: 'p1', Direction: 'input', PortType: 'event-in' }
274
+ ]
275
+ };
276
+
277
+ _PortRenderer.renderPorts(tmpNodeData, tmpGroup, 180, 80, null, 22);
278
+
279
+ let tmpCircles = tmpGroup._children.filter(function (pChild)
280
+ {
281
+ return pChild._tag === 'circle';
282
+ });
283
+ libExpect(tmpCircles.length).to.equal(1);
284
+ libExpect(tmpCircles[0]._attrs['data-port-type']).to.equal('event-in');
285
+ fDone();
286
+ }
287
+ );
288
+
289
+ test
290
+ (
291
+ 'should group ports by Side value',
292
+ function (fDone)
293
+ {
294
+ let tmpGroup = createMockSVGElement();
295
+ let tmpNodeData =
296
+ {
297
+ Hash: 'node-8',
298
+ Ports:
299
+ [
300
+ { Hash: 'p1', Direction: 'input', Side: 'left' },
301
+ { Hash: 'p2', Direction: 'input', Side: 'left' },
302
+ { Hash: 'p3', Direction: 'output', Side: 'right' },
303
+ { Hash: 'p4', Direction: 'output', Side: 'bottom' }
304
+ ]
305
+ };
306
+
307
+ _PortRenderer.renderPorts(tmpNodeData, tmpGroup, 180, 80, null, 22);
308
+
309
+ let tmpCircles = tmpGroup._children.filter(function (pChild)
310
+ {
311
+ return pChild._tag === 'circle';
312
+ });
313
+ libExpect(tmpCircles.length).to.equal(4);
314
+ fDone();
315
+ }
316
+ );
317
+ }
318
+ );
319
+
320
+ // ---- getPortLocalPosition ----
321
+
322
+ suite
323
+ (
324
+ 'getPortLocalPosition',
325
+ function ()
326
+ {
327
+ test
328
+ (
329
+ 'should delegate to GeometryProvider',
330
+ function (fDone)
331
+ {
332
+ let tmpPos = _PortRenderer.getPortLocalPosition('left', 0, 1, 180, 80, 22, {});
333
+
334
+ libExpect(tmpPos).to.have.property('x');
335
+ libExpect(tmpPos).to.have.property('y');
336
+ libExpect(tmpPos.x).to.equal(0); // left edge
337
+ fDone();
338
+ }
339
+ );
340
+
341
+ test
342
+ (
343
+ 'should return right edge position',
344
+ function (fDone)
345
+ {
346
+ let tmpPos = _PortRenderer.getPortLocalPosition('right', 0, 1, 180, 80, 22, {});
347
+
348
+ libExpect(tmpPos.x).to.equal(180); // right edge
349
+ fDone();
350
+ }
351
+ );
352
+
353
+ test
354
+ (
355
+ 'should pass title bar height correctly',
356
+ function (fDone)
357
+ {
358
+ // Port should be below the title bar
359
+ let tmpPos = _PortRenderer.getPortLocalPosition('left', 0, 1, 180, 80, 22, {});
360
+ libExpect(tmpPos.y).to.be.greaterThan(22);
361
+ fDone();
362
+ }
363
+ );
364
+ }
365
+ );
366
+ }
367
+ );