node-red-contrib-routing
Version:
A Node-RED node to route incoming messages based on their topics.
153 lines (146 loc) • 6.88 kB
HTML
<script type="text/javascript">
RED.nodes.registerType('routing',{
category: 'function',
color: '#E9967A',
defaults: {
name: {value:""},
rules: {value: [{v: ""}]},
outputs: {value: 1}
},
inputs:1,
outputs:1,
outputLabels: function(index) {
var rule = this.rules[index];
if (rule.v) {
return rule.v.length > 15 ? rule.v.substring(0,15) + " …" : rule.v;
} else {
return "Default route";
}
},
icon: 'switch.png',
label: function() {
return this.name||'routing';
},
oneditprepare: function() {
var node = this;
var outputCount = $("#node-input-outputs").val("{}");
function resizeRule(rule) {
var newWidth = rule.width();
var valueField = rule.find(".node-input-rule-value");
valueField.css("width",(newWidth-70));
}
$("#node-input-rule-container").css('min-height','250px').css('min-width','450px').editableList({
addItem: function(container,i,opt) {
if (!opt.hasOwnProperty('r')) {
opt.r = {};
}
var rule = opt.r;
if (!opt.hasOwnProperty('i')) {
opt._i = Math.floor((0x99999-0x10000)*Math.random()).toString(16);
}
var row = $('<div/>').appendTo(container);
var row2 = $('<div/>',{style:"padding-top: 5px; padding-left: 175px;"}).appendTo(container);
var row3 = $('<div/>',{style:"padding-top: 5px; padding-left: 102px;"}).appendTo(container);
var valueField = $('<input/>',{class:"node-input-rule-value",type:"text",style:"margin-left: 5px;"}).appendTo(row);
var finalspan = $('<span/>',{style:"float: right;margin-top: 6px;"}).appendTo(row);
finalspan.append(' → <span class="node-input-rule-index">'+(i+1)+'</span> ');
resizeRule(container);
if (typeof rule.v != "undefined") {
valueField.val(rule.v);
}
var currentOutputs = JSON.parse(outputCount.val()||"{}");
currentOutputs[opt.hasOwnProperty('i')?opt.i:opt._i] = i;
outputCount.val(JSON.stringify(currentOutputs));
},
removeItem: function(opt) {
var currentOutputs = JSON.parse(outputCount.val()||"{}");
if (opt.hasOwnProperty('i')) {
currentOutputs[opt.i] = -1;
} else {
delete currentOutputs[opt._i];
}
var rules = $("#node-input-rule-container").editableList('items');
rules.each(function(i) {
$(this).find(".node-input-rule-index").html(i+1);
var data = $(this).data('data');
currentOutputs[data.hasOwnProperty('i')?data.i:data._i] = i;
});
outputCount.val(JSON.stringify(currentOutputs));
},
resizeItem: resizeRule,
sortItems: function(rules) {
var currentOutputs = JSON.parse(outputCount.val()||"{}");
var rules = $("#node-input-rule-container").editableList('items');
rules.each(function(i) {
$(this).find(".node-input-rule-index").html(i+1);
var data = $(this).data('data');
currentOutputs[data.hasOwnProperty('i')?data.i:data._i] = i;
});
outputCount.val(JSON.stringify(currentOutputs));
},
sortable: true,
removable: true
});
for (var i=0;i<this.rules.length;i++) {
var rule = this.rules[i];
$("#node-input-rule-container").editableList('addItem',{r:rule,i:i});
}
},
oneditsave: function() {
var rules = $("#node-input-rule-container").editableList('items');
var node = this;
node.rules = [];
rules.each(function(i) {
var value = $(this).find(".node-input-rule-value").val();
node.rules.push({
v: value
});
});
this.propertyType = $("#node-input-property").typedInput('type');
},
oneditresize: function(size) {
var rows = $("#dialog-form>div:not(.node-input-rule-container-row)");
var height = size.height;
for (var i=0;i<rows.size();i++) {
height -= $(rows[i]).outerHeight(true);
}
var editorRow = $("#dialog-form>div.node-input-rule-container-row");
height -= (parseInt(editorRow.css("marginTop"))+parseInt(editorRow.css("marginBottom")));
$("#node-input-rule-container").editableList('height',height);
}
});
</script>
<script type="text/x-red" data-template-name="routing">
<div class="form-row">
<label for="node-input-name"><i class="fa fa-tag"></i> Name</label>
<input type="text" id="node-input-name" placeholder="Name">
<input type="hidden" id="node-input-outputs"/>
</div>
<div class="form-row node-input-rule-container-row">
<ol id="node-input-rule-container"></ol>
</div>
</script>
<script type="text/x-red" data-help-name="routing">
<p>Route messages based on their topics.</p>
<h3>Details</h3>
<p>When a message arrives, the node will forward the message according to its topic and the defined routes.</p>
<p>Order of route declaration doesn't matter, the most specific route wins. It parses query strings and supports wildcard.</p>
<h3>Examples</h3>
<ol class="node-ports">
<dl class="message-properties">
<dt> (empty)
<dd> Default route</dd>
</dt>
<dt>temperature
<dd> Simple match</dd>
</dt>
<dt>iot/:sensor/temperature
<dd> <code>iot/AJ08/temperature</code> will match and <code>msg.params.sensor</code> will be <code>AJ08</code></dd>
</dt>
<dt>iot/*path
<dd> <code>iot/AJ08/humidity</code> will match and <code>msg.params.path</code> will be <code>AJ08/humidity</code></dd>
</dt>
</dl>
</ol>
<p>Check <a href="https://github.com/chrisdavies/rlite" target="_blank">rlite's documentation</a> for more information.</p>
</script>