diff --git a/src/classes/display/box.js b/src/classes/display/box.js index 082bff5..b25746c 100644 --- a/src/classes/display/box.js +++ b/src/classes/display/box.js @@ -22,8 +22,11 @@ export class Box { } } - flex() { + flex({ center = false } = {}) { this.addClass('flex'); + if (center) { + this.addClass('flex-center'); + } return this; } diff --git a/src/classes/display/form.js b/src/classes/display/form.js index ee794d7..1b20f6e 100644 --- a/src/classes/display/form.js +++ b/src/classes/display/form.js @@ -42,10 +42,11 @@ export class Button extends FormElement { export class TextField extends FormElement { constructor(name, form, opts) { super(name, form, opts); + this.flex({ center: true }); this.label = document.createElement('label'); this.labelDiv = document.createElement('div'); this.label.appendChild(this.labelDiv); - this.labelDiv.innerHTML = name; + this.labelDiv.innerHTML = opts.label || name; this.input = document.createElement('input'); this.input.disabled = !!opts.disabled; this.input.defaultValue = opts.defaultValue || ''; @@ -99,9 +100,10 @@ export class FileInput extends FormElement { this.input = document.createElement('input'); this.input.type = 'file'; this.input.accept = 'application/json'; - // this.input.classList.add('visually-hidden') + this.input.classList.add('visually-hidden'); this.label = document.createElement('label'); - this.label.innerHTML = name; + this.button = form.button({ name, cb: () => this.input.click() }).lastItem; + this.label.appendChild(this.button.el); this.label.appendChild(this.input); this.el.appendChild(this.label); } @@ -148,7 +150,7 @@ export class Form extends Box { } fileInput(opts) { - this.items.push(new FileInput(opts.label || opts.name, this, opts)); + this.items.push(new FileInput(opts.name, this, opts)); return this; } diff --git a/src/classes/supporting/vertex.js b/src/classes/supporting/vertex.js index 9d705f0..1137bf6 100644 --- a/src/classes/supporting/vertex.js +++ b/src/classes/supporting/vertex.js @@ -144,14 +144,14 @@ export class Vertex { }); doc.remark('

New Edge

', { parentEl: form.el }); - const { subForm } = form.subForm({ name: 'newEdge' }).lastItem; - subForm.textField({ name: 'to' }); - subForm.textField({ name: 'type' }); - subForm.textField({ name: 'weight' }); - subForm.button({ + const newEdgeForm = doc.form({ name: 'newEdge' }).lastElement; + newEdgeForm.textField({ name: 'to' }); + newEdgeForm.textField({ name: 'type' }); + newEdgeForm.textField({ name: 'weight' }); + newEdgeForm.submit({ name: 'Save', cb: ({ form: { value: { to, type, weight } } }) => { - graph.addEdge(type, vertex, to, weight, null); + graph.setEdgeWeight(type, vertex, to, weight, null); doc.clear(); Edge.prepareEditorDocument(graph, doc, vertex.id, to); }, @@ -162,6 +162,7 @@ export class Vertex { id: 'cancel', name: 'Cancel', cb: () => graph.resetEditor(), + parentEl: doc.el, }); return doc; diff --git a/src/classes/supporting/wdg.js b/src/classes/supporting/wdg.js index 762c050..c454279 100644 --- a/src/classes/supporting/wdg.js +++ b/src/classes/supporting/wdg.js @@ -119,43 +119,59 @@ export class WeightedDirectedGraph { this.scene?.withSectionFlowchart(); this.flowchart = this.scene?.lastFlowchart; if (this.editable) { + this.controlDoc = new Document('WDGControl', this.flowchart.box.el, { prepend: true }); 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(); } return this; } + prepareControlDoc() { + const form = this.controlDoc.form({ name: 'controlForm' }).lastElement; + const { subForm: graphPropertiesForm } = form.subForm({ name: 'graphPropsForm' }).lastItem; + graphPropertiesForm.flex() + .textField({ name: 'name', label: 'Graph name', defaultValue: this.name }) + .submit({ + name: 'Save', + cb: (({ form: { value: { name } } }) => { + this.name = name; + }), + }); + const { subForm: exportImportForm } = form.subForm({ name: 'exportImportForm' }).lastItem; + exportImportForm.flex() + .button({ + 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(); + }, + }) + .fileInput({ + name: 'Import', + cb: ({ input: { files: [file] } }) => { + const reader = new FileReader(); + reader.onload = ({ target: { result: text } }) => { + console.log('imported file', { file }); + // this.flowchart?.log(`%% Imported file ${file}`) + const data = JSON.parse(text); + this.fromJSON(data); + }; + reader.readAsText(file); + }, + }); + } + resetEditor() { this.editorDoc.clear(); this.controlDoc.clear(); + this.prepareControlDoc(); Vertex.prepareEditorDocument(this, this.editorDoc); - const form = this.controlDoc.form({ name: 'controlForm' }).lastElement; - form.button({ - name: 'Download', - label: '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(); - }, - }); - form.fileInput({ - label: 'Import', - cb: ({ input: { files: [file] } }) => { - const reader = new FileReader(); - reader.onload = ({ target: { result: text } }) => { - const data = JSON.parse(text); - this.fromJSON(data); - }; - reader.readAsText(file); - }, - }); } addVertex(type, id, data, label, options) { @@ -220,10 +236,10 @@ export class WeightedDirectedGraph { addEdge(type, from, to, weight, data, options) { from = from instanceof Vertex ? from : this.getVertex(from); to = to instanceof Vertex ? to : this.getVertex(to); - const existingEdges = this.getEdges(type, from, to); if (this.getEdge(type, from, to)) { throw new Error(`Edge ${type} from ${from.id} to ${to.id} already exists`); } + const existingEdges = this.getEdges(null, from, to); const edge = this.setEdgeWeight(type, from, to, weight, data, options); from.edges.from.push(edge); to.edges.to.push(edge); diff --git a/src/index.css b/src/index.css index b41b51c..cfa67b0 100644 --- a/src/index.css +++ b/src/index.css @@ -26,6 +26,9 @@ a:visited { .flex { display: flex; } +.flex-center { + align-items: center; +} .monospace { font-family: monospace; } @@ -44,8 +47,8 @@ a:visited { } .scene-controls { position: relative; - left: 15em; - top: -1em; + left: 12em; + top: -0.5em; } svg { width: 800px; @@ -61,19 +64,20 @@ td { fill: #216262 !important; } button { - margin: 5px; - margin-top: 1em; background-color: #c6f4ff; border-color: #b6b6b6; - border-radius: 5px; +} +input { + margin: 1pt; +} +button, input[type=file] { + border-radius: 4pt; + margin: 4pt; } button:disabled { background-color: #2a535e; color: #919191; } -label > input { - margin-left: 1em; -} label { font-family: monospace; font-weight: bold; @@ -82,7 +86,8 @@ label { } label > div { display: inline-block; - min-width: 50px; + min-width: 5em; + margin-right: 4pt; } table { width: 100%;