diff --git a/src/classes/dao/forum.js b/src/classes/dao/forum.js index 44b9121..a5e3fee 100644 --- a/src/classes/dao/forum.js +++ b/src/classes/dao/forum.js @@ -44,7 +44,7 @@ export class Forum extends ReputationHolder { super(name, scene); this.dao = dao; this.id = this.reputationPublicKey; - this.graph = new WeightedDirectedGraph(scene); + this.graph = new WeightedDirectedGraph('forum', scene); this.actions = { propagate: new Action('propagate', scene), confirm: new Action('confirm', scene), diff --git a/src/classes/supporting/edge.js b/src/classes/supporting/edge.js index dd22fe1..08c56b0 100644 --- a/src/classes/supporting/edge.js +++ b/src/classes/supporting/edge.js @@ -10,6 +10,15 @@ export class Edge { this.installedClickCallback = false; } + toJSON() { + return { + from: this.from.id, + to: this.to.id, + type: this.type, + weight: this.weight, + }; + } + reset() { this.installedClickCallback = false; } @@ -132,7 +141,7 @@ export class Edge { .button({ id: 'cancel', name: 'Cancel', - cb: () => graph.resetEditorDocument(), + cb: () => graph.resetEditor(), }); } } diff --git a/src/classes/supporting/vertex.js b/src/classes/supporting/vertex.js index fb27be6..8219c32 100644 --- a/src/classes/supporting/vertex.js +++ b/src/classes/supporting/vertex.js @@ -18,6 +18,18 @@ export class Vertex { this.properties = new Map(); } + toJSON() { + return { + id: this.id, + type: this.type, + label: this.label, + properties: Array.from(this.properties.entries()).reduce((props, [key, value]) => { + props[key] = value; + return props; + }, {}), + }; + } + reset() { this.installedClickCallback = false; } @@ -129,7 +141,7 @@ export class Vertex { cb: () => { graph.deleteVertex(vertex.id); graph.redraw(); - graph.resetEditorDocument(); + graph.resetEditor(); }, }); @@ -151,7 +163,7 @@ export class Vertex { form.button({ id: 'cancel', name: 'Cancel', - cb: () => graph.resetEditorDocument(), + cb: () => graph.resetEditor(), }); return doc; diff --git a/src/classes/supporting/wdg.js b/src/classes/supporting/wdg.js index ab083e7..f017c3f 100644 --- a/src/classes/supporting/wdg.js +++ b/src/classes/supporting/wdg.js @@ -18,7 +18,8 @@ const makeWDGHandler = (graphIndex) => (vertexId) => { }; export class WeightedDirectedGraph { - constructor(scene, options = {}) { + constructor(name, scene, options = {}) { + this.name = name; this.scene = scene; this.vertices = new Map(); this.edgeTypes = new Map(); @@ -34,7 +35,7 @@ export class WeightedDirectedGraph { window[`WDGHandler${this.index}`] = makeWDGHandler(this.index); // TODO: Populate history - this.history = {}; + this.history = []; } getHistory() { @@ -44,9 +45,11 @@ export class WeightedDirectedGraph { toJSON() { return { - vertices: Array.from(this.vertices.values()), - edgeTypes: Array.from(this.edgeTypes.keys()), - edges: Array.from(this.edgeTypes.values()).flatMap((edges) => Array.from(edges.values())), + vertices: Array.from(this.vertices.values()) + .map((vertex) => vertex.toJSON()), + edges: Array.from(this.edgeTypes.values()) + .flatMap((edges) => Array.from(edges.values())) + .map((edge) => edge.toJSON()), history: this.getHistory(), }; } @@ -95,16 +98,31 @@ export class WeightedDirectedGraph { this.scene?.withSectionFlowchart(); this.flowchart = this.scene?.lastFlowchart; if (this.editable) { - this.editorDoc = new Document('WDGControls', this.flowchart.box.el); - this.resetEditorDocument(); + this.editorDoc = new Document('WDGEditor', this.flowchart.box.el); + this.errorDoc = new Document('WDGErrors', this.flowchart.box.el); + this.controlDoc = new Document('WDGControl', this.flowchart.box.el, { prepend: true }); + this.resetEditor(); } - this.errorDoc = new Document('WDGErrors', this.flowchart.box.el); return this; } - resetEditorDocument() { + resetEditor() { this.editorDoc.clear(); Vertex.prepareEditorDocument(this, this.editorDoc); + const form = this.controlDoc.form({ name: 'controlForm' }).lastElement; + form.button({ + id: 'export', + name: 'Export', + cb: () => { + const a = window.document.createElement('a'); + const json = JSON.stringify(this.toJSON(), null, 2); + const currentTime = Math.floor(new Date().getTime() / 1000); + a.href = `data:attachment/text,${encodeURI(json)}`; + a.target = '_blank'; + a.download = `wdg_${this.name}_${currentTime}.json`; + a.click(); + }, + }); } addVertex(type, id, data, label, options) { diff --git a/src/tests/scripts/wdg.test.js b/src/tests/scripts/wdg.test.js index 44f8c6d..1eed931 100644 --- a/src/tests/scripts/wdg.test.js +++ b/src/tests/scripts/wdg.test.js @@ -7,13 +7,13 @@ const rootElement = document.getElementById('scene'); const rootBox = new Box('rootBox', rootElement).flex(); window.scene = new Scene('WDG test', rootBox); -describe('Weighted Directed Acyclic Graph', function tests() { +describe('Weighted Directed Graph', function tests() { this.timeout(0); let graph; before(() => { - graph = (window.graph = new WeightedDirectedGraph(window.scene)).withFlowchart(); + graph = (window.graph = new WeightedDirectedGraph('test1', window.scene)).withFlowchart(); graph.addVertex('v1', {}); graph.addVertex('v1', {}); @@ -47,13 +47,64 @@ describe('Weighted Directed Acyclic Graph', function tests() { ['3', '1', 0.25], ]); }); + + it('can export to JSON', () => { + const result = graph.toJSON(); + console.log('export to JSON, result', result); + result.should.eql({ + vertices: [ + { + id: '0', type: 'v1', label: '0', properties: {}, + }, + { + id: '1', type: 'v1', label: '1', properties: {}, + }, + { + id: '2', type: 'v1', label: '2', properties: {}, + }, + { + id: '3', type: 'v1', label: '3', properties: {}, + }, + { + id: '4', type: 'v1', label: '4', properties: {}, + }, + ], + edges: [ + { + from: '0', + to: '1', + type: 'e1', + weight: 1, + }, + { + from: '2', + to: '1', + type: 'e1', + weight: 0.5, + }, + { + from: '3', + to: '1', + type: 'e1', + weight: 0.25, + }, + { + from: '1', + to: '4', + type: 'e1', + weight: 0.125, + }, + ], + history: [], + }); + }); }); -describe('editable', () => { +describe('Editable', () => { let graph; it('should be editable', () => { - graph = (window.graph2 = new WeightedDirectedGraph(window.scene, { editable: true })).withFlowchart(); + graph = (window.graph2 = new WeightedDirectedGraph('test2', window.scene, { editable: true })).withFlowchart(); graph.addVertex('v1', {}); graph.addVertex('v2', {});