diff --git a/forum-network/src/classes/display/flowchart.js b/forum-network/src/classes/display/flowchart.js index 058e928..77a4958 100644 --- a/forum-network/src/classes/display/flowchart.js +++ b/forum-network/src/classes/display/flowchart.js @@ -1,10 +1,11 @@ import { MermaidDiagram } from './mermaid.js'; export class Flowchart extends MermaidDiagram { - constructor(box, logBox, direction = 'BT') { + constructor(box, logBox, { direction = 'BT' } = {}) { super(box, logBox); this.direction = direction; this.init(); + this.controlBox = this.box.addBox('Controls'); } init() { diff --git a/forum-network/src/classes/display/mermaid.js b/forum-network/src/classes/display/mermaid.js index a11a588..911b141 100644 --- a/forum-network/src/classes/display/mermaid.js +++ b/forum-network/src/classes/display/mermaid.js @@ -9,7 +9,6 @@ export class MermaidDiagram { this.renderBox = this.box.addBox('Render'); this.box.addBox('Spacer').setInnerHTML(' '); this.logBoxPre = logBox.el.appendChild(document.createElement('pre')); - this.inSection = 0; } static initializeAPI() { @@ -20,10 +19,8 @@ export class MermaidDiagram { darkMode: true, primaryColor: '#2a5b6c', primaryTextColor: '#b6b6b6', - // lineColor: '#349cbd', lineColor: '#57747d', signalColor: '#57747d', - // signalColor: '#349cbd', noteBkgColor: '#516f77', noteTextColor: '#cecece', activationBkgColor: '#1d3f49', diff --git a/forum-network/src/classes/display/scene.js b/forum-network/src/classes/display/scene.js index cc40e96..4606c46 100644 --- a/forum-network/src/classes/display/scene.js +++ b/forum-network/src/classes/display/scene.js @@ -47,26 +47,27 @@ export class Scene { } withFlowchart({ direction = 'BT' } = {}) { - const box = this.topSection.addBox('Flowchart').addClass('padded'); - this.box.addBox('Spacer').setInnerHTML(' '); - const logBox = this.box.addBox('Flowchart text').addClass('dim'); - this.flowchart = new Flowchart(box, logBox, direction); + this.withSectionFlowchart({ direction, section: this.topSection }); + this.flowchart = this.lastFlowchart; return this; } - withAdditionalFlowchart({ id, name, direction = 'BT' } = {}) { + withSectionFlowchart({ + id, name, direction = 'BT', section, + } = {}) { + section = section ?? this.middleSection; const index = this.flowcharts.size; name = name ?? `Flowchart ${index}`; id = id ?? `flowchart_${CryptoUtil.randomUUID().slice(0, 4)}`; - const container = this.middleSection.addBox(name).flex(); + const container = section.addBox(name).flex(); const box = container.addBox('Flowchart').addClass('padded'); const logBox = container.addBox('Flowchart text').addClass('dim'); - const flowchart = new Flowchart(box, logBox, direction); + const flowchart = new Flowchart(box, logBox, { direction }); this.flowcharts.set(id, flowchart); return this; } - lastFlowchart() { + get lastFlowchart() { if (!this.flowcharts.size) { if (this.flowchart) { return this.flowchart; diff --git a/forum-network/src/classes/supporting/edge.js b/forum-network/src/classes/supporting/edge.js index 48aa0b7..83550a5 100644 --- a/forum-network/src/classes/supporting/edge.js +++ b/forum-network/src/classes/supporting/edge.js @@ -117,7 +117,7 @@ export class Edge { .button({ id: 'cancel', name: 'Cancel', - cb: () => doc.clear(), + cb: () => graph.resetEditorDocument(), }); } } diff --git a/forum-network/src/classes/supporting/vertex.js b/forum-network/src/classes/supporting/vertex.js index ae1819b..3ca1779 100644 --- a/forum-network/src/classes/supporting/vertex.js +++ b/forum-network/src/classes/supporting/vertex.js @@ -54,18 +54,15 @@ export class Vertex { static prepareEditorDocument(graph, doc, vertexId) { doc.clear(); - const vertex = graph.getVertex(vertexId); - if (!vertex) { - throw new Error(`Could not find WDG Vertex ${vertexId}`); - } + const vertex = vertexId ? graph.getVertex(vertexId) : undefined; const form = doc.form().lastElement; - doc.remark('

Edit Vertex

', { parentEl: form.el }); + doc.remark(`

${vertex ? 'Edit' : 'Add'} Vertex

`, { parentEl: form.el }); form .textField({ - id: 'id', name: 'id', defaultValue: vertex.id, + id: 'id', name: 'id', defaultValue: vertex?.id, }) - .textField({ id: 'type', name: 'type', defaultValue: vertex.type }) - .textField({ id: 'label', name: 'label', defaultValue: vertex.label }); + .textField({ id: 'type', name: 'type', defaultValue: vertex?.type }) + .textField({ id: 'label', name: 'label', defaultValue: vertex?.label }); doc.remark('

Properties

', { parentEl: form.el }); const subFormArray = form.subFormArray({ id: 'properties', name: 'properties' }).lastItem; @@ -81,8 +78,10 @@ export class Vertex { doc.remark('
', { parentEl: subForm.el }); }; - for (const [key, value] of vertex.properties.entries()) { - addPropertyForm(key, value); + if (vertex) { + for (const [key, value] of vertex.properties.entries()) { + addPropertyForm(key, value); + } } form.button({ @@ -92,26 +91,34 @@ export class Vertex { }) .button({ id: 'save', - name: 'Save', + name: this.id ? 'Save' : 'Add', type: 'submit', cb: ({ form: { value: formValue } }) => { let fullRedraw = false; - if (formValue.id !== vertex.id) { + if (vertex && formValue.id !== vertex.id) { fullRedraw = true; } // TODO: preserve data types of properties formValue.properties = new Map(formValue.properties.map(({ key, value }) => [key, value])); - Object.assign(vertex, formValue); - vertex.displayVertex(); + if (vertex) { + Object.assign(vertex, formValue); + vertex.displayVertex(); + } else { + graph.addVertex(formValue.type, formValue.id, null, formValue.label); + } if (fullRedraw) { graph.redraw(); } + if (!vertex) { + // This was a new vertex. Now let's edit. + Vertex.prepareEditorDocument(graph, doc, formValue.id); + } }, }) .button({ id: 'cancel', name: 'Cancel', - cb: () => doc.clear(), + cb: () => graph.resetEditorDocument(), }); return doc; } diff --git a/forum-network/src/classes/supporting/wdg.js b/forum-network/src/classes/supporting/wdg.js index 56312a3..28e9c8d 100644 --- a/forum-network/src/classes/supporting/wdg.js +++ b/forum-network/src/classes/supporting/wdg.js @@ -1,13 +1,13 @@ import { Vertex } from './vertex.js'; import { Edge } from './edge.js'; +import { Document } from '../display/document.js'; -const graphs = []; +const allGraphs = []; const makeWDGHandler = (graphIndex) => (vertexId) => { - const graph = graphs[graphIndex]; + const graph = allGraphs[graphIndex]; // We want a document for editing this node, which may be a vertex or an edge - const editorDoc = graph.scene.getDocument('editorDocument') - ?? graph.scene.withDocument('editorDocument').lastDocument; + const { editorDoc } = graph; if (vertexId.startsWith('edge:')) { const [, from, to] = vertexId.split(':'); Edge.prepareEditorDocument(graph, editorDoc, from, to); @@ -22,14 +22,17 @@ export class WeightedDirectedGraph { this.vertices = new Map(); this.edgeTypes = new Map(); this.nextVertexId = 0; - this.flowchart = scene?.flowchart; + this.flowchart = undefined; this.editable = options.editable; - this.index = graphs.length; - graphs.push(this); + // Mermaid supports a click callback, but we can't customize arguments; we just get the vertex ID. // In order to provide the appropriate graph context for each callback, we create a separate callback // function for each graph. + this.index = allGraphs.length; + allGraphs.push(this); window[`WDGHandler${this.index}`] = makeWDGHandler(this.index); + + // TODO: Populate history this.history = {}; } @@ -88,11 +91,19 @@ export class WeightedDirectedGraph { } withFlowchart() { - this.scene?.withAdditionalFlowchart(); - this.flowchart = this.scene?.lastFlowchart(); + this.scene?.withSectionFlowchart(); + this.flowchart = this.scene?.lastFlowchart; + if (this.editable) { + this.editorDoc = new Document('Controls', this.flowchart.controlBox.el); + this.resetEditorDocument(); + } return this; } + resetEditorDocument() { + Vertex.prepareEditorDocument(this, this.editorDoc); + } + addVertex(type, id, data, label, options) { // Supports simple case of auto-incremented numeric ids if (typeof id === 'object') { diff --git a/forum-network/src/tests/scripts/input.test.js b/forum-network/src/tests/scripts/input.test.js index a06d5ab..8908dc4 100644 --- a/forum-network/src/tests/scripts/input.test.js +++ b/forum-network/src/tests/scripts/input.test.js @@ -37,7 +37,7 @@ describe('Document > Form > TextField', () => { doc.remark('Hmm...!'); }); // it('can exist within a graph', () => { - // scene.withAdditionalFlowchart({ id: 'flowchart', name: 'Graph' }); + // scene.withSectionFlowchart({ id: 'flowchart', name: 'Graph' }); // const graph = scene.lastFlowchart(); // }); });