Add link-call node and add return mode for link-out node

This commit is contained in:
Nick O'Leary
2021-09-29 10:45:00 +01:00
parent c9d1329fc2
commit b01fd24e15
10 changed files with 192 additions and 35 deletions

View File

@@ -8,6 +8,22 @@
<div class="form-row node-input-link-row"></div>
</script>
<script type="text/html" data-template-name="link out">
<div class="form-row">
<label for="node-input-name"><i class="fa fa-tag"></i> <span data-i18n="common.label.name"></span></label>
<input type="text" id="node-input-name" data-i18n="[placeholder]common.label.name">
</div>
<div class="form-row">
<label for="node-input-mode"><span data-i18n="link.outMode"></span></label>
<select id="node-input-mode" style="width: 70%">
<option value="link" selected data-i18n="link.sendToAll"></option>
<option value="return" data-i18n="link.returnToCaller"></option>
</select>
</div>
<div class="node-input-link-rows" style="position:relative; height: 30px; text-align: right;"><div style="display:inline-block"><input type="text" id="node-input-link-target-filter"></div></div>
<div class="form-row node-input-link-row node-input-link-rows"></div>
</script>
<script type="text/html" data-template-name="link call">
<div class="form-row">
<label for="node-input-name"><i class="fa fa-tag"></i> <span data-i18n="common.label.name"></span></label>
<input type="text" id="node-input-name" data-i18n="[placeholder]common.label.name">
@@ -48,7 +64,6 @@
}
});
var candidateNodes = RED.nodes.filterNodes({type:targetType});
var search = $("#node-input-link-target-filter").searchBox({
style: "compact",
delay: 300,
@@ -104,7 +119,8 @@
node: n,
label: n.name||n.id,
selected: isChecked,
checkbox: true
checkbox: node.type !== "link call",
radio: node.type === "link call"
})
}
});
@@ -129,15 +145,22 @@
function onEditSave(node) {
var flows = treeList.treeList('data');
node.links = [];
flows.forEach(function(f) {
f.children.forEach(function(n) {
if (n.selected) {
node.links.push(n.id);
}
if (node.type !== "link out" || $("node-input-mode").val() === 'link') {
flows.forEach(function(f) {
f.children.forEach(function(n) {
if (n.selected) {
node.links.push(n.id);
}
})
})
})
}
node.oldLinks.sort();
node.links.sort();
if (node.type === "link call") {
return
}
var nodeMap = {};
var length = Math.max(node.oldLinks.length,node.links.length);
for (var i=0;i<length;i++) {
@@ -195,6 +218,7 @@
outputLabels: function(i) {
return this.name||this._("link.linkIn");
},
showLabel: false,
label: function() {
return this.name||this._("link.linkIn");
},
@@ -211,25 +235,31 @@
oneditresize: resizeNodeList
});
RED.nodes.registerType('link out',{
RED.nodes.registerType('link call',{
category: 'common',
color:"#ddd",//"#87D8CF",
defaults: {
name: {value:""},
links: { value: [], type:"link in[]"}
},
align:"right",
inputs:1,
outputs:0,
icon: "link-out.svg",
inputs: 1,
outputs: 1,
icon: "link-call.svg",
inputLabels: function(i) {
return this.name||this._("link.linkOut");
return this.name||this._("link.linkCall");
},
label: function() {
return this.name||this._("link.linkOut");
if (this.name) {
return this.name;
}
if (this.links.length > 0) {
var targetNode = RED.nodes.node(this.links[0]);
return targetNode && (targetNode.name || targetNode.id);
}
return this._("link.linkCall");
},
labelStyle: function() {
return this.name?"node_label_italic":"";
return (this.name || this.links.length > 0)?"node_label_italic":"";
},
oneditprepare: function() {
onEditPrepare(this,"link in");
@@ -237,8 +267,56 @@
oneditsave: function() {
onEditSave(this);
},
oneditresize: resizeNodeList
});
RED.nodes.registerType('link out',{
category: 'common',
color:"#ddd",//"#87D8CF",
defaults: {
name: {value:""},
mode: { value: "link" },// link || return
links: { value: [], type:"link in[]"}
},
align:"right",
inputs:1,
outputs:0,
icon: function() {
if (this.mode === "return") {
return "link-return.svg";
} else {
return "link-out.svg";
}
},
inputLabels: function(i) {
return this.name||(this.mode === "return" ?this._("link.linkOutReturn"):this._("link.linkOut"));
},
showLabel: false,
label: function() {
return this.name||(this.mode === "return" ?this._("link.linkOutReturn"):this._("link.linkOut"));
},
labelStyle: function() {
return this.name?"node_label_italic":"";
},
oneditprepare: function() {
onEditPrepare(this,"link in");
$("#node-input-mode").on("change", function() {
$(".node-input-link-rows").toggle(this.value === "link")
})
if (!this.mode) {
$("#node-input-mode").val('link').trigger("change");
}
},
oneditsave: function() {
onEditSave(this);
},
onadd: onAdd,
oneditresize: resizeNodeList
});
})();
</script>

View File

@@ -17,6 +17,8 @@
module.exports = function(RED) {
"use strict";
const crypto = require("crypto");
function LinkInNode(n) {
RED.nodes.createNode(this,n);
var node = this;
@@ -40,13 +42,70 @@ module.exports = function(RED) {
function LinkOutNode(n) {
RED.nodes.createNode(this,n);
var node = this;
var mode = n.mode || "link";
var event = "node:"+n.id;
this.on("input", function(msg, send, done) {
msg._event = event;
RED.events.emit(event,msg)
send(msg);
done();
if (mode === "return") {
if (Array.isArray(msg._linkSource) && msg._linkSource.length > 0) {
var messageEvent = msg._linkSource.pop();
var returnNode = RED.nodes.getNode(messageEvent.node);
if (returnNode && returnNode.returnLinkMessage) {
returnNode.returnLinkMessage(messageEvent.id, msg);
} else {
node.warn("Return target not a link-call node")
}
} else {
node.warn("No call return target")
}
done();
} else if (mode === "link") {
send(msg);
done();
}
});
}
RED.nodes.registerType("link out",LinkOutNode);
function LinkCallNode(n) {
RED.nodes.createNode(this,n);
const node = this;
const target = n.links[0];
const messageEvents = {};
this.on("input", function(msg, send, done) {
msg._linkSource = msg._linkSource || [];
const messageEvent = {
id: crypto.randomBytes(14).toString('hex'),
node: node.id,
}
messageEvents[messageEvent.id] = { send, done };
msg._linkSource.push(messageEvent);
var targetNode = RED.nodes.getNode(target);
if (targetNode) {
targetNode.receive(msg);
}
});
this.returnLinkMessage = function(eventId, msg) {
if (Array.isArray(msg._linkSource) && msg._linkSource.length === 0) {
delete msg._linkSource;
}
const messageEvent = messageEvents[eventId];
if (messageEvent) {
delete messageEvents[eventId];
messageEvent.send(msg);
messageEvent.done();
} else {
node.warn("Unrecognised message returned")
}
}
}
RED.nodes.registerType("link call",LinkCallNode);
}