pict-section-flow 1.3.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.
- package/package.json +7 -2
- package/source/Pict-Section-Flow.js +20 -14
- package/source/providers/PictProvider-Flow-Background.js +303 -0
- package/source/providers/PictProvider-Flow-CSS.js +99 -7
- package/source/providers/PictProvider-Flow-ConnectorShapes.js +8 -0
- package/source/providers/PictProvider-Flow-Geometry.js +11 -421
- package/source/providers/PictProvider-Flow-Icons.js +20 -0
- package/source/providers/PictProvider-Flow-Layouts.js +107 -0
- package/source/services/PictService-Flow-ConnectionRenderer.js +77 -5
- package/source/services/PictService-Flow-CursorManager.js +113 -0
- package/source/services/PictService-Flow-InteractionManager.js +443 -61
- package/source/services/PictService-Flow-Layout.js +21 -16
- package/source/services/PictService-Flow-PathGenerator.js +30 -417
- package/source/services/PictService-Flow-RenderManager.js +9 -1
- package/source/services/PictService-Flow-ViewportManager.js +102 -0
- package/source/views/PictView-Flow-FloatingToolbar.js +57 -0
- package/source/views/PictView-Flow-Node.js +36 -0
- package/source/views/PictView-Flow-PropertiesPanel.js +27 -5
- package/source/views/PictView-Flow-Toolbar.js +148 -13
- package/source/views/PictView-Flow.js +628 -3
- package/.claude/launch.json +0 -11
- package/docs/.nojekyll +0 -0
- package/docs/Architecture.md +0 -163
- package/docs/Custom-Styling.md +0 -275
- package/docs/Data_Model.md +0 -149
- package/docs/Event_System.md +0 -156
- package/docs/Getting_Started.md +0 -237
- package/docs/Implementation_Reference.md +0 -528
- package/docs/Layout_Persistence.md +0 -117
- package/docs/README.md +0 -103
- package/docs/Theme_Integration.md +0 -150
- package/docs/_brand.json +0 -18
- package/docs/_cover.md +0 -17
- package/docs/_playground.json +0 -24
- package/docs/_sidebar.md +0 -57
- package/docs/_topbar.md +0 -8
- package/docs/_version.json +0 -7
- package/docs/api/PictFlowCard.md +0 -216
- package/docs/api/PictFlowCardPropertiesPanel.md +0 -235
- package/docs/api/addConnection.md +0 -101
- package/docs/api/addNode.md +0 -137
- package/docs/api/autoLayout.md +0 -77
- package/docs/api/getFlowData.md +0 -112
- package/docs/api/marshalToView.md +0 -95
- package/docs/api/openPanel.md +0 -128
- package/docs/api/registerHandler.md +0 -174
- package/docs/api/registerNodeType.md +0 -142
- package/docs/api/removeConnection.md +0 -57
- package/docs/api/removeNode.md +0 -80
- package/docs/api/saveLayout.md +0 -152
- package/docs/api/screenToSVGCoords.md +0 -68
- package/docs/api/selectNode.md +0 -116
- package/docs/api/setTheme.md +0 -168
- package/docs/api/setZoom.md +0 -97
- package/docs/api/toggleFullscreen.md +0 -68
- package/docs/card-help/EACH.md +0 -19
- package/docs/card-help/FREAD.md +0 -24
- package/docs/card-help/FWRITE.md +0 -24
- package/docs/card-help/GET.md +0 -22
- package/docs/card-help/ITE.md +0 -23
- package/docs/card-help/LOG.md +0 -23
- package/docs/card-help/NOTE.md +0 -17
- package/docs/card-help/PREV.md +0 -18
- package/docs/card-help/SET.md +0 -27
- package/docs/card-help/SPKL.md +0 -22
- package/docs/card-help/STAT.md +0 -23
- package/docs/card-help/SW.md +0 -25
- package/docs/diagrams/architecture-at-a-glance.excalidraw +0 -4270
- package/docs/diagrams/architecture-at-a-glance.mmd +0 -30
- package/docs/diagrams/architecture-at-a-glance.svg +0 -2
- package/docs/diagrams/data-flow.excalidraw +0 -1451
- package/docs/diagrams/data-flow.mmd +0 -17
- package/docs/diagrams/data-flow.svg +0 -2
- package/docs/diagrams/high-level-design.excalidraw +0 -5767
- package/docs/diagrams/high-level-design.mmd +0 -86
- package/docs/diagrams/high-level-design.svg +0 -2
- package/docs/diagrams/relationships.excalidraw +0 -3852
- package/docs/diagrams/relationships.mmd +0 -9
- package/docs/diagrams/relationships.svg +0 -2
- package/docs/diagrams/service-initialization-sequence.excalidraw +0 -1466
- package/docs/diagrams/service-initialization-sequence.mmd +0 -19
- package/docs/diagrams/service-initialization-sequence.svg +0 -2
- package/docs/diagrams/svg-layer-structure.excalidraw +0 -1060
- package/docs/diagrams/svg-layer-structure.mmd +0 -18
- package/docs/diagrams/svg-layer-structure.svg +0 -2
- package/docs/examples/README.md +0 -9
- package/docs/examples/simple_cards/README.md +0 -677
- package/docs/examples/simple_cards/css/flowexample.css +0 -65
- package/docs/examples/simple_cards/index.html +0 -32
- package/docs/examples/simple_cards/js/pict.min.js +0 -12
- package/docs/examples/simple_cards/pict-section-flow-example-simple-cards.compatible.min.js +0 -1
- package/docs/index.html +0 -38
- package/docs/playground/app.json +0 -6
- package/docs/playground/appdata.json +0 -85
- package/docs/playground/application.js +0 -23
- package/docs/playground/pict.json +0 -17
- package/docs/playground/runtime/pict-application.min.js +0 -2
- package/docs/playground/runtime/pict-section-flow.min.js +0 -2
- package/docs/playground/runtime/pict-section-modal.min.js +0 -2
- package/docs/playground/runtime/pict.min.js +0 -12
- package/docs/retold-catalog.json +0 -244
- package/docs/retold-keyword-index.json +0 -26028
- package/example_applications/simple_cards/css/flowexample.css +0 -65
- package/example_applications/simple_cards/html/index.html +0 -32
- package/example_applications/simple_cards/package.json +0 -52
- package/example_applications/simple_cards/source/Pict-Application-FlowExample-Configuration.json +0 -15
- package/example_applications/simple_cards/source/Pict-Application-FlowExample.js +0 -539
- package/example_applications/simple_cards/source/card-help-content.js +0 -16
- package/example_applications/simple_cards/source/cards/FlowCard-Comment.js +0 -38
- package/example_applications/simple_cards/source/cards/FlowCard-DataPreview.js +0 -44
- package/example_applications/simple_cards/source/cards/FlowCard-Each.js +0 -38
- package/example_applications/simple_cards/source/cards/FlowCard-FileRead.js +0 -56
- package/example_applications/simple_cards/source/cards/FlowCard-FileWrite.js +0 -50
- package/example_applications/simple_cards/source/cards/FlowCard-GetValue.js +0 -37
- package/example_applications/simple_cards/source/cards/FlowCard-IfThenElse.js +0 -49
- package/example_applications/simple_cards/source/cards/FlowCard-LogValues.js +0 -55
- package/example_applications/simple_cards/source/cards/FlowCard-SetValue.js +0 -97
- package/example_applications/simple_cards/source/cards/FlowCard-Sparkline.js +0 -100
- package/example_applications/simple_cards/source/cards/FlowCard-StatusMonitor.js +0 -46
- package/example_applications/simple_cards/source/cards/FlowCard-Switch.js +0 -39
- package/example_applications/simple_cards/source/providers/PictRouter-FlowExample-Configuration.json +0 -22
- package/example_applications/simple_cards/source/sample-flows.js +0 -410
- package/example_applications/simple_cards/source/views/PictView-FlowExample-About.js +0 -184
- package/example_applications/simple_cards/source/views/PictView-FlowExample-BottomBar.js +0 -77
- package/example_applications/simple_cards/source/views/PictView-FlowExample-Documentation.js +0 -325
- package/example_applications/simple_cards/source/views/PictView-FlowExample-FileWriteInfo.js +0 -59
- package/example_applications/simple_cards/source/views/PictView-FlowExample-Layout.js +0 -90
- package/example_applications/simple_cards/source/views/PictView-FlowExample-MainWorkspace.js +0 -453
- package/example_applications/simple_cards/source/views/PictView-FlowExample-TopBar.js +0 -95
- package/scripts/generate-card-help.js +0 -214
- package/source/providers/edges/Edge-Bezier.js +0 -41
- package/source/providers/edges/Edge-Orthogonal.js +0 -37
- package/source/providers/edges/Edge-OrthogonalSnap.js +0 -72
- package/source/providers/edges/Edge-Perimeter-Linear.js +0 -31
- package/source/providers/edges/Edge-Perimeter-Orthogonal.js +0 -39
- package/source/providers/edges/Edge-Perimeter.js +0 -48
- package/source/providers/edges/Edge-PerimeterMath.js +0 -92
- package/source/providers/edges/Edge-Straight.js +0 -24
- package/source/providers/layouts/Layout-Circular.js +0 -203
- package/source/providers/layouts/Layout-Coerce.js +0 -40
- package/source/providers/layouts/Layout-Columnar.js +0 -134
- package/source/providers/layouts/Layout-Custom.js +0 -27
- package/source/providers/layouts/Layout-ForcedFromCenter.js +0 -256
- package/source/providers/layouts/Layout-Grid.js +0 -134
- package/source/providers/layouts/Layout-Layered.js +0 -155
- package/source/providers/layouts/Layout-Rank.js +0 -141
- package/source/providers/layouts/Layout-Staggered.js +0 -131
- package/source/providers/layouts/Layout-Tabular.js +0 -94
- package/test/ConnectionHandleManager_tests.js +0 -717
- package/test/ConnectionRenderer_tests.js +0 -591
- package/test/DataManager_tests.js +0 -859
- package/test/Geometry_tests.js +0 -767
- package/test/InteractionManager_tests.js +0 -279
- package/test/Layout_tests.js +0 -1604
- package/test/NodeView_tests.js +0 -66
- package/test/PanelManager_tests.js +0 -172
- package/test/PathGenerator_tests.js +0 -978
- package/test/PortRenderer_tests.js +0 -376
- package/test/RenderManager_tests.js +0 -756
- package/test/Renderer_tests.js +0 -133
- package/test/SelectionManager_tests.js +0 -185
- package/test/StylePresets_tests.js +0 -153
|
@@ -11,6 +11,10 @@ const _DefaultConfiguration =
|
|
|
11
11
|
|
|
12
12
|
FlowViewIdentifier: 'Pict-Flow',
|
|
13
13
|
|
|
14
|
+
// Host-supplied buttons (mirrors the docked toolbar's ToolbarExtraButtons), so floating mode keeps
|
|
15
|
+
// the same custom buttons. Each entry is { Hash, Icon, Label?, Tooltip?, Active? }.
|
|
16
|
+
ToolbarExtraButtons: [],
|
|
17
|
+
|
|
14
18
|
CSS: false,
|
|
15
19
|
|
|
16
20
|
Templates:
|
|
@@ -64,6 +68,7 @@ const _DefaultConfiguration =
|
|
|
64
68
|
onclick="_Pict.views['{~D:Record.FlowViewIdentifier~}']._ToolbarView._FloatingToolbarView._handleButtonClick('fullscreen')">
|
|
65
69
|
<span id="Flow-FloatingIcon-fullscreen-{~D:Record.FlowViewIdentifier~}"></span>
|
|
66
70
|
</button>
|
|
71
|
+
{~TS:Flow-FloatingToolbar-Extra-Button:Record.ToolbarExtraButtons~}
|
|
67
72
|
<div class="pict-flow-floating-separator"></div>
|
|
68
73
|
<button class="pict-flow-floating-btn" data-flow-action="dock-toolbar" title="Dock Toolbar"
|
|
69
74
|
onclick="_Pict.views['{~D:Record.FlowViewIdentifier~}']._ToolbarView._FloatingToolbarView._handleButtonClick('dock-toolbar')">
|
|
@@ -71,6 +76,16 @@ const _DefaultConfiguration =
|
|
|
71
76
|
</button>
|
|
72
77
|
</div>
|
|
73
78
|
`
|
|
79
|
+
},
|
|
80
|
+
{
|
|
81
|
+
Hash: 'Flow-FloatingToolbar-Extra-Button',
|
|
82
|
+
// Icon-only host button (the floating toolbar is compact). Icon span
|
|
83
|
+
// is filled post-render by _populateIcons (keyed by Hash).
|
|
84
|
+
Template: /*html*/`<button class="pict-flow-floating-btn{~D:Record.ToggleClass~}{~D:Record.ActiveClass~}" title="{~D:Record.Tooltip~}" data-flow-action="extra" data-extra-hash="{~D:Record.Hash~}"
|
|
85
|
+
onclick="_Pict.views['{~D:Record.FlowViewIdentifier~}']._ToolbarView._FloatingToolbarView._handleExtraClick('{~D:Record.Hash~}', this)">
|
|
86
|
+
<span id="Flow-FloatingExtraIcon-{~D:Record.Hash~}-{~D:Record.FlowViewIdentifier~}"></span>
|
|
87
|
+
<span class="pict-flow-toolbar-btn-led" aria-hidden="true"></span>
|
|
88
|
+
</button>`
|
|
74
89
|
}
|
|
75
90
|
],
|
|
76
91
|
|
|
@@ -111,9 +126,37 @@ class PictViewFlowFloatingToolbar extends libPictView
|
|
|
111
126
|
|
|
112
127
|
render(pRenderableHash, pRenderDestinationAddress, pTemplateRecordAddress)
|
|
113
128
|
{
|
|
129
|
+
// Stamp the owning view onto each host button so its row resolves.
|
|
130
|
+
let tmpExtraButtons = this.options.ToolbarExtraButtons;
|
|
131
|
+
if (Array.isArray(tmpExtraButtons))
|
|
132
|
+
{
|
|
133
|
+
for (let i = 0; i < tmpExtraButtons.length; i++)
|
|
134
|
+
{
|
|
135
|
+
tmpExtraButtons[i].FlowViewIdentifier = this.options.FlowViewIdentifier;
|
|
136
|
+
// Mirror the docked toolbar so toggle buttons show the same status LED here.
|
|
137
|
+
tmpExtraButtons[i].ToggleClass = tmpExtraButtons[i].Toggle ? ' pict-flow-toolbar-btn-toggle' : '';
|
|
138
|
+
tmpExtraButtons[i].ActiveClass = tmpExtraButtons[i].Active ? ' pict-flow-toolbar-btn-active' : '';
|
|
139
|
+
}
|
|
140
|
+
}
|
|
114
141
|
return super.render(pRenderableHash, pRenderDestinationAddress, this.options);
|
|
115
142
|
}
|
|
116
143
|
|
|
144
|
+
/**
|
|
145
|
+
* Handle a click on a host-supplied (ToolbarExtraButtons) floating button.
|
|
146
|
+
* Routes to the docked toolbar's _handleExtraAction (the single dispatch
|
|
147
|
+
* point that fires the FlowView's onToolbarButton hook).
|
|
148
|
+
*
|
|
149
|
+
* @param {string} pHash - The button's Hash
|
|
150
|
+
* @param {HTMLElement} pElement - The clicked button element
|
|
151
|
+
*/
|
|
152
|
+
_handleExtraClick(pHash, pElement)
|
|
153
|
+
{
|
|
154
|
+
if (this._ToolbarView)
|
|
155
|
+
{
|
|
156
|
+
this._ToolbarView._handleExtraAction(pHash, pElement);
|
|
157
|
+
}
|
|
158
|
+
}
|
|
159
|
+
|
|
117
160
|
onAfterRender(pRenderable, pRenderDestinationAddress, pRecord, pContent)
|
|
118
161
|
{
|
|
119
162
|
let tmpFlowViewIdentifier = this.options.FlowViewIdentifier;
|
|
@@ -222,6 +265,20 @@ class PictViewFlowFloatingToolbar extends libPictView
|
|
|
222
265
|
tmpElements[0].innerHTML = tmpIconProvider.getIconSVGMarkup(tmpIconMap[tmpKeys[i]], 16);
|
|
223
266
|
}
|
|
224
267
|
}
|
|
268
|
+
|
|
269
|
+
// Host-supplied extra buttons (keyed by Hash, icon from the button's Icon key).
|
|
270
|
+
let tmpExtraButtons = this.options.ToolbarExtraButtons;
|
|
271
|
+
if (Array.isArray(tmpExtraButtons))
|
|
272
|
+
{
|
|
273
|
+
for (let i = 0; i < tmpExtraButtons.length; i++)
|
|
274
|
+
{
|
|
275
|
+
let tmpExtraIcon = this.pict.ContentAssignment.getElement(`#Flow-FloatingExtraIcon-${tmpExtraButtons[i].Hash}-${tmpFlowViewIdentifier}`);
|
|
276
|
+
if (tmpExtraIcon.length > 0)
|
|
277
|
+
{
|
|
278
|
+
tmpExtraIcon[0].innerHTML = tmpIconProvider.getIconSVGMarkup(tmpExtraButtons[i].Icon, 16);
|
|
279
|
+
}
|
|
280
|
+
}
|
|
281
|
+
}
|
|
225
282
|
}
|
|
226
283
|
|
|
227
284
|
/**
|
|
@@ -52,6 +52,13 @@ class PictViewFlowNode extends libPictView
|
|
|
52
52
|
{
|
|
53
53
|
tmpClassList += ' pict-flow-node-color-' + tmpColorRole;
|
|
54
54
|
}
|
|
55
|
+
// A host can stamp an extra CSS class onto a node via node.NodeClass (e.g. a moodboard marks a
|
|
56
|
+
// card whose connection points should stay visible on a read-only board). Survives re-renders
|
|
57
|
+
// because it lives on the node data.
|
|
58
|
+
if (typeof pNodeData.NodeClass === 'string' && pNodeData.NodeClass)
|
|
59
|
+
{
|
|
60
|
+
tmpClassList += ' ' + pNodeData.NodeClass;
|
|
61
|
+
}
|
|
55
62
|
tmpGroup.setAttribute('class', tmpClassList);
|
|
56
63
|
tmpGroup.setAttribute('transform', `translate(${pNodeData.X}, ${pNodeData.Y})`);
|
|
57
64
|
tmpGroup.setAttribute('data-node-hash', pNodeData.Hash);
|
|
@@ -339,6 +346,35 @@ class PictViewFlowNode extends libPictView
|
|
|
339
346
|
tmpGroup.appendChild(tmpHandle);
|
|
340
347
|
}
|
|
341
348
|
|
|
349
|
+
// Rotate handle: a grip on a short arm above the node, shown when this node is selected, the
|
|
350
|
+
// flow allows rotation, and we are not read-only. Its data-element-type routes pointer-down to
|
|
351
|
+
// the InteractionManager's node-rotate path. Lives in node-local space, so it orbits with the card.
|
|
352
|
+
if (pIsSelected && this._FlowView.options && this._FlowView.options.EnableNodeRotation
|
|
353
|
+
&& !(typeof this._FlowView.isReadOnly === 'function' && this._FlowView.isReadOnly()))
|
|
354
|
+
{
|
|
355
|
+
let tmpArmLength = 22;
|
|
356
|
+
let tmpRotateCenterX = tmpWidth / 2;
|
|
357
|
+
|
|
358
|
+
let tmpArm = this._FlowView._SVGHelperProvider.createSVGElement('line');
|
|
359
|
+
tmpArm.setAttribute('class', 'pict-flow-node-rotate-arm');
|
|
360
|
+
tmpArm.setAttribute('x1', String(tmpRotateCenterX));
|
|
361
|
+
tmpArm.setAttribute('y1', '0');
|
|
362
|
+
tmpArm.setAttribute('x2', String(tmpRotateCenterX));
|
|
363
|
+
tmpArm.setAttribute('y2', String(-tmpArmLength));
|
|
364
|
+
tmpArm.setAttribute('data-node-hash', pNodeData.Hash);
|
|
365
|
+
tmpArm.setAttribute('data-element-type', 'node-rotate');
|
|
366
|
+
tmpGroup.appendChild(tmpArm);
|
|
367
|
+
|
|
368
|
+
let tmpGrip = this._FlowView._SVGHelperProvider.createSVGElement('circle');
|
|
369
|
+
tmpGrip.setAttribute('class', 'pict-flow-node-rotate-handle');
|
|
370
|
+
tmpGrip.setAttribute('cx', String(tmpRotateCenterX));
|
|
371
|
+
tmpGrip.setAttribute('cy', String(-tmpArmLength - 5));
|
|
372
|
+
tmpGrip.setAttribute('r', '6');
|
|
373
|
+
tmpGrip.setAttribute('data-node-hash', pNodeData.Hash);
|
|
374
|
+
tmpGrip.setAttribute('data-element-type', 'node-rotate');
|
|
375
|
+
tmpGroup.appendChild(tmpGrip);
|
|
376
|
+
}
|
|
377
|
+
|
|
342
378
|
pNodesLayer.appendChild(tmpGroup);
|
|
343
379
|
}
|
|
344
380
|
|
|
@@ -226,14 +226,36 @@ class PictViewFlowPropertiesPanel extends libPictView
|
|
|
226
226
|
let tmpFO = pPanelsLayer.querySelector(`[data-panel-hash="${pPanelData.Hash}"]`);
|
|
227
227
|
if (tmpFO)
|
|
228
228
|
{
|
|
229
|
-
//
|
|
230
|
-
//
|
|
231
|
-
//
|
|
232
|
-
|
|
233
|
-
|
|
229
|
+
// The Appearance tab edits a node's body/title appearance, which a connection (edge) has none
|
|
230
|
+
// of -- so for a connection panel, hide that tab (and the now-single-tab bar) and leave just
|
|
231
|
+
// the connection's own panel. Node panels keep the appearance + help tabs.
|
|
232
|
+
if (pPanelData.ConnectionHash)
|
|
233
|
+
{
|
|
234
|
+
this._hidePanelTabsForConnection(tmpFO);
|
|
235
|
+
}
|
|
236
|
+
else
|
|
237
|
+
{
|
|
238
|
+
// Tab-switching click handlers are inline `onclick=` attributes in Flow-PanelChrome-Template
|
|
239
|
+
// that call FlowView._handlePanelTabClick → switchPanelTab.
|
|
240
|
+
this._renderAppearanceTab(pPanelData, tmpFO);
|
|
241
|
+
this._renderHelpTab(pPanelData, tmpFO);
|
|
242
|
+
}
|
|
234
243
|
}
|
|
235
244
|
}
|
|
236
245
|
|
|
246
|
+
// Hide the node-oriented Appearance (and Help) tabs plus the tab bar for a connection panel, so it
|
|
247
|
+
// shows only its single Properties pane with no lone tab.
|
|
248
|
+
_hidePanelTabsForConnection(pForeignObject)
|
|
249
|
+
{
|
|
250
|
+
if (!pForeignObject) { return; }
|
|
251
|
+
let tmpAppearanceTab = pForeignObject.querySelector('.pict-flow-panel-tab[data-tab-target="appearance"]');
|
|
252
|
+
if (tmpAppearanceTab) { tmpAppearanceTab.style.display = 'none'; }
|
|
253
|
+
let tmpAppearancePane = pForeignObject.querySelector('.pict-flow-panel-tab-pane[data-tab="appearance"]');
|
|
254
|
+
if (tmpAppearancePane) { tmpAppearancePane.style.display = 'none'; }
|
|
255
|
+
let tmpTabbar = pForeignObject.querySelector('.pict-flow-panel-tabbar');
|
|
256
|
+
if (tmpTabbar) { tmpTabbar.style.display = 'none'; }
|
|
257
|
+
}
|
|
258
|
+
|
|
237
259
|
/**
|
|
238
260
|
* Instantiate (or reuse) the panel type implementation and render into the body container.
|
|
239
261
|
*
|
|
@@ -15,6 +15,10 @@ const _DefaultConfiguration =
|
|
|
15
15
|
EnableAddNode: true,
|
|
16
16
|
EnableCardPalette: true,
|
|
17
17
|
|
|
18
|
+
// Host-supplied buttons (set by the FlowView from its own ToolbarExtraButtons option). Each entry
|
|
19
|
+
// is { Hash, Icon, Label?, Tooltip?, Active? }. Rendered as a group via Flow-Toolbar-Extra-Button.
|
|
20
|
+
ToolbarExtraButtons: [],
|
|
21
|
+
|
|
18
22
|
CSS: false,
|
|
19
23
|
|
|
20
24
|
Templates:
|
|
@@ -77,6 +81,7 @@ const _DefaultConfiguration =
|
|
|
77
81
|
<span class="pict-flow-toolbar-btn-icon" id="Flow-Toolbar-Icon-zoom-fit-{~D:Record.FlowViewIdentifier~}"></span>
|
|
78
82
|
</button>
|
|
79
83
|
</div>
|
|
84
|
+
<div class="pict-flow-toolbar-group pict-flow-toolbar-extra">{~TS:Flow-Toolbar-Extra-Button:Record.ToolbarExtraButtons~}</div>
|
|
80
85
|
<div class="pict-flow-toolbar-group pict-flow-toolbar-right">
|
|
81
86
|
<button class="pict-flow-toolbar-btn" data-flow-action="settings-popup" id="Flow-Toolbar-Settings-{~D:Record.FlowViewIdentifier~}" title="Theme Settings"
|
|
82
87
|
onclick="_Pict.views['{~D:Record.FlowViewIdentifier~}']._ToolbarView._handleToolbarAction('settings-popup')">
|
|
@@ -105,6 +110,19 @@ const _DefaultConfiguration =
|
|
|
105
110
|
<div class="pict-flow-toolbar-popup-anchor" id="Flow-Toolbar-PopupAnchor-{~D:Record.FlowViewIdentifier~}">
|
|
106
111
|
</div>
|
|
107
112
|
`
|
|
113
|
+
},
|
|
114
|
+
{
|
|
115
|
+
Hash: 'Flow-Toolbar-Extra-Button',
|
|
116
|
+
// Host-supplied button. The icon span is filled post-render by
|
|
117
|
+
// _populateToolbarIcons (keyed by Hash), matching how the built-in
|
|
118
|
+
// button icons are injected. FlowViewIdentifier + ActiveClass are
|
|
119
|
+
// stamped onto each row in render().
|
|
120
|
+
Template: /*html*/`<button class="pict-flow-toolbar-btn{~D:Record.ToggleClass~}{~D:Record.ActiveClass~}" id="Flow-Toolbar-Extra-{~D:Record.Hash~}-{~D:Record.FlowViewIdentifier~}" title="{~D:Record.Tooltip~}" data-flow-action="extra" data-extra-hash="{~D:Record.Hash~}"
|
|
121
|
+
onclick="_Pict.views['{~D:Record.FlowViewIdentifier~}']._ToolbarView._handleExtraAction('{~D:Record.Hash~}', this)">
|
|
122
|
+
<span class="pict-flow-toolbar-btn-icon" id="Flow-Toolbar-ExtraIcon-{~D:Record.Hash~}-{~D:Record.FlowViewIdentifier~}"></span>
|
|
123
|
+
<span class="pict-flow-toolbar-btn-text">{~D:Record.Label~}</span>
|
|
124
|
+
<span class="pict-flow-toolbar-btn-led" aria-hidden="true"></span>
|
|
125
|
+
</button>`
|
|
108
126
|
},
|
|
109
127
|
{
|
|
110
128
|
Hash: 'Flow-AddNode-List',
|
|
@@ -121,7 +139,7 @@ const _DefaultConfiguration =
|
|
|
121
139
|
+ ' onclick="_Pict.views[\'{~D:Record.FlowViewIdentifier~}\']._ToolbarView._addNodeFromPopup(this.getAttribute(\'data-node-type\'))">'
|
|
122
140
|
+ '<span class="pict-flow-popup-list-item-icon">{~D:Record.IconHTML~}</span>'
|
|
123
141
|
+ '<span class="pict-flow-popup-list-item-label">{~D:Record.Label~}</span>'
|
|
124
|
-
+ '{~
|
|
142
|
+
+ '{~D:Record.CodeBlock~}'
|
|
125
143
|
+ '</div>'
|
|
126
144
|
},
|
|
127
145
|
{
|
|
@@ -137,13 +155,16 @@ const _DefaultConfiguration =
|
|
|
137
155
|
},
|
|
138
156
|
{
|
|
139
157
|
Hash: 'Flow-Cards-Card',
|
|
158
|
+
// The icon / swatch / code spans are pre-rendered into complete HTML blocks by
|
|
159
|
+
// _buildCardsPopup (a block is '' when its piece is absent). The template can't build them
|
|
160
|
+
// inline: the engine does not parse a nested {~D:~} inside a {~NE:~} (its `~}` terminator
|
|
161
|
+
// collides with the inner tag's), which left the palette showing raw template literals.
|
|
140
162
|
Template: '<div class="pict-flow-palette-card{~D:Record.DisabledClass~}" data-card-type="{~D:Record.CardType~}" title="{~D:Record.Tooltip~}"'
|
|
141
163
|
+ ' onclick="_Pict.views[\'{~D:Record.FlowViewIdentifier~}\']._ToolbarView._addCardFromPopup(this.getAttribute(\'data-card-type\'))">'
|
|
142
|
-
+ '{~
|
|
143
|
-
+ '{~
|
|
144
|
-
+ '{~NE:Record.SwatchColor^<span class="pict-flow-palette-card-swatch" style="background-color: {~D:Record.SwatchColor~};"></span>~}'
|
|
164
|
+
+ '{~D:Record.IconBlock~}'
|
|
165
|
+
+ '{~D:Record.SwatchBlock~}'
|
|
145
166
|
+ '<span class="pict-flow-palette-card-title">{~D:Record.Label~}</span>'
|
|
146
|
-
+ '{~
|
|
167
|
+
+ '{~D:Record.CodeBlock~}'
|
|
147
168
|
+ '</div>'
|
|
148
169
|
},
|
|
149
170
|
{
|
|
@@ -212,11 +233,35 @@ class PictViewFlowToolbar extends libPictView
|
|
|
212
233
|
|
|
213
234
|
render(pRenderableHash, pRenderDestinationAddress, pTemplateRecordAddress)
|
|
214
235
|
{
|
|
236
|
+
// Stamp the per-row render fields onto each host-supplied button so the
|
|
237
|
+
// Flow-Toolbar-Extra-Button rows resolve their owning view and active
|
|
238
|
+
// state (nested {~D:~} addressing inside {~TS:~} is not supported).
|
|
239
|
+
this._stampExtraButtons();
|
|
215
240
|
// Pass this.options as the template record so {~D:Record.FlowViewIdentifier~}
|
|
216
241
|
// resolves correctly in the toolbar template.
|
|
217
242
|
return super.render(pRenderableHash, pRenderDestinationAddress, this.options);
|
|
218
243
|
}
|
|
219
244
|
|
|
245
|
+
/**
|
|
246
|
+
* Stamp FlowViewIdentifier + ActiveClass onto each ToolbarExtraButtons entry
|
|
247
|
+
* so the row template can address them.
|
|
248
|
+
*/
|
|
249
|
+
_stampExtraButtons()
|
|
250
|
+
{
|
|
251
|
+
let tmpExtraButtons = this.options.ToolbarExtraButtons;
|
|
252
|
+
if (!Array.isArray(tmpExtraButtons)) return;
|
|
253
|
+
for (let i = 0; i < tmpExtraButtons.length; i++)
|
|
254
|
+
{
|
|
255
|
+
tmpExtraButtons[i].FlowViewIdentifier = this.options.FlowViewIdentifier;
|
|
256
|
+
tmpExtraButtons[i].ActiveClass = tmpExtraButtons[i].Active ? ' pict-flow-toolbar-btn-active' : '';
|
|
257
|
+
// Toggle buttons (stateful on/off, e.g. a pan or connect toggle) get a status LED that the
|
|
258
|
+
// ActiveClass fills; plain action buttons (Toggle falsy) render no LED.
|
|
259
|
+
tmpExtraButtons[i].ToggleClass = tmpExtraButtons[i].Toggle ? ' pict-flow-toolbar-btn-toggle' : '';
|
|
260
|
+
// A label-less (icon-only) button renders an empty text span; CSS (:empty) collapses it.
|
|
261
|
+
if (typeof tmpExtraButtons[i].Label !== 'string') { tmpExtraButtons[i].Label = ''; }
|
|
262
|
+
}
|
|
263
|
+
}
|
|
264
|
+
|
|
220
265
|
onAfterRender(pRenderable, pRenderDestinationAddress, pRecord, pContent)
|
|
221
266
|
{
|
|
222
267
|
let tmpFlowViewIdentifier = this.options.FlowViewIdentifier;
|
|
@@ -321,6 +366,20 @@ class PictViewFlowToolbar extends libPictView
|
|
|
321
366
|
{
|
|
322
367
|
tmpAutoChevron[0].innerHTML = tmpIconProvider.getIconSVGMarkup('chevron-down', 8);
|
|
323
368
|
}
|
|
369
|
+
|
|
370
|
+
// Host-supplied extra buttons (keyed by Hash, icon from the button's Icon key).
|
|
371
|
+
let tmpExtraButtons = this.options.ToolbarExtraButtons;
|
|
372
|
+
if (Array.isArray(tmpExtraButtons))
|
|
373
|
+
{
|
|
374
|
+
for (let i = 0; i < tmpExtraButtons.length; i++)
|
|
375
|
+
{
|
|
376
|
+
let tmpExtraIcon = this.pict.ContentAssignment.getElement(`#Flow-Toolbar-ExtraIcon-${tmpExtraButtons[i].Hash}-${tmpFlowViewIdentifier}`);
|
|
377
|
+
if (tmpExtraIcon.length > 0)
|
|
378
|
+
{
|
|
379
|
+
tmpExtraIcon[0].innerHTML = tmpIconProvider.getIconSVGMarkup(tmpExtraButtons[i].Icon, 14);
|
|
380
|
+
}
|
|
381
|
+
}
|
|
382
|
+
}
|
|
324
383
|
}
|
|
325
384
|
|
|
326
385
|
// ── Popup Management ──────────────────────────────────────────────────
|
|
@@ -548,12 +607,16 @@ class PictViewFlowToolbar extends libPictView
|
|
|
548
607
|
let tmpResolvedKey = tmpIconProvider.resolveIconKey(tmpMeta);
|
|
549
608
|
tmpIconHTML = tmpIconProvider.getIconSVGMarkup(tmpResolvedKey, 16);
|
|
550
609
|
}
|
|
610
|
+
let tmpRowCode = tmpMeta.Code || '';
|
|
551
611
|
tmpRows.push(
|
|
552
612
|
{
|
|
553
613
|
NodeType: tmpTypeKeys[i],
|
|
554
614
|
Label: tmpTypeConfig.Label || '',
|
|
555
615
|
IconHTML: tmpIconHTML,
|
|
556
|
-
Code:
|
|
616
|
+
Code: tmpRowCode,
|
|
617
|
+
// Pre-rendered so the template renders it with {~D:~} (a nested {~D:~} inside {~NE:~} is
|
|
618
|
+
// not parsed by the engine).
|
|
619
|
+
CodeBlock: tmpRowCode ? ('<span class="pict-flow-popup-list-item-code">' + tmpRowCode + '</span>') : '',
|
|
557
620
|
FlowViewIdentifier: tmpFlowViewIdentifier
|
|
558
621
|
});
|
|
559
622
|
}
|
|
@@ -682,16 +745,27 @@ class PictViewFlowToolbar extends libPictView
|
|
|
682
745
|
tmpIconHTML = tmpIconProvider.getIconSVGMarkup('default', 14);
|
|
683
746
|
}
|
|
684
747
|
|
|
748
|
+
// Pre-render each conditional span into a complete HTML block ('' when absent). The
|
|
749
|
+
// template renders these directly with {~D:~}; it cannot wrap them inline because the
|
|
750
|
+
// engine does not parse a nested {~D:~} inside a {~NE:~}.
|
|
751
|
+
let tmpCode = tmpMeta.Code || '';
|
|
752
|
+
let tmpSwatchColor = (!tmpIconHTML && !tmpIsEmoji && tmpCardConfig.TitleBarColor) ? tmpCardConfig.TitleBarColor : '';
|
|
753
|
+
let tmpIconBlock = '';
|
|
754
|
+
if (tmpIconHTML) { tmpIconBlock = '<span class="pict-flow-palette-card-icon">' + tmpIconHTML + '</span>'; }
|
|
755
|
+
else if (tmpIsEmoji) { tmpIconBlock = '<span class="pict-flow-palette-card-icon">' + tmpMeta.Icon + '</span>'; }
|
|
756
|
+
let tmpSwatchBlock = tmpSwatchColor ? ('<span class="pict-flow-palette-card-swatch" style="background-color: ' + tmpSwatchColor + ';"></span>') : '';
|
|
757
|
+
let tmpCodeBlock = tmpCode ? ('<span class="pict-flow-palette-card-code">' + tmpCode + '</span>') : '';
|
|
758
|
+
|
|
685
759
|
tmpMatching.push(
|
|
686
760
|
{
|
|
687
761
|
CardType: tmpCardConfig.Hash,
|
|
688
762
|
Label: tmpCardConfig.Label || '',
|
|
689
|
-
Code:
|
|
690
|
-
|
|
691
|
-
|
|
763
|
+
Code: tmpCode,
|
|
764
|
+
IconBlock: tmpIconBlock,
|
|
765
|
+
SwatchBlock: tmpSwatchBlock,
|
|
766
|
+
CodeBlock: tmpCodeBlock,
|
|
692
767
|
DisabledClass: (tmpMeta.Enabled === false) ? ' disabled' : '',
|
|
693
768
|
Tooltip: tmpMeta.Tooltip || tmpMeta.Description || '',
|
|
694
|
-
SwatchColor: (!tmpIconHTML && !tmpIsEmoji && tmpCardConfig.TitleBarColor) ? tmpCardConfig.TitleBarColor : '',
|
|
695
769
|
FlowViewIdentifier: tmpFlowViewIdentifier
|
|
696
770
|
});
|
|
697
771
|
}
|
|
@@ -1532,7 +1606,7 @@ class PictViewFlowToolbar extends libPictView
|
|
|
1532
1606
|
let tmpNoiseEnabled = !!(tmpActiveRenderer && tmpActiveRenderer.NoiseConfig && tmpActiveRenderer.NoiseConfig.Enabled);
|
|
1533
1607
|
let tmpNoiseDisplay = tmpNoiseEnabled ? '' : 'display:none;';
|
|
1534
1608
|
|
|
1535
|
-
|
|
1609
|
+
let tmpHTML =
|
|
1536
1610
|
'<div class="pict-flow-popup-settings-section">'
|
|
1537
1611
|
+ '<label class="pict-flow-popup-settings-label">Theme</label>'
|
|
1538
1612
|
+ '<select class="pict-flow-popup-settings-select"'
|
|
@@ -1551,7 +1625,50 @@ class PictViewFlowToolbar extends libPictView
|
|
|
1551
1625
|
+ ' oninput="_Pict.views[\'' + tmpFlowViewIdentifier + '\']._ToolbarView._handleNoiseSliderInput(this)" />'
|
|
1552
1626
|
+ '<span class="pict-flow-popup-settings-slider-value">' + tmpNoiseLevel + '%</span>'
|
|
1553
1627
|
+ '</div>'
|
|
1554
|
-
+ '</div>'
|
|
1628
|
+
+ '</div>';
|
|
1629
|
+
|
|
1630
|
+
tmpHTML += this._buildHostSettingsSections();
|
|
1631
|
+
|
|
1632
|
+
this.pict.ContentAssignment.assignContent(pContainer, tmpHTML);
|
|
1633
|
+
}
|
|
1634
|
+
|
|
1635
|
+
/**
|
|
1636
|
+
* Host-contributed settings sections. A consumer adds entries to the flow view's
|
|
1637
|
+
* `SettingsSections` option so its own controls (e.g. a whiteboard's background
|
|
1638
|
+
* picker) live in the gear popup instead of a separate panel. Each entry is
|
|
1639
|
+
* `{ Label?, HTML? , Build?(flowView) }`; Build is evaluated at open time so a
|
|
1640
|
+
* section can reflect live state. Returns concatenated section markup ('' when none).
|
|
1641
|
+
* @returns {string}
|
|
1642
|
+
*/
|
|
1643
|
+
_buildHostSettingsSections()
|
|
1644
|
+
{
|
|
1645
|
+
let tmpSections = (this._FlowView && this._FlowView.options && Array.isArray(this._FlowView.options.SettingsSections))
|
|
1646
|
+
? this._FlowView.options.SettingsSections
|
|
1647
|
+
: [];
|
|
1648
|
+
let tmpOut = '';
|
|
1649
|
+
for (let i = 0; i < tmpSections.length; i++)
|
|
1650
|
+
{
|
|
1651
|
+
let tmpSection = tmpSections[i];
|
|
1652
|
+
let tmpSectionHTML = '';
|
|
1653
|
+
if (typeof tmpSection.Build === 'function')
|
|
1654
|
+
{
|
|
1655
|
+
tmpSectionHTML = tmpSection.Build(this._FlowView) || '';
|
|
1656
|
+
}
|
|
1657
|
+
else if (typeof tmpSection.HTML === 'string')
|
|
1658
|
+
{
|
|
1659
|
+
tmpSectionHTML = tmpSection.HTML;
|
|
1660
|
+
}
|
|
1661
|
+
if (!tmpSectionHTML)
|
|
1662
|
+
{
|
|
1663
|
+
continue;
|
|
1664
|
+
}
|
|
1665
|
+
tmpOut += '<div class="pict-flow-popup-divider"></div>'
|
|
1666
|
+
+ '<div class="pict-flow-popup-settings-section">'
|
|
1667
|
+
+ (tmpSection.Label ? '<label class="pict-flow-popup-settings-label">' + tmpSection.Label + '</label>' : '')
|
|
1668
|
+
+ tmpSectionHTML
|
|
1669
|
+
+ '</div>';
|
|
1670
|
+
}
|
|
1671
|
+
return tmpOut;
|
|
1555
1672
|
}
|
|
1556
1673
|
|
|
1557
1674
|
/**
|
|
@@ -1677,7 +1794,8 @@ class PictViewFlowToolbar extends libPictView
|
|
|
1677
1794
|
FlowViewIdentifier: tmpFlowViewIdentifier,
|
|
1678
1795
|
DefaultDestinationAddress: `#Flow-FloatingToolbar-Container-${tmpFlowViewIdentifier}`,
|
|
1679
1796
|
EnableAddNode: this.options.EnableAddNode,
|
|
1680
|
-
EnableCardPalette: this.options.EnableCardPalette
|
|
1797
|
+
EnableCardPalette: this.options.EnableCardPalette,
|
|
1798
|
+
ToolbarExtraButtons: this.options.ToolbarExtraButtons
|
|
1681
1799
|
}
|
|
1682
1800
|
);
|
|
1683
1801
|
this._FloatingToolbarView._ToolbarView = this;
|
|
@@ -1742,6 +1860,23 @@ class PictViewFlowToolbar extends libPictView
|
|
|
1742
1860
|
* Handle a toolbar action
|
|
1743
1861
|
* @param {string} pAction
|
|
1744
1862
|
*/
|
|
1863
|
+
/**
|
|
1864
|
+
* Handle a click on a host-supplied (ToolbarExtraButtons) button. Routes to
|
|
1865
|
+
* the FlowView's onToolbarButton hook with the button hash and the clicked
|
|
1866
|
+
* element (so the host can anchor a popover next to it).
|
|
1867
|
+
*
|
|
1868
|
+
* @param {string} pHash - The button's Hash
|
|
1869
|
+
* @param {HTMLElement} pElement - The clicked button element
|
|
1870
|
+
*/
|
|
1871
|
+
_handleExtraAction(pHash, pElement)
|
|
1872
|
+
{
|
|
1873
|
+
if (!this._FlowView) return;
|
|
1874
|
+
if (typeof this._FlowView.options.onToolbarButton === 'function')
|
|
1875
|
+
{
|
|
1876
|
+
this._FlowView.options.onToolbarButton(pHash, pElement);
|
|
1877
|
+
}
|
|
1878
|
+
}
|
|
1879
|
+
|
|
1745
1880
|
_handleToolbarAction(pAction)
|
|
1746
1881
|
{
|
|
1747
1882
|
if (!this._FlowView) return;
|