From 710bddd8e47c4014d1692e16d7efaffab98adecc Mon Sep 17 00:00:00 2001 From: STEINNI Date: Sun, 22 Mar 2026 15:29:48 +0000 Subject: [PATCH] fixed chicked&egg&connectedCB issue between graflow & editor + fixed no Flow issue in graflow + Fixed nodesMove issue on displaced graflow + graflowEditor: DND ok --- buildoz.js | 3 +- bzGraflow-editor.js | 57 ++++++++++++++++++++--- bzGraflow.js | 42 +++++++++++------ graflow_examples/nodesLib/nodesTest1.html | 10 ++-- 4 files changed, 87 insertions(+), 25 deletions(-) diff --git a/buildoz.js b/buildoz.js index cfb44f5..0c69a4d 100644 --- a/buildoz.js +++ b/buildoz.js @@ -60,7 +60,8 @@ class Buildoz extends HTMLElement { fireEvent(eventName, detail){ let myname = this.tagName.toLocaleLowerCase() myname = myname.substring(myname.indexOf('-')+1) - this.dispatchEvent(new CustomEvent(`bz:${myname}:${eventName}`, { + const eventFullName = `bz:${myname}:${eventName}` + this.dispatchEvent(new CustomEvent(eventFullName, { detail, bubbles: true, composed: true, diff --git a/bzGraflow-editor.js b/bzGraflow-editor.js index 196e3cf..02e7ea0 100644 --- a/bzGraflow-editor.js +++ b/bzGraflow-editor.js @@ -16,7 +16,8 @@ class BZgrafloweditor extends Buildoz{ this.defaultAttrs = { } } - connectedCallback() { + async connectedCallback() { + await customElements.whenDefined('bz-graflow') super.connectedCallback() const nodesUrl = this.getBZAttribute('nodes') this.mainContainer = document.createElement('div') @@ -26,20 +27,64 @@ class BZgrafloweditor extends Buildoz{ this.mainContainer.append(this.nodesContainer) this.graflow = document.createElement('bz-graflow') this.graflow.setAttribute('nodes', nodesUrl) + this.graflow.setAttribute('edit', "nodesmove,editwires,dropnodes") + this.graflow.addEventListener('bz:graflow:domConnected', this.setupDropZone.bind(this)) this.mainContainer.append(this.graflow) - this.append(this.mainContainer) - + this.append(this.mainContainer) this.graflow.addEventListener('bz:graflow:nodesLoaded', this.refreshNodes.bind(this)) this.graflow.loadNodes(nodesUrl) - } refreshNodes(e){ for(const nodeType in this.graflow.nodesRegistry){ const nodeDef = this.graflow.nodesRegistry[nodeType] - this.nodesContainer.append(nodeDef.cloneNode(true)) + if(nodeDef.dataset.editor=='exclude') continue + const node = nodeDef.cloneNode(true) + this.makeNodeDraggable(node) + this.nodesContainer.append(node) } - + } + + makeNodeDraggable(node){ + node.draggable = true + node.style.cursor = 'pointer' + node.addEventListener('dragstart', (evt) => { + evt.dataTransfer.setData('text/plain', node.dataset.nodetype) + evt.dataTransfer.effectAllowed = 'copy' + evt.dataTransfer.setDragImage(node, evt.offsetX, evt.offsetY) + }) + } + + onNodeDragEnd(evt){ + console.log('drag end', evt) + evt.dataTransfer.clearData() + } + + setupDropZone(){ + const dropZone = this.graflow.wiresContainer + const nodesContainer = this.graflow.nodesContainer + dropZone.addEventListener('dragover', (evt) => { + evt.preventDefault() + evt.dataTransfer.dropEffect = 'copy' + }) + dropZone.addEventListener('drop', (evt) => { + evt.preventDefault() + const nodeType = evt.dataTransfer.getData('text/plain') + if(!nodeType || !(nodeType in this.graflow.nodesRegistry)) return + const rect = nodesContainer.getBoundingClientRect() + const x = evt.clientX - rect.left + nodesContainer.scrollLeft + const y = evt.clientY - rect.top + nodesContainer.scrollTop + const id = 'n' + crypto.randomUUID().replace(/-/g, '').slice(0, 8) + this.graflow.addNode({ id, nodeType, coords: { x, y } }) + for(const node of this.graflow.flow.nodes){ + if(node.id == id){ + node.coords.x = x + node.coords.y = y + break + } + } + this.graflow.refresh() + }) } } Buildoz.define('grafloweditor', BZgrafloweditor) \ No newline at end of file diff --git a/bzGraflow.js b/bzGraflow.js index a39b3a9..91ede82 100644 --- a/bzGraflow.js +++ b/bzGraflow.js @@ -66,10 +66,6 @@ class BZgraflow extends Buildoz{ connectedCallback() { super.connectedCallback() - const flowUrl = this.getBZAttribute('flow') - if(!flowUrl) return // Be tolerant: maybe injected later from JS above - // If attribute "isolated" is present, render inside a shadow root. - // Otherwise, render in light DOM (no shadow DOM). this.hostContainer = document.createElement('div') this.hostContainer.classList.add('bzgf-main-container') this.mainContainer = this.hasAttribute('isolated') @@ -96,7 +92,10 @@ class BZgraflow extends Buildoz{ this.NodesReceiver = new DroppingNodes(this, '.bzgf-node') } } - this.loadFlow(flowUrl) + this.fireEvent('domConnected', { graflow: this }) + const flowUrl = this.getBZAttribute('flow') + if(flowUrl) this.loadFlow(flowUrl) + else this.initFlow() } error(msg, err){ @@ -126,6 +125,10 @@ class BZgraflow extends Buildoz{ this.fireEvent('flowLoaded', { url: url }) } + initFlow(){ + this.flow = { nodes: [], links: [] } + } + async loadNodes(url) { const res = await fetch(url+'?'+crypto.randomUUID()) const html = await res.text() @@ -1216,18 +1219,18 @@ class MovingNodes{ handle = node.querySelector(this.handleSelector) if(e.target != handle) return } - - - + const rect = node.getBoundingClientRect() - + const parentBB = this.nodesContainer.getBoundingClientRect() + const offsetX = rect.left - parentBB.left + this.nodesContainer.scrollLeft + const offsetY = rect.top - parentBB.top + this.nodesContainer.scrollTop this.state = { node, handle, startX: e.clientX, startY: e.clientY, - offsetX: rect.left, - offsetY: rect.top + offsetX, + offsetY } const x = e.clientX - this.state.startX + this.state.offsetX const y = e.clientY - this.state.startY + this.state.offsetY @@ -1252,11 +1255,20 @@ class MovingNodes{ pointerUp(e){ if(!this.state) return - this.state.node.releasePointerCapture(e.pointerId) - this.state.node.style.pointerEvents = '' + const { node, startX, startY, offsetX, offsetY } = this.state + const x = e.clientX - startX + offsetX + const y = e.clientY - startY + offsetY + node.releasePointerCapture(e.pointerId) + node.style.pointerEvents = '' + for(const n of this.graflow.flow.nodes){ + if(n.id == node.dataset.id){ + n.coords.x = x + n.coords.y = y + break + } + } + this.graflow.fireEvent('nodeMoved', { nodeId: node.dataset.id, x, y }) this.state = null - - this.graflow.fireEvent('nodeMoved', { nodeId: this.state.node.dataset.id, x: this.state.x, y: this.state.y }) } } diff --git a/graflow_examples/nodesLib/nodesTest1.html b/graflow_examples/nodesLib/nodesTest1.html index e52008f..564721a 100644 --- a/graflow_examples/nodesLib/nodesTest1.html +++ b/graflow_examples/nodesLib/nodesTest1.html @@ -110,6 +110,7 @@ width:3em; height:3em; padding: 2px; + border: none; } .bzgf-node[data-nodetype="refnodein"] .body, .bzgf-node[data-nodetype="refnodeout"] .body{ border-radius: 50%; @@ -118,6 +119,10 @@ display: flex; align-items: center; justify-content: center; + margin:0; + } + .bzgf-node[data-nodetype="refnodein"] .port, .bzgf-node[data-nodetype="refnodeout"] .port{ + top: 50%; } .bzgf-node[data-nodetype="refnodein"] .body{ background: #0F0; } .bzgf-node[data-nodetype="refnodeout"] .body{ background: #FF0; } @@ -209,16 +214,15 @@ -