1
0
mirror of https://github.com/node-red/node-red.git synced 2023-10-10 13:36:53 +02:00

Catch node can target specific nodes

This commit is contained in:
Nick O'Leary 2015-08-13 13:58:19 +01:00
parent c64b5c2850
commit 3a6192bf73
5 changed files with 378 additions and 125 deletions

View File

@ -637,16 +637,20 @@ RED.editor = (function() {
} }
$("#dialog-form").find('[data-i18n]').each(function() { $("#dialog-form").find('[data-i18n]').each(function() {
var current = $(this).attr("data-i18n"); var current = $(this).attr("data-i18n");
if (current.indexOf(":") === -1) { var keys = current.split(";");
var prefix = ""; for (var i=0;i<keys.length;i++) {
if (current.indexOf("[")===0) { var key = keys[i];
var parts = current.split("]"); if (key.indexOf(":") === -1) {
prefix = parts[0]+"]"; var prefix = "";
current = parts[1]; if (key.indexOf("[")===0) {
var parts = key.split("]");
prefix = parts[0]+"]";
key = parts[1];
}
keys[i] = prefix+ns+":"+key;
} }
$(this).attr("data-i18n",prefix+ns+":"+current);
} }
$(this).attr("data-i18n",keys.join(";"));
}); });
$('<input type="text" style="display: none;" />').appendTo("#dialog-form"); $('<input type="text" style="display: none;" />').appendTo("#dialog-form");
prepareEditDialog(node,node._def,"node-input"); prepareEditDialog(node,node._def,"node-input");

View File

@ -15,6 +15,25 @@
--> -->
<script type="text/x-red" data-template-name="catch"> <script type="text/x-red" data-template-name="catch">
<div class="form-row">
<label style="width: auto" for="node-input-scope" data-i18n="catch.label.source"></label>
<select id="node-input-scope-select">
<option value="all" data-i18n="catch.scope.all"></option>
<option value="target" data-i18n="catch.scope.selected"></options>
</select>
</div>
<div class="form-row node-input-target-row" style="display: none;">
<div id="node-input-catch-target-container-div" style="position: relative; box-sizing: border-box; border-radius: 2px; height: 180px; border: 1px solid #ccc;overflow:hidden; ">
<div style="box-sizing: border-box; line-height: 20px; font-size: 0.8em; border-bottom: 1px solid #ddd; height: 20px;">
<input type="checkbox" data-i18n="[title]catch.label.selectAll" id="node-input-target-node-checkbox-all" style="width: 30px; margin: 0 2px 1px 2px;">
<div style="display: inline-block;"><a id="node-input-target-sort-label" href="#" data-i18n="[title]catch.label.sortByLabel"><span data-i18n="catch.label.node"></span> <i class="node-input-catch-sort-label-a fa fa-caret-down"></i><i class="node-input-catch-sort-label-d fa fa-caret-up"></i></a></div>
<div style="position: absolute; right: 10px; width: 50px; display: inline-block; text-align: right;"><a id="node-input-target-sort-type" href="#" data-i18n="[title]catch.label.sortByType"><i class="node-input-catch-sort-sublabel-a fa fa-caret-down"></i><i class="node-input-catch-sort-sublabel-d fa fa-caret-up"></i> <span data-i18n="catch.label.type"></span></a></div>
</div>
<div style="background: #fbfbfb; box-sizing: border-box; position:absolute; top:20px;bottom:0;left:0px;right:0px; overflow-y: scroll; overflow-x: hidden;">
<ul id="node-input-catch-target-container" style=" list-style-type:none; margin: 0;"></ul>
</div>
</div>
</div>
<div class="form-row"> <div class="form-row">
<label for="node-input-name"><i class="fa fa-tag"></i> <span data-i18n="common.label.name"></span></label> <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"> <input type="text" id="node-input-name" data-i18n="[placeholder]common.label.name">
@ -41,22 +60,230 @@
</p> </p>
<p>If the message already had a <code>error</code> property, it is copied to <code>_error</code>.</p> <p>If the message already had a <code>error</code> property, it is copied to <code>_error</code>.</p>
</script> </script>
<style>
#node-input-catch-target-container {
position: relative;
}
#node-input-catch-target-container li {
padding: 2px 5px;
background: none;
font-size: 0.8em;
margin:0;
white-space: nowrap;
}
#node-input-catch-target-container li label {
margin-bottom: 0;
width: 100%;
}
#node-input-catch-target-container li label input {
vertical-align: top;
width:15px;
margin-right: 10px;
}
#node-input-catch-target-container li:hover,
#node-input-catch-target-container li:hover .node-input-target-node-sublabel {
background: #f0f0f0;
}
.node-input-target-node-sublabel {
position:absolute;
right: 0px;
padding-right: 10px;
padding-left: 10px;
font-size: 0.8em;
background: #fbfbfb;
}
</style>
<script type="text/javascript"> <script type="text/javascript">
RED.nodes.registerType('catch',{ RED.nodes.registerType('catch',{
category: 'input', category: 'input',
color:"#e49191", color:"#e49191",
defaults: { defaults: {
name: {value:""} name: {value:""},
scope: {value:null}
}, },
inputs:0, inputs:0,
outputs:1, outputs:1,
icon: "alert.png", icon: "alert.png",
label: function() { label: function() {
return this.name||this._("catch.catch"); return this.name||this.scope?this._("catch.catchNodes",{number:this.scope.length}):this._("catch.catch");
}, },
labelStyle: function() { labelStyle: function() {
return this.name?"node_label_italic":""; return this.name?"node_label_italic":"";
},
oneditprepare: function() {
var nodeList = $("#node-input-catch-target-container");
var node = this;
function createNodeList() {
node.scope = node.scope || [];
nodeList.empty();
var candidateNodes = RED.nodes.filterNodes({z:node.z});
var allChecked = true;
candidateNodes.forEach(function(n) {
if (n.id === node.id) {
return;
}
var isChecked = node.scope.indexOf(n.id) !== -1;
allChecked = allChecked && isChecked;
var container = $('<li/>',{class:"node-input-target-node"});
var row = $('<label/>',{for:"node-input-target-node-"+n.id}).appendTo(container);
$('<input>',{type:"checkbox",class:"node-input-target-node-checkbox",id:"node-input-target-node-"+n.id})
.data('node-id',n.id)
.prop('checked', isChecked)
.appendTo(row);
container.on('mouseover',function(e) {
n.highlighted = true;
n.dirty = true;
RED.view.redraw();
});
container.on('mouseout',function(e) {
n.highlighted = false;
n.dirty = true;
RED.view.redraw();
});
var labelSpan = $('<span>');
var nodeDef = RED.nodes.getType(n.type);
var label;
var sublabel;
if (nodeDef) {
var l = nodeDef.label;
label = (typeof l === "function" ? l.call(n) : l)||"";
sublabel = n.type;
if (sublabel.indexOf("subflow:") === 0) {
var subflowId = sublabel.substring(8);
var subflow = RED.nodes.subflow(subflowId);
sublabel = "subflow : "+subflow.name;
}
}
if (!nodeDef || !label) {
label = n.type;
}
$('<span>',{class:"node-input-target-node-label",style:"white-space:nowrap"}).text(label).appendTo(row);
if (sublabel) {
$('<span>',{class:"node-input-target-node-sublabel"}).text(sublabel).appendTo(row);
}
container.appendTo(nodeList);
});
$(".node-input-target-node-checkbox").change(function() {
if (!this.checked) {
$("#node-input-target-node-checkbox-all").prop('checked',false);
}
});
$("#node-input-target-node-checkbox-all").prop('checked',allChecked);
sortNodeList('label');
}
function sortNodeList(sortOn) {
var currentSort = nodeList.data('currentSort');
var currentSortOrder = nodeList.data('currentSortOrder');
if (!currentSort) {
currentSort = sortOn;
currentSortOrder = 'a';
} else {
if (currentSort === sortOn) {
currentSortOrder = (currentSortOrder === 'a'?'d':'a');
} else {
currentSortOrder = 'a';
}
currentSort = sortOn;
}
nodeList.data('currentSort',currentSort);
nodeList.data('currentSortOrder',currentSortOrder);
$("#node-input-catch-target-container-div .fa").hide();
$(".node-input-catch-sort-"+currentSort+"-"+currentSortOrder).show();
var items = nodeList.find("li").get();
items.sort(function(a,b) {
var labelA = $(a).find(".node-input-target-node-"+currentSort).text().toLowerCase();
var labelB = $(b).find(".node-input-target-node-"+currentSort).text().toLowerCase();
if (labelA < labelB) { return currentSortOrder==='a'?-1:1; }
if (labelA > labelB) { return currentSortOrder==='a'?1:-1; }
return 0;
});
$.each(items, function(i, li){
nodeList.append(li);
});
}
$("#node-input-target-sort-label").click(function(e) {
e.preventDefault();
sortNodeList('label');
});
$("#node-input-target-sort-type").click(function(e) {
e.preventDefault();
sortNodeList('sublabel')
});
$("#node-input-target-node-checkbox-all").change(function() {
$(".node-input-target-node-checkbox").prop('checked',this.checked);
})
$("#node-input-scope-select").change(function(e) {
var scope = $(this).children("option:selected").val();
if (scope === "target") {
createNodeList();
$(".node-input-target-row").show();
} else {
$(".node-input-target-row").hide();
}
});
if (this.scope == null) {
$("#node-input-scope-select").val("all");
} else {
$("#node-input-scope-select").val("target");
}
$("#node-input-scope-select").change();
function dialogResize() {
var rows = $("#dialog-form>div:not(.node-input-target-row)");
var height = $("#dialog-form").height();
for (var i=0;i<rows.size();i++) {
height -= $(rows[i]).outerHeight(true);
}
var editorRow = $("#dialog-form>div.node-input-target-row");
height -= (parseInt(editorRow.css("marginTop"))+parseInt(editorRow.css("marginBottom")));
$("#node-input-catch-target-container-div").css("height",height+"px");
};
$( "#dialog" ).on("dialogresize", dialogResize);
$( "#dialog" ).one("dialogopen", function(ev) {
var size = $( "#dialog" ).dialog('option','sizeCache-catch');
if (size) {
$("#dialog").dialog('option','width',size.width);
$("#dialog").dialog('option','height',size.height);
dialogResize();
}
});
$( "#dialog" ).one("dialogclose", function(ev,ui) {
$( "#dialog" ).off("dialogresize",dialogResize);
});
},
oneditsave: function() {
var scope = $("#node-input-scope-select").children("option:selected").val();
if (scope === 'all') {
this.scope = null;
} else {
var node = this;
node.scope = [];
$(".node-input-target-node-checkbox").each(function(n) {
if ($(this).prop("checked")) {
node.scope.push($(this).data('node-id'));
}
})
}
} }
}); });
</script> </script>

View File

@ -20,6 +20,7 @@ module.exports = function(RED) {
function CatchNode(n) { function CatchNode(n) {
RED.nodes.createNode(this,n); RED.nodes.createNode(this,n);
var node = this; var node = this;
this.scope = n.scope;
this.on("input",function(msg) { this.on("input",function(msg) {
this.send(msg); this.send(msg);
}); });

View File

@ -68,7 +68,20 @@
} }
}, },
"catch": { "catch": {
"catch": "catch" "catch": "catch all",
"catchNodes": "catch (__number__)",
"label": {
"source": "Catch errors from",
"node": "node",
"type": "type",
"selectAll": "select all",
"sortByLabel": "sort by label",
"sortByType": "sort by type"
},
"scope": {
"all": "all nodes",
"selected": "selected nodes"
}
}, },
"debug": { "debug": {
"output": "Output", "output": "Output",

View File

@ -221,7 +221,8 @@ function createCatchNodeMap(nodes) {
for (id in nodes) { for (id in nodes) {
if (nodes.hasOwnProperty(id)) { if (nodes.hasOwnProperty(id)) {
if (nodes[id].type === "catch") { if (nodes[id].type === "catch") {
catchNodes[nodes[id].z] = nodes[id]; catchNodes[nodes[id].z] = catchNodes[nodes[id].z] || [];
catchNodes[nodes[id].z].push(nodes[id]);
} }
} }
} }
@ -245,7 +246,8 @@ function createCatchNodeMap(nodes) {
} }
} }
if (catchNodes[z]) { if (catchNodes[z]) {
catchNodes[id] = catchNodes[z]; catchNodes[id] = catchNodes[id]||[];
catchNodes[id].push(catchNodes[z]);
} }
} }
} }
@ -744,45 +746,51 @@ function diffFlow(flow,config) {
Flow.prototype.handleError = function(node,logMessage,msg) { Flow.prototype.handleError = function(node,logMessage,msg) {
var targetCatchNode = null; var count = 1;
if (this.catchNodeMap[node.z]) { if (msg && msg.hasOwnProperty("error")) {
targetCatchNode = this.catchNodeMap[node.z]; if (msg.error.hasOwnProperty("source")) {
} else if (this.activeNodes[node.z] && this.catchNodeMap[this.activeNodes[node.z].z]) { if (msg.error.source.id === node.id) {
targetCatchNode = this.catchNodeMap[this.activeNodes[node.z].z]; count = msg.error.source.count+1;
} if (count === 10) {
node.warn(Log._("nodes.flow.error-loop"));
if (targetCatchNode) { return;
var count = 1;
if (msg && msg.hasOwnProperty("error")) {
if (msg.error.hasOwnProperty("source")) {
if (msg.error.source.id === node.id) {
count = msg.error.source.count+1;
if (count === 10) {
node.warn(Log._("nodes.flow.error-loop"));
return;
}
} }
} }
} }
}
var errorMessage; var targetCatchNodes = null;
if (msg) { if (this.catchNodeMap[node.z]) {
errorMessage = redUtil.cloneMessage(msg); targetCatchNodes = this.catchNodeMap[node.z];
} else { } else if (this.activeNodes[node.z] && this.catchNodeMap[this.activeNodes[node.z].z]) {
errorMessage = {}; targetCatchNodes = this.catchNodeMap[this.activeNodes[node.z].z];
} }
if (errorMessage.hasOwnProperty("error")) {
errorMessage._error = errorMessage.error; if (targetCatchNodes) {
} targetCatchNodes.forEach(function(targetCatchNode) {
errorMessage.error = { console.log(targetCatchNode.scope);
message: logMessage.toString(), if (targetCatchNode.scope && targetCatchNode.scope.indexOf(node.id) === -1) {
source: { return;
id: node.id,
type: node.type,
count: count
} }
}; var errorMessage;
targetCatchNode.receive(errorMessage); if (msg) {
errorMessage = redUtil.cloneMessage(msg);
} else {
errorMessage = {};
}
if (errorMessage.hasOwnProperty("error")) {
errorMessage._error = errorMessage.error;
}
errorMessage.error = {
message: logMessage.toString(),
source: {
id: node.id,
type: node.type,
count: count
}
};
targetCatchNode.receive(errorMessage);
})
} }
} }