mirror of
https://github.com/The-Low-Code-Foundation/OpenNoodl.git
synced 2026-01-12 23:32:55 +01:00
Initial commit
Co-Authored-By: Eric Tuvesson <eric.tuvesson@gmail.com> Co-Authored-By: mikaeltellhed <2311083+mikaeltellhed@users.noreply.github.com> Co-Authored-By: kotte <14197736+mrtamagotchi@users.noreply.github.com> Co-Authored-By: Anders Larsson <64838990+anders-topp@users.noreply.github.com> Co-Authored-By: Johan <4934465+joolsus@users.noreply.github.com> Co-Authored-By: Tore Knudsen <18231882+torekndsn@users.noreply.github.com> Co-Authored-By: victoratndl <99176179+victoratndl@users.noreply.github.com>
This commit is contained in:
284
packages/noodl-runtime/src/editormodeleventshandler.js
Normal file
284
packages/noodl-runtime/src/editormodeleventshandler.js
Normal file
@@ -0,0 +1,284 @@
|
||||
"use strict";
|
||||
|
||||
function difference(array1, array2) {
|
||||
const valueSet = new Set(array2);
|
||||
return array1.filter(e => !valueSet.has(e));
|
||||
}
|
||||
|
||||
async function handleEvent(context, graphModel, event) {
|
||||
|
||||
function applyPortDelta(nodeModel, newPorts) {
|
||||
var inputPorts = {};
|
||||
var outputPorts = {};
|
||||
|
||||
newPorts.forEach(function(port) {
|
||||
//some ports are incorrectly named outputs instead of output, patch it here so
|
||||
//the rest of the code doesn't need to care
|
||||
if(port && port.plug === "outputs") {
|
||||
port.plug = "output";
|
||||
}
|
||||
|
||||
if(port.plug === 'input' || port.plug === 'input/output') {
|
||||
inputPorts[port.name] = port;
|
||||
}
|
||||
if(port.plug === 'output' || port.plug === 'input/output') {
|
||||
outputPorts[port.name] = port;
|
||||
}
|
||||
});
|
||||
|
||||
var existingInputs = Object.keys(nodeModel.getInputPorts());
|
||||
|
||||
var inputPortsToRemove = difference(existingInputs, Object.keys(inputPorts));
|
||||
var inputPortsToAdd = difference(Object.keys(inputPorts), existingInputs);
|
||||
|
||||
// Update port types if it has changed
|
||||
nodeModel.updateInputPortTypes(inputPorts);
|
||||
|
||||
// Remove and add input ports
|
||||
inputPortsToRemove.forEach(nodeModel.removeInputPortWithName.bind(nodeModel));
|
||||
inputPortsToAdd.forEach(function(portName) {
|
||||
nodeModel.addInputPort(inputPorts[portName]);
|
||||
if(nodeModel.parameters && nodeModel.parameters.hasOwnProperty(portName)) {
|
||||
setInputValueOnNodeInstancesWithModel(context.rootComponent.nodeScope, nodeModel, portName, nodeModel.parameters[portName]);
|
||||
}
|
||||
});
|
||||
|
||||
// Update port types if it has changed
|
||||
nodeModel.updateOutputPortTypes(outputPorts);
|
||||
|
||||
// Remove and add output ports
|
||||
var existingOutputs = Object.keys(nodeModel.getOutputPorts());
|
||||
|
||||
var outputPortsToRemove = difference(existingOutputs, Object.keys(outputPorts));
|
||||
var outputPortsToAdd = difference(Object.keys(outputPorts), existingOutputs);
|
||||
|
||||
outputPortsToRemove.forEach(nodeModel.removeOutputPortWithName.bind(nodeModel));
|
||||
outputPortsToAdd.forEach(function(portName) {
|
||||
nodeModel.addOutputPort(outputPorts[portName]);
|
||||
});
|
||||
}
|
||||
|
||||
function setInputValueOnNodeInstancesWithModel(nodeScope, nodeModel, port, value) {
|
||||
var nodes = nodeScope.getNodesWithIdRecursive(nodeModel.id);
|
||||
nodes.forEach(function(node) {
|
||||
node.queueInput(port, value);
|
||||
});
|
||||
}
|
||||
|
||||
var componentModel;
|
||||
if(event.componentName) {
|
||||
componentModel = graphModel.getComponentWithName(event.componentName);
|
||||
if(!componentModel) {
|
||||
//if we haven't received this component yet, just ignore the delta update
|
||||
return;
|
||||
}
|
||||
}
|
||||
|
||||
//some ports are incorrectly named outputs instead of output, patch it here so
|
||||
//the rest of the code doesn't need to care
|
||||
if(event.port && event.port.plug === "outputs") {
|
||||
event.port.plug = "output";
|
||||
}
|
||||
|
||||
var eventHandlers = {
|
||||
nodeAdded: function(event) {
|
||||
componentModel.importEditorNodeData(event.model, event.parentId, event.childIndex);
|
||||
},
|
||||
nodeRemoved: async function(event) {
|
||||
if(componentModel.hasNodeWithId(event.model.id)) {
|
||||
await componentModel.removeNodeWithId(event.model.id);
|
||||
}
|
||||
},
|
||||
connectionAdded: function(event) {
|
||||
componentModel.addConnection(event.model);
|
||||
},
|
||||
connectionRemoved: function(event) {
|
||||
componentModel.removeConnection(event.model);
|
||||
|
||||
//revert to default value or parameter if this was the last connection to that port
|
||||
var targetNodeModel = componentModel.getNodeWithId(event.model.targetId);
|
||||
if(componentModel.getConnectionsToPort(targetNodeModel.id, event.model.targetId).length === 0) {
|
||||
var value = targetNodeModel.parameters[event.model.targetPort];
|
||||
if(value === undefined) {
|
||||
value = context.getDefaultValueForInput(targetNodeModel.type, event.model.targetPort);
|
||||
}
|
||||
|
||||
setInputValueOnNodeInstancesWithModel(context.rootComponent.nodeScope, targetNodeModel, event.model.targetPort, value);
|
||||
}
|
||||
|
||||
},
|
||||
parameterChanged: function(event) {
|
||||
|
||||
const nodeModel = componentModel.getNodeWithId(event.nodeId);
|
||||
if(nodeModel === undefined) {
|
||||
console.log("parameterChanged: Unknown node id",event);
|
||||
return;
|
||||
}
|
||||
|
||||
//did we get a bunch of parameters at once?
|
||||
if(event.parameters) {
|
||||
//note: some props might be deleted, then they only exist in oldParameters
|
||||
const allParams = new Set(Object.keys(event.parameters).concat(Object.keys(event.oldParameters)));
|
||||
for(const param of allParams) {
|
||||
nodeModel.setParameter(param, event.parameters[param]);
|
||||
}
|
||||
}
|
||||
|
||||
//did we get a single parameters?
|
||||
if(event.parameterName) {
|
||||
nodeModel.setParameter(event.parameterName, event.parameterValue, event.state);
|
||||
}
|
||||
},
|
||||
nodeAttached: function(event) {
|
||||
componentModel.setNodeParent(componentModel.getNodeWithId(event.nodeId), componentModel.getNodeWithId(event.parentId), event.childIndex);
|
||||
},
|
||||
nodeDetached: function(event) {
|
||||
componentModel.setNodeParent(componentModel.getNodeWithId(event.nodeId), null);
|
||||
componentModel.addRootId(event.nodeId);
|
||||
},
|
||||
componentAdded: function(event) {
|
||||
graphModel.importComponentFromEditorData(event.model);
|
||||
},
|
||||
componentRemoved: async function(event) {
|
||||
await graphModel.removeComponentWithName(event.componentName);
|
||||
},
|
||||
rootAdded: function(event) {
|
||||
componentModel.addRootId(event.nodeId);
|
||||
},
|
||||
portAdded: function(event) {
|
||||
var nodeModel = componentModel.getNodeWithId(event.nodeId);
|
||||
if(event.port.plug === "input" || event.port.plug === "input/output") {
|
||||
nodeModel.addInputPort(event.port);
|
||||
|
||||
//if node already has an old value for this port, set that value on all instances of the node
|
||||
//example: expression a+b, a=1, b=2. User removes b and then adds it again, the value 2 should be restored since it's still in the model
|
||||
if(nodeModel.parameters.hasOwnProperty(event.port)) {
|
||||
setInputValueOnNodeInstancesWithModel(context.rootComponent.nodeScope, nodeModel, event.port, nodeModel.parameters[event.port]);
|
||||
}
|
||||
}
|
||||
if(event.port.plug === "output" || event.port.plug === "input/output") {
|
||||
nodeModel.addOutputPort(event.port);
|
||||
}
|
||||
},
|
||||
portRemoved: function(event) {
|
||||
var nodeModel = componentModel.getNodeWithId(event.nodeId);
|
||||
if(event.port.plug === "input" || event.port.plug === "input/output") {
|
||||
nodeModel.removeInputPortWithName(event.port.name);
|
||||
}
|
||||
if(event.port.plug === "output" || event.port.plug === "input/output") {
|
||||
nodeModel.removeOutputPortWithName(event.port.name);
|
||||
}
|
||||
},
|
||||
nodePortRenamed: function(event) {
|
||||
if(event.port.plug === "input" || event.port.plug === "input/output") {
|
||||
componentModel.renameInputPortOnNodeWithId(event.nodeId, event.oldName, event.port.name);
|
||||
}
|
||||
if(event.port.plug === "output" || event.port.plug === "input/output") {
|
||||
componentModel.renameOutputPortOnNodeWithId(event.nodeId, event.oldName, event.port.name);
|
||||
}
|
||||
var node = componentModel.getNodeWithId(event.nodeId);
|
||||
if(node.type === "Component Inputs") {
|
||||
componentModel.addInputPort(event.port);
|
||||
graphModel.getNodesWithType(componentModel.name).forEach(function(componentInstance) {
|
||||
componentInstance.component.renameInputPortOnNodeWithId(componentInstance.id, event.oldName, event.port.name);
|
||||
});
|
||||
componentModel.removeInputPortWithName(event.oldName);
|
||||
}
|
||||
else if(node.type === "Component Outputs") {
|
||||
componentModel.addOutputPort(event.port);
|
||||
graphModel.getNodesWithType(componentModel.name).forEach(function(componentInstance) {
|
||||
componentInstance.component.renameOutputPortOnNodeWithId(componentInstance.id, event.oldName, event.port.name);
|
||||
});
|
||||
componentModel.removeOutputPortWithName(event.oldName);
|
||||
}
|
||||
},
|
||||
componentPortsUpdated: function(event) {
|
||||
applyPortDelta(componentModel, event.ports);
|
||||
},
|
||||
instancePortsChanged: function(event) {
|
||||
if(!componentModel.hasNodeWithId(event.nodeId)) return;
|
||||
var nodeModel = componentModel.getNodeWithId(event.nodeId);
|
||||
applyPortDelta(nodeModel, event.ports);
|
||||
},
|
||||
componentRenamed: function(event) {
|
||||
graphModel.renameComponent(event.oldName, event.newName);
|
||||
},
|
||||
settingsChanged: function(event) {
|
||||
graphModel.setSettings(event.settings);
|
||||
},
|
||||
metadataChanged: function(event) {
|
||||
graphModel.setMetaData(event.key,event.data);
|
||||
},
|
||||
componentMetadataChanged: function(event) {
|
||||
const c = graphModel.getComponentWithName(event.componentName);
|
||||
if(!c) return;
|
||||
c.setMetadata(event.key, event.data);
|
||||
},
|
||||
variantParametersChanged: function(event) {
|
||||
if(event.variant) {
|
||||
//we got the whole variant
|
||||
graphModel.updateVariant(event.variant);
|
||||
}
|
||||
else {
|
||||
//we got a specific value to update
|
||||
graphModel.updateVariantParameter(event.variantName, event.variantTypeName, event.parameterName, event.parameterValue, event.state);
|
||||
|
||||
//check if value has been deleted from the variant
|
||||
if(event.parameterValue === undefined) {
|
||||
//all active nodes with this variant will have to revert back to the default value, if they don't have local overrides
|
||||
const variant = graphModel.getVariant(event.variantTypeName, event.variantName);
|
||||
const nodes = context.rootComponent.nodeScope.getAllNodesWithVariantRecursive(variant);
|
||||
nodes.forEach(node => {
|
||||
node.queueInput(event.parameterName, node.getParameter(event.parameterName));
|
||||
});
|
||||
}
|
||||
}
|
||||
},
|
||||
variantDeleted: function(event) {
|
||||
graphModel.deleteVariant(event.variantTypeName, event.variantName);
|
||||
},
|
||||
variantChanged: function(event) {
|
||||
const nodeModel = componentModel.getNodeWithId(event.nodeId);
|
||||
const variant = graphModel.getVariant(nodeModel.type, event.variantName);
|
||||
|
||||
nodeModel.setVariant(variant);
|
||||
},
|
||||
variantRenamed: function(event) {
|
||||
const variant = graphModel.getVariant(event.variantTypeName, event.oldVariantName);
|
||||
if(variant) {
|
||||
variant.name = variant.variantName;
|
||||
}
|
||||
},
|
||||
defaultStateTransitionChanged: function(event) {
|
||||
const nodeModel = componentModel.getNodeWithId(event.nodeId);
|
||||
nodeModel.setDefaultStateTransition(event.curve, event.state);
|
||||
},
|
||||
stateTransitionsChanged: function(event) {
|
||||
const nodeModel = componentModel.getNodeWithId(event.nodeId);
|
||||
if(event.parameterName) {
|
||||
nodeModel.setStateTransitionParamter(event.parameterName, event.curve, event.state);
|
||||
}
|
||||
},
|
||||
variantDefaultStateTransitionChanged: function(event) {
|
||||
graphModel.updateVariantDefaultStateTransition(event.variantName, event.variantTypeName, event.curve, event.state);
|
||||
},
|
||||
variantStateTransitionsChanged: function(event) {
|
||||
graphModel.updateVariantStateTransition(event);
|
||||
},
|
||||
routerIndexChanged: function(event) {
|
||||
graphModel.routerIndex = event.data;
|
||||
}
|
||||
};
|
||||
|
||||
if(eventHandlers.hasOwnProperty(event.type)) {
|
||||
await eventHandlers[event.type](event);
|
||||
context.scheduleUpdate();
|
||||
}
|
||||
else {
|
||||
console.log('Unknown event', event);
|
||||
}
|
||||
}
|
||||
|
||||
module.exports = {
|
||||
handleEvent: handleEvent
|
||||
};
|
||||
Reference in New Issue
Block a user